diff --git a/src/all_types.hpp b/src/all_types.hpp index a0b4fadedc..91676d0c39 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2306,6 +2306,7 @@ enum IrInstructionId { IrInstructionIdAssertZero, IrInstructionIdAssertNonNull, IrInstructionIdHasDecl, + IrInstructionIdUndeclaredIdent, }; struct IrInstruction { @@ -3519,6 +3520,12 @@ struct IrInstructionHasDecl { IrInstruction *name; }; +struct IrInstructionUndeclaredIdent { + IrInstruction base; + + Buf *name; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index e00ec12615..7d9e03baf4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5606,6 +5606,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdBitCast: case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: + case IrInstructionIdUndeclaredIdent: zig_unreachable(); case IrInstructionIdDeclVarGen: diff --git a/src/ir.cpp b/src/ir.cpp index 42b1acc4df..5d3cf5303c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1015,6 +1015,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionHasDecl *) { return IrInstructionIdHasDecl; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionUndeclaredIdent *) { + return IrInstructionIdUndeclaredIdent; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -3031,6 +3035,15 @@ static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_undeclared_identifier(IrBuilder *irb, Scope *scope, AstNode *source_node, + Buf *name) +{ + IrInstructionUndeclaredIdent *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -3896,13 +3909,18 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, Buf *variable_name = node->data.symbol_expr.symbol; - if (buf_eql_str(variable_name, "_") && lval == LValPtr) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, node); - const_instruction->base.value.type = get_pointer_to_type(irb->codegen, - irb->codegen->builtin_types.entry_void, false); - const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard; - return &const_instruction->base; + if (buf_eql_str(variable_name, "_")) { + if (lval == LValPtr) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, node); + const_instruction->base.value.type = get_pointer_to_type(irb->codegen, + irb->codegen->builtin_types.entry_void, false); + const_instruction->base.value.special = ConstValSpecialStatic; + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard; + return &const_instruction->base; + } else { + add_node_error(irb->codegen, node, buf_sprintf("`_` may only be used to assign things to")); + return irb->codegen->invalid_instruction; + } } ZigType *primitive_type; @@ -3943,11 +3961,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_instruction; } - // 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; + return ir_build_undeclared_identifier(irb, scope, node, variable_name); } static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { @@ -23237,6 +23251,16 @@ static IrInstruction *ir_analyze_instruction_has_decl(IrAnalyze *ira, IrInstruct return ir_const_bool(ira, &instruction->base, true); } +static IrInstruction *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, IrInstructionUndeclaredIdent *instruction) { + // 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(ira->codegen, instruction->base.scope, instruction->base.source_node, + instruction->name); + ir_add_error(ira, &instruction->base, + buf_sprintf("use of undeclared identifier '%s'", buf_ptr(instruction->name))); + return ira->codegen->invalid_instruction; +} + static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -23533,6 +23557,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction); case IrInstructionIdHasDecl: return ir_analyze_instruction_has_decl(ira, (IrInstructionHasDecl *)instruction); + case IrInstructionIdUndeclaredIdent: + return ir_analyze_instruction_undeclared_ident(ira, (IrInstructionUndeclaredIdent *)instruction); } zig_unreachable(); } @@ -23667,6 +23693,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: + case IrInstructionIdUndeclaredIdent: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index dd671231c0..bf9ced89c5 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1461,6 +1461,10 @@ static void ir_print_has_decl(IrPrint *irp, IrInstructionHasDecl *instruction) { fprintf(irp->f, ")"); } +static void ir_print_undeclared_ident(IrPrint *irp, IrInstructionUndeclaredIdent *instruction) { + fprintf(irp->f, "@undeclaredIdent(%s)", buf_ptr(instruction->name)); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1931,6 +1935,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdHasDecl: ir_print_has_decl(irp, (IrInstructionHasDecl *)instruction); break; + case IrInstructionIdUndeclaredIdent: + ir_print_undeclared_ident(irp, (IrInstructionUndeclaredIdent *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/std/os/bits/windows.zig b/std/os/bits/windows.zig index a242113ba0..4959249a9a 100644 --- a/std/os/bits/windows.zig +++ b/std/os/bits/windows.zig @@ -158,10 +158,3 @@ pub const EWOULDBLOCK = 140; pub const EDQUOT = 10069; pub const F_OK = 0; - -// These are workarounds for "use of undeclared identifier" compile errors -// TODO make the compiler even more lazy. don't emit "use of undeclared identifier" errors -// for if branches that aren't taken. -pub const SIGKILL = @compileError("Windows libc does not have this"); - - diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 0d28ac4932..7da5247d89 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1219,7 +1219,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:2:5: error: `_` is not a declarable symbol", - "tmp.zig:3:12: error: use of undeclared identifier '_'", ); cases.add( @@ -1232,7 +1231,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ } \\} , - "tmp.zig:4:20: error: use of undeclared identifier '_'", + "tmp.zig:4:20: error: `_` may only be used to assign things to", ); cases.add( @@ -1248,7 +1247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return 1; \\} , - "tmp.zig:4:20: error: use of undeclared identifier '_'", + "tmp.zig:4:20: error: `_` may only be used to assign things to", ); cases.add( @@ -1266,7 +1265,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.optionalReturnError; \\} , - "tmp.zig:6:17: error: use of undeclared identifier '_'", + "tmp.zig:6:17: error: `_` may only be used to assign things to", ); cases.add( diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 6d5ede418e..6d581c1128 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -93,11 +93,13 @@ pub const Vec3 = struct { data: [3]f32, }; pub fn vec3(x: f32, y: f32, z: f32) Vec3 { - return Vec3{ .data = []f32{ - x, - y, - z, - } }; + return Vec3{ + .data = []f32{ + x, + y, + z, + }, + }; } test "constant expressions" { @@ -776,3 +778,9 @@ fn oneItem(x: i32) [1]i32 { fn scalar(x: u32) u32 { return x; } + +test "no undeclared identifier error in unanalyzed branches" { + if (false) { + lol_this_doesnt_exist = nonsense; + } +}