| author | |
| committer | |
| log | a11da377347aea1085d3b43726040993952122c9 |
| tree | 3c5e61dd1ff0ff0d51f4d163ade020a3a8dd8328 |
| parent | d89f39d71949c85b26f2ccd4071c9445aa8b6d7c |
Fixes #36812 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; |
| 4352 | 4352 | ||
| 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 | } |
| 4367 | 4382 |
test/stage1/behavior/union.zig+15-4| ... | @@ -110,7 +110,7 @@ fn doTest() void { | ... | @@ -110,7 +110,7 @@ fn doTest() void { |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | fn bar(value: Payload) i32 { | 112 | fn 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 | } |
| 209 | 209 | ||
| 210 | fn testCastUnionToTagType(x: TheUnion) void { | 210 | fn testCastUnionToTagType(x: TheUnion) void { |
| 211 | expect(@as(TheTag,x) == TheTag.B); | 211 | expect(@as(TheTag, x) == TheTag.B); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | test "cast tag type of union to union" { | 214 | test "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 | }; |
| 559 | 559 | ||
| 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 | } |
| 566 | 566 | ||
| 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 | |||
| 575 | test "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 | } |