Skip to content

Commit

Permalink
LLVM: fix lowering of untagged union types
Browse files Browse the repository at this point in the history
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
  • Loading branch information
andrewrk committed Jun 30, 2022
1 parent 8f2f0d8 commit cebd878
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
3 changes: 0 additions & 3 deletions lib/std/net/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down
7 changes: 5 additions & 2 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions test/behavior/union.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit cebd878

Please sign in to comment.