Sema: preserve extern struct field alignment

In

    extern struct { x: u32, y: u16 }

we actually know that y's alignment is `@alignOf(u32)`, and not just
`@alignOf(u16)`.

closes: #16134
This commit is contained in:
Alex Kladov 2023-06-28 01:44:02 +01:00 committed by Jakub Konka
parent 28f515acd7
commit 4620972d08
3 changed files with 20 additions and 15 deletions

View File

@ -316,7 +316,7 @@ pub const Ip6Address = extern struct {
.addr = undefined,
},
};
var ip_slice = result.sa.addr[0..];
var ip_slice: *[16]u8 = result.sa.addr[0..];
var tail: [16]u8 = undefined;
@ -431,7 +431,7 @@ pub const Ip6Address = extern struct {
.addr = undefined,
},
};
var ip_slice = result.sa.addr[0..];
var ip_slice: *[16]u8 = result.sa.addr[0..];
var tail: [16]u8 = undefined;

View File

@ -25926,9 +25926,13 @@ fn structFieldPtrByIndex(
ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
}
}
} else if (struct_obj.layout == .Extern and field_index == 0) {
// This is the first field in memory, so can inherit the struct alignment
ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align);
} else if (struct_obj.layout == .Extern) {
// For extern structs, field aligment might be bigger than type's natural alignment. Eg, in
// `extern struct { x: u32, y: u16 }` the second field is aligned as u32.
const field_offset = struct_ty.structFieldOffset(field_index, mod);
ptr_ty_data.flags.alignment = Alignment.fromByteUnits(
if (parent_align == 0) 0 else std.math.gcd(field_offset, parent_align),
);
} else {
// Our alignment is capped at the field alignment
const field_align = try sema.structFieldAlignment(field, struct_obj.layout);

View File

@ -1680,9 +1680,9 @@ test "extern struct field pointer has correct alignment" {
const S = struct {
fn doTheTest() !void {
var a: extern struct { x: u32, y: u32 } = .{ .x = 1, .y = 2 };
var b: extern struct { x: u32, y: u32 } align(1) = .{ .x = 3, .y = 4 };
var c: extern struct { x: u32, y: u32 } align(64) = .{ .x = 5, .y = 6 };
var a: extern struct { x: u32, y: u16 } = .{ .x = 1, .y = 2 };
var b: extern struct { x: u32, y: u16 } align(1) = .{ .x = 3, .y = 4 };
var c: extern struct { x: u32, y: u16 } align(64) = .{ .x = 5, .y = 6 };
const axp = &a.x;
const bxp = &b.x;
@ -1693,18 +1693,19 @@ test "extern struct field pointer has correct alignment" {
comptime assert(@TypeOf(axp) == *u32);
comptime assert(@TypeOf(bxp) == *align(1) u32);
comptime assert(@TypeOf(cxp) == *align(64) u32); // first field, inherits larger alignment
comptime assert(@TypeOf(ayp) == *u32);
comptime assert(@TypeOf(byp) == *align(1) u32);
comptime assert(@TypeOf(cyp) == *u32);
comptime assert(@TypeOf(cxp) == *align(64) u32);
comptime assert(@TypeOf(ayp) == *align(@alignOf(u32)) u16);
comptime assert(@TypeOf(byp) == *align(1) u16);
comptime assert(@TypeOf(cyp) == *align(@alignOf(u32)) u16);
try expectEqual(@as(u32, 1), axp.*);
try expectEqual(@as(u32, 3), bxp.*);
try expectEqual(@as(u32, 5), cxp.*);
try expectEqual(@as(u32, 2), ayp.*);
try expectEqual(@as(u32, 4), byp.*);
try expectEqual(@as(u32, 6), cyp.*);
try expectEqual(@as(u16, 2), ayp.*);
try expectEqual(@as(u16, 4), byp.*);
try expectEqual(@as(u16, 6), cyp.*);
}
};