From c3516b80044732e18eedcd8cd49c424fec497bb3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 28 Jan 2016 21:38:01 -0700 Subject: [PATCH] parseh handles self referential structs and fn pointers --- src/ast_render.cpp | 10 +++--- src/parseh.cpp | 80 +++++++++++++++++++++++++++++++++++++--------- test/run_tests.cpp | 9 ++++++ 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 6c8844aef7..01aed4dfbc 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -509,7 +509,8 @@ static void render_node(AstRender *ar, AstNode *node) { if (child->type == NodeTypeImport || child->type == NodeTypeVariableDeclaration || - child->type == NodeTypeErrorValueDecl) + child->type == NodeTypeErrorValueDecl || + child->type == NodeTypeFnProto) { fprintf(ar->f, ";"); } @@ -530,8 +531,10 @@ static void render_node(AstRender *ar, AstNode *node) { AstNode *param_decl = node->data.fn_proto.params.at(arg_i); assert(param_decl->type == NodeTypeParamDecl); const char *arg_name = buf_ptr(¶m_decl->data.param_decl.name); - const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; - fprintf(ar->f, "%s%s: ", noalias_str, arg_name); + if (buf_len(¶m_decl->data.param_decl.name) > 0) { + const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; + fprintf(ar->f, "%s%s: ", noalias_str, arg_name); + } render_node(ar, param_decl->data.param_decl.type); if (arg_i + 1 < arg_count || is_var_args) { @@ -548,7 +551,6 @@ static void render_node(AstRender *ar, AstNode *node) { fprintf(ar->f, " -> "); render_node(ar, return_type_node); } - fprintf(ar->f, ";"); break; } case NodeTypeFnDef: diff --git a/src/parseh.cpp b/src/parseh.cpp index e7c87a084e..8efef636a5 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -121,6 +121,17 @@ static AstNode *create_struct_field_node(Context *c, const char *name, AstNode * return node; } +static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) { + assert(type_node); + AstNode *node = create_node(c, NodeTypeParamDecl); + buf_init_from_str(&node->data.param_decl.name, name); + node->data.param_decl.type = type_node; + node->data.param_decl.is_noalias = is_noalias; + + normalize_parent_ptrs(node); + return node; +} + static AstNode *create_num_lit_unsigned(Context *c, uint64_t x) { AstNode *node = create_node(c, NodeTypeNumberLiteral); node->data.number_literal.kind = NumLitUInt; @@ -255,6 +266,12 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl, const PointerType *pointer_ty = static_cast(ty); QualType child_qt = pointer_ty->getPointeeType(); AstNode *type_node = make_qual_type_node(c, child_qt, decl); + if (child_qt.getTypePtr()->getTypeClass() == Type::Paren) { + const ParenType *paren_type = static_cast(child_qt.getTypePtr()); + if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { + return create_prefix_node(c, PrefixOpMaybe, type_node); + } + } return pointer_to_type(c, type_node, child_qt.isConstQualified()); } case Type::Typedef: @@ -311,8 +328,32 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl, } } case Type::FunctionProto: - emit_warning(c, decl, "ignoring function type"); - return nullptr; + { + const FunctionProtoType *fn_proto_ty = static_cast(ty); + AstNode *node = create_node(c, NodeTypeFnProto); + buf_resize(&node->data.fn_proto.name, 0); + node->data.fn_proto.is_extern = true; + node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); + node->data.fn_proto.return_type = make_qual_type_node(c, fn_proto_ty->getReturnType(), decl); + + if (!node->data.fn_proto.return_type) { + return nullptr; + } + + int arg_count = fn_proto_ty->getNumParams(); + for (int i = 0; i < arg_count; i += 1) { + QualType qt = fn_proto_ty->getParamType(i); + bool is_noalias = qt.isRestrictQualified(); + AstNode *type_node = make_qual_type_node(c, qt, decl); + if (!type_node) { + return nullptr; + } + node->data.fn_proto.params.append(create_param_decl_node(c, "", type_node, is_noalias)); + } + + normalize_parent_ptrs(node); + return node; + } case Type::Record: { const RecordType *record_ty = static_cast(ty); @@ -356,6 +397,11 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl, uint64_t size = const_arr_ty->getSize().getLimitedValue(); return create_array_type_node(c, child_type_node, size, false); } + case Type::Paren: + { + const ParenType *paren_ty = static_cast(ty); + return make_qual_type_node(c, paren_ty->getInnerType(), decl); + } case Type::BlockPointer: case Type::LValueReference: case Type::RValueReference: @@ -368,7 +414,6 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl, case Type::ExtVector: case Type::FunctionNoProto: case Type::UnresolvedUsing: - case Type::Paren: case Type::Adjusted: case Type::Decayed: case Type::TypeOfExpr: @@ -423,23 +468,19 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { int arg_count = fn_decl->getNumParams(); for (int i = 0; i < arg_count; i += 1) { const ParmVarDecl *param = fn_decl->getParamDecl(i); - AstNode *param_decl_node = create_node(c, NodeTypeParamDecl); const char *name = decl_name(param); if (strlen(name) == 0) { name = buf_ptr(buf_sprintf("arg%d", i)); } - buf_init_from_str(¶m_decl_node->data.param_decl.name, name); QualType qt = param->getOriginalType(); - param_decl_node->data.param_decl.is_noalias = qt.isRestrictQualified(); - param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, fn_decl); - if (!param_decl_node->data.param_decl.type) { - emit_warning(c, param, "skipping function %s, unresolved param type\n", - buf_ptr(&node->data.fn_proto.name)); + bool is_noalias = qt.isRestrictQualified(); + AstNode *type_node = make_qual_type_node(c, qt, fn_decl); + if (!type_node) { + emit_warning(c, param, "skipping function %s, unresolved param type\n", name); return; } - normalize_parent_ptrs(param_decl_node); - node->data.fn_proto.params.append(param_decl_node); + node->data.fn_proto.params.append(create_param_decl_node(c, name, type_node, is_noalias)); } if (fn_decl->isNoReturn()) { @@ -512,6 +553,11 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { node->data.struct_decl.visib_mod = VisibModExport; node->data.struct_decl.directives = create_empty_directives(c); + // eagerly put the name in the table, but we need to remember to remove it if it fails + // boy it would be nice to have defer here wouldn't it + c->enum_type_table.put(bare_name, true); + + ZigList var_decls = {0}; int i = 0; for (auto it = enum_def->enumerator_begin(), @@ -520,6 +566,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { { const EnumConstantDecl *enum_const = *it; if (enum_const->getInitExpr()) { + c->enum_type_table.remove(bare_name); emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name)); return; } @@ -549,8 +596,6 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { var_decls.append(var_node); } - c->enum_type_table.put(bare_name, true); - normalize_parent_ptrs(node); c->root->data.root.top_level_decls.append(node); @@ -594,6 +639,10 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { node->data.struct_decl.visib_mod = VisibModExport; node->data.struct_decl.directives = create_empty_directives(c); + // eagerly put the name in the table, but we need to remember to remove it if it fails + // boy it would be nice to have defer here wouldn't it + c->struct_type_table.put(bare_name, true); + for (auto it = record_def->field_begin(), it_end = record_def->field_end(); it != it_end; ++it) @@ -601,12 +650,14 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { const FieldDecl *field_decl = *it; if (field_decl->isBitField()) { + c->struct_type_table.remove(bare_name); emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name)); return; } AstNode *type_node = make_qual_type_node(c, field_decl->getType(), field_decl); if (!type_node) { + c->struct_type_table.remove(bare_name); emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(bare_name)); return; } @@ -615,7 +666,6 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { node->data.struct_decl.fields.append(field_node); } - c->struct_type_table.put(bare_name, true); normalize_parent_ptrs(node); c->root->data.root.top_level_decls.append(node); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 6fa6e2eed9..a4cd3bbe57 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1961,6 +1961,15 @@ pub const Bar = enum_Bar;)OUTPUT"); add_parseh_case("constant size array", R"SOURCE( void func(int array[20]); )SOURCE", R"OUTPUT(pub extern fn func(array: [20]c_int);)OUTPUT"); + + add_parseh_case("self referential struct with function pointer", R"SOURCE( +struct Foo { + void (*derp)(struct Foo *foo); +}; + )SOURCE", R"OUTPUT(export struct struct_Foo { + derp: ?extern fn (?&struct_Foo), +} +pub const Foo = struct_Foo;)OUTPUT"); } static void print_compiler_invocation(TestCase *test_case) {