Commit c1977bf0fb
Changed files (6)
test
cases
compile_errors
src/codegen/spirv.zig
@@ -464,7 +464,7 @@ const NavGen = struct {
const zcu = self.pt.zcu;
const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
- const decl_ptr_ty_id = try self.ptrType(ty, .Generic, .indirect);
+ const decl_ptr_ty_id = try self.ptrType(ty, self.spvStorageClass(.generic), .indirect);
const spv_decl_index = blk: {
const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function });
@@ -4230,7 +4230,7 @@ const NavGen = struct {
defer self.gpa.free(ids);
const result_id = self.spv.allocId();
- if (self.spv.hasFeature(.kernel)) {
+ if (self.spv.hasFeature(.addresses)) {
try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
.id_result_type = result_ty_id,
.id_result = result_id,
@@ -5293,7 +5293,7 @@ const NavGen = struct {
/// The final storage class of the pointer. This may be either `.Generic` or `.Function`.
/// In either case, the local is allocated in the `.Function` storage class, and optionally
/// cast back to `.Generic`.
- storage_class: StorageClass = .Generic,
+ storage_class: StorageClass,
};
// Allocate a function-local variable, with possible initializer.
@@ -5333,9 +5333,10 @@ const NavGen = struct {
fn airAlloc(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const zcu = self.pt.zcu;
const ptr_ty = self.typeOfIndex(inst);
- assert(ptr_ty.ptrAddressSpace(zcu) == .generic);
const child_ty = ptr_ty.childType(zcu);
- return try self.alloc(child_ty, .{});
+ return try self.alloc(child_ty, .{
+ .storage_class = self.spvStorageClass(ptr_ty.ptrAddressSpace(zcu)),
+ });
}
fn airArg(self: *NavGen) IdRef {
src/Sema.zig
@@ -3648,7 +3648,7 @@ fn indexablePtrLen(
const object_ty = sema.typeOf(object);
const is_pointer_to = object_ty.isSinglePointer(zcu);
const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty;
- try checkIndexable(sema, block, src, indexable_ty);
+ try sema.checkIndexable(block, src, indexable_ty);
const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls);
return sema.fieldVal(block, src, object, field_name, src);
}
@@ -10103,6 +10103,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src);
try sema.validateRuntimeValue(block, ptr_src, operand);
+ try sema.checkLogicalPtrOperation(block, ptr_src, ptr_ty);
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
return block.addBitCast(dest_ty, operand);
}
@@ -16389,6 +16390,8 @@ fn analyzeArithmetic(
};
try sema.requireRuntimeBlock(block, src, runtime_src);
+ try sema.checkLogicalPtrOperation(block, src, lhs_ty);
+ try sema.checkLogicalPtrOperation(block, src, rhs_ty);
const lhs_int = try block.addBitCast(.usize, lhs);
const rhs_int = try block.addBitCast(.usize, rhs);
const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int);
@@ -16620,24 +16623,7 @@ fn analyzePtrArithmetic(
};
try sema.requireRuntimeBlock(block, op_src, runtime_src);
-
- const target = zcu.getTarget();
- if (target_util.arePointersLogical(target, ptr_info.flags.address_space)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(op_src, "illegal pointer arithmetic on pointer of type '{}'", .{ptr_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);
- try sema.errNote(op_src, msg, "arithmetic cannot be performed on pointers with address space '{s}' on target {s}-{s} by compiler backend {s}", .{
- @tagName(ptr_info.flags.address_space),
- target.cpu.arch.genericName(),
- @tagName(target.os.tag),
- @tagName(backend),
- });
-
- break :msg msg;
- });
- }
+ try sema.checkLogicalPtrOperation(block, op_src, ptr_ty);
return block.addInst(.{
.tag = air_tag,
@@ -22501,6 +22487,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
});
}
try sema.requireRuntimeBlock(block, src, operand_src);
+ try sema.checkLogicalPtrOperation(block, src, ptr_ty);
if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) {
if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) {
if (!ptr_ty.isAllowzeroPtr(zcu)) {
@@ -23165,8 +23152,9 @@ fn ptrCastFull(
try sema.validateRuntimeValue(block, operand_src, operand);
- const need_null_check = block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu);
- const need_align_check = block.wantSafety() and dest_align.compare(.gt, src_align);
+ const can_cast_to_int = !target_util.arePointersLogical(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu));
+ const need_null_check = can_cast_to_int and block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu);
+ const need_align_check = can_cast_to_int and block.wantSafety() and dest_align.compare(.gt, src_align);
// `operand` might be a slice. If `need_operand_ptr`, we'll populate `operand_ptr` with the raw pointer.
const need_operand_ptr = src_info.flags.size != .slice or // we already have it
@@ -23832,6 +23820,32 @@ fn checkPtrType(
return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)});
}
+fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ if (zcu.intern_pool.indexToKey(ty.toIntern()) == .ptr_type) {
+ const target = zcu.getTarget();
+ const as = ty.ptrAddressSpace(zcu);
+ if (target_util.arePointersLogical(target, as)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(
+ src,
+ msg,
+ "cannot perform arithmetic on pointers with address space '{s}' on target {s}-{s}",
+ .{
+ @tagName(as),
+ target.cpu.arch.genericName(),
+ @tagName(target.os.tag),
+ },
+ );
+ break :msg msg;
+ });
+ }
+ }
+}
+
fn checkVectorElemType(
sema: *Sema,
block: *Block,
@@ -28326,7 +28340,7 @@ fn elemPtr(
.pointer => indexable_ptr_ty.childType(zcu),
else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}),
};
- try checkIndexable(sema, block, src, indexable_ty);
+ try sema.checkIndexable(block, src, indexable_ty);
const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {
.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(
const pt = sema.pt;
const zcu = pt.zcu;
- try checkIndexable(sema, block, src, indexable_ty);
+ try sema.checkIndexable(block, src, indexable_ty);
switch (indexable_ty.ptrSize(zcu)) {
.slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
@@ -28376,6 +28390,8 @@ fn elemPtrOneLayerOnly(
const elem_ptr = try ptr_val.ptrElem(index, pt);
return Air.internedToRef(elem_ptr.toIntern());
}
+
+ try sema.checkLogicalPtrOperation(block, src, indexable_ty);
const result_ty = try indexable_ty.elemPtrType(null, pt);
return block.addPtrElemPtr(indexable, elem_index, result_ty);
@@ -28412,7 +28428,7 @@ fn elemVal(
const pt = sema.pt;
const zcu = pt.zcu;
- try checkIndexable(sema, block, src, indexable_ty);
+ try sema.checkIndexable(block, src, indexable_ty);
// TODO in case of a vector of pointers, we need to detect whether the element
// index is a scalar or vector instead of unconditionally casting to usize.
@@ -28438,6 +28454,7 @@ fn elemVal(
return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern());
}
+ try sema.checkLogicalPtrOperation(block, src, indexable_ty);
return block.addBinOp(.ptr_elem_val, indexable, elem_index);
},
.one => {
@@ -28477,6 +28494,9 @@ fn validateRuntimeElemAccess(
parent_ty: Type,
parent_src: LazySrcLoc,
) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+
if (try elem_ty.comptimeOnlySema(sema.pt)) {
const msg = msg: {
const msg = try sema.errMsg(
@@ -28492,6 +28512,14 @@ fn validateRuntimeElemAccess(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
+
+ if (zcu.intern_pool.indexToKey(parent_ty.toIntern()) == .ptr_type) {
+ const target = zcu.getTarget();
+ const as = parent_ty.ptrAddressSpace(zcu);
+ if (target_util.arePointersLogical(target, as)) {
+ return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)});
+ }
+ }
}
fn tupleFieldPtr(
@@ -31158,6 +31186,7 @@ fn coerceCompatiblePtrs(
if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and
(try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn"))
{
+ try sema.checkLogicalPtrOperation(block, inst_src, inst_ty);
const actual_ptr = if (inst_ty.isSlice(zcu))
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
else
test/behavior/globals.zig
@@ -69,6 +69,8 @@ test "global loads can affect liveness" {
}
test "global const can be self-referential" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
const S = struct {
self: *const @This(),
x: u32,
@@ -113,6 +115,8 @@ test "global var can be self-referential" {
}
test "global const can be indirectly self-referential" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
const S = struct {
other: *const @This(),
x: u32,
test/behavior/ptrfromint.zig
@@ -3,6 +3,8 @@ const builtin = @import("builtin");
const expectEqual = std.testing.expectEqual;
test "casting integer address to function pointer" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
addressToFunction();
comptime addressToFunction();
}
test/behavior/sizeof_and_typeof.zig
@@ -233,6 +233,8 @@ test "@sizeOf comparison against zero" {
}
test "hardcoded address in typeof expression" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
const S = struct {
fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) {
return 0;
test/cases/compile_errors/illegal_operation_on_logical_ptr.zig
@@ -0,0 +1,52 @@
+export fn elemPtr() void {
+ var ptr: [*]u8 = undefined;
+ ptr[0] = 0;
+}
+
+export fn elemVal() void {
+ var ptr: [*]u8 = undefined;
+ var val = ptr[0];
+ _ = &ptr;
+ _ = &val;
+}
+
+export fn intFromPtr() void {
+ var value: u8 = 0;
+ _ = @intFromPtr(&value);
+}
+
+export fn ptrFromInt() void {
+ var v: u32 = 0x1234;
+ var ptr: *u8 = @ptrFromInt(v);
+ _ = &v;
+ _ = &ptr;
+}
+
+export fn ptrPtrArithmetic() void {
+ var value0: u8 = 0;
+ var value1: u8 = 0;
+ _ = &value0 - &value1;
+}
+
+export fn ptrIntArithmetic() void {
+ var ptr0: [*]u8 = undefined;
+ _ = &ptr0;
+ _ = ptr0 - 10;
+}
+
+// error
+// backend=stage2
+// target=spirv64-vulkan
+//
+// :3:8: error: illegal operation on logical pointer of type '[*]u8'
+// :3:8: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
+// :8:18: error: illegal operation on logical pointer of type '[*]u8'
+// :8:18: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
+// :15:21: error: illegal operation on logical pointer of type '*u8'
+// :15:21: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
+// :20:20: error: illegal operation on logical pointer of type '*u8'
+// :20:20: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
+// :28:17: error: illegal operation on logical pointer of type '*u8'
+// :28:17: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan
+// :34:14: error: illegal operation on logical pointer of type '[*]u8'
+// :34:14: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan