Skip to content

Commit 20b9b54

Browse files
authored
LLVM: Fix panic when using tagged union backed by enum with negative values
1 parent 5571c03 commit 20b9b54

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

src/codegen/llvm.zig

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
2305+
test "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+
}

0 commit comments

Comments
 (0)