authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-08 21:30:56-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-24 11:08:00-04:00
loga8428b777c588e2dedfaebdd8c22a5b838d6b5ee
treed45f95557ee4a08febef2766efb628202c5ca3e7
parentec3f362ae9722415223d15270ae58cfd3b50ddd0

start implementing restricted types


34 files changed, 918 insertions(+), 181 deletions(-)

doc/langref.html.in+7
......@@ -5769,6 +5769,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
57695769 <p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>
57705770 {#header_close#}
57715771
5772 {#header_open|@Restricted#}
5773 <pre>{#syntax#}@Restricted(
5774 comptime Pointer: type,
5775) type{#endsyntax#}</pre>
5776 <p>Returns a restricted pointer type based on the specified pointer type.</p>
5777 {#header_close#}
5778
57725779 {#header_open|@Fn#}
57735780 <pre>{#syntax#}@Fn(
57745781 comptime param_types: []const type,
lib/std/debug.zig+4
......@@ -201,6 +201,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
201201 @branchHint(.cold);
202202 call("'noreturn' function returned", @returnAddress());
203203 }
204 pub fn corruptRestrictedPointer() noreturn {
205 @branchHint(.cold);
206 call("corrupt restricted pointer value", @returnAddress());
207 }
204208 };
205209}
206210
lib/std/debug/no_panic.zig+5
......@@ -134,3 +134,8 @@ pub fn noreturnReturned() noreturn {
134134 @branchHint(.cold);
135135 @trap();
136136}
137
138pub fn corruptRestrictedPointer() noreturn {
139 @branchHint(.cold);
140 @trap();
141}
lib/std/debug/simple_panic.zig+4
......@@ -126,3 +126,7 @@ pub fn memcpyAlias() noreturn {
126126pub fn noreturnReturned() noreturn {
127127 call("'noreturn' function returned", null);
128128}
129
130pub fn corruptRestrictedPointer() noreturn {
131 call("corrupt restricted pointer value", null);
132}
lib/std/zig/AstGen.zig+10-1
......@@ -1208,7 +1208,7 @@ fn nameStratExpr(
12081208 const builtin_name = tree.tokenSlice(builtin_token);
12091209 const info = BuiltinFn.list.get(builtin_name) orelse return null;
12101210 switch (info.tag) {
1211 .Enum, .Struct, .Union => {
1211 .Restricted, .Enum, .Struct, .Union => {
12121212 var buf: [2]Ast.Node.Index = undefined;
12131213 const params = tree.builtinCallParams(&buf, node).?;
12141214 return try builtinCall(gz, scope, ri, node, params, false, name_strat);
......@@ -9320,6 +9320,15 @@ fn builtinCall(
93209320 });
93219321 return rvalue(gz, ri, result, node);
93229322 },
9323 .Restricted => {
9324 const unrestricted_ptr_ty = try typeExpr(gz, scope, params[0]);
9325 const result = try gz.addExtendedPayloadSmall(
9326 .reify_restricted,
9327 @intFromEnum(reify_name_strat),
9328 Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = unrestricted_ptr_ty },
9329 );
9330 return rvalue(gz, ri, result, node);
9331 },
93239332 .Fn => {
93249333 const fn_attrs_ty = try gz.addBuiltinValue(node, .fn_attributes);
93259334 const param_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .fn_param_types);
lib/std/zig/AstRlAnnotate.zig+1
......@@ -903,6 +903,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
903903 .error_name,
904904 .set_runtime_safety,
905905 .Tuple,
906 .Restricted,
906907 .wasm_memory_size,
907908 .splat,
908909 .set_float_mode,
lib/std/zig/BuiltinFn.zig+8
......@@ -110,6 +110,7 @@ pub const Tag = enum {
110110 Int,
111111 Tuple,
112112 Pointer,
113 Restricted,
113114 Fn,
114115 Struct,
115116 Union,
......@@ -943,6 +944,13 @@ pub const list = list: {
943944 .param_count = 4,
944945 },
945946 },
947 .{
948 "@Restricted",
949 .{
950 .tag = .Restricted,
951 .param_count = 1,
952 },
953 },
946954 .{
947955 "@Fn",
948956 .{
lib/std/zig/Zir.zig+9-3
......@@ -2062,6 +2062,10 @@ pub const Inst = struct {
20622062 /// Implements builtin `@Pointer`.
20632063 /// `operand` is payload index to `ReifyPointer`.
20642064 reify_pointer,
2065 /// Implements builtin `@Restricted`.
2066 /// `operand` is payload index to `UnNode`.
2067 /// `small` contains `NameStrategy`.
2068 reify_restricted,
20652069 /// Implements builtin `@Fn`.
20662070 /// `operand` is payload index to `ReifyFn`.
20672071 reify_fn,
......@@ -4431,15 +4435,16 @@ fn findTrackableInner(
44314435 },
44324436
44334437 // Reifications need tracking.
4434 .reify_enum,
4438 .reify_restricted,
44354439 .reify_struct,
44364440 .reify_union,
4441 .reify_enum,
44374442 => return contents.other.append(gpa, inst),
44384443
44394444 // Type declarations need tracking.
44404445 .struct_decl,
4441 .union_decl,
44424446 .enum_decl,
4447 .union_decl,
44434448 .opaque_decl,
44444449 => return contents.type_decls.append(gpa, inst),
44454450 }
......@@ -5232,9 +5237,10 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
52325237 .union_decl,
52335238 .enum_decl,
52345239 .opaque_decl,
5235 .reify_enum,
5240 .reify_restricted,
52365241 .reify_struct,
52375242 .reify_union,
5243 .reify_enum,
52385244 => {}, // tracked in order, as the owner instructions of explicit container types
52395245 else => unreachable, // assertion failure; not trackable
52405246 },
src/Air.zig+14
......@@ -633,6 +633,16 @@ pub const Inst = struct {
633633 /// wrap from E to E!T
634634 /// Uses the `ty_op` field.
635635 wrap_errunion_err,
636 /// Converts a runtime restricted pointer into the corresponding unrestricted pointer.
637 /// Uses the `ty_op` field.
638 unwrap_restricted,
639 /// Converts a runtime restricted pointer into the corresponding unrestricted pointer.
640 /// All invalid pointers are a guaranteed safety panic, which is only applicable
641 /// when the restricted pointer type belongs to a module with safety enabled.
642 /// The panic handler function must be populated before lowering AIR
643 /// that contains this instruction.
644 /// Uses the `ty_op` field.
645 unwrap_restricted_safe,
636646 /// Given a pointer to a struct or union and a field index, returns a pointer to the field.
637647 /// Uses the `ty_pl` field, payload is `StructField`.
638648 /// TODO rename to `agg_field_ptr`.
......@@ -1681,6 +1691,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
16811691 .unwrap_errunion_err_ptr,
16821692 .wrap_errunion_payload,
16831693 .wrap_errunion_err,
1694 .unwrap_restricted,
1695 .unwrap_restricted_safe,
16841696 .slice_ptr,
16851697 .ptr_slice_len_ptr,
16861698 .ptr_slice_ptr_ptr,
......@@ -1886,6 +1898,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
18861898 .unreach,
18871899 .optional_payload_ptr_set,
18881900 .errunion_payload_ptr_set,
1901 .unwrap_restricted_safe,
18891902 .set_union_tag,
18901903 .memset,
18911904 .memset_safe,
......@@ -2014,6 +2027,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
20142027 .unwrap_errunion_payload_ptr,
20152028 .wrap_errunion_payload,
20162029 .wrap_errunion_err,
2030 .unwrap_restricted,
20172031 .struct_field_ptr,
20182032 .struct_field_ptr_index_0,
20192033 .struct_field_ptr_index_1,
src/Air/Legalize.zig+2
......@@ -741,6 +741,8 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
741741 .errunion_payload_ptr_set,
742742 .wrap_errunion_payload,
743743 .wrap_errunion_err,
744 .unwrap_restricted,
745 .unwrap_restricted_safe,
744746 .struct_field_ptr,
745747 .struct_field_ptr_index_0,
746748 .struct_field_ptr_index_1,
src/Air/Liveness.zig+2
......@@ -506,6 +506,8 @@ fn analyzeInst(
506506 .unwrap_errunion_err_ptr,
507507 .wrap_errunion_payload,
508508 .wrap_errunion_err,
509 .unwrap_restricted,
510 .unwrap_restricted_safe,
509511 .slice_ptr,
510512 .slice_len,
511513 .ptr_slice_len_ptr,
src/Air/Liveness/Verify.zig+2
......@@ -96,6 +96,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
9696 .unwrap_errunion_err_ptr,
9797 .wrap_errunion_payload,
9898 .wrap_errunion_err,
99 .unwrap_restricted,
100 .unwrap_restricted_safe,
99101 .slice_ptr,
100102 .slice_len,
101103 .ptr_slice_len_ptr,
src/Air/print.zig+2
......@@ -250,6 +250,8 @@ const Writer = struct {
250250 .unwrap_errunion_err_ptr,
251251 .wrap_errunion_payload,
252252 .wrap_errunion_err,
253 .unwrap_restricted,
254 .unwrap_restricted_safe,
253255 .slice_ptr,
254256 .slice_len,
255257 .ptr_slice_len_ptr,
src/InternPool.zig+176-54
......@@ -1969,6 +1969,7 @@ pub const CaptureValue = packed struct(u32) {
19691969pub const Key = union(enum) {
19701970 int_type: IntType,
19711971 ptr_type: PtrType,
1972 restricted_ptr_type: RestrictedPtrType,
19721973 array_type: ArrayType,
19731974 vector_type: VectorType,
19741975 opt_type: Index,
......@@ -2094,6 +2095,14 @@ pub const Key = union(enum) {
20942095 pub const AddressSpace = std.builtin.AddressSpace;
20952096 };
20962097
2098 /// Extern layout so it can be hashed with `std.mem.asBytes`.
2099 pub const RestrictedPtrType = extern struct {
2100 /// A `reify_restricted` instruction.
2101 zir_index: TrackedInst.Index,
2102 /// The underlying pointer type.
2103 unrestricted_ptr_type: Index,
2104 };
2105
20972106 /// Extern so that hashing can be done via memory reinterpreting.
20982107 pub const ArrayType = extern struct {
20992108 len: u64,
......@@ -2590,6 +2599,7 @@ pub const Key = union(enum) {
25902599 return switch (key) {
25912600 // TODO: assert no padding in these types
25922601 inline .ptr_type,
2602 .restricted_ptr_type,
25932603 .array_type,
25942604 .vector_type,
25952605 .opt_type,
......@@ -2606,11 +2616,11 @@ pub const Key = union(enum) {
26062616 .un,
26072617 => |x| Hash.hash(seed, asBytes(&x)),
26082618
2609 .int_type => |x| Hash.hash(seed + @intFromEnum(x.signedness), asBytes(&x.bits)),
2619 .int_type => |x| Hash.hash(seed | @shlExact(@as(u64, @intFromEnum(x.signedness)), 63), asBytes(&x.bits)),
26102620
26112621 .error_union => |x| switch (x.val) {
2612 .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),
2613 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
2622 .err_name => |y| Hash.hash(seed | @as(u64, 0 << 63), asBytes(&x.ty) ++ asBytes(&y)),
2623 .payload => |y| Hash.hash(seed | @as(u64, 1 << 63), asBytes(&x.ty) ++ asBytes(&y)),
26142624 },
26152625
26162626 .opaque_type,
......@@ -2631,10 +2641,7 @@ pub const Key = union(enum) {
26312641 std.hash.autoHash(&hasher, cv);
26322642 }
26332643 },
2634 .reified => |reified| {
2635 std.hash.autoHash(&hasher, reified.zir_index);
2636 std.hash.autoHash(&hasher, reified.type_hash);
2637 },
2644 .reified => |reified| std.hash.autoHash(&hasher, reified),
26382645 .generated_union_tag => |union_type| {
26392646 std.hash.autoHash(&hasher, union_type);
26402647 },
......@@ -2672,7 +2679,7 @@ pub const Key = union(enum) {
26722679 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
26732680 // This is sound due to pointer provenance rules.
26742681 const addr_tag: Key.Ptr.BaseAddr.Tag = ptr.base_addr;
2675 const seed2 = seed + @intFromEnum(addr_tag);
2682 const seed2 = seed | @shlExact(@as(u64, @intFromEnum(addr_tag)), 60);
26762683 const big_offset: i128 = ptr.byte_offset;
26772684 const common = asBytes(&ptr.ty) ++ asBytes(&big_offset);
26782685 return switch (ptr.base_addr) {
......@@ -3020,6 +3027,8 @@ pub const Key = union(enum) {
30203027 }
30213028 },
30223029
3030 .restricted_ptr_type => |a_r| return std.meta.eql(a_r, b.restricted_ptr_type),
3031
30233032 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {
30243033 const b_info = @field(b, @tagName(a_tag_ct));
30253034 if (std.meta.activeTag(a_info) != b_info) return false;
......@@ -3037,11 +3046,7 @@ pub const Key = union(enum) {
30373046 };
30383047 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
30393048 },
3040 .reified => |a_r| {
3041 const b_r = b_info.reified;
3042 return a_r.zir_index == b_r.zir_index and
3043 a_r.type_hash == b_r.type_hash;
3044 },
3049 .reified => |a_r| return std.meta.eql(a_r, b_info.reified),
30453050 .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag,
30463051 }
30473052 },
......@@ -3125,6 +3130,7 @@ pub const Key = union(enum) {
31253130 return switch (key) {
31263131 .int_type,
31273132 .ptr_type,
3133 .restricted_ptr_type,
31283134 .array_type,
31293135 .vector_type,
31303136 .opt_type,
......@@ -3172,6 +3178,8 @@ pub const Key = union(enum) {
31723178 }
31733179};
31743180
3181pub const LoadedRestrictedType = Tag.TypeRestricted;
3182
31753183pub const LoadedStructType = struct {
31763184 /// Index of the `struct_decl` or `reify` ZIR instruction.
31773185 zir_index: TrackedInst.Index,
......@@ -3499,6 +3507,12 @@ pub const LoadedOpaqueType = struct {
34993507 namespace: NamespaceIndex,
35003508};
35013509
3510pub fn loadRestrictedType(ip: *const InternPool, index: Index) LoadedRestrictedType {
3511 const unwrapped_index = index.unwrap(ip);
3512 const item = unwrapped_index.getItem(ip);
3513 return extraData(unwrapped_index.getExtra(ip), Tag.TypeRestricted, item.data);
3514}
3515
35023516pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
35033517 const unwrapped_index = index.unwrap(ip);
35043518 const extra_list = unwrapped_index.getExtra(ip);
......@@ -4173,6 +4187,7 @@ pub const Index = enum(u32) {
41734187 type_array_small: struct { data: *Vector },
41744188 type_vector: struct { data: *Vector },
41754189 type_pointer: struct { data: *Tag.TypePointer },
4190 type_restricted: struct { data: *Tag.TypeRestricted },
41764191 type_slice: DataIsIndex,
41774192 type_optional: DataIsIndex,
41784193 type_anyframe: DataIsIndex,
......@@ -4771,6 +4786,9 @@ pub const Tag = enum(u8) {
47714786 /// A slice type.
47724787 /// data is Index of underlying pointer type.
47734788 type_slice,
4789 /// A restricted pointer type.
4790 /// data is payload to `TypeRestricted`.
4791 type_restricted,
47744792 /// An optional type.
47754793 /// data is the child type.
47764794 type_optional,
......@@ -5024,13 +5042,6 @@ pub const Tag = enum(u8) {
50245042 /// data is extra index to `MemoizedCall`
50255043 memoized_call,
50265044
5027 const ErrorUnionType = Key.ErrorUnionType;
5028 const TypeValue = Key.TypeValue;
5029 const Error = Key.Error;
5030 const EnumTag = Key.EnumTag;
5031 const Union = Key.Union;
5032 const TypePointer = Key.PtrType;
5033
50345045 const struct_packed_encoding = .{
50355046 .summary = .@"{.payload.name%summary#\"}",
50365047 .payload = TypeStructPacked,
......@@ -5116,6 +5127,7 @@ pub const Tag = enum(u8) {
51165127 .type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
51175128 .type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
51185129 .type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
5130 .type_restricted = .{ .summary = .@"@Restricted({.payload.ptr_type%summary})", .payload = TypeRestricted },
51195131 .type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
51205132 .type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
51215133 .type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },
......@@ -5363,6 +5375,25 @@ pub const Tag = enum(u8) {
53635375 return @field(encodings, @tagName(tag)).payload;
53645376 }
53655377
5378 const ErrorUnionType = Key.ErrorUnionType;
5379 const TypeValue = Key.TypeValue;
5380 const Error = Key.Error;
5381 const EnumTag = Key.EnumTag;
5382 const Union = Key.Union;
5383 const TypePointer = Key.PtrType;
5384
5385 const TypeRestricted = struct {
5386 /// Index of the `reify_restricted` ZIR instruction.
5387 zir_index: TrackedInst.Index,
5388
5389 // TODO: the non-fqn will be needed by the new dwarf structure
5390 /// The name of this restricted type.
5391 name: NullTerminatedString,
5392
5393 /// The pointer type this restricted type is based on.
5394 unrestricted_ptr_type: Index,
5395 };
5396
53665397 pub const Extern = struct {
53675398 // name, is_const, alignment, addrspace come from `owner_nav`.
53685399 ty: Index,
......@@ -6455,6 +6486,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
64556486 return .{ .ptr_type = ptr_info };
64566487 },
64576488
6489 .type_restricted => {
6490 const restricted_ptr_info = extraData(unwrapped_index.getExtra(ip), Tag.TypeRestricted, data);
6491 return .{ .restricted_ptr_type = .{
6492 .zir_index = restricted_ptr_info.zir_index,
6493 .unrestricted_ptr_type = restricted_ptr_info.unrestricted_ptr_type,
6494 } };
6495 },
6496
64586497 .type_optional => .{ .opt_type = @enumFromInt(data) },
64596498 .type_anyframe => .{ .anyframe_type = @enumFromInt(data) },
64606499
......@@ -7237,6 +7276,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
72377276 .data = try addExtra(extra, ptr_type_adjusted),
72387277 });
72397278 },
7279 .restricted_ptr_type => unreachable, // instead getReifiedRestrictedType
72407280 .array_type => |array_type| {
72417281 assert(array_type.child != .none);
72427282 assert(array_type.sentinel == .none or ip.typeOf(array_type.sentinel) == array_type.child);
......@@ -7367,7 +7407,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
73677407 },
73687408
73697409 .ptr => |ptr| {
7370 const ptr_type = ip.indexToKey(ptr.ty).ptr_type;
7410 const ptr_type = switch (ip.indexToKey(ptr.ty)) {
7411 .ptr_type => |ptr_type| ptr_type,
7412 .restricted_ptr_type => |restricted_ptr_type| ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
7413 else => unreachable,
7414 };
73717415 assert(ptr_type.flags.size != .slice);
73727416 items.appendAssumeCapacity(switch (ptr.base_addr) {
73737417 .nav => |nav| .{
......@@ -7959,6 +8003,65 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
79598003 return gop.put();
79608004}
79618005
8006pub fn getReifiedRestrictedType(
8007 ip: *InternPool,
8008 gpa: Allocator,
8009 io: Io,
8010 tid: Zcu.PerThread.Id,
8011 zir_index: TrackedInst.Index,
8012 unrestricted_ptr_type: Index,
8013) Allocator.Error!WipRestrictedType.Result {
8014 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .restricted_ptr_type = .{
8015 .zir_index = zir_index,
8016 .unrestricted_ptr_type = unrestricted_ptr_type,
8017 } });
8018 defer gop.deinit();
8019 if (gop == .existing) return .{ .existing = gop.existing };
8020
8021 const local = ip.getLocal(tid);
8022 const items = local.getMutableItems(gpa, io);
8023 const extra = local.getMutableExtra(gpa, io);
8024 try items.ensureUnusedCapacity(1);
8025
8026 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeRestricted).@"struct".fields.len);
8027
8028 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeRestricted{
8029 .zir_index = zir_index,
8030 .name = undefined,
8031 .unrestricted_ptr_type = unrestricted_ptr_type,
8032 });
8033 items.appendAssumeCapacity(.{
8034 .tag = .type_restricted,
8035 .data = extra_index,
8036 });
8037 return .{ .wip = .{
8038 .index = gop.put(),
8039 .tid = tid,
8040 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeRestricted, "name").?,
8041 } };
8042}
8043
8044pub const WipRestrictedType = struct {
8045 index: Index,
8046 tid: Zcu.PerThread.Id,
8047 type_name_index: u32,
8048
8049 pub fn setName(wip: WipRestrictedType, ip: *InternPool, type_name: NullTerminatedString) void {
8050 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8051 const extra_items = extra.view().items(.@"0");
8052 extra_items[wip.type_name_index] = @intFromEnum(type_name);
8053 }
8054
8055 pub fn cancel(wip: WipRestrictedType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
8056 ip.remove(tid, wip.index);
8057 }
8058
8059 pub const Result = union(enum) {
8060 wip: WipRestrictedType,
8061 existing: Index,
8062 };
8063};
8064
79628065pub fn getDeclaredStructType(
79638066 ip: *InternPool,
79648067 gpa: Allocator,
......@@ -9925,6 +10028,7 @@ test "basic usage" {
992510028pub fn childType(ip: *const InternPool, i: Index) Index {
992610029 return switch (ip.indexToKey(i)) {
992710030 .ptr_type => |ptr_type| ptr_type.child,
10031 .restricted_ptr_type => |restricted_ptr_type| ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type.child,
992810032 .vector_type => |vector_type| vector_type.child,
992910033 .array_type => |array_type| array_type.child,
993010034 .opt_type, .anyframe_type => |child| child,
......@@ -10007,22 +10111,28 @@ pub fn getCoerced(
1000710111 .val = .none,
1000810112 } });
1000910113
10010 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
10011 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{
10012 .ty = new_ty,
10013 .base_addr = .int,
10014 .byte_offset = 0,
10015 } }),
10016 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
10017 .ty = new_ty,
10018 .ptr = try ip.get(gpa, io, tid, .{ .ptr = .{
10019 .ty = ip.slicePtrType(new_ty),
10114 new_ty: switch (ip.indexToKey(new_ty)) {
10115 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10116 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{
10117 .ty = new_ty,
1002010118 .base_addr = .int,
1002110119 .byte_offset = 0,
1002210120 } }),
10023 .len = .undef_usize,
10024 } }),
10025 };
10121 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
10122 .ty = new_ty,
10123 .ptr = try ip.get(gpa, io, tid, .{ .ptr = .{
10124 .ty = ip.slicePtrType(new_ty),
10125 .base_addr = .int,
10126 .byte_offset = 0,
10127 } }),
10128 .len = .undef_usize,
10129 } }),
10130 },
10131 .restricted_ptr_type => |restricted_ptr_type| continue :new_ty .{
10132 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
10133 },
10134 else => {},
10135 }
1002610136 },
1002710137 else => {
1002810138 const unwrapped_val = val.unwrap(ip);
......@@ -10101,28 +10211,40 @@ pub fn getCoerced(
1010110211 },
1010210212 else => {},
1010310213 },
10104 .slice => |slice| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size == .slice)
10105 return ip.get(gpa, io, tid, .{ .slice = .{
10106 .ty = new_ty,
10107 .ptr = try ip.getCoerced(gpa, io, tid, slice.ptr, ip.slicePtrType(new_ty)),
10108 .len = slice.len,
10109 } })
10110 else if (ip.isIntegerType(new_ty))
10111 return ip.getCoerced(gpa, io, tid, slice.ptr, new_ty),
10112 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .slice)
10113 return ip.get(gpa, io, tid, .{ .ptr = .{
10114 .ty = new_ty,
10115 .base_addr = ptr.base_addr,
10116 .byte_offset = ptr.byte_offset,
10117 } })
10118 else if (ip.isIntegerType(new_ty))
10119 switch (ptr.base_addr) {
10214 .slice => |slice| new_ty: switch (ip.indexToKey(new_ty)) {
10215 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10216 .one, .many, .c => {},
10217 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
10218 .ty = new_ty,
10219 .ptr = try ip.getCoerced(gpa, io, tid, slice.ptr, ip.slicePtrType(new_ty)),
10220 .len = slice.len,
10221 } }),
10222 },
10223 .restricted_ptr_type => |restricted_ptr_type| continue :new_ty .{
10224 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
10225 },
10226 else => if (ip.isIntegerType(new_ty)) return ip.getCoerced(gpa, io, tid, slice.ptr, new_ty),
10227 },
10228 .ptr => |ptr| new_ty: switch (ip.indexToKey(new_ty)) {
10229 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10230 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{
10231 .ty = new_ty,
10232 .base_addr = ptr.base_addr,
10233 .byte_offset = ptr.byte_offset,
10234 } }),
10235 .slice => {},
10236 },
10237 .restricted_ptr_type => |restricted_ptr_type| continue :new_ty .{
10238 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
10239 },
10240 else => if (ip.isIntegerType(new_ty)) switch (ptr.base_addr) {
1012010241 .int => return ip.get(gpa, io, tid, .{ .int = .{
1012110242 .ty = .usize_type,
1012210243 .storage = .{ .u64 = @intCast(ptr.byte_offset) },
1012310244 } }),
1012410245 else => {},
1012510246 },
10247 },
1012610248 .opt => |opt| switch (ip.indexToKey(new_ty)) {
1012710249 .ptr_type => |ptr_type| return switch (opt.val) {
1012810250 .none => switch (ptr_type.flags.size) {
......@@ -10397,10 +10519,6 @@ pub fn isFunctionType(ip: *const InternPool, ty: Index) bool {
1039710519 return ip.indexToKey(ty) == .func_type;
1039810520}
1039910521
10400pub fn isPointerType(ip: *const InternPool, ty: Index) bool {
10401 return ip.indexToKey(ty) == .ptr_type;
10402}
10403
1040410522pub fn isOptionalType(ip: *const InternPool, ty: Index) bool {
1040510523 return ip.indexToKey(ty) == .opt_type;
1040610524}
......@@ -10577,6 +10695,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1057710695 .type_array_big => @sizeOf(Array),
1057810696 .type_vector => @sizeOf(Vector),
1057910697 .type_pointer => @sizeOf(Tag.TypePointer),
10698 .type_restricted => @sizeOf(Tag.TypeRestricted),
1058010699 .type_slice => 0,
1058110700 .type_optional => 0,
1058210701 .type_anyframe => 0,
......@@ -10838,6 +10957,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
1083810957 .type_array_big,
1083910958 .type_vector,
1084010959 .type_pointer,
10960 .type_restricted,
1084110961 .type_optional,
1084210962 .type_anyframe,
1084310963 .type_error_union,
......@@ -11576,6 +11696,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
1157611696 .type_array_small,
1157711697 .type_vector,
1157811698 .type_pointer,
11699 .type_restricted,
1157911700 .type_slice,
1158011701 .type_optional,
1158111702 .type_anyframe,
......@@ -11921,6 +12042,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1192112042
1192212043 .type_pointer,
1192312044 .type_slice,
12045 .type_restricted,
1192412046 => .pointer,
1192512047
1192612048 .type_optional => .optional,
src/Sema.zig+197-34
......@@ -398,7 +398,7 @@ pub const Block = struct {
398398 /// The name of the current "context" for naming namespace types.
399399 /// The interpretation of this depends on the name strategy in ZIR, but the name
400400 /// is always incorporated into the type name somehow.
401 /// See `Sema.setTypeName`.
401 /// See `Sema.computeTypeName`.
402402 type_name_ctx: InternPool.NullTerminatedString,
403403
404404 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
......@@ -1435,6 +1435,7 @@ fn analyzeBodyInner(
14351435 .reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended),
14361436 .reify_tuple => try sema.zirReifyTuple( block, extended),
14371437 .reify_pointer => try sema.zirReifyPointer( block, extended),
1438 .reify_restricted => try sema.zirReifyRestricted( block, extended, inst),
14381439 .reify_fn => try sema.zirReifyFn( block, extended),
14391440 .reify_struct => try sema.zirReifyStruct( block, extended, inst),
14401441 .reify_union => try sema.zirReifyUnion( block, extended, inst),
......@@ -18956,7 +18957,8 @@ fn structInitAnon(
1895618957 .existing => |ty| .fromInterned(ty),
1895718958 .wip => |wip| ty: {
1895818959 errdefer wip.cancel(ip, pt.tid);
18959 try sema.setTypeName(block, &wip, .anon, "struct", inst);
18960 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, .anon, "struct", inst);
18961 wip.setName(ip, type_name, name_nav);
1896018962
1896118963 // Reified structs have field information populated immediately.
1896218964 @memcpy(wip.field_names.get(ip), names);
......@@ -19879,6 +19881,62 @@ fn zirReifyPointer(
1987919881 }));
1988019882}
1988119883
19884fn zirReifyRestricted(
19885 sema: *Sema,
19886 block: *Block,
19887 extended: Zir.Inst.Extended.InstData,
19888 inst: Zir.Inst.Index,
19889) CompileError!Air.Inst.Ref {
19890 const pt = sema.pt;
19891 const zcu = pt.zcu;
19892 const comp = zcu.comp;
19893 const gpa = comp.gpa;
19894 const io = comp.io;
19895 const ip = &zcu.intern_pool;
19896
19897 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
19898 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
19899 const tracked_inst = try block.trackZir(inst);
19900
19901 const src: LazySrcLoc = .{
19902 .base_node_inst = tracked_inst,
19903 .offset = .nodeOffset(.zero),
19904 };
19905 const ptr_type_src: LazySrcLoc = .{
19906 .base_node_inst = tracked_inst,
19907 .offset = .{ .node_offset_builtin_call_arg = .{
19908 .builtin_call_node = extra.node,
19909 .arg_index = 0,
19910 } },
19911 };
19912
19913 const operand = try sema.resolveType(block, src, extra.operand);
19914 const unrestricted_ptr_type: Type = switch (ip.indexToKey(operand.toIntern())) {
19915 else => return sema.fail(block, ptr_type_src, "expected pointer type, found '{f}'", .{operand.fmt(pt)}),
19916 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
19917 .one, .many, .c => operand,
19918 .slice => return sema.fail(block, ptr_type_src, "slice types cannot be restricted", .{}),
19919 },
19920 .restricted_ptr_type => |restricted_ptr_type| .fromInterned(restricted_ptr_type.unrestricted_ptr_type),
19921 };
19922
19923 switch (try ip.getReifiedRestrictedType(gpa, io, pt.tid, tracked_inst, unrestricted_ptr_type.toIntern())) {
19924 .existing => |ty| {
19925 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
19926 // No need for `ensureNamespaceUpToDate` because this type doesn't have a namespace.
19927 return .fromIntern(ty);
19928 },
19929 .wip => |wip| {
19930 errdefer wip.cancel(ip, pt.tid);
19931 const type_name, _ = try sema.computeTypeName(block, wip.index, name_strategy, "restricted", inst);
19932 wip.setName(ip, type_name);
19933 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
19934 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
19935 return .fromIntern(wip.index);
19936 },
19937 }
19938}
19939
1988219940fn zirReifyFn(
1988319941 sema: *Sema,
1988419942 block: *Block,
......@@ -20194,7 +20252,8 @@ fn zirReifyStruct(
2019420252 },
2019520253 .wip => |wip| {
2019620254 errdefer wip.cancel(ip, pt.tid);
20197 try sema.setTypeName(block, &wip, name_strategy, "struct", inst);
20255 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, name_strategy, "struct", inst);
20256 wip.setName(ip, type_name, name_nav);
2019820257 for (0..fields_len) |field_idx| {
2019920258 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
2020020259 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
......@@ -20438,7 +20497,8 @@ fn zirReifyUnion(
2043820497 },
2043920498 .wip => |wip| {
2044020499 errdefer wip.cancel(ip, pt.tid);
20441 try sema.setTypeName(block, &wip, name_strategy, "union", inst);
20500 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, name_strategy, "union", inst);
20501 wip.setName(ip, type_name, name_nav);
2044220502
2044320503 for (0..fields_len) |field_idx| {
2044420504 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
......@@ -20603,8 +20663,8 @@ fn zirReifyEnum(
2060320663 },
2060420664 .wip => |wip| {
2060520665 errdefer wip.cancel(ip, pt.tid);
20606
20607 try sema.setTypeName(block, &wip, name_strategy, "enum", inst);
20666 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, name_strategy, "enum", inst);
20667 wip.setName(ip, type_name, name_nav);
2060820668
2060920669 // Populate field names and values. Duplicate checking will be handled by type resolution.
2061020670 for (0..fields_len) |field_index| {
......@@ -27736,6 +27796,22 @@ fn coerceExtra(
2773627796 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
2773727797 },
2773827798 }
27799
27800 // Restricted coercions
27801 if (maybe_inst_val != null) {
27802 if (dest_ty.unrestrictedType(zcu)) |dest_unrestricted_ty| {
27803 if (sema.resolveValue(try sema.coerceExtra(block, dest_unrestricted_ty, inst, inst_src, opts))) |inst_val| {
27804 return .fromIntern(try ip.getCoerced(gpa, io, pt.tid, inst_val.toIntern(), dest_ty.toIntern()));
27805 }
27806 }
27807 }
27808 if (inst_ty.unrestrictedType(zcu)) |inst_unrestricted_ty| {
27809 const inst_unrestricted: Air.Inst.Ref = if (maybe_inst_val) |inst_val|
27810 .fromIntern(try ip.getCoerced(gpa, io, pt.tid, inst_val.toIntern(), inst_unrestricted_ty.toIntern()))
27811 else
27812 try sema.unwrapRestrictedPtr(block, inst_unrestricted_ty, inst, inst_src);
27813 return sema.coerceExtra(block, dest_ty, inst_unrestricted, inst_src, opts);
27814 }
2773927815 },
2774027816 .int, .comptime_int => switch (inst_ty.zigTypeTag(zcu)) {
2774127817 .float, .comptime_float => float: {
......@@ -28084,6 +28160,7 @@ const InMemoryCoercionResult = union(enum) {
2808428160 ptr_alignment: AlignPair,
2808528161 double_ptr_to_anyopaque: Pair,
2808628162 slice_to_anyopaque: Pair,
28163 ptr_restricted: Pair,
2808728164
2808828165 const Pair = struct {
2808928166 actual: Type,
......@@ -28415,6 +28492,15 @@ const InMemoryCoercionResult = union(enum) {
2841528492 try sema.errNote(src, msg, "consider using '.ptr'", .{});
2841628493 break;
2841728494 },
28495 .ptr_restricted => |pair| {
28496 for ([_]Type{ pair.actual, pair.wanted }) |restricted_ptr_type| {
28497 const unrestricted_ptr_type = restricted_ptr_type.unrestrictedType(pt.zcu) orelse continue;
28498 try sema.errNote(src, msg, "restricted type '{f}' is not guaranteed to have the same representation as its unrestricted type '{f}'", .{
28499 restricted_ptr_type.fmt(pt), unrestricted_ptr_type.fmt(pt),
28500 });
28501 }
28502 break;
28503 },
2841828504 };
2841928505 }
2842028506};
......@@ -28479,7 +28565,7 @@ pub fn coerceInMemoryAllowed(
2847928565 (dest_info.signedness == .signed and src_info.signedness == .unsigned and dest_info.bits <= src_info.bits) or
2848028566 (dest_info.signedness == .unsigned and src_info.signedness == .signed))
2848128567 {
28482 return InMemoryCoercionResult{ .int_not_coercible = .{
28568 return .{ .int_not_coercible = .{
2848328569 .actual_signedness = src_info.signedness,
2848428570 .wanted_signedness = dest_info.signedness,
2848528571 .actual_bits = src_info.bits,
......@@ -28913,7 +28999,7 @@ fn coerceInMemoryAllowedPtrs(
2891328999 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
2891429000 src_info.flags.size == .c or dest_info.flags.size == .c;
2891529001 if (!ok_ptr_size) {
28916 return InMemoryCoercionResult{ .ptr_size = .{
29002 return .{ .ptr_size = .{
2891729003 .actual = src_info.flags.size,
2891829004 .wanted = dest_info.flags.size,
2891929005 } };
......@@ -29049,13 +29135,19 @@ fn coerceInMemoryAllowedPtrs(
2904929135 break :a dest_child.abiAlignment(zcu);
2905029136 } else dest_info.flags.alignment;
2905129137 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {
29052 return InMemoryCoercionResult{ .ptr_alignment = .{
29138 return .{ .ptr_alignment = .{
2905329139 .actual = src_align,
2905429140 .wanted = dest_align,
2905529141 } };
2905629142 }
2905729143 }
2905829144
29145 // Restricted pointers have a different in-memory representation depending on the safety mode of the module that created it.
29146 if (dest_ty.unrestrictedType(zcu) != null or src_ty.unrestrictedType(zcu) != null) return .{ .ptr_restricted = .{
29147 .actual = src_ty,
29148 .wanted = dest_ty,
29149 } };
29150
2905929151 return .ok;
2906029152}
2906129153
......@@ -29202,10 +29294,15 @@ fn storePtr2(
2920229294
2920329295 try sema.requireRuntimeBlock(block, src, runtime_src);
2920429296
29297 const unrestricted_ptr = if (ptr_ty.unrestrictedType(zcu)) |unrestricted_ptr_ty|
29298 try sema.unwrapRestrictedPtr(block, unrestricted_ptr_ty, ptr, ptr_src)
29299 else
29300 ptr;
29301
2920529302 const store_inst = if (is_ret)
29206 try block.addBinOp(.store, ptr, operand)
29303 try block.addBinOp(.store, unrestricted_ptr, operand)
2920729304 else
29208 try block.addBinOp(air_tag, ptr, operand);
29305 try block.addBinOp(air_tag, unrestricted_ptr, operand);
2920929306
2921029307 try sema.checkComptimeKnownStore(block, store_inst, operand_src);
2921129308
......@@ -30282,7 +30379,12 @@ fn analyzeLoad(
3028230379 break :msg msg;
3028330380 });
3028430381
30285 return block.addTyOp(.load, elem_ty, ptr);
30382 const unrestricted_ptr = if (ptr_ty.unrestrictedType(zcu)) |unrestricted_ptr_ty|
30383 try sema.unwrapRestrictedPtr(block, unrestricted_ptr_ty, ptr, ptr_src)
30384 else
30385 ptr;
30386
30387 return block.addTyOp(.load, elem_ty, unrestricted_ptr);
3028630388}
3028730389
3028830390fn analyzeSlicePtr(
......@@ -31494,6 +31596,19 @@ fn wrapErrorUnionSet(
3149431596 }
3149531597}
3149631598
31599fn unwrapRestrictedPtr(
31600 sema: *Sema,
31601 block: *Block,
31602 unrestricted_ptr_ty: Type,
31603 ptr: Air.Inst.Ref,
31604 ptr_src: LazySrcLoc,
31605) !Air.Inst.Ref {
31606 return block.addTyOp(if (block.wantSafety()) tag: {
31607 try sema.preparePanicId(ptr_src, .corrupt_restricted_pointer);
31608 break :tag .unwrap_restricted_safe;
31609 } else .unwrap_restricted, unrestricted_ptr_ty, ptr);
31610}
31611
3149731612/// Returns the enum tag value for the active tag of a tagged union value.
3149831613///
3149931614/// Asserts that the type of `un` is a tagged union type.
......@@ -34211,13 +34326,59 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C
3421134326fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Type {
3421234327 const pt = sema.pt;
3421334328 return switch (decl) {
34329 .Signedness,
34330 .AddressSpace,
34331 .CallingConvention,
34332 => unreachable,
3421434333 // `noinline fn () void`
3421534334 .returnError => try pt.funcType(.{
3421634335 .param_types = &.{},
3421734336 .return_type = .void_type,
3421834337 .is_noinline = true,
3421934338 }),
34339 .StackTrace,
34340 .SourceLocation,
34341 .CallModifier,
34342 .AtomicOrder,
34343 .AtomicRmwOp,
34344 .ReduceOp,
34345 .FloatMode,
34346 .PrefetchOptions,
34347 .ExportOptions,
34348 .ExternOptions,
34349 .BranchHint,
34350 => unreachable,
34351
34352 .Type,
34353 .@"Type.Fn",
34354 .@"Type.Fn.Param",
34355 .@"Type.Fn.Param.Attributes",
34356 .@"Type.Fn.Attributes",
34357 .@"Type.Int",
34358 .@"Type.Float",
34359 .@"Type.Pointer",
34360 .@"Type.Pointer.Size",
34361 .@"Type.Pointer.Attributes",
34362 .@"Type.Array",
34363 .@"Type.Vector",
34364 .@"Type.Optional",
34365 .@"Type.Error",
34366 .@"Type.ErrorUnion",
34367 .@"Type.EnumField",
34368 .@"Type.Enum",
34369 .@"Type.Enum.Mode",
34370 .@"Type.Union",
34371 .@"Type.UnionField",
34372 .@"Type.UnionField.Attributes",
34373 .@"Type.Struct",
34374 .@"Type.StructField",
34375 .@"Type.StructField.Attributes",
34376 .@"Type.ContainerLayout",
34377 .@"Type.Opaque",
34378 .@"Type.Declaration",
34379 => unreachable,
3422034380
34381 .panic => unreachable,
3422134382 // `fn ([]const u8, ?usize) noreturn`
3422234383 .@"panic.call" => try pt.funcType(.{
3422334384 .param_types = &.{
......@@ -34226,7 +34387,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3422634387 },
3422734388 .return_type = .noreturn_type,
3422834389 }),
34229
3423034390 // `fn (anytype, anytype) noreturn`
3423134391 .@"panic.sentinelMismatch",
3423234392 .@"panic.inactiveUnionField",
......@@ -34234,19 +34394,16 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3423434394 .param_types = &.{ .generic_poison_type, .generic_poison_type },
3423534395 .return_type = .noreturn_type,
3423634396 }),
34237
3423834397 // `fn (anyerror) noreturn`
3423934398 .@"panic.unwrapError" => try pt.funcType(.{
3424034399 .param_types = &.{.anyerror_type},
3424134400 .return_type = .noreturn_type,
3424234401 }),
34243
3424434402 // `fn (usize) noreturn`
3424534403 .@"panic.sliceCastLenRemainder" => try pt.funcType(.{
3424634404 .param_types = &.{.usize_type},
3424734405 .return_type = .noreturn_type,
3424834406 }),
34249
3425034407 // `fn (usize, usize) noreturn`
3425134408 .@"panic.outOfBounds",
3425234409 .@"panic.startGreaterThanEnd",
......@@ -34254,7 +34411,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3425434411 .param_types = &.{ .usize_type, .usize_type },
3425534412 .return_type = .noreturn_type,
3425634413 }),
34257
3425834414 // `fn () noreturn`
3425934415 .@"panic.reachedUnreachable",
3426034416 .@"panic.unwrapNull",
......@@ -34275,23 +34431,28 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3427534431 .@"panic.copyLenMismatch",
3427634432 .@"panic.memcpyAlias",
3427734433 .@"panic.noreturnReturned",
34434 .@"panic.corruptRestrictedPointer",
3427834435 => try pt.funcType(.{
3427934436 .param_types = &.{},
3428034437 .return_type = .noreturn_type,
3428134438 }),
3428234439
34283 else => unreachable,
34440 .VaList => unreachable,
34441
34442 .assembly,
34443 .@"assembly.Clobbers",
34444 => unreachable,
3428434445 };
3428534446}
3428634447
34287pub fn setTypeName(
34448pub fn computeTypeName(
3428834449 sema: *Sema,
3428934450 block: *Block,
34290 wip: *const InternPool.WipContainerType,
34451 index: InternPool.Index,
3429134452 name_strategy: Zir.Inst.NameStrategy,
3429234453 anon_prefix: []const u8,
3429334454 inst: Zir.Inst.Index,
34294) CompileError!void {
34455) CompileError!struct { InternPool.NullTerminatedString, InternPool.Nav.Index.Optional } {
3429534456 const pt = sema.pt;
3429634457 const zcu = pt.zcu;
3429734458 const comp = zcu.comp;
......@@ -34308,16 +34469,16 @@ pub fn setTypeName(
3430834469 // TODO: that would be possible, by detecting line number changes and renaming
3430934470 // types appropriately. However, `@typeName` becomes a problem then. If we remove
3431034471 // that builtin from the language, we can consider this.
34311 wip.setName(ip, try ip.getOrPutStringFmt(
34472 return .{ try ip.getOrPutStringFmt(
3431234473 gpa,
3431334474 io,
3431434475 pt.tid,
3431534476 "{f}__{s}_{d}",
34316 .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(wip.index) },
34477 .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(index) },
3431734478 .no_embedded_nulls,
34318 ), .none);
34479 ), .none };
3431934480 },
34320 .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()),
34481 .parent => return .{ block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional() },
3432134482 .func => {
3432234483 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
3432334484 const zir_tags = sema.code.instructions.items(.tag);
......@@ -34360,8 +34521,7 @@ pub fn setTypeName(
3436034521 };
3436134522
3436234523 w.writeByte(')') catch return error.OutOfMemory;
34363 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
34364 wip.setName(ip, name, .none);
34524 return .{ try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), .none };
3436534525 },
3436634526 .dbg_var => {
3436734527 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
......@@ -34376,10 +34536,9 @@ pub fn setTypeName(
3437634536 } else {
3437734537 continue :strat .anon;
3437834538 };
34379 const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
34539 return .{ try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
3438034540 block.type_name_ctx.fmt(ip), var_name,
34381 }, .no_embedded_nulls);
34382 wip.setName(ip, name, .none);
34541 }, .no_embedded_nulls), .none };
3438334542 },
3438434543 }
3438534544}
......@@ -34420,7 +34579,8 @@ fn zirStructDecl(
3442034579 .existing => |ty| .fromInterned(ty),
3442134580 .wip => |wip| ty: {
3442234581 errdefer wip.cancel(ip, pt.tid);
34423 try sema.setTypeName(block, &wip, struct_decl.name_strategy, "struct", inst);
34582 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, struct_decl.name_strategy, "struct", inst);
34583 wip.setName(ip, type_name, name_nav);
3442434584 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3442534585 .parent = block.namespace.toOptional(),
3442634586 .owner_type = wip.index,
......@@ -34493,7 +34653,8 @@ fn zirUnionDecl(
3449334653 .existing => |ty| .fromInterned(ty),
3449434654 .wip => |wip| ty: {
3449534655 errdefer wip.cancel(ip, pt.tid);
34496 try sema.setTypeName(block, &wip, union_decl.name_strategy, "union", inst);
34656 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, union_decl.name_strategy, "union", inst);
34657 wip.setName(ip, type_name, name_nav);
3449734658 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3449834659 .parent = block.namespace.toOptional(),
3449934660 .owner_type = wip.index,
......@@ -34545,7 +34706,8 @@ fn zirEnumDecl(
3454534706 .existing => |ty| .fromInterned(ty),
3454634707 .wip => |wip| ty: {
3454734708 errdefer wip.cancel(ip, pt.tid);
34548 try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst);
34709 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, enum_decl.name_strategy, "enum", inst);
34710 wip.setName(ip, type_name, name_nav);
3454934711 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3455034712 .parent = block.namespace.toOptional(),
3455134713 .owner_type = wip.index,
......@@ -34594,7 +34756,8 @@ fn zirOpaqueDecl(
3459434756 .existing => |ty| .fromInterned(ty),
3459534757 .wip => |wip| ty: {
3459634758 errdefer wip.cancel(ip, pt.tid);
34597 try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst);
34759 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, opaque_decl.name_strategy, "opaque", inst);
34760 wip.setName(ip, type_name, name_nav);
3459834761 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3459934762 .parent = block.namespace.toOptional(),
3460034763 .owner_type = wip.index,
src/Sema/LowerZon.zig+2-1
......@@ -150,7 +150,8 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
150150 errdefer wip.cancel(ip, pt.tid);
151151 const block = self.block;
152152 const zcu = pt.zcu;
153 try self.sema.setTypeName(block, &wip, .anon, "struct", self.base_node_inst.resolve(ip).?);
153 const type_name, const name_nav = try self.sema.computeTypeName(block, wip.index, .anon, "struct", self.base_node_inst.resolve(ip).?);
154 wip.setName(ip, type_name, name_nav);
154155
155156 // Reified structs have field information populated immediately.
156157 @memcpy(wip.field_values.get(ip), elems);
src/Sema/bitcast.zig+1
......@@ -239,6 +239,7 @@ const UnpackValueBits = struct {
239239 switch (ip.indexToKey(val.toIntern())) {
240240 .int_type,
241241 .ptr_type,
242 .restricted_ptr_type,
242243 .array_type,
243244 .vector_type,
244245 .opt_type,
src/Sema/type_resolution.zig+1
......@@ -84,6 +84,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons
8484 switch (ip.indexToKey(ty.toIntern())) {
8585 .int_type,
8686 .ptr_type,
87 .restricted_ptr_type,
8788 .anyframe_type,
8889 .simple_type,
8990 .opaque_type,
src/Type.zig+138-70
......@@ -165,6 +165,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class {
165165 .error_set_type,
166166 .inferred_error_set_type,
167167 .ptr_type,
168 .restricted_ptr_type,
168169 .anyframe_type,
169170 => .runtime,
170171
......@@ -373,13 +374,28 @@ pub fn arrayInfo(self: Type, zcu: *const Zcu) ArrayInfo {
373374}
374375
375376pub fn ptrInfo(ty: Type, zcu: *const Zcu) InternPool.Key.PtrType {
376 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
377 return ty.ptrInfoOrNull(&zcu.intern_pool, .{}).?;
378}
379
380pub fn ptrInfoOrNull(ty: Type, ip: *const InternPool, comptime opts: struct {
381 allow_optional: bool = true,
382 allow_restricted: bool = true,
383}) ?InternPool.Key.PtrType {
384 return switch (ip.indexToKey(ty.toIntern())) {
377385 .ptr_type => |p| p,
378 .opt_type => |child| switch (zcu.intern_pool.indexToKey(child)) {
386 .restricted_ptr_type => |rp| if (opts.allow_restricted)
387 ip.indexToKey(rp.unrestricted_ptr_type).ptr_type
388 else
389 null,
390 .opt_type => |child| if (opts.allow_optional) switch (ip.indexToKey(child)) {
379391 .ptr_type => |p| p,
380 else => unreachable,
381 },
382 else => unreachable,
392 .restricted_ptr_type => |rp| if (opts.allow_restricted)
393 ip.indexToKey(rp.unrestricted_ptr_type).ptr_type
394 else
395 null,
396 else => null, // not a pointer type
397 } else null,
398 else => null, // not a pointer type
383399 };
384400}
385401
......@@ -488,6 +504,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
488504 try print(Type.fromInterned(info.child), writer, pt, ctx);
489505 return;
490506 },
507 .restricted_ptr_type => {
508 const name = ip.loadRestrictedType(ty.toIntern()).name;
509 try writer.print("{f}", .{name.fmt(ip)});
510 },
491511 .array_type => |array_type| {
492512 if (array_type.sentinel == .none) {
493513 try writer.print("[{d}]", .{array_type.len});
......@@ -747,6 +767,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
747767 .vector_type,
748768 => true,
749769
770 .restricted_ptr_type,
750771 .error_union_type,
751772 .error_set_type,
752773 .inferred_error_set_type,
......@@ -893,22 +914,13 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
893914
894915/// Never returns `none`. Asserts that all necessary type resolution is already done.
895916pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment {
896 const ip = &zcu.intern_pool;
897 const ptr_key: InternPool.Key.PtrType = switch (ip.indexToKey(ptr_ty.toIntern())) {
898 .ptr_type => |key| key,
899 .opt_type => |child| ip.indexToKey(child).ptr_type,
900 else => unreachable,
901 };
917 const ptr_key = ptr_ty.ptrInfo(zcu);
902918 if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment;
903919 return Type.fromInterned(ptr_key.child).abiAlignment(zcu);
904920}
905921
906922pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
907 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
908 .ptr_type => |ptr_type| ptr_type.flags.address_space,
909 .opt_type => |child| zcu.intern_pool.indexToKey(child).ptr_type.flags.address_space,
910 else => unreachable,
911 };
923 return ty.ptrInfo(zcu).flags.address_space;
912924}
913925
914926/// Never returns `.none`. Asserts that the layout of `ty` is resolved.
......@@ -924,7 +936,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
924936 if (int_type.bits == 0) return .@"1";
925937 return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits));
926938 },
927 .ptr_type, .anyframe_type => ptrAbiAlignment(target),
939 .ptr_type, .restricted_ptr_type, .anyframe_type => ptrAbiAlignment(target),
928940 .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu),
929941 .vector_type => |vector_type| {
930942 if (vector_type.len == 0) return .@"1";
......@@ -1078,7 +1090,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
10781090 .slice => ptrAbiSize(target) * 2,
10791091 .one, .many, .c => ptrAbiSize(target),
10801092 },
1081 .anyframe_type => ptrAbiSize(target),
1093 .restricted_ptr_type, .anyframe_type => ptrAbiSize(target),
10821094 .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu),
10831095 .vector_type => |vec| {
10841096 const elem_ty: Type = .fromInterned(vec.child);
......@@ -1231,7 +1243,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
12311243 .slice => target.ptrBitWidth() * 2,
12321244 else => target.ptrBitWidth(),
12331245 },
1234 .anyframe_type => target.ptrBitWidth(),
1246 .restricted_ptr_type, .anyframe_type => target.ptrBitWidth(),
12351247 .array_type => |array_type| {
12361248 const elem_ty: Type = .fromInterned(array_type.child);
12371249 const len = array_type.lenIncludingSentinel();
......@@ -1329,13 +1341,31 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
13291341 };
13301342}
13311343
1332pub fn isSinglePointer(ty: Type, zcu: *const Zcu) bool {
1333 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1334 .ptr_type => |ptr_info| ptr_info.flags.size == .one,
1335 else => false,
1344/// Returns `null` if `ty` is not a restricted pointer.
1345pub fn unrestrictedType(ty: Type, zcu: *const Zcu) ?Type {
1346 const ip = &zcu.intern_pool;
1347 return switch (ip.indexToKey(ty.toIntern())) {
1348 .restricted_ptr_type => |restricted_ptr_type| return .fromInterned(restricted_ptr_type.unrestricted_ptr_type),
1349 else => null,
1350 };
1351}
1352
1353const RestrictedRepr = enum { double_pointer, single_pointer };
1354pub fn restrictedRepr(ty: Type, zcu: *const Zcu) RestrictedRepr {
1355 return restrictedReprByZirIndex(zcu.intern_pool.indexToKey(ty.toIntern()).restricted_ptr_type.zir_index, zcu);
1356}
1357pub fn restrictedReprByZirIndex(zir_index: InternPool.TrackedInst.Index, zcu: *const Zcu) RestrictedRepr {
1358 return switch (zcu.fileByIndex(zir_index.resolveFile(&zcu.intern_pool)).mod.?.optimize_mode) {
1359 .Debug, .ReleaseSafe => .double_pointer,
1360 .ReleaseFast, .ReleaseSmall => .single_pointer,
13361361 };
13371362}
13381363
1364pub fn isSinglePointer(ty: Type, zcu: *const Zcu) bool {
1365 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1366 return ptr_info.flags.size == .one;
1367}
1368
13391369/// Asserts `ty` is a pointer.
13401370pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {
13411371 return ty.ptrSizeOrNull(zcu).?;
......@@ -1343,24 +1373,27 @@ pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {
13431373
13441374/// Returns `null` if `ty` is not a pointer.
13451375pub fn ptrSizeOrNull(ty: Type, zcu: *const Zcu) ?std.builtin.Type.Pointer.Size {
1346 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1347 .ptr_type => |ptr_info| ptr_info.flags.size,
1348 else => null,
1349 };
1376 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return null;
1377 return ptr_info.flags.size;
13501378}
13511379
13521380pub fn isSlice(ty: Type, zcu: *const Zcu) bool {
1353 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1354 .ptr_type => |ptr_type| ptr_type.flags.size == .slice,
1355 else => false,
1356 };
1381 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1382 return ptr_info.flags.size == .slice;
13571383}
13581384
13591385pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {
1360 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1386 const ip = &zcu.intern_pool;
1387 return ty: switch (ip.indexToKey(ty.toIntern())) {
13611388 .ptr_type => |ptr_type| ptr_type.flags.size == .slice,
1362 .opt_type => |child| switch (zcu.intern_pool.indexToKey(child)) {
1389 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1390 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1391 },
1392 .opt_type => |child| opt_child: switch (zcu.intern_pool.indexToKey(child)) {
13631393 .ptr_type => |ptr_type| !ptr_type.flags.is_allowzero and ptr_type.flags.size == .slice,
1394 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1395 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1396 },
13641397 else => false,
13651398 },
13661399 else => false,
......@@ -1372,10 +1405,8 @@ pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {
13721405}
13731406
13741407pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {
1375 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1376 .ptr_type => |ptr_type| ptr_type.flags.is_const,
1377 else => false,
1378 };
1408 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1409 return ptr_info.flags.is_const;
13791410}
13801411
13811412pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {
......@@ -1383,38 +1414,45 @@ pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {
13831414}
13841415
13851416pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {
1386 return switch (ip.indexToKey(ty.toIntern())) {
1387 .ptr_type => |ptr_type| ptr_type.flags.is_volatile,
1388 else => false,
1389 };
1417 const ptr_info = ty.ptrInfoOrNull(ip, .{ .allow_optional = false }) orelse return false;
1418 return ptr_info.flags.is_volatile;
13901419}
13911420
13921421pub fn isAllowzeroPtr(ty: Type, zcu: *const Zcu) bool {
1393 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1422 const ip = &zcu.intern_pool;
1423 return ty: switch (ip.indexToKey(ty.toIntern())) {
13941424 .ptr_type => |ptr_type| ptr_type.flags.is_allowzero,
1425 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1426 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1427 },
13951428 .opt_type => true,
13961429 else => false,
13971430 };
13981431}
13991432
14001433pub fn isCPtr(ty: Type, zcu: *const Zcu) bool {
1401 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1402 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
1403 else => false,
1404 };
1434 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1435 return ptr_info.flags.size == .c;
14051436}
14061437
14071438pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool {
1408 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1439 const ip = &zcu.intern_pool;
1440 return ty: switch (ip.indexToKey(ty.toIntern())) {
14091441 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
14101442 .slice => false,
14111443 .one, .many, .c => true,
14121444 },
1413 .opt_type => |child| switch (zcu.intern_pool.indexToKey(child)) {
1445 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1446 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1447 },
1448 .opt_type => |child| opt_child: switch (ip.indexToKey(child)) {
14141449 .ptr_type => |p| switch (p.flags.size) {
14151450 .slice, .c => false,
14161451 .many, .one => !p.flags.is_allowzero,
14171452 },
1453 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1454 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1455 },
14181456 else => false,
14191457 },
14201458 else => false,
......@@ -1429,13 +1467,20 @@ pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {
14291467
14301468/// See also `isPtrLikeOptional`.
14311469pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
1432 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1433 .opt_type => |child_type| child_type == .anyerror_type or switch (zcu.intern_pool.indexToKey(child_type)) {
1470 const ip = &zcu.intern_pool;
1471 return ty: switch (ip.indexToKey(ty.toIntern())) {
1472 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
1473 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1474 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1475 },
1476 .opt_type => |child_type| child_type == .anyerror_type or opt_child: switch (ip.indexToKey(child_type)) {
14341477 .ptr_type => |ptr_type| ptr_type.flags.size != .c and !ptr_type.flags.is_allowzero,
1478 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1479 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1480 },
14351481 .error_set_type, .inferred_error_set_type => true,
14361482 else => false,
14371483 },
1438 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
14391484 else => false,
14401485 };
14411486}
......@@ -1443,13 +1488,20 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
14431488/// Returns true if the type is optional and would be lowered to a single pointer
14441489/// address value, using 0 for null. Note that this returns true for C pointers.
14451490pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {
1446 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1491 const ip = &zcu.intern_pool;
1492 return ty: switch (ip.indexToKey(ty.toIntern())) {
14471493 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
1448 .opt_type => |child| switch (zcu.intern_pool.indexToKey(child)) {
1494 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1495 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1496 },
1497 .opt_type => |child| opt_child: switch (ip.indexToKey(child)) {
14491498 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
14501499 .slice, .c => false,
14511500 .many, .one => !ptr_type.flags.is_allowzero,
14521501 },
1502 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1503 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1504 },
14531505 else => false,
14541506 },
14551507 else => false,
......@@ -1486,7 +1538,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
14861538 .pointer => return ty.childType(zcu),
14871539 .optional => {
14881540 const ptr_ty = ty.childType(zcu);
1489 const ptr_info = zcu.intern_pool.indexToKey(ptr_ty.toIntern()).ptr_type;
1541 const ptr_info = ptr_ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }).?;
14901542 assert(ptr_info.flags.size != .c);
14911543 assert(!ptr_info.flags.is_allowzero);
14921544 return .fromInterned(ptr_info.child);
......@@ -1508,7 +1560,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
15081560/// * `[*c]T`
15091561pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
15101562 const ip = &zcu.intern_pool;
1511 return switch (ip.indexToKey(ty.toIntern())) {
1563 return ty: switch (ip.indexToKey(ty.toIntern())) {
15121564 inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
15131565 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
15141566 .many, .slice, .c => .fromInterned(ptr_type.child),
......@@ -1517,6 +1569,9 @@ pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
15171569 else => unreachable,
15181570 },
15191571 },
1572 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1573 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1574 },
15201575 else => unreachable,
15211576 };
15221577}
......@@ -1532,12 +1587,16 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {
15321587/// Asserts that the type is an optional, or a C pointer.
15331588/// For C pointers this returns the type unmodified.
15341589pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
1535 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1590 const ip = &zcu.intern_pool;
1591 ty: switch (ip.indexToKey(ty.toIntern())) {
15361592 .opt_type => |child| return .fromInterned(child),
15371593 .ptr_type => |ptr_type| {
15381594 assert(ptr_type.flags.size == .c);
15391595 return ty;
15401596 },
1597 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1598 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1599 },
15411600 else => unreachable,
15421601 }
15431602}
......@@ -1755,7 +1814,8 @@ pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 {
17551814
17561815/// Asserts the type is an array, pointer or vector.
17571816pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {
1758 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1817 const ip = &zcu.intern_pool;
1818 return ty: switch (ip.indexToKey(ty.toIntern())) {
17591819 .vector_type,
17601820 .struct_type,
17611821 .tuple_type,
......@@ -1763,6 +1823,9 @@ pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {
17631823
17641824 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
17651825 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
1826 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1827 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1828 },
17661829
17671830 else => unreachable,
17681831 };
......@@ -1851,6 +1914,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
18511914 .tuple_type => unreachable,
18521915
18531916 .ptr_type => unreachable,
1917 .restricted_ptr_type => unreachable,
18541918 .anyframe_type => unreachable,
18551919 .array_type => unreachable,
18561920
......@@ -2021,6 +2085,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
20212085 assertHasLayout(ty, zcu);
20222086 return switch (ip.indexToKey(ty.toIntern())) {
20232087 .ptr_type,
2088 .restricted_ptr_type, // number of possible values is not known until the end of compilation, so never treated as NPV/OPV
20242089 .error_union_type,
20252090 .func_type,
20262091 .anyframe_type,
......@@ -2829,7 +2894,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
28292894pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type {
28302895 const zcu = pt.zcu;
28312896 const ip = &zcu.intern_pool;
2832 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
2897 const ptr_info = ptr_ty.ptrInfoOrNull(ip, .{ .allow_optional = false }).?;
28332898 const elem_ty: Type = switch (ptr_info.flags.size) {
28342899 .slice, .many, .c => .fromInterned(ptr_info.child),
28352900 .one => switch (ip.indexToKey(ptr_info.child)) {
......@@ -2883,7 +2948,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error
28832948pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type {
28842949 const zcu = pt.zcu;
28852950 const ip = &zcu.intern_pool;
2886 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
2951 const ptr_info = ptr_ty.ptrInfoOrNull(ip, .{ .allow_optional = false }).?;
28872952 assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c);
28882953 const aggregate_ty: Type = .fromInterned(ptr_info.child);
28892954 aggregate_ty.assertHasLayout(zcu);
......@@ -3011,7 +3076,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
30113076 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {
30123077 .tuple_type, .union_type => field_ty.abiAlignment(zcu),
30133078 .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),
3014 .ptr_type => Type.usize.abiAlignment(zcu),
3079 .ptr_type, .restricted_ptr_type => ptrAbiAlignment(zcu.getTarget()),
30153080 else => unreachable,
30163081 },
30173082 else => |a| a,
......@@ -3040,6 +3105,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
30403105
30413106pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
30423107 return switch (ip.indexToKey(ty.toIntern())) {
3108 .restricted_ptr_type => ip.loadRestrictedType(ty.toIntern()).name,
30433109 .struct_type => ip.loadStructType(ty.toIntern()).name,
30443110 .union_type => ip.loadUnionType(ty.toIntern()).name,
30453111 .enum_type => ip.loadEnumType(ty.toIntern()).name,
......@@ -3247,6 +3313,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
32473313 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
32483314 .int_type,
32493315 .ptr_type,
3316 .restricted_ptr_type,
32503317 .anyframe_type,
32513318 .simple_type,
32523319 .opaque_type,
......@@ -3315,34 +3382,34 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
33153382 }
33163383
33173384 switch (ip.indexToKey(ty.toIntern())) {
3318 .ptr_type => try collectSubtypes(Type.fromInterned(ty.ptrInfo(zcu).child), pt, visited),
3319 .array_type => |array_type| try collectSubtypes(Type.fromInterned(array_type.child), pt, visited),
3320 .vector_type => |vector_type| try collectSubtypes(Type.fromInterned(vector_type.child), pt, visited),
3321 .opt_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited),
3385 .ptr_type => |ptr_type| try collectSubtypes(.fromInterned(ptr_type.child), pt, visited),
3386 .array_type => |array_type| try collectSubtypes(.fromInterned(array_type.child), pt, visited),
3387 .vector_type => |vector_type| try collectSubtypes(.fromInterned(vector_type.child), pt, visited),
3388 .opt_type => |child| try collectSubtypes(.fromInterned(child), pt, visited),
33223389 .error_union_type => |error_union_type| {
3323 try collectSubtypes(Type.fromInterned(error_union_type.error_set_type), pt, visited);
3390 try collectSubtypes(.fromInterned(error_union_type.error_set_type), pt, visited);
33243391 if (error_union_type.payload_type != .generic_poison_type) {
3325 try collectSubtypes(Type.fromInterned(error_union_type.payload_type), pt, visited);
3392 try collectSubtypes(.fromInterned(error_union_type.payload_type), pt, visited);
33263393 }
33273394 },
33283395 .tuple_type => |tuple| {
33293396 for (tuple.types.get(ip)) |field_ty| {
3330 try collectSubtypes(Type.fromInterned(field_ty), pt, visited);
3397 try collectSubtypes(.fromInterned(field_ty), pt, visited);
33313398 }
33323399 },
33333400 .func_type => |fn_info| {
33343401 const param_types = fn_info.param_types.get(&zcu.intern_pool);
33353402 for (param_types) |param_ty| {
33363403 if (param_ty != .generic_poison_type) {
3337 try collectSubtypes(Type.fromInterned(param_ty), pt, visited);
3404 try collectSubtypes(.fromInterned(param_ty), pt, visited);
33383405 }
33393406 }
33403407
33413408 if (fn_info.return_type != .generic_poison_type) {
3342 try collectSubtypes(Type.fromInterned(fn_info.return_type), pt, visited);
3409 try collectSubtypes(.fromInterned(fn_info.return_type), pt, visited);
33433410 }
33443411 },
3345 .anyframe_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited),
3412 .anyframe_type => |child| try collectSubtypes(.fromInterned(child), pt, visited),
33463413
33473414 // leaf types
33483415 .undef,
......@@ -3354,6 +3421,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
33543421 .enum_type,
33553422 .simple_type,
33563423 .int_type,
3424 .restricted_ptr_type,
33573425 => {},
33583426
33593427 // values, not types
src/Zcu.zig+5-1
......@@ -501,6 +501,7 @@ pub const BuiltinDecl = enum {
501501 @"panic.copyLenMismatch",
502502 @"panic.memcpyAlias",
503503 @"panic.noreturnReturned",
504 @"panic.corruptRestrictedPointer",
504505
505506 VaList,
506507
......@@ -588,6 +589,7 @@ pub const BuiltinDecl = enum {
588589 .@"panic.copyLenMismatch",
589590 .@"panic.memcpyAlias",
590591 .@"panic.noreturnReturned",
592 .@"panic.corruptRestrictedPointer",
591593 => .func,
592594 };
593595 }
......@@ -661,6 +663,7 @@ pub const SimplePanicId = enum {
661663 copy_len_mismatch,
662664 memcpy_alias,
663665 noreturn_returned,
666 corrupt_restricted_pointer,
664667
665668 pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
666669 return switch (id) {
......@@ -684,6 +687,7 @@ pub const SimplePanicId = enum {
684687 .copy_len_mismatch => .@"panic.copyLenMismatch",
685688 .memcpy_alias => .@"panic.memcpyAlias",
686689 .noreturn_returned => .@"panic.noreturnReturned",
690 .corrupt_restricted_pointer => .@"panic.corruptRestrictedPointer",
687691 // zig fmt: on
688692 };
689693 }
......@@ -4215,7 +4219,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag
42154219
42164220 // Queue any decls within this type which would be automatically analyzed.
42174221 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
4218 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?;
4222 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap() orelse continue;
42194223 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {
42204224 // `comptime` decls are always analyzed.
42214225 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
src/codegen.zig+4
......@@ -281,6 +281,9 @@ pub fn generateLazySymbol(
281281 w.writeAll(tag_name) catch unreachable;
282282 w.writeByte(0) catch unreachable;
283283 }
284 } else if (Type.fromInterned(lazy_sym.ty).unrestrictedType(zcu)) |unrestricted_ptr_ty| {
285 alignment.* = unrestricted_ptr_ty.abiAlignment(zcu);
286 try w.splatByteAll(0, @divExact(zcu.getTarget().ptrBitWidth(), 8)); // to be filled in later
284287 } else {
285288 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{
286289 @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt),
......@@ -325,6 +328,7 @@ pub fn generateSymbol(
325328 switch (ip.indexToKey(val.toIntern())) {
326329 .int_type,
327330 .ptr_type,
331 .restricted_ptr_type,
328332 .array_type,
329333 .vector_type,
330334 .opt_type,
src/codegen/aarch64/Select.zig+45
......@@ -658,6 +658,28 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
658658 air_inst_index = air_body[air_body_index];
659659 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
660660 },
661 .unwrap_restricted, .unwrap_restricted_safe => {
662 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
663
664 maybe_noop: {
665 switch (isel.air.typeOf(ty_op.operand, ip).restrictedRepr(zcu)) {
666 .double_pointer => break :maybe_noop,
667 .single_pointer => {},
668 }
669 if (true) break :maybe_noop;
670 if (ty_op.operand.toIndex()) |src_air_inst_index| {
671 if (isel.hints.get(src_air_inst_index)) |hint_vpsi| {
672 try isel.hints.putNoClobber(gpa, air_inst_index, hint_vpsi);
673 }
674 }
675 }
676 try isel.analyzeUse(ty_op.operand);
677 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
678
679 air_body_index += 1;
680 air_inst_index = air_body[air_body_index];
681 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
682 },
661683 .struct_field_ptr, .struct_field_val => {
662684 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
663685 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -5737,6 +5759,29 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
57375759 }
57385760 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
57395761 },
5762 .unwrap_restricted, .unwrap_restricted_safe => |air_tag| {
5763 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
5764 defer dst_vi.value.deref(isel);
5765 const ty_op = air.data(air.inst_index).ty_op;
5766 const unrestricted_ty = ty_op.ty.toType();
5767 const restricted_ty = isel.air.typeOf(ty_op.operand, ip);
5768 switch (restricted_ty.restrictedRepr(zcu)) {
5769 .double_pointer => {
5770 switch (air_tag) {
5771 else => unreachable,
5772 .unwrap_restricted => {},
5773 .unwrap_restricted_safe => {}, // TODO
5774 }
5775 const ptr_vi = try isel.use(ty_op.operand);
5776 const ptr_mat = try ptr_vi.matReg(isel);
5777 _ = try dst_vi.value.load(isel, unrestricted_ty, ptr_mat.ra, .{});
5778 try ptr_mat.finish(isel);
5779 },
5780 .single_pointer => try dst_vi.value.move(isel, ty_op.operand),
5781 }
5782 }
5783 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5784 },
57405785 .struct_field_ptr => {
57415786 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
57425787 defer dst_vi.value.deref(isel);
src/codegen/c.zig+36-1
......@@ -896,6 +896,7 @@ pub const DeclGen = struct {
896896 // types, not values
897897 .int_type,
898898 .ptr_type,
899 .restricted_ptr_type,
899900 .array_type,
900901 .vector_type,
901902 .opt_type,
......@@ -1334,7 +1335,7 @@ pub const DeclGen = struct {
13341335 return w.writeByte(')');
13351336 },
13361337 .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"),
1337 else => switch (ip.indexToKey(ty.toIntern())) {
1338 else => ty: switch (ip.indexToKey(ty.toIntern())) {
13381339 .simple_type, // anyerror, c_char (etc), usize, isize
13391340 .int_type,
13401341 .enum_type,
......@@ -1405,6 +1406,9 @@ pub const DeclGen = struct {
14051406 try w.writeByte('}');
14061407 },
14071408 },
1409 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1410 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1411 },
14081412 .opt_type => |child_type| switch (CType.classifyOptional(ty, zcu)) {
14091413 .npv_payload => unreachable, // opv optional
14101414
......@@ -2840,6 +2844,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
28402844 .set_err_return_trace => try airSetErrReturnTrace(f, inst),
28412845 .save_err_return_trace_index => try airSaveErrReturnTraceIndex(f, inst),
28422846
2847 .unwrap_restricted => try airUnwrapRestricted(f, inst, false),
2848 .unwrap_restricted_safe => try airUnwrapRestricted(f, inst, true),
2849
28432850 .wasm_memory_size => try airWasmMemorySize(f, inst),
28442851 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
28452852
......@@ -5533,6 +5540,34 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
55335540 return local;
55345541}
55355542
5543fn airUnwrapRestricted(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
5544 const pt = f.dg.pt;
5545 const zcu = pt.zcu;
5546 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5547
5548 const unrestricted_ty = ty_op.ty.toType();
5549 const restricted_ty = f.typeOf(ty_op.operand);
5550 const operand = try f.resolveInst(ty_op.operand);
5551 try reap(f, inst, &.{ty_op.operand});
5552
5553 const w = &f.code.writer;
5554 const local = try f.allocLocal(inst, unrestricted_ty);
5555
5556 try f.writeCValue(w, local, .other);
5557 try w.writeAll(" = ");
5558 switch (restricted_ty.restrictedRepr(zcu)) {
5559 .double_pointer => {
5560 _ = safety; // TODO
5561 try f.writeCValueDeref(w, operand);
5562 },
5563 .single_pointer => try f.writeCValue(w, operand, .other),
5564 }
5565 try w.writeByte(';');
5566 try f.newline();
5567
5568 return local;
5569}
5570
55365571fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
55375572 const pt = f.dg.pt;
55385573 const w = &f.code.writer;
src/codegen/c/type.zig+19-1
......@@ -284,6 +284,20 @@ pub const CType = union(enum) {
284284
285285 .pointer => {
286286 const ptr = cur_ty.ptrInfo(zcu);
287 if (cur_ty.unrestrictedType(zcu)) |unrestricted_ty| switch (cur_ty.restrictedRepr(zcu)) {
288 .double_pointer => {
289 const unrestricted_cty = try lowerInner(unrestricted_ty, true, deps, arena, zcu);
290 const unrestricted_cty_buf = try arena.create(CType);
291 unrestricted_cty_buf.* = unrestricted_cty;
292 return .{ .pointer = .{
293 .@"const" = true,
294 .@"volatile" = false,
295 .elem_ty = unrestricted_cty_buf,
296 .nonstring = false,
297 } };
298 },
299 .single_pointer => {},
300 };
287301 switch (ptr.flags.size) {
288302 .slice => {
289303 try deps.addType(gpa, cur_ty, allow_incomplete);
......@@ -912,7 +926,10 @@ pub const CType = union(enum) {
912926 .optional => try w.print("opt_{f}", .{fmtZigType(ty.optionalChild(zcu), zcu)}),
913927 .error_union => try w.print("errunion_{f}", .{fmtZigType(ty.errorUnionPayload(zcu), zcu)}),
914928
915 .pointer => switch (ty.ptrSize(zcu)) {
929 .pointer => if (ty.unrestrictedType(zcu)) |_| {
930 const name = ty.containerTypeName(ip).toSlice(ip);
931 try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
932 } else switch (ty.ptrSize(zcu)) {
916933 .one, .many, .c => try w.print("ptr_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
917934 .slice => try w.print("slice_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
918935 },
......@@ -985,6 +1002,7 @@ pub const CType = union(enum) {
9851002 return switch (ip.indexToKey(ty.toIntern())) {
9861003 .int_type,
9871004 .ptr_type,
1005 .restricted_ptr_type,
9881006 .anyframe_type,
9891007 .simple_type,
9901008 .opaque_type,
src/codegen/llvm.zig+2
......@@ -3061,6 +3061,7 @@ pub const Object = struct {
30613061 }),
30623062 };
30633063 },
3064 .restricted_ptr_type => @panic("TODO implement restricted pointers"),
30643065 .array_type => |array_type| o.builder.arrayType(
30653066 array_type.lenIncludingSentinel(),
30663067 try o.lowerType(.fromInterned(array_type.child)),
......@@ -3443,6 +3444,7 @@ pub const Object = struct {
34433444 return switch (val_key) {
34443445 .int_type,
34453446 .ptr_type,
3447 .restricted_ptr_type,
34463448 .array_type,
34473449 .vector_type,
34483450 .opt_type,
src/codegen/llvm/FuncGen.zig+19
......@@ -413,6 +413,9 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air
413413 .wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]),
414414 .wrap_errunion_err => try self.airWrapErrUnionErr(body[i..]),
415415
416 .unwrap_restricted => try self.airUnwrapRestricted(inst, false),
417 .unwrap_restricted_safe => try self.airUnwrapRestricted(inst, true),
418
416419 .wasm_memory_size => try self.airWasmMemorySize(inst),
417420 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),
418421
......@@ -3250,6 +3253,22 @@ fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocat
32503253 return result_ptr;
32513254}
32523255
3256fn airUnwrapRestricted(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value {
3257 const o = self.object;
3258 const zcu = o.zcu;
3259 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3260 const unrestricted_ty = ty_op.ty.toType();
3261 const restricted_ty = self.typeOf(ty_op.operand);
3262 const operand = try self.resolveInst(ty_op.operand);
3263 switch (restricted_ty.restrictedRepr(zcu)) {
3264 .double_pointer => {
3265 _ = safety; // TODO
3266 return self.wip.load(.normal, .ptr, operand, unrestricted_ty.abiAlignment(zcu).toLlvm(), "restricted.unwrap");
3267 },
3268 .single_pointer => return operand,
3269 }
3270}
3271
32533272fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
32543273 const o = self.object;
32553274 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
src/codegen/riscv64/CodeGen.zig+4
......@@ -1614,6 +1614,10 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
16141614 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
16151615 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16161616
1617 .unwrap_restricted,
1618 .unwrap_restricted_safe,
1619 => return func.fail("TODO implement restricted pointers", .{}),
1620
16171621 .runtime_nav_ptr => try func.airRuntimeNavPtr(inst),
16181622
16191623 .add_optimized,
src/codegen/sparc64/CodeGen.zig+4
......@@ -676,6 +676,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
676676 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
677677 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
678678
679 .unwrap_restricted,
680 .unwrap_restricted_safe,
681 => return self.fail("TODO implement restricted pointers", .{}),
682
679683 .add_optimized,
680684 .sub_optimized,
681685 .mul_optimized,
src/codegen/spirv/CodeGen.zig+4-1
......@@ -774,6 +774,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
774774 switch (ip.indexToKey(val.toIntern())) {
775775 .int_type,
776776 .ptr_type,
777 .restricted_ptr_type,
777778 .array_type,
778779 .vector_type,
779780 .opt_type,
......@@ -2774,7 +2775,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
27742775 .unwrap_errunion_err => try cg.airErrUnionErr(inst),
27752776 .unwrap_errunion_payload => try cg.airErrUnionPayload(inst),
27762777 .wrap_errunion_err => try cg.airWrapErrUnionErr(inst),
2777 .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
2778 .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
2779
2780 .unwrap_restricted => return cg.fail("TODO implement restricted pointers", .{}),
27782781
27792782 .is_null => try cg.airIsNull(inst, false, .is_null),
27802783 .is_non_null => try cg.airIsNull(inst, false, .is_non_null),
src/codegen/wasm/CodeGen.zig+20
......@@ -1815,6 +1815,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18151815 .errunion_payload_ptr_set => cg.airErrUnionPayloadPtrSet(inst),
18161816 .error_name => cg.airErrorName(inst),
18171817
1818 .unwrap_restricted => cg.airUnwrapRestricted(inst, false),
1819 .unwrap_restricted_safe => cg.airUnwrapRestricted(inst, true),
1820
18181821 .wasm_memory_size => cg.airWasmMemorySize(inst),
18191822 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),
18201823
......@@ -4676,6 +4679,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
46764679 switch (ip.indexToKey(val.ip_index)) {
46774680 .int_type,
46784681 .ptr_type,
4682 .restricted_ptr_type,
46794683 .array_type,
46804684 .vector_type,
46814685 .opt_type,
......@@ -6719,6 +6723,22 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
67196723 return cg.finishAir(inst, result, &.{ty_op.operand});
67206724}
67216725
6726fn airUnwrapRestricted(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6727 const zcu = cg.pt.zcu;
6728 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6729 const operand = try cg.resolveInst(ty_op.operand);
6730 const unrestricted_ty = ty_op.ty.toType();
6731 const restricted_ty = cg.typeOf(ty_op.operand);
6732 const result = result: switch (restricted_ty.restrictedRepr(zcu)) {
6733 .double_pointer => {
6734 _ = safety; // TODO
6735 break :result try cg.load(operand, unrestricted_ty, 0);
6736 },
6737 .single_pointer => cg.reuseOperand(ty_op.operand, operand),
6738 };
6739 return cg.finishAir(inst, result, &.{ty_op.operand});
6740}
6741
67226742fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
67236743 const pt = cg.pt;
67246744 const zcu = pt.zcu;
src/codegen/x86_64/CodeGen.zig+153-13
......@@ -103829,6 +103829,121 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
103829103829 try eu.write(&ops[0], .{ .disp = eu_err_off }, cg);
103830103830 try eu.finish(inst, &.{ty_op.operand}, &ops, cg);
103831103831 },
103832 .unwrap_restricted, .unwrap_restricted_safe => |air_tag| {
103833 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
103834 const unrestricted_ty = ty_op.ty.toType();
103835 const restricted_ty = cg.typeOf(ty_op.operand);
103836 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
103837 const res = res: switch (restricted_ty.restrictedRepr(zcu)) {
103838 .double_pointer => {
103839 switch (air_tag) {
103840 else => unreachable,
103841 .unwrap_restricted => {},
103842 .unwrap_restricted_safe => cg.select(&.{}, &.{}, &ops, &.{ .{
103843 .required_features = .{ .avx, null, null, null },
103844 .patterns = &.{
103845 .{ .src = .{ .mem, .none, .none } },
103846 .{ .src = .{ .to_gpr, .none, .none } },
103847 },
103848 .call_frame = .{ .alignment = .@"32" },
103849 .extra_temps = .{
103850 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103851 .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .const_data, .ref = .src0 } } },
103852 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103853 .{ .type = .usize, .kind = .{ .panic_func = .corrupt_restricted_pointer } },
103854 .unused,
103855 .unused,
103856 .unused,
103857 .unused,
103858 .unused,
103859 .unused,
103860 .unused,
103861 },
103862 .clobbers = .{ .eflags = true },
103863 .each = .{ .once = &.{
103864 .{ ._, ._, .lea, .tmp0p, .leaa(.tmp1, .add_ptr_size), ._, ._ },
103865 .{ ._, ._, .mov, .tmp2p, .src0p, ._, ._ },
103866 .{ ._, ._, .sub, .tmp2p, .tmp0p, ._, ._ },
103867 .{ ._, ._r, .ro, .tmp2p, .sa(.none, .add_log2_ptr_size), ._, ._ },
103868 .{ ._, ._, .cmp, .tmp2p, .leaa(.tmp0p, .sub_ptr_size), ._, ._ },
103869 .{ ._, ._b, .j, .@"0f", ._, ._, ._ },
103870 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
103871 } },
103872 }, .{
103873 .required_features = .{ .sse, null, null, null },
103874 .patterns = &.{
103875 .{ .src = .{ .mem, .none, .none } },
103876 .{ .src = .{ .to_gpr, .none, .none } },
103877 },
103878 .call_frame = .{ .alignment = .@"16" },
103879 .extra_temps = .{
103880 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103881 .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .const_data, .ref = .src0 } } },
103882 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103883 .{ .type = .usize, .kind = .{ .panic_func = .corrupt_restricted_pointer } },
103884 .unused,
103885 .unused,
103886 .unused,
103887 .unused,
103888 .unused,
103889 .unused,
103890 .unused,
103891 },
103892 .clobbers = .{ .eflags = true },
103893 .each = .{ .once = &.{
103894 .{ ._, ._, .lea, .tmp0p, .leaa(.tmp1, .add_ptr_size), ._, ._ },
103895 .{ ._, ._, .mov, .tmp2p, .src0p, ._, ._ },
103896 .{ ._, ._, .sub, .tmp2p, .tmp0p, ._, ._ },
103897 .{ ._, ._r, .ro, .tmp2p, .sa(.none, .add_log2_ptr_size), ._, ._ },
103898 .{ ._, ._, .cmp, .tmp2p, .leaa(.tmp0p, .sub_ptr_size), ._, ._ },
103899 .{ ._, ._b, .j, .@"0f", ._, ._, ._ },
103900 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
103901 } },
103902 }, .{
103903 .patterns = &.{
103904 .{ .src = .{ .mem, .none, .none } },
103905 .{ .src = .{ .to_gpr, .none, .none } },
103906 },
103907 .call_frame = .{ .alignment = .@"8" },
103908 .extra_temps = .{
103909 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103910 .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .const_data, .ref = .src0 } } },
103911 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
103912 .{ .type = .usize, .kind = .{ .panic_func = .corrupt_restricted_pointer } },
103913 .unused,
103914 .unused,
103915 .unused,
103916 .unused,
103917 .unused,
103918 .unused,
103919 .unused,
103920 },
103921 .clobbers = .{ .eflags = true },
103922 .each = .{ .once = &.{
103923 .{ ._, ._, .lea, .tmp0p, .leaa(.tmp1, .add_ptr_size), ._, ._ },
103924 .{ ._, ._, .mov, .tmp2p, .src0p, ._, ._ },
103925 .{ ._, ._, .sub, .tmp2p, .tmp0p, ._, ._ },
103926 .{ ._, ._r, .ro, .tmp2p, .sa(.none, .add_log2_ptr_size), ._, ._ },
103927 .{ ._, ._, .cmp, .tmp2p, .leaa(.tmp0p, .sub_ptr_size), ._, ._ },
103928 .{ ._, ._b, .j, .@"0f", ._, ._, ._ },
103929 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
103930 } },
103931 } }) catch |err| switch (err) {
103932 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
103933 @tagName(air_tag),
103934 unrestricted_ty.fmt(pt),
103935 restricted_ty.fmt(pt),
103936 ops[0].tracking(cg),
103937 }),
103938 else => |e| return e,
103939 },
103940 }
103941 break :res try ops[0].load(unrestricted_ty, .{}, cg);
103942 },
103943 .single_pointer => ops[0],
103944 };
103945 try res.finish(inst, &.{ty_op.operand}, &ops, cg);
103946 },
103832103947 .struct_field_ptr => {
103833103948 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
103834103949 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -176216,20 +176331,22 @@ fn genCall(self: *CodeGen, info: union(enum) {
176216176331 // Due to incremental compilation, how function calls are generated depends
176217176332 // on linking.
176218176333 switch (info) {
176219 .air => |callee| if (callee.toInterned()) |func_ip_index| {
176220 const func_key = ip.indexToKey(func_ip_index);
176221 switch (switch (func_key) {
176222 else => func_key,
176223 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
176224 .nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),
176225 else => func_key,
176226 } else func_key,
176334 .air => |callee| if (callee.toInterned()) |func_ip_index| try self.asmImmediate(
176335 .{ ._, .call },
176336 switch (switch (ip.indexToKey(func_ip_index)) {
176337 else => |func_key| func_key,
176338 .ptr => |ptr| switch (ptr.byte_offset) {
176339 0 => switch (ptr.base_addr) {
176340 .nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),
176341 else => unreachable,
176342 },
176343 else => unreachable,
176344 },
176227176345 }) {
176228176346 else => unreachable,
176229 .func => |func| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = func.owner_nav } }),
176230 .@"extern" => |@"extern"| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = @"extern".owner_nav } }),
176231 }
176232 } else {
176347 inline .func, .@"extern" => |func| .{ .nav = .{ .index = func.owner_nav } },
176348 },
176349 ) else {
176233176350 assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer);
176234176351 const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);
176235176352 try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{});
......@@ -188525,6 +188642,7 @@ const Select = struct {
188525188642 splat_float_mem: struct { ref: Select.Operand.Ref, inside: enum { zero } = .zero, outside: f16 },
188526188643 frame: FrameIndex,
188527188644 lazy_sym: struct { kind: link.File.LazySymbol.Kind, ref: Select.Operand.Ref = .none },
188645 panic_func: Zcu.SimplePanicId,
188528188646 extern_func: [*:0]const u8,
188529188647
188530188648 const ConstSpec = struct {
......@@ -188986,7 +189104,25 @@ const Select = struct {
188986189104 },
188987189105 } }), true };
188988189106 },
188989 .extern_func => |extern_func_spec| .{ try cg.tempInit(spec.type, .{ .lea_extern_func = try cg.addString(std.mem.span(extern_func_spec)) }), true },
189107 .panic_func => |panic_id| .{ try cg.tempInit(
189108 spec.type,
189109 switch (switch (pt.zcu.intern_pool.indexToKey(pt.zcu.builtin_decl_values.get(panic_id.toBuiltin()))) {
189110 else => |func_key| func_key,
189111 .ptr => |ptr| switch (ptr.byte_offset) {
189112 0 => switch (ptr.base_addr) {
189113 .nav => |nav| pt.zcu.intern_pool.indexToKey(pt.zcu.navValue(nav).toIntern()),
189114 else => unreachable,
189115 },
189116 else => unreachable,
189117 },
189118 }) {
189119 else => unreachable,
189120 inline .func, .@"extern" => |func| .{ .lea_nav = func.owner_nav },
189121 },
189122 ), true },
189123 .extern_func => |extern_func_spec| .{ try cg.tempInit(spec.type, .{
189124 .lea_extern_func = try cg.addString(std.mem.span(extern_func_spec)),
189125 }), true },
188990189126 };
188991189127 }
188992189128
......@@ -189036,6 +189172,7 @@ const Select = struct {
189036189172 lhs: enum(u6) {
189037189173 none,
189038189174 ptr_size,
189175 log2_ptr_size,
189039189176 ptr_bit_size,
189040189177 size,
189041189178 src0_size,
......@@ -189072,7 +189209,9 @@ const Select = struct {
189072189209 rhs: Memory.Scale,
189073189210
189074189211 const none: Adjust = .{ .sign = .pos, .lhs = .none, .op = .mul, .rhs = .@"1" };
189212 const add_ptr_size: Adjust = .{ .sign = .pos, .lhs = .ptr_size, .op = .mul, .rhs = .@"1" };
189075189213 const sub_ptr_size: Adjust = .{ .sign = .neg, .lhs = .ptr_size, .op = .mul, .rhs = .@"1" };
189214 const add_log2_ptr_size: Adjust = .{ .sign = .pos, .lhs = .log2_ptr_size, .op = .mul, .rhs = .@"1" };
189076189215 const add_ptr_bit_size: Adjust = .{ .sign = .pos, .lhs = .ptr_bit_size, .op = .mul, .rhs = .@"1" };
189077189216 const add_size: Adjust = .{ .sign = .pos, .lhs = .size, .op = .mul, .rhs = .@"1" };
189078189217 const add_size_div_4: Adjust = .{ .sign = .pos, .lhs = .size, .op = .div, .rhs = .@"4" };
......@@ -190013,6 +190152,7 @@ const Select = struct {
190013190152 const lhs: SignedImm = lhs: switch (op.flags.adjust.lhs) {
190014190153 .none => 0,
190015190154 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),
190155 .log2_ptr_size => std.math.log2(@divExact(s.cg.target.ptrBitWidth(), 8)),
190016190156 .ptr_bit_size => s.cg.target.ptrBitWidth(),
190017190157 .size => @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu)),
190018190158 .src0_size => @intCast(Select.Operand.Ref.src0.typeOf(s).abiSize(s.cg.pt.zcu)),
src/link/Dwarf.zig+9-1
......@@ -3060,6 +3060,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
30603060 } = switch (ip.indexToKey(nav_val.toIntern())) {
30613061 .int_type,
30623062 .ptr_type,
3063 .restricted_ptr_type,
30633064 .array_type,
30643065 .vector_type,
30653066 .opt_type,
......@@ -3566,7 +3567,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
35663567
35673568 const diw = &wip_nav.debug_info.writer;
35683569 var big_int_space: Value.BigIntSpace = undefined;
3569 switch (value_ip_key) {
3570 key: switch (value_ip_key) {
35703571 .func => unreachable, // handled above
35713572 .@"extern" => unreachable, // handled above
35723573
......@@ -3629,6 +3630,13 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
36293630 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
36303631 },
36313632 },
3633 .restricted_ptr_type => |restricted_ptr_type| switch (Type.restrictedReprByZirIndex(restricted_ptr_type.zir_index, zcu)) {
3634 .double_pointer => continue :key .{ .ptr_type = .{
3635 .child = restricted_ptr_type.unrestricted_ptr_type,
3636 .flags = .{ .is_const = true },
3637 } },
3638 .single_pointer => continue :key .{ .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type },
3639 },
36323640 .array_type => |array_type| {
36333641 const array_child_type: Type = .fromInterned(array_type.child);
36343642 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
src/print_value.zig+1
......@@ -49,6 +49,7 @@ pub fn print(
4949 switch (ip.indexToKey(val.toIntern())) {
5050 .int_type,
5151 .ptr_type,
52 .restricted_ptr_type,
5253 .array_type,
5354 .vector_type,
5455 .opt_type,
src/print_zir.zig+8
......@@ -622,6 +622,14 @@ const Writer = struct {
622622 try stream.writeAll(")) ");
623623 try self.writeSrcNode(stream, extra.node);
624624 },
625 .reify_restricted => {
626 const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
627 const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
628 try stream.print("{t}, ", .{name_strat});
629 try self.writeInstRef(stream, extra.operand);
630 try stream.writeAll(")) ");
631 try self.writeSrcNode(stream, extra.node);
632 },
625633 .reify_fn => {
626634 const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
627635 try self.writeInstRef(stream, extra.param_types);