authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-29 19:01:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-30 02:43:05-04:00
logc248af3bdcd17c334e742d53a7ac7bda2422a688
tree8d47cfaa0f653ef1b835c6e250178c763270000a
parent54454fd0102af8b25dbc85751d37fd265380d920

LLVM: fix lowering of untagged union types

The LLVM backend was calculating the amount of padding solely based on the payload size. However, in the case where there is no union tag, this fails to take into account alignment. Closes #11857

3 files changed, 24 insertions(+), 5 deletions(-)

lib/std/net/test.zig-3
...@@ -5,7 +5,6 @@ const mem = std.mem;...@@ -5,7 +5,6 @@ const mem = std.mem;
5const testing = std.testing;5const testing = std.testing;
66
7test "parse and render IPv6 addresses" {7test "parse and render IPv6 addresses" {
8 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
9 if (builtin.os.tag == .wasi) return error.SkipZigTest;8 if (builtin.os.tag == .wasi) return error.SkipZigTest;
109
11 var buffer: [100]u8 = undefined;10 var buffer: [100]u8 = undefined;
...@@ -68,7 +67,6 @@ test "invalid but parseable IPv6 scope ids" {...@@ -68,7 +67,6 @@ test "invalid but parseable IPv6 scope ids" {
68}67}
6968
70test "parse and render IPv4 addresses" {69test "parse and render IPv4 addresses" {
71 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
72 if (builtin.os.tag == .wasi) return error.SkipZigTest;70 if (builtin.os.tag == .wasi) return error.SkipZigTest;
7371
74 var buffer: [18]u8 = undefined;72 var buffer: [18]u8 = undefined;
...@@ -93,7 +91,6 @@ test "parse and render IPv4 addresses" {...@@ -93,7 +91,6 @@ test "parse and render IPv4 addresses" {
93}91}
9492
95test "parse and render UNIX addresses" {93test "parse and render UNIX addresses" {
96 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
97 if (builtin.os.tag == .wasi) return error.SkipZigTest;94 if (builtin.os.tag == .wasi) return error.SkipZigTest;
98 if (!net.has_unix_sockets) return error.SkipZigTest;95 if (!net.has_unix_sockets) return error.SkipZigTest;
9996
src/codegen/llvm.zig+5-2
...@@ -2708,7 +2708,10 @@ pub const DeclGen = struct {...@@ -2708,7 +2708,10 @@ pub const DeclGen = struct {
2708 if (layout.most_aligned_field_size == layout.payload_size) {2708 if (layout.most_aligned_field_size == layout.payload_size) {
2709 break :t llvm_aligned_field_ty;2709 break :t llvm_aligned_field_ty;
2710 }2710 }
2711 const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);2711 const padding_len = if (layout.tag_size == 0)
2712 @intCast(c_uint, layout.abi_size - layout.most_aligned_field_size)
2713 else
2714 @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
2712 const fields: [2]*const llvm.Type = .{2715 const fields: [2]*const llvm.Type = .{
2713 llvm_aligned_field_ty,2716 llvm_aligned_field_ty,
2714 dg.context.intType(8).arrayType(padding_len),2717 dg.context.intType(8).arrayType(padding_len),
...@@ -5756,7 +5759,7 @@ pub const FuncGen = struct {...@@ -5756,7 +5759,7 @@ pub const FuncGen = struct {
5756 // First set the non-null bit.5759 // First set the non-null bit.
5757 const indices: [2]*const llvm.Value = .{5760 const indices: [2]*const llvm.Value = .{
5758 index_type.constNull(), // dereference the pointer5761 index_type.constNull(), // dereference the pointer
5759 index_type.constInt(1, .False), // second field is the payload5762 index_type.constInt(1, .False), // second field is the non-null bit
5760 };5763 };
5761 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");5764 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
5762 _ = self.builder.buildStore(non_null_bit, non_null_ptr);5765 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
test/behavior/union.zig+19
...@@ -1194,3 +1194,22 @@ test "union tag is set when initiated as a temporary value at runtime" {...@@ -1194,3 +1194,22 @@ test "union tag is set when initiated as a temporary value at runtime" {
1194 var b: u32 = 1;1194 var b: u32 = 1;
1195 try (U{ .b = b }).doTheTest();1195 try (U{ .b = b }).doTheTest();
1196}1196}
1197
1198test "extern union most-aligned field is smaller" {
1199 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1203
1204 const U = extern union {
1205 in6: extern struct {
1206 family: u16,
1207 port: u16,
1208 flowinfo: u32,
1209 addr: [20]u8,
1210 },
1211 un: [110]u8,
1212 };
1213 var a: ?U = .{ .un = [_]u8{0} ** 110 };
1214 try expect(a != null);
1215}