authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-11-14 10:20:57+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-14 17:07:20+00:00
loga11da377347aea1085d3b43726040993952122c9
tree3c5e61dd1ff0ff0d51f4d163ade020a3a8dd8328
parentd89f39d71949c85b26f2ccd4071c9445aa8b6d7c

Update discriminant value also for zero-sized unions

Fixes #3681

2 files changed, 39 insertions(+), 13 deletions(-)

src/codegen.cpp+24-9
...@@ -4351,17 +4351,32 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab...@@ -4351,17 +4351,32 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
4351 TypeUnionField *field = instruction->field;4351 TypeUnionField *field = instruction->field;
43524352
4353 if (!type_has_bits(field->type_entry)) {4353 if (!type_has_bits(field->type_entry)) {
4354 if (union_type->data.unionation.gen_tag_index == SIZE_MAX) {4354 ZigType *tag_type = union_type->data.unionation.tag_type;
4355 if (!instruction->initializing || !type_has_bits(tag_type))
4355 return nullptr;4356 return nullptr;
4357
4358 // The field has no bits but we still have to change the discriminant
4359 // value here
4360 LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);
4361
4362 LLVMTypeRef tag_type_ref = get_llvm_type(g, tag_type);
4363 LLVMValueRef tag_field_ptr = nullptr;
4364 if (union_type->data.unionation.gen_field_count == 0) {
4365 assert(union_type->data.unionation.gen_tag_index == SIZE_MAX);
4366 // The whole union is collapsed into the discriminant
4367 tag_field_ptr = LLVMBuildBitCast(g->builder, union_ptr,
4368 LLVMPointerType(tag_type_ref, 0), "");
4369 } else {
4370 assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
4371 tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
4372 union_type->data.unionation.gen_tag_index, "");
4356 }4373 }
4357 if (instruction->initializing) {4374
4358 LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);4375 LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref,
4359 LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,4376 &field->enum_field->value);
4360 union_type->data.unionation.gen_tag_index, "");4377 assert(tag_field_ptr != nullptr);
4361 LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type),4378 gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
4362 &field->enum_field->value);4379
4363 gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
4364 }
4365 return nullptr;4380 return nullptr;
4366 }4381 }
43674382
test/stage1/behavior/union.zig+15-4
...@@ -110,7 +110,7 @@ fn doTest() void {...@@ -110,7 +110,7 @@ fn doTest() void {
110}110}
111111
112fn bar(value: Payload) i32 {112fn bar(value: Payload) i32 {
113 expect(@as(Letter,value) == Letter.A);113 expect(@as(Letter, value) == Letter.A);
114 return switch (value) {114 return switch (value) {
115 Payload.A => |x| return x - 1244,115 Payload.A => |x| return x - 1244,
116 Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,116 Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,
...@@ -208,7 +208,7 @@ test "cast union to tag type of union" {...@@ -208,7 +208,7 @@ test "cast union to tag type of union" {
208}208}
209209
210fn testCastUnionToTagType(x: TheUnion) void {210fn testCastUnionToTagType(x: TheUnion) void {
211 expect(@as(TheTag,x) == TheTag.B);211 expect(@as(TheTag, x) == TheTag.B);
212}212}
213213
214test "cast tag type of union to union" {214test "cast tag type of union to union" {
...@@ -558,16 +558,27 @@ test "anonymous union literal syntax" {...@@ -558,16 +558,27 @@ test "anonymous union literal syntax" {
558 };558 };
559559
560 fn doTheTest() void {560 fn doTheTest() void {
561 var i: Number = .{.int = 42};561 var i: Number = .{ .int = 42 };
562 var f = makeNumber();562 var f = makeNumber();
563 expect(i.int == 42);563 expect(i.int == 42);
564 expect(f.float == 12.34);564 expect(f.float == 12.34);
565 }565 }
566566
567 fn makeNumber() Number {567 fn makeNumber() Number {
568 return .{.float = 12.34};568 return .{ .float = 12.34 };
569 }569 }
570 };570 };
571 S.doTheTest();571 S.doTheTest();
572 comptime S.doTheTest();572 comptime S.doTheTest();
573}573}
574
575test "update the tag value for zero-sized unions" {
576 const S = union(enum) {
577 U0: void,
578 U1: void,
579 };
580 var x = S{ .U0 = {} };
581 expect(x == .U0);
582 x = S{ .U1 = {} };
583 expect(x == .U1);
584}