Commit c0fee9dfc7

Andrew Kelley <andrew@ziglang.org>
2020-01-27 23:30:39
fix nested bitcast passed as tuple element
1 parent e2778c0
Changed files (4)
src/analyze.cpp
@@ -593,9 +593,9 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
     }
 
     if (inferred_struct_field != nullptr) {
-        entry->abi_size = g->builtin_types.entry_usize->abi_size;
-        entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
-        entry->abi_align = g->builtin_types.entry_usize->abi_align;
+        entry->abi_size = SIZE_MAX;
+        entry->size_in_bits = SIZE_MAX;
+        entry->abi_align = UINT32_MAX;
     } else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) {
         if (type_has_bits(child_type)) {
             entry->abi_size = g->builtin_types.entry_usize->abi_size;
@@ -6474,7 +6474,21 @@ static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) {
     }
     ty->data.pointer.resolve_loop_flag_zero_bits = true;
 
-    ZigType *elem_type = ty->data.pointer.child_type;
+    ZigType *elem_type;
+    InferredStructField *isf = ty->data.pointer.inferred_struct_field;
+    if (isf != nullptr) {
+        TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name);
+        assert(field != nullptr);
+        if (field->is_comptime) {
+            ty->abi_size = 0;
+            ty->size_in_bits = 0;
+            ty->abi_align = 0;
+            return ErrorNone;
+        }
+        elem_type = field->type_entry;
+    } else {
+        elem_type = ty->data.pointer.child_type;
+    }
 
     bool has_bits;
     if ((err = type_has_bits2(g, elem_type, &has_bits)))
src/codegen.cpp
@@ -3120,8 +3120,14 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutableGen *executab
 static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutableGen *executable,
         IrInstGenCast *cast_instruction)
 {
+    Error err;
     ZigType *actual_type = cast_instruction->value->value->type;
     ZigType *wanted_type = cast_instruction->base.value->type;
+    bool wanted_type_has_bits;
+    if ((err = type_has_bits2(g, wanted_type, &wanted_type_has_bits)))
+        codegen_report_errors_and_exit(g);
+    if (!wanted_type_has_bits)
+        return nullptr;
     LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value);
     ir_assert(expr_val, &cast_instruction->base);
 
src/ir.cpp
@@ -880,7 +880,6 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte
         case ZigTypeIdComptimeFloat:
         case ZigTypeIdComptimeInt:
         case ZigTypeIdEnumLiteral:
-        case ZigTypeIdPointer:
         case ZigTypeIdUndefined:
         case ZigTypeIdNull:
         case ZigTypeIdBoundFn:
@@ -889,6 +888,8 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte
         case ZigTypeIdAnyFrame:
         case ZigTypeIdFn:
             return true;
+        case ZigTypeIdPointer:
+            return expected->data.pointer.inferred_struct_field == actual->data.pointer.inferred_struct_field;
         case ZigTypeIdFloat:
             return expected->data.floating.bit_count == actual->data.floating.bit_count;
         case ZigTypeIdInt:
@@ -7014,6 +7015,7 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
                 ResultLocBitCast *result_loc_bit_cast = allocate<ResultLocBitCast>(1);
                 result_loc_bit_cast->base.id = ResultLocIdBitCast;
                 result_loc_bit_cast->base.source_instruction = dest_type;
+                result_loc_bit_cast->base.allow_write_through_const = result_loc->allow_write_through_const;
                 ir_ref_instruction(dest_type, irb->current_basic_block);
                 result_loc_bit_cast->parent = result_loc;
 
@@ -13597,32 +13599,31 @@ static IrInstGen *ir_analyze_null_to_c_pointer(IrAnalyze *ira, IrInst *source_in
     return result;
 }
 
