diff --git a/src/ir.cpp b/src/ir.cpp index 3e48779b9..0eb1f2d53 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3674,6 +3674,22 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode return ir_build_const_null(irb, scope, node); } +static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) { + ScopeDecls *scope_decls = nullptr; + while (scope != nullptr) { + if (scope->id == ScopeIdDecls) { + scope_decls = reinterpret_cast(scope); + } + scope = scope->parent; + } + TldVar *tld_var = allocate(1); + init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); + tld_var->base.resolution = TldResolutionInvalid; + tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, + &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid); + scope_decls->decl_table.put(var_name, &tld_var->base); +} + static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { Error err; assert(node->type == NodeTypeSymbol); @@ -3727,8 +3743,9 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_instruction; } - // TODO put a variable of same name with invalid type in global scope + // put a variable of same name with invalid type in global scope // so that future references to this same name will find a variable with an invalid type + populate_invalid_variable_in_scope(irb->codegen, scope, node, variable_name); add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); return irb->codegen->invalid_instruction; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 86dfd59be..a9c748bcd 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,22 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addCase(x: { + var tc = cases.create( + "deduplicate undeclared identifier", + \\export fn a() void { + \\ x += 1; + \\} + \\export fn b() void { + \\ x += 1; + \\} + , + ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'", + ); + tc.expect_exact = true; + break :x tc; + }); + cases.addTest( "export generic function", \\export fn foo(num: var) i32 { @@ -2280,7 +2296,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", - ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'", ); cases.add( @@ -5618,8 +5633,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid", ); - cases.add( - "compileLog of tagged enum doesn't crash the compiler", + cases.add("compileLog of tagged enum doesn't crash the compiler", \\const Bar = union(enum(u32)) { \\ X: i32 = 1 \\}; @@ -5631,7 +5645,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\pub fn main () void { \\ comptime testCompileLog(Bar{.X = 123}); \\} - , - ".tmp_source.zig:6:5: error: found compile log statement" - ); + , ".tmp_source.zig:6:5: error: found compile log statement"); } diff --git a/test/tests.zig b/test/tests.zig index f9c9207f0..2591ab4f2 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -716,7 +716,8 @@ pub const CompileErrorContext = struct { for (self.case.expected_errors.toSliceConst()) |expected| { if (mem.indexOf(u8, stderr, expected) == null) { warn( - \\\n=========== Expected compile error: ============ + \\ + \\=========== Expected compile error: ============ \\{} \\ , expected);