Commit 2e27407161

Andrew Kelley <superjoe30@gmail.com>
2018-09-22 00:47:12
stage1: unify 2 implementations of pointer deref
I found out there were accidentally two code paths in zig ir for pointer dereference. So this should fix a few bugs. closes #1486
1 parent 9e5cd43
Changed files (4)
src/ir.cpp
@@ -153,6 +153,8 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali
 static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
 static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
 static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
+static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
+        ConstExprValue *out_val, ConstExprValue *ptr_val);
 
 static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
     assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -11205,34 +11207,42 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig
 }
 
 static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
+    Error err;
     ZigType *type_entry = ptr->value.type;
     if (type_is_invalid(type_entry)) {
         return ira->codegen->invalid_instruction;
     } else if (type_entry->id == ZigTypeIdPointer) {
         ZigType *child_type = type_entry->data.pointer.child_type;
+        // dereferencing a *u0 is comptime known to be 0
+        if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
+            IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
+                source_instruction->source_node, child_type);
+            init_const_unsigned_negative(&result->value, child_type, 0, false);
+            return result;
+        }
         if (instr_is_comptime(ptr)) {
+            if (ptr->value.special == ConstValSpecialUndef) {
+                ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
+                return ira->codegen->invalid_instruction;
+            }
             if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
                 ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
             {
-                ConstExprValue *pointee = ir_const_ptr_pointee(ira, &ptr->value, source_instruction->source_node);
-                if (pointee == nullptr)
-                    return ira->codegen->invalid_instruction;
+                ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
                 if (pointee->special != ConstValSpecialRuntime) {
                     IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
                         source_instruction->source_node, child_type);
-                    copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
+
+                    if ((err = ir_read_const_ptr(ira, source_instruction->source_node, &result->value,
+                                    &ptr->value)))
+                    {
+                        return ira->codegen->invalid_instruction;
+                    }
                     result->value.type = child_type;
                     return result;
                 }
             }
         }
-        // dereferencing a *u0 is comptime known to be 0
-        if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
-                source_instruction->source_node, child_type);
-            init_const_unsigned_negative(&result->value, child_type, 0, false);
-            return result;
-        }
         // TODO if the instruction is a const ref instruction we can skip it
         IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
                 source_instruction->source_node, ptr);
@@ -13931,10 +13941,16 @@ static ZigType *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *c
 static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
         ConstExprValue *out_val, ConstExprValue *ptr_val)
 {
+    Error err;
     assert(out_val->type != nullptr);
 
     ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr_val);
 
+    if ((err = type_resolve(ira->codegen, pointee->type, ResolveStatusSizeKnown)))
+        return ErrorSemanticAnalyzeFail;
+    if ((err = type_resolve(ira->codegen, out_val->type, ResolveStatusSizeKnown)))
+        return ErrorSemanticAnalyzeFail;
+
     size_t src_size = type_size(ira->codegen, pointee->type);
     size_t dst_size = type_size(ira->codegen, out_val->type);
 
@@ -13957,48 +13973,6 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
     return ErrorNone;
 }
 
-static ZigType *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
-    Error err;
-    IrInstruction *value = un_op_instruction->value->other;
-
-    ZigType *ptr_type = value->value.type;
-    ZigType *child_type;
-    if (type_is_invalid(ptr_type)) {
-        return ira->codegen->builtin_types.entry_invalid;
-    } else if (ptr_type->id == ZigTypeIdPointer) {
-        if (ptr_type->data.pointer.ptr_len == PtrLenUnknown) {
-            ir_add_error_node(ira, un_op_instruction->base.source_node,
-                buf_sprintf("index syntax required for unknown-length pointer type '%s'",
-                    buf_ptr(&ptr_type->name)));
-            return ira->codegen->builtin_types.entry_invalid;
-        }
-        child_type = ptr_type->data.pointer.child_type;
-    } else {
-        ir_add_error_node(ira, un_op_instruction->base.source_node,
-            buf_sprintf("attempt to dereference non-pointer type '%s'",
-                buf_ptr(&ptr_type->name)));
-        return ira->codegen->builtin_types.entry_invalid;
-    }
-
-    // this dereference is always an rvalue because in the IR gen we identify lvalue and emit
-    // one of the ptr instructions
-
-    if (instr_is_comptime(value)) {
-        ConstExprValue *comptime_value = ir_resolve_const(ira, value, UndefBad);
-        if (comptime_value == nullptr)
-            return ira->codegen->builtin_types.entry_invalid;
-
-        ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
-        out_val->type = child_type;
-        if ((err = ir_read_const_ptr(ira, un_op_instruction->base.source_node, out_val, comptime_value)))
-            return ira->codegen->builtin_types.entry_invalid;
-        return child_type;
-    }
-
-    ir_build_load_ptr_from(&ira->new_irb, &un_op_instruction->base, value);
-    return child_type;
-}
-
 static ZigType *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
     Error err;
     IrInstruction *value = un_op_instruction->value->other;
@@ -14131,8 +14105,25 @@ static ZigType *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *
         case IrUnOpNegation:
         case IrUnOpNegationWrap:
             return ir_analyze_negation(ira, un_op_instruction);
-        case IrUnOpDereference:
-            return ir_analyze_dereference(ira, un_op_instruction);
+        case IrUnOpDereference: {
+            IrInstruction *ptr = un_op_instruction->value->other;
+            if (type_is_invalid(ptr->value.type))
+                return ira->codegen->builtin_types.entry_invalid;
+            ZigType *ptr_type = ptr->value.type;
+            if (ptr_type->id == ZigTypeIdPointer && ptr_type->data.pointer.ptr_len == PtrLenUnknown) {
+                ir_add_error_node(ira, un_op_instruction->base.source_node,
+                    buf_sprintf("index syntax required for unknown-length pointer type '%s'",
+                        buf_ptr(&ptr_type->name)));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+            // this dereference is always an rvalue because in the IR gen we identify lvalue and emit
+            // one of the ptr instructions
+            IrInstruction *result = ir_get_deref(ira, &un_op_instruction->base, ptr);
+            if (result == ira->codegen->invalid_instruction)
+                return ira->codegen->builtin_types.entry_invalid;
+            ir_link_new_instruction(result, &un_op_instruction->base);
+            return result->value.type;
+        }
         case IrUnOpOptional:
             return ir_analyze_maybe(ira, un_op_instruction);
     }
test/cases/bugs/1486.zig
@@ -0,0 +1,11 @@
+const assert = @import("std").debug.assert;
+
+const ptr = &global;
+var global: u64 = 123;
+
+test "constant pointer to global variable causes runtime load" {
+    global = 1234;
+    assert(&global == ptr);
+    assert(ptr.* == 1234);
+}
+
test/behavior.zig
@@ -15,6 +15,7 @@ comptime {
     _ = @import("cases/bugs/1381.zig");
     _ = @import("cases/bugs/1421.zig");
     _ = @import("cases/bugs/1442.zig");
+    _ = @import("cases/bugs/1486.zig");
     _ = @import("cases/bugs/394.zig");
     _ = @import("cases/bugs/655.zig");
     _ = @import("cases/bugs/656.zig");
test/compile_errors.zig
@@ -2896,7 +2896,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    _ = a.*;
         \\}
     ,
-        ".tmp_source.zig:3:9: error: use of undefined value",
+        ".tmp_source.zig:3:9: error: attempt to dereference undefined value",
     );
 
     cases.add(