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 {...@@ -10091,20 +10091,21 @@ pub const FuncGen = struct {
10091 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");10091 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
10092 }10092 }
1009310093
10094 const tag_int = blk: {10094 const tag_int_val = blk: {
10095 const tag_ty = union_ty.unionTagTypeHypothetical(mod);10095 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
10096 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];10096 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
10097 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;10097 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
10098 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);10098 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
10099 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);10099 break :blk try tag_val.intFromEnum(tag_ty, mod);
10100 break :blk tag_int_val.toUnsignedInt(mod);
10101 };10100 };
10102 if (layout.payload_size == 0) {10101 if (layout.payload_size == 0) {
10103 if (layout.tag_size == 0) {10102 if (layout.tag_size == 0) {
10104 return .none;10103 return .none;
10105 }10104 }
10106 assert(!isByRef(union_ty, mod));10105 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);
10108 }10109 }
10109 assert(isByRef(union_ty, mod));10110 assert(isByRef(union_ty, mod));
10110 // The llvm type of the alloca will be the named LLVM union type, and will not10111 // The llvm type of the alloca will be the named LLVM union type, and will not
...@@ -10178,7 +10179,9 @@ pub const FuncGen = struct {...@@ -10178,7 +10179,9 @@ pub const FuncGen = struct {
10178 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };10179 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
10179 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");10180 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
10180 const tag_ty = try o.lowerType(Type.fromInterned(union_obj.enum_tag_ty));10181 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);
10182 const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm();10185 const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm();
10183 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);10186 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
10184 }10187 }
test/behavior/union.zig+22
...@@ -2301,3 +2301,25 @@ test "matching captures causes union equivalence" {...@@ -2301,3 +2301,25 @@ test "matching captures causes union equivalence" {
2301 comptime assert(@TypeOf(a) == @TypeOf(b));2301 comptime assert(@TypeOf(a) == @TypeOf(b));
2302 try expect(a.u == b.u);2302 try expect(a.u == b.u);
2303}2303}
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}