authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-16 22:06:08-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-16 22:06:08-05:00
log5d2ba056c801f46a07182a05c07887e06fd197fa
treee05d1de9c4d201ee4ed3787facb189b1f7baeb7e
parente26ccd5166000f81a589c446d04102c21045bff6

fix codegen for union init with runtime value

see #144

2 files changed, 40 insertions(+), 5 deletions(-)

src/codegen.cpp+22-5
...@@ -3414,17 +3414,34 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,...@@ -3414,17 +3414,34 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
3414static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {3414static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
3415 TypeUnionField *type_union_field = instruction->field;3415 TypeUnionField *type_union_field = instruction->field;
34163416
3417 assert(type_has_bits(type_union_field->type_entry));3417 if (!type_has_bits(type_union_field->type_entry))
34183418 return nullptr;
3419 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
3420 LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
34213419
3422 uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);3420 uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
3423
3424 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,3421 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
3425 false, false, field_align_bytes,3422 false, false, field_align_bytes,
3426 0, 0);3423 0, 0);
34273424
3425 LLVMValueRef uncasted_union_ptr;
3426 // Even if safety is off in this block, if the union type has the safety field, we have to populate it
3427 // correctly. Otherwise safety code somewhere other than here could fail.
3428 TypeTableEntry *union_type = instruction->union_type;
3429 if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
3430 LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
3431 union_type->data.unionation.gen_tag_index, "");
3432 LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
3433 type_union_field->value, false);
3434 gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
3435
3436 uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
3437 (unsigned)union_type->data.unionation.gen_union_index, "");
3438 } else {
3439 uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
3440 }
3441
3442 LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
3443 LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
3444
3428 gen_assign_raw(g, field_ptr, ptr_type, value);3445 gen_assign_raw(g, field_ptr, ptr_type, value);
34293446
3430 return instruction->tmp_ptr;3447 return instruction->tmp_ptr;
test/cases/union.zig+18
...@@ -45,6 +45,23 @@ test "basic unions" {...@@ -45,6 +45,23 @@ test "basic unions" {
45 assert(foo.float == 12.34);45 assert(foo.float == 12.34);
46}46}
4747
48test "init union with runtime value" {
49 var foo: Foo = undefined;
50
51 setFloat(&foo, 12.34);
52 assert(foo.float == 12.34);
53
54 setInt(&foo, 42);
55 assert(foo.int == 42);
56}
57
58fn setFloat(foo: &Foo, x: f64) {
59 *foo = Foo { .float = x };
60}
61
62fn setInt(foo: &Foo, x: i32) {
63 *foo = Foo { .int = x };
64}
4865
49const FooExtern = extern union {66const FooExtern = extern union {
50 float: f64,67 float: f64,
...@@ -57,3 +74,4 @@ test "basic extern unions" {...@@ -57,3 +74,4 @@ test "basic extern unions" {
57 foo.float = 12.34;74 foo.float = 12.34;
58 assert(foo.float == 12.34);75 assert(foo.float == 12.34);
59}76}
77