Commit 8058b5e0a9

Andrew Kelley <superjoe30@gmail.com>
2016-02-03 03:09:53
fix crash when incomplete struct used as argument
closes #107
1 parent 79adf55
Changed files (3)
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;
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();
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");
 }