Commit f785e4745d

xdBronch <51252236+xdBronch@users.noreply.github.com>
2025-10-13 23:25:00
detect invalid `@bitCast` with arrays
1 parent 173f497
Changed files (3)
src/Sema.zig
@@ -9952,8 +9952,19 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
                 dest_ty.fmt(pt), container,
             });
         },
+        .array => {
+            const elem_ty = dest_ty.childType(zcu);
+            if (!elem_ty.hasWellDefinedLayout(zcu)) {
+                const msg = msg: {
+                    const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)});
+                    errdefer msg.destroy(sema.gpa);
+                    try sema.errNote(src, msg, "array element type '{f}' does not have a guaranteed in-memory layout", .{elem_ty.fmt(pt)});
+                    break :msg msg;
+                };
+                return sema.failWithOwnedErrorMsg(block, msg);
+            }
+        },
 
-        .array,
         .bool,
         .float,
         .int,
@@ -10015,8 +10026,19 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
                 operand_ty.fmt(pt), container,
             });
         },
+        .array => {
+            const elem_ty = operand_ty.childType(zcu);
+            if (!elem_ty.hasWellDefinedLayout(zcu)) {
+                const msg = msg: {
+                    const msg = try sema.errMsg(src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)});
+                    errdefer msg.destroy(sema.gpa);
+                    try sema.errNote(src, msg, "array element type '{f}' does not have a guaranteed in-memory layout", .{elem_ty.fmt(pt)});
+                    break :msg msg;
+                };
+                return sema.failWithOwnedErrorMsg(block, msg);
+            }
+        },
 
-        .array,
         .bool,
         .float,
         .int,
src/Type.zig
@@ -1924,9 +1924,12 @@ pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {
     };
 }
 
-/// For *[N]T,  returns [N]T.
-/// For *T,     returns T.
-/// For [*]T,   returns T.
+/// For *[N]T,         returns [N]T.
+/// For *T,            returns T.
+/// For [*]T,          returns T.
+/// For @Vector(N, T), returns T.
+/// For [N]T,          returns T.
+/// For ?T,            returns T.
 pub fn childType(ty: Type, zcu: *const Zcu) Type {
     return childTypeIp(ty, &zcu.intern_pool);
 }
test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig
@@ -0,0 +1,26 @@
+export fn foo() void {
+    const S = struct {
+        f: u8,
+    };
+    _ = @as([@sizeOf(S)]u8, @bitCast([1]S{undefined}));
+}
+
+export fn bar() void {
+    const S = struct {
+        f: u8,
+    };
+    _ = @as([1]S, @bitCast(@as([@sizeOf(S)]u8, undefined)));
+}
+
+export fn baz() void {
+    _ = @as([1]u32, @bitCast([1]comptime_int{0}));
+}
+
+// error
+//
+// :5:29: error: cannot @bitCast from '[1]tmp.foo.S'
+// :5:29: note: array element type 'tmp.foo.S' does not have a guaranteed in-memory layout
+// :12:19: error: cannot @bitCast to '[1]tmp.bar.S'
+// :12:19: note: array element type 'tmp.bar.S' does not have a guaranteed in-memory layout
+// :16:21: error: cannot @bitCast from '[1]comptime_int'
+// :16:21: note: array element type 'comptime_int' does not have a guaranteed in-memory layout