authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-05 09:53:39+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-05 09:53:39+03:30
log18f2ab7882235009c9e8a45a776ae375132db247
treed535a10bd0fde4a23e0aafaad67577f2810feda3
parenteb2a1bb0d04532c84c042eaad1c3ee092c8c8a23

Sema: disallow loading spirv runtime arrays


4 files changed, 63 insertions(+), 2 deletions(-)

src/Sema.zig+9-1
...@@ -25377,12 +25377,16 @@ pub fn explainWhyTypeIsNotExtern(...@@ -25377,12 +25377,16 @@ pub fn explainWhyTypeIsNotExtern(
25377 .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),25377 .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
2537825378
25379 .@"opaque",25379 .@"opaque",
25380 .spirv,
25381 .bool,25380 .bool,
25382 .float,25381 .float,
25383 .@"anyframe",25382 .@"anyframe",
25384 => unreachable, // these *are* allowed25383 => unreachable, // these *are* allowed
2538525384
25385 .spirv => {
25386 assert(ty.isSpirvRuntimeArray(zcu));
25387 try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{});
25388 },
25389
25386 .pointer => if (ty.isSlice(zcu)) {25390 .pointer => if (ty.isSlice(zcu)) {
25387 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});25391 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
25388 } else {25392 } else {
...@@ -30541,6 +30545,10 @@ fn analyzeLoad(...@@ -30541,6 +30545,10 @@ fn analyzeLoad(
3054130545
30542 try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);30546 try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
3054330547
30548 if (elem_ty.isSpirvRuntimeArray(zcu)) {
30549 return sema.fail(block, src, "cannot load SPIR-V runtime array value", .{});
30550 }
30551
30544 const comptime_only = switch (elem_ty.classify(zcu)) {30552 const comptime_only = switch (elem_ty.classify(zcu)) {
30545 .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) {30553 .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) {
30546 .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}),30554 .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}),
src/Type.zig+5-1
...@@ -3119,12 +3119,16 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool...@@ -3119,12 +3119,16 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool
3119 .noreturn => position == .ret_ty,3119 .noreturn => position == .ret_ty,
31203120
3121 .@"opaque",3121 .@"opaque",
3122 .spirv,
3123 .bool,3122 .bool,
3124 .float,3123 .float,
3125 .@"anyframe",3124 .@"anyframe",
3126 => true,3125 => true,
31273126
3127 .spirv => switch (position) {
3128 .struct_field, .union_field => true,
3129 .ret_ty, .param_ty, .element, .other => !ty.isSpirvRuntimeArray(zcu),
3130 },
3131
3128 .pointer => {3132 .pointer => {
3129 if (ty.isSlice(zcu)) return false;3133 if (ty.isSlice(zcu)) return false;
3130 const child_ty = ty.childType(zcu);3134 const child_ty = ty.childType(zcu);
test/cases/compile_errors/loading_spirv_runtime_array_value.zig created+23
...@@ -0,0 +1,23 @@
1const RuntimeArray = @SpirvType(.{ .runtime_array = f32 });
2const Buffer = extern struct {
3 data: RuntimeArray,
4};
5const buf = @extern(*addrspace(.storage_buffer) Buffer, .{
6 .name = "buf",
7 .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } },
8});
9export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
10 const a = buf.data;
11 _ = a;
12}
13export fn main2() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
14 const p: *addrspace(.storage_buffer) const RuntimeArray = &buf.data;
15 _ = p.*;
16}
17
18// error
19// backend=selfhosted
20// target=spirv32-vulkan
21//
22// :10:15: error: cannot load SPIR-V runtime array value
23// :15:12: error: cannot load SPIR-V runtime array value
test/cases/compile_errors/spirv_runtime_array_as_value_type.zig created+26
...@@ -0,0 +1,26 @@
1const RuntimeArray = @SpirvType(.{ .runtime_array = u32 });
2
3const a = @extern(*addrspace(.storage_buffer) RuntimeArray, .{
4 .name = "a",
5 .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } },
6});
7const b = @extern(*addrspace(.uniform) const RuntimeArray, .{
8 .name = "b",
9 .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } },
10});
11
12comptime {
13 _ = a;
14 _ = b;
15}
16
17// error
18// backend=selfhosted
19// target=spirv32-vulkan
20//
21// :3:19: error: extern symbol cannot have type '*addrspace(.storage_buffer) @SpirvType(.runtime_array, u32)'
22// :3:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible
23// :3:19: note: SPIR-V runtime arrays must be the last field of an extern struct
24// :7:19: error: extern symbol cannot have type '*addrspace(.uniform) const @SpirvType(.runtime_array, u32)'
25// :7:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible
26// :7:19: note: SPIR-V runtime arrays must be the last field of an extern struct