Commit c87a576cb5

Andrew Kelley <superjoe30@gmail.com>
2018-09-05 21:53:36
stage1 compile error instead of crashing for unsupported comptime ptr cast
See #955
1 parent ba7836e
Changed files (3)
doc/langref.html.in
@@ -1587,7 +1587,7 @@ test "pointer casting" {
     // operation that Zig cannot protect you against. Use @ptrCast only when other
     // conversions are not possible.
     const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
-    const u32_ptr = @ptrCast(*const u32, &bytes[0]);
+    const u32_ptr = @ptrCast(*const u32, &bytes);
     assert(u32_ptr.* == 0x12121212);
 
     // Even this example is contrived - there are better ways to do the above than
src/ir.cpp
@@ -150,8 +150,10 @@ static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruct
 static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
 static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
 static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *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);
 
-ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
+static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
     assert(get_codegen_ptr_type(const_val->type) != nullptr);
     assert(const_val->special == ConstValSpecialStatic);
     ConstExprValue *result;
@@ -181,6 +183,27 @@ ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
     return result;
 }
 
+static bool types_have_same_zig_comptime_repr(TypeTableEntry *a, TypeTableEntry *b) {
+    if (a == b)
+        return true;
+
+    if (a->id == b->id)
+        return true;
+
+    if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
+        return true;
+
+    return false;
+}
+
+ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
+    ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val);
+    if (const_val->type->id == TypeTableEntryIdPointer) {
+        assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type));
+    }
+    return result;
+}
+
 static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
     if (exec->is_inline)
         return true;
@@ -7602,6 +7625,19 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction,
     return ir_add_error_node(ira, source_instruction->source_node, msg);
 }
 
+static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) {
+    ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val);
+    assert(val != nullptr);
+    assert(const_val->type->id == TypeTableEntryIdPointer);
+    TypeTableEntry *expected_type = const_val->type->data.pointer.child_type;
+    if (!types_have_same_zig_comptime_repr(val->type, expected_type)) {
+        ir_add_error_node(ira, source_node,
+            buf_sprintf("TODO handle comptime reinterpreted pointer. See https://github.com/ziglang/zig/issues/955"));
+        return nullptr;
+    }
+    return val;
+}
+
 static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
     IrBasicBlock *bb = exec->basic_block_list.at(0);
     for (size_t i = 0; i < bb->instruction_list.length; i += 1) {
@@ -9461,7 +9497,9 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
     wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
 
     if (instr_is_comptime(value)) {
-        ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
+        ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
+        if (pointee == nullptr)
+            return ira->codegen->invalid_instruction;
         if (pointee->special != ConstValSpecialRuntime) {
             IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
                     source_instr->source_node, wanted_type);
@@ -9487,7 +9525,9 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
     wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
 
     if (instr_is_comptime(value)) {
-        ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
+        ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
+        if (pointee == nullptr)
+            return ira->codegen->invalid_instruction;
         if (pointee->special != ConstValSpecialRuntime) {
             assert(value->value.type->id == TypeTableEntryIdPointer);
             TypeTableEntry *array_type = value->value.type->data.pointer.child_type;
@@ -10458,7 +10498,9 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
             return ira->codegen->invalid_instruction;
 
         assert(val->type->id == TypeTableEntryIdPointer);
-        ConstExprValue *pointee = const_ptr_pointee(ira->codegen, val);
+        ConstExprValue *pointee = ir_const_ptr_pointee(ira, val, source_instr->source_node);
+        if (pointee == nullptr)
+            return ira->codegen->invalid_instruction;
         if (pointee->special != ConstValSpecialRuntime) {
             ConstExprValue *array_val = create_const_vals(1);
             array_val->special = ConstValSpecialStatic;
@@ -10773,6 +10815,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
             !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk)
         {
             IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_child_type);
+            if (type_is_invalid(cast1->value.type))
+                return ira->codegen->invalid_instruction;
             return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
         }
     }
@@ -11045,7 +11089,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
             if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
                 ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
             {
-                ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &ptr->value);
+                ConstExprValue *pointee = ir_const_ptr_pointee(ira, &ptr->value, source_instruction->source_node);
+                if (pointee == nullptr)
+                    return ira->codegen->invalid_instruction;
                 if (pointee->special != ConstValSpecialRuntime) {
                     IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
                         source_instruction->source_node, child_type);
@@ -13716,7 +13762,39 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
     }
 }
 
