type: correct condition for eliding pointer alignment canonicalization

Closes #14373
This commit is contained in:
Veikka Tuominen 2023-01-19 16:30:25 +02:00
parent d284c00fda
commit a492a607d5
2 changed files with 49 additions and 6 deletions

View File

@ -3789,6 +3789,39 @@ pub const Type = extern union {
}
}
/// Returns true if the type's layout is already resolved and it is safe
/// to use `abiSize`, `abiAlignment` and `bitSize` on it.
pub fn layoutIsResolved(ty: Type) bool {
switch (ty.zigTypeTag()) {
.Struct => {
if (ty.castTag(.@"struct")) |struct_ty| {
return struct_ty.data.haveLayout();
}
return true;
},
.Union => {
if (ty.cast(Payload.Union)) |union_ty| {
return union_ty.data.haveLayout();
}
return true;
},
.Array => {
if (ty.arrayLenIncludingSentinel() == 0) return true;
return ty.childType().layoutIsResolved();
},
.Optional => {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = ty.optionalChild(&buf);
return payload_ty.layoutIsResolved();
},
.ErrorUnion => {
const payload_ty = ty.errorUnionPayload();
return payload_ty.layoutIsResolved();
},
else => return true,
}
}
pub fn isSinglePointer(self: Type) bool {
return switch (self.tag()) {
.single_const_pointer,
@ -6498,12 +6531,7 @@ pub const Type = extern union {
// pointee type needs to be resolved more, that needs to be done before calling
// this ptr() function.
if (d.@"align" != 0) canonicalize: {
if (d.pointee_type.castTag(.@"struct")) |struct_ty| {
if (!struct_ty.data.haveLayout()) break :canonicalize;
}
if (d.pointee_type.cast(Payload.Union)) |union_ty| {
if (!union_ty.data.haveLayout()) break :canonicalize;
}
if (!d.pointee_type.layoutIsResolved()) break :canonicalize;
if (d.@"align" == d.pointee_type.abiAlignment(target)) {
d.@"align" = 0;
}

View File

@ -532,3 +532,18 @@ test "pointer alignment and element type include call expression" {
};
try expect(@alignOf(S.P) > 0);
}
test "pointer to array has explicit alignment" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const S = struct {
const Base = extern struct { a: u8 };
const Base2 = extern struct { a: u8 };
fn func(ptr: *[4]Base) *align(1) [4]Base2 {
return @alignCast(1, @ptrCast(*[4]Base2, ptr));
}
};
var bases = [_]S.Base{.{ .a = 2 }} ** 4;
const casted = S.func(&bases);
try expect(casted[0].a == 2);
}