Commit 6b74fd2e12

LemonBoy <thatlemon@gmail.com>
2020-02-16 20:19:30
ir: Avoid invalidating the decl_table iterator
Collect the declarations to resolve first and run resolve_top_level_decl on them later. Closes #4310
1 parent 59a243c
Changed files (2)
src/ir.cpp
@@ -23653,14 +23653,13 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
     if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown)))
         return err;
 
-    // Loop through our declarations once to figure out how many declarations we will generate info for.
+    // The unresolved declarations are collected in a separate queue to avoid
+    // modifying decl_table while iterating over it
+    ZigList<Tld*> resolve_decl_queue{};
+
     auto decl_it = decls_scope->decl_table.entry_iterator();
     decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;
-    int declaration_count = 0;
-
     while ((curr_entry = decl_it.next()) != nullptr) {
-        // If the declaration is unresolved, force it to be resolved again.
-        resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false);
         if (curr_entry->value->resolution == TldResolutionInvalid) {
             return ErrorSemanticAnalyzeFail;
         }
@@ -23670,16 +23669,36 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
             return ErrorSemanticAnalyzeFail;
         }
 
+        // If the declaration is unresolved, force it to be resolved again.
+        if (curr_entry->value->resolution == TldResolutionUnresolved)
+            resolve_decl_queue.append(curr_entry->value);
+    }
+
+    for (size_t i = 0; i < resolve_decl_queue.length; i++) {
+        Tld *decl = resolve_decl_queue.at(i);
+        resolve_top_level_decl(ira->codegen, decl, decl->source_node, false);
+        if (decl->resolution == TldResolutionInvalid) {
+            return ErrorSemanticAnalyzeFail;
+        }
+    }
+
+    resolve_decl_queue.deinit();
+
+    // Loop through our declarations once to figure out how many declarations we will generate info for.
+    int declaration_count = 0;
+    decl_it = decls_scope->decl_table.entry_iterator();
+    while ((curr_entry = decl_it.next()) != nullptr) {
         // Skip comptime blocks and test functions.
-        if (curr_entry->value->id != TldIdCompTime) {
-            if (curr_entry->value->id == TldIdFn) {
-                ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
-                if (fn_entry->is_test)
-                    continue;
-            }
+        if (curr_entry->value->id == TldIdCompTime)
+            continue;
 
-            declaration_count += 1;
+        if (curr_entry->value->id == TldIdFn) {
+            ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
+            if (fn_entry->is_test)
+                continue;
         }
+
+        declaration_count += 1;
     }
 
     ZigValue *declaration_array = ira->codegen->pass1_arena->create<ZigValue>();
test/compile_errors.zig
@@ -3,13 +3,13 @@ const builtin = @import("builtin");
 const Target = @import("std").Target;
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
-    cases.addTest("access of undefined pointer to array",
-        \\const ram_u32: *[4096]u32 = undefined;
-        \\export fn entry() void {
-        \\    @ptrCast(*u32, &(ram_u32[0])) = &(ram_u32[0]);
+    cases.addTest("",
+        \\const A = B;
+        \\test "Crash" {
+        \\    _ = @typeInfo(@This()).Struct.decls;
         \\}
     , &[_][]const u8{
-        "tmp.zig:3:29: error: use of undefined value here causes undefined behavior",
+        "tmp.zig:1:11: error: use of undeclared identifier 'B'",
     });
 
     cases.addTest("duplicate field in anonymous struct literal",