Skip to content

Commit

Permalink
add compile error for duplicate struct, enum, union fields
Browse files Browse the repository at this point in the history
closes #730
  • Loading branch information
andrewrk committed Jan 30, 2018
1 parent 0995a81 commit 3ef6a00
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 25 deletions.
9 changes: 9 additions & 0 deletions src/all_types.hpp
Expand Up @@ -331,12 +331,14 @@ struct TypeEnumField {
Buf *name;
BigInt value;
uint32_t decl_index;
AstNode *decl_node;
};

struct TypeUnionField {
Buf *name;
TypeEnumField *enum_field;
TypeTableEntry *type_entry;
AstNode *decl_node;
uint32_t gen_index;
};

Expand Down Expand Up @@ -961,6 +963,7 @@ struct TypeStructField {
size_t packed_bits_offset;
size_t packed_bits_size;
size_t unaligned_bit_count;
AstNode *decl_node;
};
struct TypeTableEntryStruct {
AstNode *decl_node;
Expand All @@ -982,6 +985,8 @@ struct TypeTableEntryStruct {
bool zero_bits_loop_flag;
bool zero_bits_known;
uint32_t abi_alignment; // also figured out with zero_bits pass

HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
};

struct TypeTableEntryMaybe {
Expand Down Expand Up @@ -1013,6 +1018,8 @@ struct TypeTableEntryEnum {

bool generate_name_table;
LLVMValueRef name_table;

HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
};

uint32_t type_ptr_hash(const TypeTableEntry *ptr);
Expand Down Expand Up @@ -1045,6 +1052,8 @@ struct TypeTableEntryUnion {

uint32_t union_size_bytes;
TypeTableEntry *most_aligned_union_member;

HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name;
};

struct FnGenParamInfo {
Expand Down
93 changes: 70 additions & 23 deletions src/analyze.cpp
Expand Up @@ -633,20 +633,27 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t

static void slice_type_common_init(CodeGen *g, TypeTableEntry *pointer_type, TypeTableEntry *entry) {
unsigned element_count = 2;
Buf *ptr_field_name = buf_create_from_str("ptr");
Buf *len_field_name = buf_create_from_str("len");

entry->data.structure.layout = ContainerLayoutAuto;
entry->data.structure.is_slice = true;
entry->data.structure.src_field_count = element_count;
entry->data.structure.gen_field_count = element_count;
entry->data.structure.fields = allocate<TypeStructField>(element_count);
entry->data.structure.fields[slice_ptr_index].name = buf_create_from_str("ptr");
entry->data.structure.fields_by_name.init(element_count);
entry->data.structure.fields[slice_ptr_index].name = ptr_field_name;
entry->data.structure.fields[slice_ptr_index].type_entry = pointer_type;
entry->data.structure.fields[slice_ptr_index].src_index = slice_ptr_index;
entry->data.structure.fields[slice_ptr_index].gen_index = 0;
entry->data.structure.fields[slice_len_index].name = buf_create_from_str("len");
entry->data.structure.fields[slice_len_index].name = len_field_name;
entry->data.structure.fields[slice_len_index].type_entry = g->builtin_types.entry_usize;
entry->data.structure.fields[slice_len_index].src_index = slice_len_index;
entry->data.structure.fields[slice_len_index].gen_index = 1;

entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]);
entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]);

assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type));
if (pointer_type->data.pointer.child_type->zero_bits) {
entry->data.structure.gen_field_count = 1;
Expand Down Expand Up @@ -1555,6 +1562,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
struct_type->data.structure.zero_bits_known = true;
struct_type->data.structure.complete = true;
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
struct_type->data.structure.fields_by_name.init(field_count);

ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(field_count);
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
Expand All @@ -1566,6 +1574,9 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
field->type_entry = field_types[i];
field->src_index = i;
field->gen_index = i;

auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
assert(prev_entry == nullptr);
}

struct_type->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), type_name);
Expand Down Expand Up @@ -2102,6 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {

enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
enum_type->data.enumeration.fields_by_name.init(field_count);

Scope *scope = &enum_type->data.enumeration.decls_scope->base;

Expand Down Expand Up @@ -2139,6 +2151,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
type_enum_field->name = field_node->data.struct_field.name;
type_enum_field->decl_index = field_i;
type_enum_field->decl_node = field_node;

if (field_node->data.struct_field.type != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type,
Expand All @@ -2147,6 +2160,15 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
buf_sprintf("consider 'union(enum)' here"));
}

auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
enum_type->data.enumeration.is_invalid = true;
continue;
}

AstNode *tag_value = field_node->data.struct_field.value;

