From 8a2ab60fca405d97d2d86456c92db1e5606622e4 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 15 Dec 2020 16:07:23 +0100 Subject: [PATCH] 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 --- src/stage1/analyze.cpp | 31 +++++++------------------------ test/stage1/behavior/union.zig | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index ed0a033592c81fdbf6d0fba48d042479f445c030..3f95456c3fcc2a532f1095802ab17563ae05952c 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -2550,8 +2550,8 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { union_type->data.unionation.gen_tag_index = 1; } } else { - assert(most_aligned_union_member != nullptr); - union_type->abi_align = most_aligned_union_member->align; + union_type->abi_align = most_aligned_union_member? + most_aligned_union_member->align : 0; union_type->data.unionation.gen_union_index = SIZE_MAX; union_type->data.unionation.gen_tag_index = SIZE_MAX; } @@ -3535,33 +3535,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { union_type->data.unionation.resolve_loop_flag_zero_bits = false; union_type->data.unionation.gen_field_count = gen_field_index; - bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag); + bool zero_bits = gen_field_index == 0 && + (tag_type == nullptr || !type_has_bits(g, tag_type)); if (!zero_bits) { union_type->abi_size = SIZE_MAX; union_type->size_in_bits = SIZE_MAX; } - if (zero_bits) { - // Don't forget to resolve the types for each union member even though - // the type is zero sized. - // XXX: Do it in a nicer way in stage2. - union_type->data.unionation.resolve_loop_flag_other = true; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - ZigType *field_type = resolve_union_field_type(g, union_field); - if (field_type == nullptr) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - - union_type->data.unionation.resolve_loop_flag_other = false; - union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; - - return ErrorNone; - } - union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown; return ErrorNone; @@ -8877,6 +8857,9 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta union_type->llvm_type = get_llvm_type(g, tag_type); union_type->llvm_di_type = get_llvm_di_type(g, tag_type); } + + union_type->data.unionation.gen_union_index = SIZE_MAX; + union_type->data.unionation.gen_tag_index = SIZE_MAX; union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; return; } diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 915f412c51f16e74882db38561854884b37ef63b..b243cee11e0347fd1dfd56ff0d728240611802a9 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -734,3 +734,30 @@ test "containers with single-field enums" { S.doTheTest(); comptime S.doTheTest(); } + +test "@unionInit on union w/ tag but no fields" { + const S = struct { + const Type = enum(u8) { no_op = 105 }; + + const Data = union(Type) { + no_op: void, + + pub fn decode(buf: []const u8) !Data { + return @unionInit(Data, "no_op", {}); + } + }; + + comptime { + expect(@sizeOf(Data) != 0); + } + + fn doTheTest() void { + var data: Data = .{ .no_op = .{} }; + var o = try Data.decode(&[_]u8{}); + expectEqual(Type.no_op, o); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} -- 2.54.0