diff --git a/src/type.zig b/src/type.zig index 65391aabfc..dd4be91937 100644 --- a/src/type.zig +++ b/src/type.zig @@ -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; } diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index c8879453ad..d93e991889 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -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); +}