From c248af3bdcd17c334e742d53a7ac7bda2422a688 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 29 Jun 2022 19:01:48 -0700 Subject: [PATCH] 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 --- lib/std/net/test.zig | 3 --- src/codegen/llvm.zig | 7 +++++-- test/behavior/union.zig | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig index 710eb91376b3f3684b84fa3b3d98a885b00b6f99..5d350be7e0eb24e18955cd770b9270e4516f835c 100644 --- a/lib/std/net/test.zig +++ b/lib/std/net/test.zig @@ -5,7 +5,6 @@ const mem = std.mem; const testing = std.testing; test "parse and render IPv6 addresses" { - if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; if (builtin.os.tag == .wasi) return error.SkipZigTest; var buffer: [100]u8 = undefined; @@ -68,7 +67,6 @@ test "invalid but parseable IPv6 scope ids" { } test "parse and render IPv4 addresses" { - if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; if (builtin.os.tag == .wasi) return error.SkipZigTest; var buffer: [18]u8 = undefined; @@ -93,7 +91,6 @@ test "parse and render IPv4 addresses" { } test "parse and render UNIX addresses" { - if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; if (builtin.os.tag == .wasi) return error.SkipZigTest; if (!net.has_unix_sockets) return error.SkipZigTest; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2b320923ad177dc789456b3a74a70cd503170f54..c62860c88dba25ae9041dc1d0fa99c39a6889ca2 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2708,7 +2708,10 @@ pub const DeclGen = struct { if (layout.most_aligned_field_size == layout.payload_size) { break :t llvm_aligned_field_ty; } - const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); + const padding_len = if (layout.tag_size == 0) + @intCast(c_uint, layout.abi_size - layout.most_aligned_field_size) + else + @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); const fields: [2]*const llvm.Type = .{ llvm_aligned_field_ty, dg.context.intType(8).arrayType(padding_len), @@ -5756,7 +5759,7 @@ pub const FuncGen = struct { // First set the non-null bit. const indices: [2]*const llvm.Value = .{ index_type.constNull(), // dereference the pointer - index_type.constInt(1, .False), // second field is the payload + index_type.constInt(1, .False), // second field is the non-null bit }; const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); _ = self.builder.buildStore(non_null_bit, non_null_ptr); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 3c8874e3a8560cdfddad99283962f69ebc254a67..be01b3a048af2feb3eb5a326626f1fe84b171852 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1194,3 +1194,22 @@ test "union tag is set when initiated as a temporary value at runtime" { var b: u32 = 1; try (U{ .b = b }).doTheTest(); } + +test "extern union most-aligned field is smaller" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const U = extern union { + in6: extern struct { + family: u16, + port: u16, + flowinfo: u32, + addr: [20]u8, + }, + un: [110]u8, + }; + var a: ?U = .{ .un = [_]u8{0} ** 110 }; + try expect(a != null); +} -- 2.54.0