// In this first pass we resolve explicit tag values.
Expand Down Expand Up @@ -2242,6 +2264,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
size_t field_count = decl_node->data.container_decl.fields.length;
struct_type->data.structure.src_field_count = (uint32_t)field_count;
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
struct_type->data.structure.fields_by_name.init(field_count);

Scope *scope = &struct_type->data.structure.decls_scope->base;

Expand All @@ -2250,13 +2273,23 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = field_node->data.struct_field.name;
type_struct_field->decl_node = field_node;

if (field_node->data.struct_field.type == nullptr) {
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
struct_type->data.structure.is_invalid = true;
continue;
}

auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
struct_type->data.structure.is_invalid = true;
continue;
}

TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
type_struct_field->type_entry = field_type;
type_struct_field->src_index = i;
Expand Down Expand Up @@ -2344,6 +2377,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
}
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.fields = allocate<TypeUnionField>(field_count);
union_type->data.unionation.fields_by_name.init(field_count);

uint32_t biggest_align_bytes = 0;

Expand Down Expand Up @@ -2395,6 +2429,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
tag_type->data.enumeration.layout = ContainerLayoutAuto;
tag_type->data.enumeration.src_field_count = field_count;
tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
tag_type->data.enumeration.fields_by_name.init(field_count);
tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
tag_type->data.enumeration.complete = true;
} else if (enum_type_node != nullptr) {
Expand Down Expand Up @@ -2424,6 +2459,16 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
Buf *field_name = field_node->data.struct_field.name;
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
union_field->name = field_node->data.struct_field.name;
union_field->decl_node = field_node;

auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
union_type->data.unionation.is_invalid = true;
continue;
}

TypeTableEntry *field_type;
if (field_node->data.struct_field.type == nullptr) {
Expand Down Expand Up @@ -2456,6 +2501,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
union_field->enum_field = &tag_type->data.enumeration.fields[i];
union_field->enum_field->name = field_name;
union_field->enum_field->decl_index = i;
union_field->enum_field->decl_node = field_node;

auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
assert(prev_entry == nullptr); // caught by union de-duplicator above

AstNode *tag_value = field_node->data.struct_field.value;
// In this first pass we resolve explicit tag values.
Expand Down Expand Up @@ -3499,37 +3548,35 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
}

TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) {
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
if (buf_eql_buf(type_enum_field->name, name)) {
return type_enum_field;
}
}
return nullptr;
assert(enum_type->id == TypeTableEntryIdEnum);
if (enum_type->data.enumeration.src_field_count == 0)
return nullptr;
auto entry = enum_type->data.enumeration.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}

TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdStruct);
assert(type_entry->data.structure.complete);
for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *field = &type_entry->data.structure.fields[i];
if (buf_eql_buf(field->name, name)) {
return field;
}
}
return nullptr;
if (type_entry->data.structure.src_field_count == 0)
return nullptr;
auto entry = type_entry->data.structure.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}

TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdUnion);
assert(type_entry->data.unionation.zero_bits_known);
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
TypeUnionField *field = &type_entry->data.unionation.fields[i];
if (buf_eql_buf(field->enum_field->name, name)) {
return field;
}
}
return nullptr;
if (type_entry->data.unionation.src_field_count == 0)
return nullptr;
auto entry = type_entry->data.unionation.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}

TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
Expand Down
2 changes: 1 addition & 1 deletion src/analyze.hpp
Expand Up @@ -60,8 +60,8 @@ bool type_is_complete(TypeTableEntry *type_entry);
bool type_is_invalid(TypeTableEntry *type_entry);
bool type_has_zero_bits_known(TypeTableEntry *type_entry);
void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
Expand Down
38 changes: 37 additions & 1 deletion test/compile_errors.zig
@@ -1,6 +1,43 @@
const tests = @import("tests.zig");

pub fn addCases(cases: &tests.CompileErrorContext) void {
cases.add("duplicate struct field",
\\const Foo = struct {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");

cases.add("duplicate union field",
\\const Foo = union {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");

cases.add("duplicate enum field",
\\const Foo = enum {
\\ Bar,
\\ Bar,
\\};
\\
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");

cases.add("calling function with naked calling convention",
\\export fn entry() void {
\\ foo();
Expand All @@ -10,7 +47,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
".tmp_source.zig:2:5: error: unable to call function with naked calling convention",
".tmp_source.zig:4:9: note: declared here");


cases.add("function with invalid return type",
\\export fn foo() boid {}
, ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'");
Expand Down

0 comments on commit 3ef6a00

Please sign in to comment.