-static IrInstGen *ir_get_ref(IrAnalyze *ira, IrInst* source_instruction, IrInstGen *value,
-        bool is_const, bool is_volatile)
+static IrInstGen *ir_get_ref2(IrAnalyze *ira, IrInst* source_instruction, IrInstGen *value,
+        ZigType *elem_type, bool is_const, bool is_volatile)
 {
     Error err;
 
-    if (type_is_invalid(value->value->type))
+    if (type_is_invalid(elem_type))
         return ira->codegen->invalid_inst_gen;
 
     if (instr_is_comptime(value)) {
         ZigValue *val = ir_resolve_const(ira, value, LazyOk);
         if (!val)
             return ira->codegen->invalid_inst_gen;
-        return ir_get_const_ptr(ira, source_instruction, val, value->value->type,
+        return ir_get_const_ptr(ira, source_instruction, val, elem_type,
                 ConstPtrMutComptimeConst, is_const, is_volatile, 0);
     }
 
-    ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value->type,
+    ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type,
             is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
 
     if ((err = type_resolve(ira->codegen, ptr_type, ResolveStatusZeroBitsKnown)))
         return ira->codegen->invalid_inst_gen;
 
     IrInstGen *result_loc;
-    if (type_has_bits(ptr_type) && !handle_is_ptr(value->value->type)) {
-        result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value->type,
-                nullptr, true, true);
+    if (type_has_bits(ptr_type) && !handle_is_ptr(elem_type)) {
+        result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), elem_type, nullptr, true, true);
     } else {
         result_loc = nullptr;
     }
@@ -13632,6 +13633,12 @@ static IrInstGen *ir_get_ref(IrAnalyze *ira, IrInst* source_instruction, IrInstG
     return new_instruction;
 }
 
