aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-08-31 20:40:15 -0700
committerAndrew Kelley <andrew@ziglang.org>2025-08-31 20:40:15 -0700
commitf250802ce794589f77367113335216c1993f7412 (patch)
tree80f260bc0447d67924caa4162344ad21bf71ea2a /src
parentfc23fe90ce1f3d28841c5a5a93a8bdf7edaefc54 (diff)
downloadzig-f250802ce794589f77367113335216c1993f7412.tar.gz
zig-f250802ce794589f77367113335216c1993f7412.zip
compiler: introduce `@Restrict` builtinrestricted-function-pointers
conservative, incomplete change
Diffstat (limited to 'src')
-rw-r--r--src/InternPool.zig41
-rw-r--r--src/Sema.zig22
-rw-r--r--src/Zcu/PerThread.zig6
-rw-r--r--src/print_zir.zig1
4 files changed, 70 insertions, 0 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig
index 9965497742..ed20d939a9 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -117,6 +117,13 @@ pub const empty: InternPool = .{
.free_dep_entries = .empty,
};
+pub const RestrictedSetIndex = enum(u32) {
+ /// placeholder while I slowly work my way towards a more complete implementation
+ some = 0,
+ none = std.math.maxInt(u32),
+ _,
+};
+
/// A `TrackedInst.Index` provides a single, unchanging reference to a ZIR instruction across a whole
/// compilation. From this index, you can acquire a `TrackedInst`, which containss a reference to both
/// the file which the instruction lives in, and the instruction index itself, which is updated on
@@ -2079,6 +2086,7 @@ pub const Key = union(enum) {
sentinel: Index = .none,
flags: Flags = .{},
packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 },
+ restricted_set: RestrictedSetIndex = .none,
pub const VectorIndex = enum(u16) {
none = std.math.maxInt(u16),
@@ -5389,6 +5397,9 @@ pub const Tag = enum(u8) {
type_vector,
/// A fully explicitly specified pointer type.
type_pointer,
+ /// A pointer type created by using the `@Restrict` builtin.
+ /// data is `Index` of underlying, non-restrict pointer type.
+ type_pointer_restricted,
/// A slice type.
/// data is Index of underlying pointer type.
type_slice,
@@ -5666,6 +5677,7 @@ pub const Tag = enum(u8) {
.type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
.type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
.type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
+ .type_pointer_restricted = .{ .summary = .@"@Restrict(*... {.payload.child%summary})", .data = Index },
.type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
.type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
.type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },
@@ -6970,6 +6982,16 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.type_pointer => .{ .ptr_type = extraData(unwrapped_index.getExtra(ip), Tag.TypePointer, data) },
+ .type_pointer_restricted => {
+ const child_ptr_index: Index = @enumFromInt(data);
+ const child_ptr_unwrapped = child_ptr_index.unwrap(ip);
+ const child_ptr_item = child_ptr_unwrapped.getItem(ip);
+ assert(child_ptr_item.tag == .type_pointer);
+ var ptr_info = extraData(child_ptr_unwrapped.getExtra(ip), Tag.TypePointer, child_ptr_item.data);
+ ptr_info.restricted_set = .some;
+ return .{ .ptr_type = ptr_info };
+ },
+
.type_slice => {
const many_ptr_index: Index = @enumFromInt(data);
const many_ptr_unwrapped = many_ptr_index.unwrap(ip);
@@ -10388,6 +10410,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
TrackedInst.Index,
TrackedInst.Index.Optional,
ComptimeAllocIndex,
+ RestrictedSetIndex,
=> @intFromEnum(@field(item, field.name)),
u32,
@@ -10451,6 +10474,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
TrackedInst.Index,
TrackedInst.Index.Optional,
ComptimeAllocIndex,
+ RestrictedSetIndex,
=> @enumFromInt(extra_item),
u32,
@@ -11092,6 +11116,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
.type_array_big => @sizeOf(Array),
.type_vector => @sizeOf(Vector),
.type_pointer => @sizeOf(Tag.TypePointer),
+ .type_pointer_restricted => 0,
.type_slice => 0,
.type_optional => 0,
.type_anyframe => 0,
@@ -11319,6 +11344,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
.type_array_big,
.type_vector,
.type_pointer,
+ .type_pointer_restricted,
.type_optional,
.type_anyframe,
.type_error_union,
@@ -11902,6 +11928,19 @@ pub fn getOrPutTrailingString(
return value;
}
+pub fn restrictedFunctionPointerType(
+ ip: *InternPool,
+ gpa: Allocator,
+ tid: Zcu.PerThread.Id,
+ fn_ty: Index,
+) Allocator.Error!Index {
+ _ = ip;
+ _ = gpa;
+ _ = tid;
+ _ = fn_ty;
+ @panic("TODO");
+}
+
pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString {
const full_hash = Hash.hash(0, key);
const hash: u32 = @truncate(full_hash >> 32);
@@ -12055,6 +12094,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.type_array_small,
.type_vector,
.type_pointer,
+ .type_pointer_restricted,
.type_slice,
.type_optional,
.type_anyframe,
@@ -12411,6 +12451,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.type_vector => .vector,
.type_pointer,
+ .type_pointer_restricted,
.type_slice,
=> .pointer,
diff --git a/src/Sema.zig b/src/Sema.zig
index 007e1a7fef..a714bda4e3 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1305,6 +1305,7 @@ fn analyzeBodyInner(
.validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst),
.opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
.coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst),
+ .restrict => try sema.zirRestrict(block, inst),
.clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
.ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
@@ -4681,6 +4682,26 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
}
}
+fn zirRestrict(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+
+ const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
+ const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
+ const ptr_ty = try sema.resolveType(block, ty_src, inst_data.operand);
+
+ try sema.checkPtrOperand(block, ty_src, ptr_ty);
+
+ const ptr_info = ptr_ty.ptrInfo(zcu);
+ const pointee_ty: Type = .fromInterned(ptr_info.child);
+ if (ptr_info.flags.size != .one or pointee_ty.zigTypeTag(zcu) == .@"fn") {
+ return sema.fail(block, ty_src, "expected function pointer type; found {f}", .{ptr_ty.fmt(pt)});
+ }
+
+ const new_ty = try pt.restrictedFunctionPointerType(pointee_ty);
+ return .fromType(new_ty);
+}
+
fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
@@ -36062,6 +36083,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.type_int_signed, // i0 handled above
.type_int_unsigned, // u0 handled above
.type_pointer,
+ .type_pointer_restricted,
.type_slice,
.type_anyframe,
.type_error_union,
diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig
index 3c2bb27dab..f3daa13ccd 100644
--- a/src/Zcu/PerThread.zig
+++ b/src/Zcu/PerThread.zig
@@ -3420,6 +3420,8 @@ pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!
/// this because it requires potentially pushing to the job queue.
pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
const ip = &pt.zcu.intern_pool;
+ // TODO: avoid indexToKey
+ // TODO: check if dest is restricted function pointer type
switch (ip.indexToKey(val.toIntern())) {
.@"extern" => |e| {
const coerced = try pt.getExtern(.{
@@ -3544,6 +3546,10 @@ pub fn funcType(pt: Zcu.PerThread, key: InternPool.GetFuncTypeKey) Allocator.Err
return Type.fromInterned(try pt.zcu.intern_pool.getFuncType(pt.zcu.gpa, pt.tid, key));
}
+pub fn restrictedFunctionPointerType(pt: Zcu.PerThread, fn_ty: Type) Allocator.Error!Type {
+ return .fromInterned(try pt.zcu.intern_pool.restrictedFunctionPointerType(pt.zcu.gpa, pt.tid, fn_ty.toIntern()));
+}
+
/// Use this for `anyframe->T` only.
/// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
pub fn anyframeType(pt: Zcu.PerThread, payload_ty: Type) Allocator.Error!Type {
diff --git a/src/print_zir.zig b/src/print_zir.zig
index f875aaa552..bc0d02a5fd 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -266,6 +266,7 @@ const Writer = struct {
.opt_eu_base_ptr_init,
.restore_err_ret_index_unconditional,
.restore_err_ret_index_fn_entry,
+ .restrict,
=> try self.writeUnNode(stream, inst),
.ref,