diff --git a/src/analyze.cpp b/src/analyze.cpp index fe274195ef..a5ab984228 100644 --- a/src/analyze.cpp +++ b/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))) diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a58a8c980..ef43ebd575 100644 --- a/src/codegen.cpp +++ b/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); diff --git a/src/ir.cpp b/src/ir.cpp index 4e06ab5f65..d4a0cb39c9 100644 --- a/src/ir.cpp +++ b/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(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(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(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- diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index bb45fe00bc..9eefdb01cf 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/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))}); +}