Commit b66438eb80

Andrew Kelley <andrew@ziglang.org>
2019-05-29 00:18:52
no "use of undeclared identifer" in dead comptime branches
1 parent 528c151
Changed files (7)
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;
 
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:
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<typename T>
 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(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<IrInstructionUndeclaredIdent>(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<IrInstructionCheckRuntimeScope>(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<IrInstructionConst>(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<IrInstructionConst>(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:
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");
 }
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");
-
-
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;
+    }
+}
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(