From 38ba425b26312ea073c7082e576e8583913139d7 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 12 Aug 2025 22:58:52 +0100 Subject: [PATCH 1/2] llvm: support small error limits Resolves: #23533 --- src/codegen/llvm.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a46c2d0e76..bccb67ec3c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10475,11 +10475,14 @@ pub const FuncGen = struct { const slice_ty = self.typeOfIndex(inst); const slice_llvm_ty = try o.lowerType(pt, slice_ty); + // If operand is small (e.g. `u8`), then signedness becomes a problem -- GEP always treats the index as signed. + const extended_operand = try self.wip.conv(.unsigned, operand, try o.lowerType(pt, .usize), ""); + const error_name_table_ptr = try self.getErrorNameTable(); const error_name_table = try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, ""); const error_name_ptr = - try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{operand}, ""); + try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{extended_operand}, ""); return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, ""); } From ba6abd71c2d3664bc658cf5ce55b5c53052dc720 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 12 Aug 2025 23:18:05 +0100 Subject: [PATCH 2/2] llvm: unions which are equivalent to enums are not by-ref The LLVM backend lowers unions where all fields are zero-bit as equivalent to their backing enum, and expects them to have the same by-ref-ness in at least one place in the backend, probably more. Resolves: #23577 --- src/codegen/llvm.zig | 2 +- test/behavior/cast.zig | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index bccb67ec3c..1aa8e86a7f 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -12777,7 +12777,7 @@ fn isByRef(ty: Type, zcu: *Zcu) bool { }, .@"union" => switch (ty.containerLayout(zcu)) { .@"packed" => return false, - else => return ty.hasRuntimeBits(zcu), + else => return ty.hasRuntimeBits(zcu) and !ty.unionHasAllZeroBitFieldTypes(zcu), }, .error_union => { const payload_ty = ty.errorUnionPayload(zcu); diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 740d123170..7eee20e3e0 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -2722,3 +2722,18 @@ test "@intFromFloat vector boundary cases" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "coerce enum to union with zero-bit fields through local variables" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + + const E = enum(u1) { foo, bar }; + const U = union(E) { foo, bar }; + + var runtime: E = undefined; + runtime = .foo; + + var result: U = undefined; + result = runtime; + + try expect(result == .foo); +}