authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-12-15 16:07:23+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-15 14:40:21-05:00
log8a2ab60fca405d97d2d86456c92db1e5606622e4
tree6abb6579ebe362777950dcfb649af93e4ba3f63c
parent8591f30b0d53a597682bebdfcd570f5f44339b26

stage1: Don't skip steps when analyzing union types

Don't cut any corner and properly run the type trough every single step even though it has no fields (or, better, the sum of the size of all its fields is zero). Fix the logic to consider an explicit non-zero-sized tag enough to treat the type as sized. Closes #7451

2 files changed, 34 insertions(+), 24 deletions(-)

src/stage1/analyze.cpp+7-24
......@@ -2550,8 +2550,8 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
25502550 union_type->data.unionation.gen_tag_index = 1;
25512551 }
25522552 } else {
2553 assert(most_aligned_union_member != nullptr);
2554 union_type->abi_align = most_aligned_union_member->align;
2553 union_type->abi_align = most_aligned_union_member?
2554 most_aligned_union_member->align : 0;
25552555 union_type->data.unionation.gen_union_index = SIZE_MAX;
25562556 union_type->data.unionation.gen_tag_index = SIZE_MAX;
25572557 }
......@@ -3535,33 +3535,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
35353535 union_type->data.unionation.resolve_loop_flag_zero_bits = false;
35363536
35373537 union_type->data.unionation.gen_field_count = gen_field_index;
3538 bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag);
3538 bool zero_bits = gen_field_index == 0 &&
3539 (tag_type == nullptr || !type_has_bits(g, tag_type));
35393540 if (!zero_bits) {
35403541 union_type->abi_size = SIZE_MAX;
35413542 union_type->size_in_bits = SIZE_MAX;
35423543 }
35433544
3544 if (zero_bits) {
3545 // Don't forget to resolve the types for each union member even though
3546 // the type is zero sized.
3547 // XXX: Do it in a nicer way in stage2.
3548 union_type->data.unionation.resolve_loop_flag_other = true;
3549
3550 for (uint32_t i = 0; i < field_count; i += 1) {
3551 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
3552 ZigType *field_type = resolve_union_field_type(g, union_field);
3553 if (field_type == nullptr) {
3554 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
3555 return ErrorSemanticAnalyzeFail;
3556 }
3557 }
3558
3559 union_type->data.unionation.resolve_loop_flag_other = false;
3560 union_type->data.unionation.resolve_status = ResolveStatusSizeKnown;
3561
3562 return ErrorNone;
3563 }
3564
35653545 union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown;
35663546
35673547 return ErrorNone;
......@@ -8877,6 +8857,9 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
88778857 union_type->llvm_type = get_llvm_type(g, tag_type);
88788858 union_type->llvm_di_type = get_llvm_di_type(g, tag_type);
88798859 }
8860
8861 union_type->data.unionation.gen_union_index = SIZE_MAX;
8862 union_type->data.unionation.gen_tag_index = SIZE_MAX;
88808863 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
88818864 return;
88828865 }
test/stage1/behavior/union.zig+27
......@@ -734,3 +734,30 @@ test "containers with single-field enums" {
734734 S.doTheTest();
735735 comptime S.doTheTest();
736736}
737
738test "@unionInit on union w/ tag but no fields" {
739 const S = struct {
740 const Type = enum(u8) { no_op = 105 };
741
742 const Data = union(Type) {
743 no_op: void,
744
745 pub fn decode(buf: []const u8) !Data {
746 return @unionInit(Data, "no_op", {});
747 }
748 };
749
750 comptime {
751 expect(@sizeOf(Data) != 0);
752 }
753
754 fn doTheTest() void {
755 var data: Data = .{ .no_op = .{} };
756 var o = try Data.decode(&[_]u8{});
757 expectEqual(Type.no_op, o);
758 }
759 };
760
761 S.doTheTest();
762 comptime S.doTheTest();
763}