authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2024-05-02 16:15:44+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-05-02 14:15:44+00:00
log20b9b54e6b276c993f723f5aa3fafea72409a4fe
tree59b8475ae7412952e8ad552caee94fdbe3cef4a7
parent5571c03a5a20a088c269f03c71631137f1ca2c3c
signaturebadge-check Signed by PGP key B5690EEEBB952194

LLVM: Fix panic when using tagged union backed by enum with negative values


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

src/codegen/llvm.zig+8-5
......@@ -10091,20 +10091,21 @@ pub const FuncGen = struct {
1009110091 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
1009210092 }
1009310093
10094 const tag_int = blk: {
10094 const tag_int_val = blk: {
1009510095 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
1009610096 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
1009710097 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
1009810098 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
10099 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
10100 break :blk tag_int_val.toUnsignedInt(mod);
10099 break :blk try tag_val.intFromEnum(tag_ty, mod);
1010110100 };
1010210101 if (layout.payload_size == 0) {
1010310102 if (layout.tag_size == 0) {
1010410103 return .none;
1010510104 }
1010610105 assert(!isByRef(union_ty, mod));
10107 return o.builder.intValue(union_llvm_ty, tag_int);
10106 var big_int_space: Value.BigIntSpace = undefined;
10107 const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod);
10108 return try o.builder.bigIntValue(union_llvm_ty, tag_big_int);
1010810109 }
1010910110 assert(isByRef(union_ty, mod));
1011010111 // The llvm type of the alloca will be the named LLVM union type, and will not
......@@ -10178,7 +10179,9 @@ pub const FuncGen = struct {
1017810179 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
1017910180 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
1018010181 const tag_ty = try o.lowerType(Type.fromInterned(union_obj.enum_tag_ty));
10181 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
10182 var big_int_space: Value.BigIntSpace = undefined;
10183 const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod);
10184 const llvm_tag = try o.builder.bigIntValue(tag_ty, tag_big_int);
1018210185 const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm();
1018310186 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
1018410187 }
test/behavior/union.zig+22
......@@ -2301,3 +2301,25 @@ test "matching captures causes union equivalence" {
23012301 comptime assert(@TypeOf(a) == @TypeOf(b));
23022302 try expect(a.u == b.u);
23032303}
2304
2305test "signed enum tag with negative value" {
2306 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2307 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2308 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2309 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2310 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2311
2312 const Enum = enum(i8) {
2313 a = -1,
2314 };
2315
2316 const Union = union(Enum) {
2317 a: i32,
2318 };
2319
2320 var i: i32 = 0;
2321 i = i;
2322 const e = Union{ .a = i };
2323
2324 try expect(e.a == i);
2325}