+// out_val->type must be the type to read the pointer as
+// if the type is different than the actual type then it does a comptime byte reinterpretation
+static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
+        ConstExprValue *out_val, ConstExprValue *ptr_val)
+{
+    assert(out_val->type != nullptr);
+
+    ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr_val);
+
+    size_t src_size = type_size(ira->codegen, pointee->type);
+    size_t dst_size = type_size(ira->codegen, out_val->type);
+
+    if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) {
+        copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
+        return ErrorNone;
+    }
+
+    if (dst_size > src_size) {
+        ir_add_error_node(ira, source_node,
+            buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
+            dst_size, buf_ptr(&pointee->type->name), src_size));
+        return ErrorSemanticAnalyzeFail;
+    }
+
+    Buf buf = BUF_INIT;
+    buf_resize(&buf, src_size);
+    buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee);
+    buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
+    return ErrorNone;
+}
+
 static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
+    Error err;
     IrInstruction *value = un_op_instruction->value->other;
 
     TypeTableEntry *ptr_type = value->value.type;
@@ -13746,12 +13824,11 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
         if (comptime_value == nullptr)
             return ira->codegen->builtin_types.entry_invalid;
 
-        ConstExprValue *pointee = const_ptr_pointee(ira->codegen, comptime_value);
-        if (pointee->type == child_type) {
-            ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
-            copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
-            return child_type;
-        }
+        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);
@@ -14152,7 +14229,10 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
             array_type = array_type->data.pointer.child_type;
             ptr_type = ptr_type->data.pointer.child_type;
             if (orig_array_ptr_val->special != ConstValSpecialRuntime) {
-                orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val);
+                orig_array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val,
+                        elem_ptr_instruction->base.source_node);
+                if (orig_array_ptr_val == nullptr)
+                    return ira->codegen->builtin_types.entry_invalid;
             }
         }
         if (array_type->data.array.len == 0) {
@@ -14193,7 +14273,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
         ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
         if (!ptr_val)
             return ira->codegen->builtin_types.entry_invalid;
-        ConstExprValue *args_val = const_ptr_pointee(ira->codegen, ptr_val);
+        ConstExprValue *args_val = ir_const_ptr_pointee(ira, ptr_val, elem_ptr_instruction->base.source_node);
+        if (args_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
         size_t start = args_val->data.x_arg_tuple.start_index;
         size_t end = args_val->data.x_arg_tuple.end_index;
         uint64_t elem_index_val;
@@ -14269,120 +14351,126 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
             return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);
         }
 