+static IrInstGen *ir_get_ref(IrAnalyze *ira, IrInst* source_instruction, IrInstGen *value,
+        bool is_const, bool is_volatile)
+{
+    return ir_get_ref2(ira, source_instruction, value, value->value->type, is_const, is_volatile);
+}
+
 static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, AstNode *source_node, ZigType *union_type) {
     assert(union_type->id == ZigTypeIdUnion);
 
@@ -18204,6 +18211,21 @@ static IrInstGen *ir_resolve_no_result_loc(IrAnalyze *ira, IrInst *suspend_sourc
     return result_loc->resolved_loc;
 }
 
+static bool result_loc_is_discard(ResultLoc *result_loc_pass1) {
+    if (result_loc_pass1->id == ResultLocIdInstruction &&
+        result_loc_pass1->source_instruction->id == IrInstSrcIdConst)
+    {
+        IrInstSrcConst *const_inst = reinterpret_cast<IrInstSrcConst *>(result_loc_pass1->source_instruction);
+        if (value_is_comptime(const_inst->value) &&
+            const_inst->value->type->id == ZigTypeIdPointer &&
+            const_inst->value->data.x_ptr.special == ConstPtrSpecialDiscard)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
 // when calling this function, at the callsite must check for result type noreturn and propagate it up
 static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_instr,
         ResultLoc *result_loc, ZigType *value_type, IrInstGen *value, bool force_runtime,
@@ -18494,13 +18516,7 @@ static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_i
             assert(parent_ptr_type->id == ZigTypeIdPointer);
             ZigType *child_type = parent_ptr_type->data.pointer.child_type;
 
-            bool has_bits;
-            if ((err = type_has_bits2(ira->codegen, child_type, &has_bits))) {
-                return ira->codegen->invalid_inst_gen;
-            }
-
-            // This happens when the bitCast result is assigned to _
-            if (!has_bits) {
+            if (result_loc_is_discard(result_bit_cast->parent)) {
                 assert(allow_discard);
                 return parent_result_loc;
             }
@@ -18531,16 +18547,8 @@ static IrInstGen *ir_resolve_result(IrAnalyze *ira, IrInst *suspend_source_instr
         bool allow_discard)
 {
     Error err;
-    if (!allow_discard && result_loc_pass1->id == ResultLocIdInstruction &&
-        result_loc_pass1->source_instruction->id == IrInstSrcIdConst)
-    {
-        IrInstSrcConst *const_inst = reinterpret_cast<IrInstSrcConst *>(result_loc_pass1->source_instruction);
-        if (value_is_comptime(const_inst->value) &&
-            const_inst->value->type->id == ZigTypeIdPointer &&
-            const_inst->value->data.x_ptr.special == ConstPtrSpecialDiscard)
-        {
-            result_loc_pass1 = no_result_loc();
-        }
+    if (!allow_discard && result_loc_is_discard(result_loc_pass1)) {
+        result_loc_pass1 = no_result_loc();
     }
     bool was_written = result_loc_pass1->written;
     IrInstGen *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type,
@@ -21062,7 +21070,7 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins
         IrInstGen *elem = ir_const(ira, source_instr, field_type);
         memoize_field_init_val(ira->codegen, struct_type, field);
         copy_const_val(elem->value, field->init_val);
-        return ir_get_ref(ira, source_instr, elem, true, false);
+        return ir_get_ref2(ira, source_instr, elem, field_type, true, false);
     }
     switch (type_has_one_possible_value(ira->codegen, field_type)) {
         case OnePossibleValueInvalid:
@@ -27708,7 +27716,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
     if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
         return ira->codegen->invalid_inst_gen;
 
-    if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
+    if (type_has_bits(dest_type) && !type_has_bits(src_type) && safety_check_on) {
         ErrorMsg *msg = ir_add_error(ira, source_instr,
             buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
                 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
@@ -27723,7 +27731,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
         bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
         UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
         ZigValue *val = ir_resolve_const(ira, ptr, is_undef_allowed);
-        if (!val)
+        if (val == nullptr)
             return ira->codegen->invalid_inst_gen;
 
         if (value_is_comptime(val) && val->special != ConstValSpecialUndef) {
@@ -27738,15 +27746,31 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
         }
 
         IrInstGen *result;
-        if (ptr->value->data.x_ptr.mut == ConstPtrMutInfer) {
+        if (val->data.x_ptr.mut == ConstPtrMutInfer) {
             result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on);
-
-            if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
-                return ira->codegen->invalid_inst_gen;
         } else {
             result = ir_const(ira, source_instr, dest_type);
         }
-        copy_const_val(result->value, val);
+        InferredStructField *isf = (val->type->id == ZigTypeIdPointer) ?
+            val->type->data.pointer.inferred_struct_field : nullptr;
+        if (isf == nullptr) {
+            copy_const_val(result->value, val);
+        } else {
+            // The destination value should have x_ptr struct pointing to underlying struct value
+            result->value->data.x_ptr.mut = val->data.x_ptr.mut;
+            TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name);
+            assert(field != nullptr);
+            if (field->is_comptime) {
+                result->value->data.x_ptr.special = ConstPtrSpecialRef;
+                result->value->data.x_ptr.data.ref.pointee = field->init_val;
+            } else {
+                assert(val->data.x_ptr.special == ConstPtrSpecialRef);
+                result->value->data.x_ptr.special = ConstPtrSpecialBaseStruct;
+                result->value->data.x_ptr.data.base_struct.struct_val = val->data.x_ptr.data.ref.pointee;
+                result->value->data.x_ptr.data.base_struct.field_index = field->src_index;
+            }
+            result->value->special = ConstValSpecialStatic;
+        }
         result->value->type = dest_type;
 
         // Keep the bigger alignment, it can only help-
test/stage1/behavior/bitcast.zig
@@ -168,11 +168,12 @@ test "nested bitcast" {
     comptime S.foo(42);
 }
 
-//test "bitcast passed as tuple element" {
-//    const S = struct {
-//        fn foo(args: var) void {
-//            expect(args[0] == 1.00000e-09);
-//        }
-//    };
-//    S.foo(.{@bitCast(f32, @as(u32, 814313563))});
-//}
+test "bitcast passed as tuple element" {
+    const S = struct {
+        fn foo(args: var) void {
+            comptime expect(@TypeOf(args[0]) == f32);
+            expect(args[0] == 12.34);
+        }
+    };
+    S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))});
+}