diff --git a/src/codegen.cpp b/src/codegen.cpp index 730f2695e0..87881ccaf3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3331,12 +3331,16 @@ static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutableGen *executable, LLVMPointerType(get_llvm_type(g, wanted_type), 0) : get_llvm_type(g, wanted_type); return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); } else if (actual_is_ptr) { + // A scalar is wanted but we got a pointer LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, wanted_type), 0); LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); uint32_t alignment = get_abi_alignment(g, actual_type); return gen_load_untyped(g, bitcasted_ptr, alignment, false, ""); } else { - zig_unreachable(); + // A pointer is wanted but we got a scalar + assert(actual_type->id == ZigTypeIdPointer); + LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, wanted_type), 0); + return LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); } } diff --git a/src/ir.cpp b/src/ir.cpp index 0fcbc1be10..00bd83f95e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28878,8 +28878,11 @@ static IrInstGen *ir_analyze_bit_cast(IrAnalyze *ira, IrInst* source_instr, IrIn if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_inst_gen; - uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); - uint64_t src_size_bytes = type_size(ira->codegen, src_type); + const bool src_is_ptr = handle_is_ptr(ira->codegen, src_type); + const bool dest_is_ptr = handle_is_ptr(ira->codegen, dest_type); + + const uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); + const uint64_t src_size_bytes = type_size(ira->codegen, src_type); if (dest_size_bytes != src_size_bytes) { ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64, @@ -28888,8 +28891,8 @@ static IrInstGen *ir_analyze_bit_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return ira->codegen->invalid_inst_gen; } - uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); - uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); + const uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); + const uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); if (dest_size_bits != src_size_bits) { ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", @@ -28911,6 +28914,11 @@ static IrInstGen *ir_analyze_bit_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return result; } + if (dest_is_ptr && !src_is_ptr) { + // Spill the scalar into a local memory location and take its address + value = ir_get_ref(ira, source_instr, value, false, false); + } + return ir_build_bit_cast_gen(ira, source_instr, value, dest_type); } diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index 2cc1026354..009f4544ba 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; const maxInt = std.math.maxInt; test "@bitCast i32 -> u32" { @@ -187,3 +188,9 @@ test "triple level result location with bitcast sandwich passed as tuple element }; S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); } + +test "bitcast generates a temporary value" { + var y = @as(u16, 0x55AA); + const x = @bitCast(u16, @bitCast([2]u8, y)); + expectEqual(y, x); +}