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
This commit is contained in:
Andrew Kelley 2022-06-29 19:01:48 -07:00
parent 54454fd010
commit c248af3bdc
3 changed files with 24 additions and 5 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);
}