authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-03-09 06:41:56+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-03-17 21:56:14+03:30
logc1977bf0fbe523afb4721bc8346ee6536e3c0aa2
tree0cff580546cdab5f638ae74991e0b496cb3f6904
parent2fc409a32f18b0c62e3918f0b832ed9e4c8d142d

Sema: error on illegal code when targeting spirv


6 files changed, 119 insertions(+), 29 deletions(-)

src/Sema.zig+53-24
......@@ -3648,7 +3648,7 @@ fn indexablePtrLen(
36483648 const object_ty = sema.typeOf(object);
36493649 const is_pointer_to = object_ty.isSinglePointer(zcu);
36503650 const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty;
3651 try checkIndexable(sema, block, src, indexable_ty);
3651 try sema.checkIndexable(block, src, indexable_ty);
36523652 const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls);
36533653 return sema.fieldVal(block, src, object, field_name, src);
36543654}
......@@ -10103,6 +10103,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1010310103 }
1010410104 try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src);
1010510105 try sema.validateRuntimeValue(block, ptr_src, operand);
10106 try sema.checkLogicalPtrOperation(block, ptr_src, ptr_ty);
1010610107 if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
1010710108 return block.addBitCast(dest_ty, operand);
1010810109 }
......@@ -16389,6 +16390,8 @@ fn analyzeArithmetic(
1638916390 };
1639016391
1639116392 try sema.requireRuntimeBlock(block, src, runtime_src);
16393 try sema.checkLogicalPtrOperation(block, src, lhs_ty);
16394 try sema.checkLogicalPtrOperation(block, src, rhs_ty);
1639216395 const lhs_int = try block.addBitCast(.usize, lhs);
1639316396 const rhs_int = try block.addBitCast(.usize, rhs);
1639416397 const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int);
......@@ -16620,24 +16623,7 @@ fn analyzePtrArithmetic(
1662016623 };
1662116624
1662216625 try sema.requireRuntimeBlock(block, op_src, runtime_src);
16623
16624 const target = zcu.getTarget();
16625 if (target_util.arePointersLogical(target, ptr_info.flags.address_space)) {
16626 return sema.failWithOwnedErrorMsg(block, msg: {
16627 const msg = try sema.errMsg(op_src, "illegal pointer arithmetic on pointer of type '{}'", .{ptr_ty.fmt(pt)});
16628 errdefer msg.destroy(sema.gpa);
16629
16630 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);
16631 try sema.errNote(op_src, msg, "arithmetic cannot be performed on pointers with address space '{s}' on target {s}-{s} by compiler backend {s}", .{
16632 @tagName(ptr_info.flags.address_space),
16633 target.cpu.arch.genericName(),
16634 @tagName(target.os.tag),
16635 @tagName(backend),
16636 });
16637
16638 break :msg msg;
16639 });
16640 }
16626 try sema.checkLogicalPtrOperation(block, op_src, ptr_ty);
1664116627
1664216628 return block.addInst(.{
1664316629 .tag = air_tag,
......@@ -22501,6 +22487,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2250122487 });
2250222488 }
2250322489 try sema.requireRuntimeBlock(block, src, operand_src);
22490 try sema.checkLogicalPtrOperation(block, src, ptr_ty);
2250422491 if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
2250522492 if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) {
2250622493 if (!ptr_ty.isAllowzeroPtr(zcu)) {
......@@ -23165,8 +23152,9 @@ fn ptrCastFull(
2316523152
2316623153 try sema.validateRuntimeValue(block, operand_src, operand);
2316723154
23168 const need_null_check = block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu);
23169 const need_align_check = block.wantSafety() and dest_align.compare(.gt, src_align);
23155 const can_cast_to_int = !target_util.arePointersLogical(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu));
23156 const need_null_check = can_cast_to_int and block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu);
23157 const need_align_check = can_cast_to_int and block.wantSafety() and dest_align.compare(.gt, src_align);
2317023158
2317123159 // `operand` might be a slice. If `need_operand_ptr`, we'll populate `operand_ptr` with the raw pointer.
2317223160 const need_operand_ptr = src_info.flags.size != .slice or // we already have it
......@@ -23832,6 +23820,32 @@ fn checkPtrType(
2383223820 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)});
2383323821}
2383423822
23823fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
23824 const pt = sema.pt;
23825 const zcu = pt.zcu;
23826 if (zcu.intern_pool.indexToKey(ty.toIntern()) == .ptr_type) {
23827 const target = zcu.getTarget();
23828 const as = ty.ptrAddressSpace(zcu);
23829 if (target_util.arePointersLogical(target, as)) {
23830 return sema.failWithOwnedErrorMsg(block, msg: {
23831 const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)});
23832 errdefer msg.destroy(sema.gpa);
23833 try sema.errNote(
23834 src,
23835 msg,
23836 "cannot perform arithmetic on pointers with address space '{s}' on target {s}-{s}",
23837 .{
23838 @tagName(as),
23839 target.cpu.arch.genericName(),
23840 @tagName(target.os.tag),
23841 },
23842 );
23843 break :msg msg;
23844 });
23845 }
23846 }
23847}
23848
2383523849fn checkVectorElemType(
2383623850 sema: *Sema,
2383723851 block: *Block,
......@@ -28326,7 +28340,7 @@ fn elemPtr(
2832628340 .pointer => indexable_ptr_ty.childType(zcu),
2832728341 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}),
2832828342 };
28329 try checkIndexable(sema, block, src, indexable_ty);
28343 try sema.checkIndexable(block, src, indexable_ty);
2833028344
2833128345 const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {
2833228346 .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
......@@ -28362,7 +28376,7 @@ fn elemPtrOneLayerOnly(
2836228376 const pt = sema.pt;
2836328377 const zcu = pt.zcu;
2836428378
28365 try checkIndexable(sema, block, src, indexable_ty);
28379 try sema.checkIndexable(block, src, indexable_ty);
2836628380
2836728381 switch (indexable_ty.ptrSize(zcu)) {
2836828382 .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
......@@ -28376,6 +28390,8 @@ fn elemPtrOneLayerOnly(
2837628390 const elem_ptr = try ptr_val.ptrElem(index, pt);
2837728391 return Air.internedToRef(elem_ptr.toIntern());
2837828392 }
28393
28394 try sema.checkLogicalPtrOperation(block, src, indexable_ty);
2837928395 const result_ty = try indexable_ty.elemPtrType(null, pt);
2838028396
2838128397 return block.addPtrElemPtr(indexable, elem_index, result_ty);
......@@ -28412,7 +28428,7 @@ fn elemVal(
2841228428 const pt = sema.pt;
2841328429 const zcu = pt.zcu;
2841428430
28415 try checkIndexable(sema, block, src, indexable_ty);
28431 try sema.checkIndexable(block, src, indexable_ty);
2841628432
2841728433 // TODO in case of a vector of pointers, we need to detect whether the element
2841828434 // index is a scalar or vector instead of unconditionally casting to usize.
......@@ -28438,6 +28454,7 @@ fn elemVal(
2843828454 return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern());
2843928455 }
2844028456
28457 try sema.checkLogicalPtrOperation(block, src, indexable_ty);
2844128458 return block.addBinOp(.ptr_elem_val, indexable, elem_index);
2844228459 },
2844328460 .one => {
......@@ -28477,6 +28494,9 @@ fn validateRuntimeElemAccess(
2847728494 parent_ty: Type,
2847828495 parent_src: LazySrcLoc,
2847928496) CompileError!void {
28497 const pt = sema.pt;
28498 const zcu = pt.zcu;
28499
2848028500 if (try elem_ty.comptimeOnlySema(sema.pt)) {
2848128501 const msg = msg: {
2848228502 const msg = try sema.errMsg(
......@@ -28492,6 +28512,14 @@ fn validateRuntimeElemAccess(
2849228512 };
2849328513 return sema.failWithOwnedErrorMsg(block, msg);
2849428514 }
28515
28516 if (zcu.intern_pool.indexToKey(parent_ty.toIntern()) == .ptr_type) {
28517 const target = zcu.getTarget();
28518 const as = parent_ty.ptrAddressSpace(zcu);
28519 if (target_util.arePointersLogical(target, as)) {
28520 return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)});
28521 }
28522 }
2849528523}
2849628524
2849728525fn tupleFieldPtr(
......@@ -31158,6 +31186,7 @@ fn coerceCompatiblePtrs(
3115831186 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and
3115931187 (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn"))
3116031188 {
31189 try sema.checkLogicalPtrOperation(block, inst_src, inst_ty);
3116131190 const actual_ptr = if (inst_ty.isSlice(zcu))
3116231191 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
3116331192 else
src/codegen/spirv.zig+6-5
......@@ -464,7 +464,7 @@ const NavGen = struct {
464464
465465 const zcu = self.pt.zcu;
466466 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
467 const decl_ptr_ty_id = try self.ptrType(ty, .Generic, .indirect);
467 const decl_ptr_ty_id = try self.ptrType(ty, self.spvStorageClass(.generic), .indirect);
468468
469469 const spv_decl_index = blk: {
470470 const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function });
......@@ -4230,7 +4230,7 @@ const NavGen = struct {
42304230 defer self.gpa.free(ids);
42314231
42324232 const result_id = self.spv.allocId();
4233 if (self.spv.hasFeature(.kernel)) {
4233 if (self.spv.hasFeature(.addresses)) {
42344234 try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
42354235 .id_result_type = result_ty_id,
42364236 .id_result = result_id,
......@@ -5293,7 +5293,7 @@ const NavGen = struct {
52935293 /// The final storage class of the pointer. This may be either `.Generic` or `.Function`.
52945294 /// In either case, the local is allocated in the `.Function` storage class, and optionally
52955295 /// cast back to `.Generic`.
5296 storage_class: StorageClass = .Generic,
5296 storage_class: StorageClass,
52975297 };
52985298
52995299 // Allocate a function-local variable, with possible initializer.
......@@ -5333,9 +5333,10 @@ const NavGen = struct {
53335333 fn airAlloc(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
53345334 const zcu = self.pt.zcu;
53355335 const ptr_ty = self.typeOfIndex(inst);
5336 assert(ptr_ty.ptrAddressSpace(zcu) == .generic);
53375336 const child_ty = ptr_ty.childType(zcu);
5338 return try self.alloc(child_ty, .{});
5337 return try self.alloc(child_ty, .{
5338 .storage_class = self.spvStorageClass(ptr_ty.ptrAddressSpace(zcu)),
5339 });
53395340 }
53405341
53415342 fn airArg(self: *NavGen) IdRef {
test/behavior/globals.zig+4
......@@ -69,6 +69,8 @@ test "global loads can affect liveness" {
6969}
7070
7171test "global const can be self-referential" {
72 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
73
7274 const S = struct {
7375 self: *const @This(),
7476 x: u32,
......@@ -113,6 +115,8 @@ test "global var can be self-referential" {
113115}
114116
115117test "global const can be indirectly self-referential" {
118 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
119
116120 const S = struct {
117121 other: *const @This(),
118122 x: u32,
test/behavior/ptrfromint.zig+2
......@@ -3,6 +3,8 @@ const builtin = @import("builtin");
33const expectEqual = std.testing.expectEqual;
44
55test "casting integer address to function pointer" {
6 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7
68 addressToFunction();
79 comptime addressToFunction();
810}
test/behavior/sizeof_and_typeof.zig+2
......@@ -233,6 +233,8 @@ test "@sizeOf comparison against zero" {
233233}
234234
235235test "hardcoded address in typeof expression" {
236 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
237
236238 const S = struct {
237239 fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) {
238240 return 0;
test/cases/compile_errors/illegal_operation_on_logical_ptr.zig created+52
......@@ -0,0 +1,52 @@
1export fn elemPtr() void {
2 var ptr: [*]u8 = undefined;
3 ptr[0] = 0;
4}
5
6export fn elemVal() void {
7 var ptr: [*]u8 = undefined;
8 var val = ptr[0];
9 _ = &ptr;
10 _ = &val;
11}
12
13export fn intFromPtr() void {
14 var value: u8 = 0;
15 _ = @intFromPtr(&value);
16}
17
18export fn ptrFromInt() void {
19 var v: u32 = 0x1234;
20 var ptr: *u8 = @ptrFromInt(v);
21 _ = &v;
22 _ = &ptr;
23}
24
25export fn ptrPtrArithmetic() void {
26 var value0: u8 = 0;
27 var value1: u8 = 0;
28 _ = &value0 - &value1;
29}
30
31export fn ptrIntArithmetic() void {
32 var ptr0: [*]u8 = undefined;
33 _ = &ptr0;
34 _ = ptr0 - 10;
35}
36
37// error
38// backend=stage2
39// target=spirv64-vulkan
40//
41// :3:8: error: illegal operation on logical pointer of type '[*]u8'
42// :3:8: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
43// :8:18: error: illegal operation on logical pointer of type '[*]u8'
44// :8:18: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
45// :15:21: error: illegal operation on logical pointer of type '*u8'
46// :15:21: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
47// :20:20: error: illegal operation on logical pointer of type '*u8'
48// :20:20: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
49// :28:17: error: illegal operation on logical pointer of type '*u8'
50// :28:17: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
51// :34:14: error: illegal operation on logical pointer of type '[*]u8'
52// :34:14: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan