Commit a492a607d5

Veikka Tuominen <git@vexu.eu>
2023-01-19 15:30:25
type: correct condition for eliding pointer alignment canonicalization
Closes #14373
1 parent d284c00
Changed files (2)
src
test
behavior
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;
             }
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);
+}