diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 779e1d14de27..9be2316a558f 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10091,20 +10091,21 @@ pub const FuncGen = struct { return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, ""); } - const tag_int = blk: { + const tag_int_val = blk: { const tag_ty = union_ty.unionTagTypeHypothetical(mod); const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index]; const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?; const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); - const tag_int_val = try tag_val.intFromEnum(tag_ty, mod); - break :blk tag_int_val.toUnsignedInt(mod); + break :blk try tag_val.intFromEnum(tag_ty, mod); }; if (layout.payload_size == 0) { if (layout.tag_size == 0) { return .none; } assert(!isByRef(union_ty, mod)); - return o.builder.intValue(union_llvm_ty, tag_int); + var big_int_space: Value.BigIntSpace = undefined; + const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod); + return try o.builder.bigIntValue(union_llvm_ty, tag_big_int); } assert(isByRef(union_ty, mod)); // The llvm type of the alloca will be the named LLVM union type, and will not @@ -10178,7 +10179,9 @@ pub const FuncGen = struct { const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) }; const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, ""); const tag_ty = try o.lowerType(Type.fromInterned(union_obj.enum_tag_ty)); - const llvm_tag = try o.builder.intValue(tag_ty, tag_int); + var big_int_space: Value.BigIntSpace = undefined; + const tag_big_int = tag_int_val.toBigInt(&big_int_space, mod); + const llvm_tag = try o.builder.bigIntValue(tag_ty, tag_big_int); const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(mod).toLlvm(); _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment); } diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 5ed336b50b3c..b652d52896f7 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -2301,3 +2301,25 @@ test "matching captures causes union equivalence" { comptime assert(@TypeOf(a) == @TypeOf(b)); try expect(a.u == b.u); } + +test "signed enum tag with negative value" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + + const Enum = enum(i8) { + a = -1, + }; + + const Union = union(Enum) { + a: i32, + }; + + var i: i32 = 0; + i = i; + const e = Union{ .a = i }; + + try expect(e.a == i); +}