-        ConstExprValue *array_ptr_val;
         if (orig_array_ptr_val->special != ConstValSpecialRuntime &&
-            (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
-            (array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val)) &&
-            array_ptr_val->special != ConstValSpecialRuntime &&
-            (array_type->id != TypeTableEntryIdPointer ||
-                array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
+            (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar ||
+                array_type->id == TypeTableEntryIdArray))
         {
-            if (array_type->id == TypeTableEntryIdPointer) {
-                ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
-                out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
-                size_t new_index;
-                size_t mem_size;
-                size_t old_size;
-                switch (array_ptr_val->data.x_ptr.special) {
-                    case ConstPtrSpecialInvalid:
-                    case ConstPtrSpecialDiscard:
-                        zig_unreachable();
-                    case ConstPtrSpecialRef:
-                        mem_size = 1;
-                        old_size = 1;
-                        new_index = index;
-
-                        out_val->data.x_ptr.special = ConstPtrSpecialRef;
-                        out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee;
-                        break;
-                    case ConstPtrSpecialBaseArray:
-                        {
-                            size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
-                            new_index = offset + index;
-                            mem_size = array_ptr_val->data.x_ptr.data.base_array.array_val->type->data.array.len;
-                            old_size = mem_size - offset;
-
-                            assert(array_ptr_val->data.x_ptr.data.base_array.array_val);
-
-                            out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
-                            out_val->data.x_ptr.data.base_array.array_val =
-                                array_ptr_val->data.x_ptr.data.base_array.array_val;
-                            out_val->data.x_ptr.data.base_array.elem_index = new_index;
-                            out_val->data.x_ptr.data.base_array.is_cstr =
-                                array_ptr_val->data.x_ptr.data.base_array.is_cstr;
+            ConstExprValue *array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val,
+                                        elem_ptr_instruction->base.source_node);
+            if (array_ptr_val == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
 
+            if (array_ptr_val->special != ConstValSpecialRuntime &&
+                (array_type->id != TypeTableEntryIdPointer ||
+                    array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
+            {
+                if (array_type->id == TypeTableEntryIdPointer) {
+                    ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
+                    out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
+                    size_t new_index;
+                    size_t mem_size;
+                    size_t old_size;
+                    switch (array_ptr_val->data.x_ptr.special) {
+                        case ConstPtrSpecialInvalid:
+                        case ConstPtrSpecialDiscard:
+                            zig_unreachable();
+                        case ConstPtrSpecialRef:
+                            mem_size = 1;
+                            old_size = 1;
+                            new_index = index;
+
+                            out_val->data.x_ptr.special = ConstPtrSpecialRef;
+                            out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee;
                             break;
-                        }
-                    case ConstPtrSpecialBaseStruct:
-                        zig_panic("TODO elem ptr on a const inner struct");
-                    case ConstPtrSpecialHardCodedAddr:
-                        zig_unreachable();
-                    case ConstPtrSpecialFunction:
-                        zig_panic("TODO element ptr of a function casted to a ptr");
-                }
-                if (new_index >= mem_size) {
-                    ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
-                        buf_sprintf("index %" ZIG_PRI_u64 " outside pointer of size %" ZIG_PRI_usize "", index, old_size));
-                    return ira->codegen->builtin_types.entry_invalid;
-                }
-                return return_type;
-            } else if (is_slice(array_type)) {
-                ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
-                if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
-                    IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
-                            array_ptr, casted_elem_index, false, elem_ptr_instruction->ptr_len);
-                    result->value.type = return_type;
-                    ir_link_new_instruction(result, &elem_ptr_instruction->base);
+                        case ConstPtrSpecialBaseArray:
+                            {
+                                size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
+                                new_index = offset + index;
+                                mem_size = array_ptr_val->data.x_ptr.data.base_array.array_val->type->data.array.len;
+                                old_size = mem_size - offset;
+
+                                assert(array_ptr_val->data.x_ptr.data.base_array.array_val);
+
+                                out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
+                                out_val->data.x_ptr.data.base_array.array_val =
+                                    array_ptr_val->data.x_ptr.data.base_array.array_val;
+                                out_val->data.x_ptr.data.base_array.elem_index = new_index;
+                                out_val->data.x_ptr.data.base_array.is_cstr =
+                                    array_ptr_val->data.x_ptr.data.base_array.is_cstr;
+
+                                break;
+                            }
+                        case ConstPtrSpecialBaseStruct:
+                            zig_panic("TODO elem ptr on a const inner struct");
+                        case ConstPtrSpecialHardCodedAddr:
+                            zig_unreachable();
+                        case ConstPtrSpecialFunction:
+                            zig_panic("TODO element ptr of a function casted to a ptr");
+                    }
+                    if (new_index >= mem_size) {
+                        ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
+                            buf_sprintf("index %" ZIG_PRI_u64 " outside pointer of size %" ZIG_PRI_usize "", index, old_size));
+                        return ira->codegen->builtin_types.entry_invalid;
+                    }
                     return return_type;
-                }
-                ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index];
-                ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
-                uint64_t slice_len = bigint_as_unsigned(&len_field->data.x_bigint);
-                if (index >= slice_len) {
-                    ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
-                        buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64,
-                            index, slice_len));
-                    return ira->codegen->builtin_types.entry_invalid;
-                }
-                out_val->data.x_ptr.mut = ptr_field->data.x_ptr.mut;
-                switch (ptr_field->data.x_ptr.special) {
-                    case ConstPtrSpecialInvalid:
-                    case ConstPtrSpecialDiscard:
-                        zig_unreachable();
-                    case ConstPtrSpecialRef:
-                        out_val->data.x_ptr.special = ConstPtrSpecialRef;
-                        out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;
-                        break;
-                    case ConstPtrSpecialBaseArray:
-                        {
-                            size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
-                            uint64_t new_index = offset + index;
-                            assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len);
-                            out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
-                            out_val->data.x_ptr.data.base_array.array_val =
-                                ptr_field->data.x_ptr.data.base_array.array_val;
-                            out_val->data.x_ptr.data.base_array.elem_index = new_index;
-                            out_val->data.x_ptr.data.base_array.is_cstr =
-                                ptr_field->data.x_ptr.data.base_array.is_cstr;
+                } else if (is_slice(array_type)) {
+                    ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
+                    if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
+                        IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
+                                array_ptr, casted_elem_index, false, elem_ptr_instruction->ptr_len);
+                        result->value.type = return_type;
+                        ir_link_new_instruction(result, &elem_ptr_instruction->base);
+                        return return_type;
+                    }
+                    ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index];
+                    ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
+                    uint64_t slice_len = bigint_as_unsigned(&len_field->data.x_bigint);
+                    if (index >= slice_len) {
+                        ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
+                            buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64,
+                                index, slice_len));
+                        return ira->codegen->builtin_types.entry_invalid;
+                    }
+                    out_val->data.x_ptr.mut = ptr_field->data.x_ptr.mut;
+                    switch (ptr_field->data.x_ptr.special) {
+                        case ConstPtrSpecialInvalid:
+                        case ConstPtrSpecialDiscard:
+                            zig_unreachable();
+                        case ConstPtrSpecialRef:
+                            out_val->data.x_ptr.special = ConstPtrSpecialRef;
+                            out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;
                             break;
-                        }
-                    case ConstPtrSpecialBaseStruct:
-                        zig_panic("TODO elem ptr on a slice backed by const inner struct");
-                    case ConstPtrSpecialHardCodedAddr:
-                        zig_unreachable();
-                    case ConstPtrSpecialFunction:
-                        zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
+                        case ConstPtrSpecialBaseArray:
+                            {
+                                size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
+                                uint64_t new_index = offset + index;
+                                assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len);
+                                out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
+                                out_val->data.x_ptr.data.base_array.array_val =
+                                    ptr_field->data.x_ptr.data.base_array.array_val;
+                                out_val->data.x_ptr.data.base_array.elem_index = new_index;
+                                out_val->data.x_ptr.data.base_array.is_cstr =
+                                    ptr_field->data.x_ptr.data.base_array.is_cstr;
+                                break;
+                            }
+                        case ConstPtrSpecialBaseStruct:
+                            zig_panic("TODO elem ptr on a slice backed by const inner struct");
+                        case ConstPtrSpecialHardCodedAddr:
+                            zig_unreachable();
+                        case ConstPtrSpecialFunction:
+                            zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
+                    }
+                    return return_type;
+                } else if (array_type->id == TypeTableEntryIdArray) {
+                    ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
+                    out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
+                    out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
+                    out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
+                    out_val->data.x_ptr.data.base_array.elem_index = index;
+                    return return_type;
+                } else {
+                    zig_unreachable();
                 }
