authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2024-05-02 16:15:44+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-22 06:56:49-07:00
log7ce03acb9db361a2313ec4fb8477a2536530bede
tree3e212841129b2aae5de0565908209eca8d290229
parentc3aa32e98408c8e6e1578e573b8e2eef47fd4c54

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
...@@ -9997,20 +9997,21 @@ pub const FuncGen = struct {...@@ -9997,20 +9997,21 @@ pub const FuncGen = struct {
9997 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");9997 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
9998 }9998 }
99999999
10000 const tag_int = blk: {10000 const tag_int_val = blk: {
10001 const tag_ty = union_ty.unionTagTypeHypothetical(mod);10001 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
10002 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];10002 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
10003 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;10003 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
10004 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);10004 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
10005 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);10005 break :blk try tag_val.intFromEnum(tag_ty, mod);
10006 break :blk tag_int_val.toUnsignedInt(mod);
10007 };10006 };
10008 if (layout.payload_size == 0) {10007 if (layout.payload_size == 0) {
10009 if (layout.tag_size == 0) {10008 if (layout.tag_size == 0) {
10010 return .none;10009 return .none;
10011 }10010 }
10012 assert(!isByRef(union_ty, mod));10011 assert(!isByRef(union_ty, mod));
10013 return o.builder.intValue(union_llvm_ty, tag_int);10012 var big_int_space: Value.BigIntSpace = undefined;
10013 const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod);
10014 return try o.builder.bigIntValue(union_llvm_ty, tag_big_int);
10014 }10015 }
10015 assert(isByRef(union_ty, mod));10016 assert(isByRef(union_ty, mod));
10016 // The llvm type of the alloca will be the named LLVM union type, and will not10017 // The llvm type of the alloca will be the named LLVM union type, and will not
...@@ -10084,7 +10085,9 @@ pub const FuncGen = struct {...@@ -10084,7 +10085,9 @@ pub const FuncGen = struct {
10084 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };10085 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
10085 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");10086 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
10086 const tag_ty = try o.lowerType(Type.fromInterned(union_obj.enum_tag_ty));10087 const tag_ty = try o.lowerType(Type.fromInterned(union_obj.enum_tag_ty));
10087 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);10088 var big_int_space: Value.BigIntSpace = undefined;
10089 const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod);
10090 const llvm_tag = try o.builder.bigIntValue(tag_ty, tag_big_int);
10088 const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm();10091 const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm();
10089 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);10092 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
10090 }10093 }
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}