Commit c77637d172
Changed files (2)
src
test
src/parseh.cpp
@@ -36,6 +36,7 @@ struct Context {
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_type_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_value_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_decl_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> enum_type_table;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
@@ -51,6 +52,7 @@ static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, con
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table);
static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl);
+static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl);
__attribute__ ((format (printf, 3, 4)))
@@ -79,12 +81,17 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...)
fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg));
}
+static uint32_t get_next_node_index(Context *c) {
+ uint32_t result = c->codegen->next_node_index;
+ c->codegen->next_node_index += 1;
+ return result;
+}
+
static AstNode *create_node(Context *c, NodeType type) {
AstNode *node = allocate<AstNode>(1);
node->type = type;
node->owner = c->import;
- node->create_index = c->codegen->next_node_index;
- c->codegen->next_node_index += 1;
+ node->create_index = get_next_node_index(c);
return node;
}
@@ -437,18 +444,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
case Type::Record:
{
const RecordType *record_ty = static_cast<const RecordType*>(ty);
- Buf *record_name = buf_create_from_str(decl_name(record_ty->getDecl()));
- if (buf_len(record_name) == 0) {
- emit_warning(c, decl, "unhandled anonymous struct");
- return c->codegen->builtin_types.entry_invalid;
- }
-
- auto entry = type_table->maybe_get(record_name);
- if (!entry) {
- return c->codegen->builtin_types.entry_invalid;
- }
-
- return entry->value;
+ return resolve_record_decl(c, record_ty->getDecl());
}
case Type::Enum:
{
@@ -754,47 +750,39 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
}
-static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
+static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
const char *raw_name = decl_name(record_decl);
- // we have no interest in top level anonymous structs since they're
- // not exposing anything.
- if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) {
- return;
- }
-
if (!record_decl->isStruct()) {
emit_warning(c, record_decl, "skipping record %s, not a struct", raw_name);
- return;
+ return c->codegen->builtin_types.entry_invalid;
}
- Buf *bare_name = buf_create_from_str(raw_name);
- Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));
+ Buf *bare_name;
+ if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) {
+ bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c));
+ } else {
+ bare_name = buf_create_from_str(raw_name);
- if (c->struct_type_table.maybe_get(bare_name)) {
- // we've already seen it
- return;
+ auto existing_entry = c->struct_type_table.maybe_get(bare_name);
+ if (existing_entry) {
+ return existing_entry->value;
+ }
}
- RecordDecl *record_def = record_decl->getDefinition();
- if (!record_def) {
- TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name),
- c->codegen->builtin_types.entry_u8);
- c->struct_type_table.put(bare_name, typedecl_type);
+ Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));
- // this is a type that we can point to but that's it, such as `struct Foo;`.
- add_typedef_node(c, typedecl_type);
- add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
- return;
- }
TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,
ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
c->struct_type_table.put(bare_name, struct_type);
- // make an alias without the "struct_" prefix. this will get emitted at the
- // end if it doesn't conflict with anything else
- add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
+
+ RecordDecl *record_def = record_decl->getDefinition();
+ if (!record_def) {
+ return struct_type;
+ }
+
// count fields and validate
uint32_t field_count = 0;
@@ -805,8 +793,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
const FieldDecl *field_decl = *it;
if (field_decl->isBitField()) {
- emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name));
- return;
+ emit_warning(c, field_decl, "struct %s demoted to typedef - has bitfield\n", buf_ptr(bare_name));
+ return struct_type;
}
}
@@ -837,8 +825,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
type_struct_field->type_entry = resolve_qual_type(c, field_decl->getType(), field_decl);
if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {
- emit_warning(c, field_decl, "skipping struct %s - unresolved type\n", buf_ptr(bare_name));
- return;
+ emit_warning(c, field_decl, "struct %s demoted to typedef - unresolved type\n", buf_ptr(bare_name));
+ return struct_type;
}
di_element_types[i] = LLVMZigCreateDebugMemberType(c->codegen->dbuilder,
@@ -878,25 +866,52 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
struct_type->di_type = replacement_di_type;
- //////
+ return struct_type;
+}
- // now create a top level decl node for the type
- AstNode *struct_node = create_node(c, NodeTypeStructDecl);
- buf_init_from_buf(&struct_node->data.struct_decl.name, full_type_name);
- struct_node->data.struct_decl.kind = ContainerKindStruct;
- struct_node->data.struct_decl.visib_mod = VisibModExport;
- struct_node->data.struct_decl.directives = create_empty_directives(c);
- struct_node->data.struct_decl.type_entry = struct_type;
+static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
+ TypeTableEntry *struct_type = resolve_record_decl(c, record_decl);
- for (uint32_t i = 0; i < field_count; i += 1) {
- TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
- AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
- AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
- struct_node->data.struct_decl.fields.append(field_node);
+ if (struct_type->id == TypeTableEntryIdInvalid) {
+ return;
+ }
+
+ assert(struct_type->id == TypeTableEntryIdStruct);
+
+ if (c->struct_decl_table.maybe_get(&struct_type->name)) {
+ return;
+ }
+ c->struct_decl_table.put(&struct_type->name, struct_type);
+
+ // make an alias without the "struct_" prefix. this will get emitted at the
+ // end if it doesn't conflict with anything else
+ if (decl_name(record_decl)[0] != 0) {
+ add_alias(c, decl_name(record_decl), buf_ptr(&struct_type->name));
}
- normalize_parent_ptrs(struct_node);
- c->root->data.root.top_level_decls.append(struct_node);
+ if (struct_type->data.structure.complete) {
+ // now create a top level decl node for the type
+ AstNode *struct_node = create_node(c, NodeTypeStructDecl);
+ buf_init_from_buf(&struct_node->data.struct_decl.name, &struct_type->name);
+ struct_node->data.struct_decl.kind = ContainerKindStruct;
+ struct_node->data.struct_decl.visib_mod = VisibModExport;
+ struct_node->data.struct_decl.directives = create_empty_directives(c);
+ struct_node->data.struct_decl.type_entry = struct_type;
+
+ for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
+ TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+ AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
+ AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
+ struct_node->data.struct_decl.fields.append(field_node);
+ }
+
+ normalize_parent_ptrs(struct_node);
+ c->root->data.root.top_level_decls.append(struct_node);
+ } else {
+ TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name),
+ c->codegen->builtin_types.entry_u8);
+ add_typedef_node(c, typedecl_type);
+ }
}
static void visit_var_decl(Context *c, const VarDecl *var_decl) {
@@ -1253,6 +1268,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
c->global_value_table.init(8);
c->enum_type_table.init(8);
c->struct_type_table.init(8);
+ c->struct_decl_table.init(8);
c->fn_table.init(8);
c->macro_table.init(8);
c->codegen = codegen;
test/run_tests.cpp
@@ -2019,6 +2019,25 @@ static const int int_var = 13;
)SOURCE", 2,
"pub extern var extern_var: c_int;",
"pub const int_var: c_int = 13;");
+
+
+ add_parseh_case("circular struct definitions", R"SOURCE(
+struct Bar;
+
+struct Foo {
+ struct Bar *next;
+};
+
+struct Bar {
+ struct Foo *next;
+};
+ )SOURCE", 2,
+ R"SOURCE(export struct struct_Bar {
+ next: ?&struct_Foo,
+})SOURCE",
+ R"SOURCE(export struct struct_Foo {
+ next: ?&struct_Bar,
+})SOURCE");
}
static void print_compiler_invocation(TestCase *test_case) {