authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-31 14:53:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-31 14:54:28-07:00
logc77637d1720bc80f97c21214596cec9ffc617d12
treedfc8f1dc16d6808a8427ee5ada1334f9cf0e1261
parentc1640a924643d0b3d3616c2a41f70918d6150301

parseh understands forward struct definitions

See #88

2 files changed, 94 insertions(+), 59 deletions(-)

src/parseh.cpp+75-59
...@@ -36,6 +36,7 @@ struct Context {...@@ -36,6 +36,7 @@ struct Context {
36 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_type_table;36 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_type_table;
37 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_value_table;37 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_value_table;
38 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;38 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;
39 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_decl_table;
39 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> enum_type_table;40 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> enum_type_table;
40 HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;41 HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
41 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;42 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...@@ -51,6 +52,7 @@ static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, con
51 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table);52 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table);
5253
53static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl);54static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl);
55static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl);
5456
5557
56__attribute__ ((format (printf, 3, 4)))58__attribute__ ((format (printf, 3, 4)))
...@@ -79,12 +81,17 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...)...@@ -79,12 +81,17 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...)
79 fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg));81 fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg));
80}82}
8183
84static uint32_t get_next_node_index(Context *c) {
85 uint32_t result = c->codegen->next_node_index;
86 c->codegen->next_node_index += 1;
87 return result;
88}
89
82static AstNode *create_node(Context *c, NodeType type) {90static AstNode *create_node(Context *c, NodeType type) {
83 AstNode *node = allocate<AstNode>(1);91 AstNode *node = allocate<AstNode>(1);
84 node->type = type;92 node->type = type;
85 node->owner = c->import;93 node->owner = c->import;
86 node->create_index = c->codegen->next_node_index;94 node->create_index = get_next_node_index(c);
87 c->codegen->next_node_index += 1;
88 return node;95 return node;
89}96}
9097
...@@ -437,18 +444,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const...@@ -437,18 +444,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
437 case Type::Record:444 case Type::Record:
438 {445 {
439 const RecordType *record_ty = static_cast<const RecordType*>(ty);446 const RecordType *record_ty = static_cast<const RecordType*>(ty);
440 Buf *record_name = buf_create_from_str(decl_name(record_ty->getDecl()));447 return resolve_record_decl(c, record_ty->getDecl());
441 if (buf_len(record_name) == 0) {
442 emit_warning(c, decl, "unhandled anonymous struct");
443 return c->codegen->builtin_types.entry_invalid;
444 }
445
446 auto entry = type_table->maybe_get(record_name);
447 if (!entry) {
448 return c->codegen->builtin_types.entry_invalid;
449 }
450
451 return entry->value;
452 }448 }
453 case Type::Enum:449 case Type::Enum:
454 {450 {
...@@ -754,47 +750,39 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {...@@ -754,47 +750,39 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
754750
755}751}
756752
757static void visit_record_decl(Context *c, const RecordDecl *record_decl) {753static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
758 const char *raw_name = decl_name(record_decl);754 const char *raw_name = decl_name(record_decl);
759755
760 // we have no interest in top level anonymous structs since they're
761 // not exposing anything.
762 if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) {
763 return;
764 }
765
766 if (!record_decl->isStruct()) {756 if (!record_decl->isStruct()) {
767 emit_warning(c, record_decl, "skipping record %s, not a struct", raw_name);757 emit_warning(c, record_decl, "skipping record %s, not a struct", raw_name);
768 return;758 return c->codegen->builtin_types.entry_invalid;
769 }759 }
770760
771 Buf *bare_name = buf_create_from_str(raw_name);761 Buf *bare_name;
772 Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));762 if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) {
763 bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c));
764 } else {
765 bare_name = buf_create_from_str(raw_name);
773766
774 if (c->struct_type_table.maybe_get(bare_name)) {767 auto existing_entry = c->struct_type_table.maybe_get(bare_name);
775 // we've already seen it768 if (existing_entry) {
776 return;769 return existing_entry->value;
770 }
777 }771 }
778772
779 RecordDecl *record_def = record_decl->getDefinition();773 Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));
780 if (!record_def) {
781 TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name),
782 c->codegen->builtin_types.entry_u8);
783 c->struct_type_table.put(bare_name, typedecl_type);
784774
785 // this is a type that we can point to but that's it, such as `struct Foo;`.
786 add_typedef_node(c, typedecl_type);
787 add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
788 return;
789 }
790775
791 TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,776 TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,
792 ContainerKindStruct, c->source_node, buf_ptr(full_type_name));777 ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
793778
794 c->struct_type_table.put(bare_name, struct_type);779 c->struct_type_table.put(bare_name, struct_type);
795 // make an alias without the "struct_" prefix. this will get emitted at the780
796 // end if it doesn't conflict with anything else781 RecordDecl *record_def = record_decl->getDefinition();
797 add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));782 if (!record_def) {
783 return struct_type;
784 }
785
798786
799 // count fields and validate787 // count fields and validate
800 uint32_t field_count = 0;788 uint32_t field_count = 0;
...@@ -805,8 +793,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {...@@ -805,8 +793,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
805 const FieldDecl *field_decl = *it;793 const FieldDecl *field_decl = *it;
806794
807 if (field_decl->isBitField()) {795 if (field_decl->isBitField()) {
808 emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name));796 emit_warning(c, field_decl, "struct %s demoted to typedef - has bitfield\n", buf_ptr(bare_name));
809 return;797 return struct_type;
810 }798 }
811 }799 }
812800
...@@ -837,8 +825,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {...@@ -837,8 +825,8 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
837 type_struct_field->type_entry = resolve_qual_type(c, field_decl->getType(), field_decl);825 type_struct_field->type_entry = resolve_qual_type(c, field_decl->getType(), field_decl);
838826
839 if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {827 if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {
840 emit_warning(c, field_decl, "skipping struct %s - unresolved type\n", buf_ptr(bare_name));828 emit_warning(c, field_decl, "struct %s demoted to typedef - unresolved type\n", buf_ptr(bare_name));
841 return;829 return struct_type;
842 }830 }
843831
844 di_element_types[i] = LLVMZigCreateDebugMemberType(c->codegen->dbuilder,832 di_element_types[i] = LLVMZigCreateDebugMemberType(c->codegen->dbuilder,
...@@ -878,25 +866,52 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {...@@ -878,25 +866,52 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
878 LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);866 LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
879 struct_type->di_type = replacement_di_type;867 struct_type->di_type = replacement_di_type;
880868
881 //////869 return struct_type;
870}
882871
883 // now create a top level decl node for the type872static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
884 AstNode *struct_node = create_node(c, NodeTypeStructDecl);873 TypeTableEntry *struct_type = resolve_record_decl(c, record_decl);
885 buf_init_from_buf(&struct_node->data.struct_decl.name, full_type_name);
886 struct_node->data.struct_decl.kind = ContainerKindStruct;
887 struct_node->data.struct_decl.visib_mod = VisibModExport;
888 struct_node->data.struct_decl.directives = create_empty_directives(c);
889 struct_node->data.struct_decl.type_entry = struct_type;
890874
891 for (uint32_t i = 0; i < field_count; i += 1) {875 if (struct_type->id == TypeTableEntryIdInvalid) {
892 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];876 return;
893 AstNode *type_node = make_type_node(c, type_struct_field->type_entry);877 }
894 AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);878
895 struct_node->data.struct_decl.fields.append(field_node);879 assert(struct_type->id == TypeTableEntryIdStruct);
880
881 if (c->struct_decl_table.maybe_get(&struct_type->name)) {
882 return;
883 }
884 c->struct_decl_table.put(&struct_type->name, struct_type);
885
886 // make an alias without the "struct_" prefix. this will get emitted at the
887 // end if it doesn't conflict with anything else
888 if (decl_name(record_decl)[0] != 0) {
889 add_alias(c, decl_name(record_decl), buf_ptr(&struct_type->name));
896 }890 }
897891
898 normalize_parent_ptrs(struct_node);892 if (struct_type->data.structure.complete) {
899 c->root->data.root.top_level_decls.append(struct_node);893 // now create a top level decl node for the type
894 AstNode *struct_node = create_node(c, NodeTypeStructDecl);
895 buf_init_from_buf(&struct_node->data.struct_decl.name, &struct_type->name);
896 struct_node->data.struct_decl.kind = ContainerKindStruct;
897 struct_node->data.struct_decl.visib_mod = VisibModExport;
898 struct_node->data.struct_decl.directives = create_empty_directives(c);
899 struct_node->data.struct_decl.type_entry = struct_type;
900
901 for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
902 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
903 AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
904 AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
905 struct_node->data.struct_decl.fields.append(field_node);
906 }
907
908 normalize_parent_ptrs(struct_node);
909 c->root->data.root.top_level_decls.append(struct_node);
910 } else {
911 TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name),
912 c->codegen->builtin_types.entry_u8);
913 add_typedef_node(c, typedecl_type);
914 }
900}915}
901916
902static void visit_var_decl(Context *c, const VarDecl *var_decl) {917static 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...@@ -1253,6 +1268,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
1253 c->global_value_table.init(8);1268 c->global_value_table.init(8);
1254 c->enum_type_table.init(8);1269 c->enum_type_table.init(8);
1255 c->struct_type_table.init(8);1270 c->struct_type_table.init(8);
1271 c->struct_decl_table.init(8);
1256 c->fn_table.init(8);1272 c->fn_table.init(8);
1257 c->macro_table.init(8);1273 c->macro_table.init(8);
1258 c->codegen = codegen;1274 c->codegen = codegen;
test/run_tests.cpp+19
...@@ -2019,6 +2019,25 @@ static const int int_var = 13;...@@ -2019,6 +2019,25 @@ static const int int_var = 13;
2019 )SOURCE", 2,2019 )SOURCE", 2,
2020 "pub extern var extern_var: c_int;",2020 "pub extern var extern_var: c_int;",
2021 "pub const int_var: c_int = 13;");2021 "pub const int_var: c_int = 13;");
2022
2023
2024 add_parseh_case("circular struct definitions", R"SOURCE(
2025struct Bar;
2026
2027struct Foo {
2028 struct Bar *next;
2029};
2030
2031struct Bar {
2032 struct Foo *next;
2033};
2034 )SOURCE", 2,
2035 R"SOURCE(export struct struct_Bar {
2036 next: ?&struct_Foo,
2037})SOURCE",
2038 R"SOURCE(export struct struct_Foo {
2039 next: ?&struct_Bar,
2040})SOURCE");
2022}2041}
20232042
2024static void print_compiler_invocation(TestCase *test_case) {2043static void print_compiler_invocation(TestCase *test_case) {