-                return return_type;
-            } else if (array_type->id == TypeTableEntryIdArray) {
-                ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
-                out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
-                out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
-                out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
-                out_val->data.x_ptr.data.base_array.elem_index = index;
-                return return_type;
-            } else {
-                zig_unreachable();
             }
         }
 
@@ -14474,7 +14562,9 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
                     return ira->codegen->invalid_instruction;
 
                 if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
-                    ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val);
+                    ConstExprValue *struct_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node);
+                    if (struct_val == nullptr)
+                        return ira->codegen->invalid_instruction;
                     if (type_is_invalid(struct_val->type))
                         return ira->codegen->invalid_instruction;
                     ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
@@ -14516,7 +14606,9 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
                     return ira->codegen->invalid_instruction;
 
                 if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
-                    ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val);
+                    ConstExprValue *union_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node);
+                    if (union_val == nullptr)
+                        return ira->codegen->invalid_instruction;
                     if (type_is_invalid(union_val->type))
                         return ira->codegen->invalid_instruction;
 
@@ -14711,7 +14803,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
 
         assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
-        ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
+        ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node);
+        if (child_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
 
         if (buf_eql_str(field_name, "len")) {
             ConstExprValue *len_val = create_const_vals(1);
@@ -14735,7 +14829,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
 
         assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
-        ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
+        ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node);
+        if (child_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
         TypeTableEntry *child_type = child_val->data.x_type;
 
         if (type_is_invalid(child_type)) {
@@ -15003,7 +15099,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
         if (!container_ptr_val)
             return ira->codegen->builtin_types.entry_invalid;
 
-        ConstExprValue *namespace_val = const_ptr_pointee(ira->codegen, container_ptr_val);
+        ConstExprValue *namespace_val = ir_const_ptr_pointee(ira, container_ptr_val,
+                field_ptr_instruction->base.source_node);
+        if (namespace_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
         assert(namespace_val->special == ConstValSpecialStatic);
 
         ImportTableEntry *namespace_import = namespace_val->data.x_import;
@@ -15079,7 +15178,9 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
         }
         if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
             if (instr_is_comptime(casted_value)) {
-                ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value);
+                ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, store_ptr_instruction->base.source_node);
+                if (dest_val == nullptr)
+                    return ira->codegen->builtin_types.entry_invalid;
                 if (dest_val->special != ConstValSpecialRuntime) {
                     *dest_val = casted_value->value;
                     if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
@@ -15090,7 +15191,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
             }
             ir_add_error(ira, &store_ptr_instruction->base,
                     buf_sprintf("cannot store runtime value in compile time variable"));
-            ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value);
+            ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
             dest_val->type = ira->codegen->builtin_types.entry_invalid;
 
             return ira->codegen->builtin_types.entry_invalid;
@@ -15656,7 +15757,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
         ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
         if (!val)
             return ira->codegen->builtin_types.entry_invalid;
-        ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val);
+        ConstExprValue *maybe_val = ir_const_ptr_pointee(ira, val, unwrap_maybe_instruction->base.source_node);
+        if (maybe_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
 
         if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
             if (optional_value_is_null(maybe_val)) {
@@ -15947,7 +16050,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
     TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
     ConstExprValue *pointee_val = nullptr;
     if (instr_is_comptime(target_value_ptr)) {
-        pointee_val = const_ptr_pointee(ira->codegen, &target_value_ptr->value);
+        pointee_val = ir_const_ptr_pointee(ira, &target_value_ptr->value, target_value_ptr->source_node);
+        if (pointee_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
+            
         if (pointee_val->special == ConstValSpecialRuntime)
             pointee_val = nullptr;
     }
@@ -16078,7 +16184,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
             if (!target_value_ptr)
                 return ira->codegen->builtin_types.entry_invalid;
 
-            ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, target_val_ptr);
+            ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, target_val_ptr, instruction->base.source_node);
+            if (pointee_val == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
+
             ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
             out_val->data.x_ptr.special = ConstPtrSpecialRef;
             out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut;
@@ -18815,19 +18924,30 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
             if (array_type->id == TypeTableEntryIdPointer) {
                 TypeTableEntry *child_array_type = array_type->data.pointer.child_type;
                 assert(child_array_type->id == TypeTableEntryIdArray);
-                parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
-                array_val = const_ptr_pointee(ira->codegen, parent_ptr);
+                parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+                if (parent_ptr == nullptr)
+                    return ira->codegen->builtin_types.entry_invalid;
+
+                array_val = ir_const_ptr_pointee(ira, parent_ptr, instruction->base.source_node);
+                if (array_val == nullptr)
+                    return ira->codegen->builtin_types.entry_invalid;
+
                 rel_end = child_array_type->data.array.len;
                 abs_offset = 0;
             } else {
-                array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
+                array_val = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+                if (array_val == nullptr)
+                    return ira->codegen->builtin_types.entry_invalid;
                 rel_end = array_type->data.array.len;
                 parent_ptr = nullptr;
                 abs_offset = 0;
             }
         } else if (array_type->id == TypeTableEntryIdPointer) {
             assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
-            parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
+            parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+            if (parent_ptr == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
+
             if (parent_ptr->special == ConstValSpecialUndef) {
                 array_val = nullptr;
                 abs_offset = 0;
@@ -18858,7 +18978,10 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
                     zig_panic("TODO slice of ptr cast from function");
             }
         } else if (is_slice(array_type)) {
-            ConstExprValue *slice_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
+            ConstExprValue *slice_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+            if (slice_ptr == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
+
             parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index];
             ConstExprValue *len_val = &slice_ptr->data.x_struct.fields[slice_len_index];
 
@@ -19258,7 +19381,9 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
         BigInt *op1_bigint = &casted_op1->value.data.x_bigint;
         BigInt *op2_bigint = &casted_op2->value.data.x_bigint;
-        ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, &casted_result_ptr->value);
+        ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, &casted_result_ptr->value, casted_result_ptr->source_node);
+        if (pointee_val == nullptr)
+            return ira->codegen->builtin_types.entry_invalid;
         BigInt *dest_bigint = &pointee_val->data.x_bigint;
         switch (instruction->op) {
             case IrOverflowOpAdd:
@@ -19358,7 +19483,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
             ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
             if (!ptr_val)
                 return ira->codegen->builtin_types.entry_invalid;
-            ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+            ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
+            if (err_union_val == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
             if (err_union_val->special != ConstValSpecialRuntime) {
                 ErrorTableEntry *err = err_union_val->data.x_err_union.err;
                 assert(err);
@@ -19406,7 +19533,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
             ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
             if (!ptr_val)
                 return ira->codegen->builtin_types.entry_invalid;
-            ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+            ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
+            if (err_union_val == nullptr)
+                return ira->codegen->builtin_types.entry_invalid;
             if (err_union_val->special != ConstValSpecialRuntime) {
                 ErrorTableEntry *err = err_union_val->data.x_err_union.err;
                 if (err != nullptr) {
test/compile_errors.zig
@@ -1,6 +1,18 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "load too many bytes from comptime reinterpreted pointer",
+        \\export fn entry() void {
+        \\    const float: f32 = 5.99999999999994648725e-01;
+        \\    const float_ptr = &float;
+        \\    const int_ptr = @ptrCast(*const i64, float_ptr);
+        \\    const int_val = int_ptr.*;
+        \\}
+    ,
+        ".tmp_source.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",
+    );
+
     cases.add(
         "invalid type used in array type",
         \\const Item = struct {