diff --git a/src/Sema.zig b/src/Sema.zig index dfd37d70ec9787b7d8ded314ea5314b1e8513b64..3d6274a0b75ad597768276a9e32723709ae42b6f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29752,6 +29752,39 @@ pub fn bitCastVal( } } +fn checkSpirvSliceAllowed( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + address_space: std.lang.AddressSpace, +) CompileError!void { + const zcu = sema.pt.zcu; + const target = zcu.getTarget(); + + if (!target.cpu.arch.isSpirV()) return; + if (block.isComptime()) return; + + // This probably lets some invalid OpPtrAccessChains slip through, but it's better than nothing + if (!target.cpu.has(.spirv, .variable_pointers) and !target.cpu.has(.spirv, .variable_pointers_storage_buffer)) { + return sema.failWithOwnedErrorMsg( + block, + try sema.errMsg(src, "cannot construct slices without the 'variable_pointers' or 'variable_pointers_storage_buffer' features", .{}), + ); + } + + switch (address_space) { + .shared, .storage_buffer => {}, + else => { + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(src, "cannot construct slice from address space '{t}'", .{address_space}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(src, msg, "only 'shared' and 'storage_buffer' address spaces support slicing on SPIR-V", .{}); + break :msg msg; + }); + }, + } +} + fn coerceArrayPtrToSlice( sema: *Sema, block: *Block, @@ -29773,6 +29806,7 @@ fn coerceArrayPtrToSlice( } }); return Air.internedToRef(slice_val); } + try sema.checkSpirvSliceAllowed(block, inst_src, dest_ty.ptrInfo(zcu).flags.address_space); try sema.requireRuntimeBlock(block, inst_src, null); return block.addTyOp(.array_to_slice, dest_ty, inst); } @@ -31066,6 +31100,7 @@ fn analyzeSlice( } try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); + try sema.checkSpirvSliceAllowed(block, src, slice_ty.ptrInfo(zcu).flags.address_space); const ptr = if (slice_ty.isSlice(zcu)) try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) diff --git a/src/target.zig b/src/target.zig index f7e9e5581b34accbceaffc94ed5ef16ecf7bdd0d..7c568d239bf978ac342e6466224110ccafc7788b 100644 --- a/src/target.zig +++ b/src/target.zig @@ -625,7 +625,7 @@ pub fn addrSpaceCastIsValid( /// (c) some logical pointers (.storage_buffer, .shared) do support operations when /// the VariablePointers capability is enabled (which enables OpPtrAccessChain). pub fn shouldBlockPointerOps(target: *const std.Target, as: AddressSpace) bool { - if (target.os.tag != .vulkan) return false; + if (target.os.tag != .vulkan and target.os.tag != .opengl) return false; return switch (as) { // TODO: Vulkan doesn't support pointers in the generic address space, we diff --git a/test/cases/compile_errors/spirv_slices.zig b/test/cases/compile_errors/spirv_slices.zig new file mode 100644 index 0000000000000000000000000000000000000000..8e6e657025982ad316bc058025e1374e30520aec --- /dev/null +++ b/test/cases/compile_errors/spirv_slices.zig @@ -0,0 +1,41 @@ +export fn a() void { + var buf: [3]f32 = undefined; + takesSlice(&buf); // error +} + +fn takesSlice(buf: []f32) void { + _ = buf; +} + +export fn b() void { + var buf: [3]f32 = undefined; + for (buf[0..3]) |_| {} // error +} + +export fn c() void { + var buf: [3]f32 = undefined; + for (&buf) |_| {} // not an error +} + +export fn d() void { + const buf: [3]f32 = .{1, 2, 3}; + for (comptime buf[0..3]) |_| {} // not an error +} + +export fn e() void { + const buf: [3]f32 = .{1, 2, 3}; + for (comptime buf[0..3]) |_| {} // not an error + for (buf[0..3]) |_| {} // error +} + +// error +// backend=auto +// target=spirv32-opengl,spirv32-vulkan +// cpu_features=baseline+variable_pointers +// +// :3:16: error: cannot construct slice from address space 'generic' +// :3:16: note: only 'shared' and 'storage_buffer' address spaces support slicing on SPIR-V +// :12:13: error: cannot construct slice from address space 'generic' +// :12:13: note: only 'shared' and 'storage_buffer' address spaces support slicing on SPIR-V +// :28:13: error: cannot construct slice from address space 'generic' +// :28:13: note: only 'shared' and 'storage_buffer' address spaces support slicing on SPIR-V