From 8058b5e0a92e4eac05ba19aabed1fc041353c69b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 Feb 2016 19:09:53 -0700 Subject: [PATCH] fix crash when incomplete struct used as argument closes #107 --- src/analyze.cpp | 34 +++++++++++++++++++++++++++++++++- src/codegen.cpp | 1 + test/run_tests.cpp | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index bf6bcee289..c093f551f1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -153,6 +153,34 @@ static int bits_needed_for_unsigned(uint64_t x) { } } +static bool type_is_complete(TypeTableEntry *type_entry) { + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + zig_unreachable(); + case TypeTableEntryIdStruct: + return type_entry->data.structure.complete; + case TypeTableEntryIdEnum: + return type_entry->data.enumeration.complete; + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdFn: + case TypeTableEntryIdTypeDecl: + return true; + } +} + TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { return get_int_type(g, false, bits_needed_for_unsigned(x)); } @@ -391,6 +419,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c entry->type_ref = var_peer->type_ref; entry->di_type = var_peer->di_type; + entry->data.structure.complete = true; *parent_pointer = entry; return entry; @@ -421,6 +450,8 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c buf_ptr(&entry->name), g->dummy_di_file, 0, entry->size_in_bits, entry->align_in_bits, 0, nullptr, di_element_types, element_count, 0, nullptr, ""); + entry->data.structure.complete = true; + *parent_pointer = entry; return entry; } @@ -527,6 +558,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) { gen_param_info->src_index = i; gen_param_info->gen_index = -1; + assert(type_is_complete(type_entry)); if (type_entry->size_in_bits > 0) { TypeTableEntry *gen_type; if (handle_is_ptr(type_entry)) { @@ -4751,7 +4783,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode if (!table_entry) { table_entry = import->block_context->type_table.maybe_get(name); } - if (!table_entry) { + if (!table_entry || !type_is_complete(table_entry->value)) { decl_node->deps.put(name, node); } break; diff --git a/src/codegen.cpp b/src/codegen.cpp index c68632100a..abcfbd0965 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2830,6 +2830,7 @@ static void do_code_gen(CodeGen *g) { arg_no = var->gen_arg_index + 1; var->is_ptr = false; + assert(var->gen_arg_index >= 0); var->value_ref = LLVMGetParam(fn, var->gen_arg_index); } else { tag = LLVMZigTag_DW_auto_variable(); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 39bbf504b8..946f55f9fd 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1513,6 +1513,42 @@ pub fn main(args: [][]u8) -> %void { %%stdout.printf("OK\n"); } )SOURCE", "OK\n"); + + + add_simple_case("incomplete struct parameter top level decl", R"SOURCE( +import "std.zig"; +struct A { + b: B, +} + +struct B { + c: C, +} + +struct C { + x: i32, + + fn d(c: C) { + %%stdout.printf("OK\n"); + } +} + +fn foo(a: A) { + a.b.c.d(); +} + +pub fn main(args: [][]u8) -> %void { + const a = A { + .b = B { + .c = C { + .x = 13, + }, + }, + }; + foo(a); +} + + )SOURCE", "OK\n"); }