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...@@ -5769,6 +5769,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5769 <p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>5769 <p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>
5770 {#header_close#}5770 {#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
5772 {#header_open|@Fn#}5779 {#header_open|@Fn#}
5773 <pre>{#syntax#}@Fn(5780 <pre>{#syntax#}@Fn(
5774 comptime param_types: []const type,5781 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 {...@@ -201,6 +201,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
201 @branchHint(.cold);201 @branchHint(.cold);
202 call("'noreturn' function returned", @returnAddress());202 call("'noreturn' function returned", @returnAddress());
203 }203 }
204 pub fn corruptRestrictedPointer() noreturn {
205 @branchHint(.cold);
206 call("corrupt restricted pointer value", @returnAddress());
207 }
204 };208 };
205}209}
206210
lib/std/debug/no_panic.zig+5
...@@ -134,3 +134,8 @@ pub fn noreturnReturned() noreturn {...@@ -134,3 +134,8 @@ pub fn noreturnReturned() noreturn {
134 @branchHint(.cold);134 @branchHint(.cold);
135 @trap();135 @trap();
136}136}
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 {...@@ -126,3 +126,7 @@ pub fn memcpyAlias() noreturn {
126pub fn noreturnReturned() noreturn {126pub fn noreturnReturned() noreturn {
127 call("'noreturn' function returned", null);127 call("'noreturn' function returned", null);
128}128}
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(...@@ -1208,7 +1208,7 @@ fn nameStratExpr(
1208 const builtin_name = tree.tokenSlice(builtin_token);1208 const builtin_name = tree.tokenSlice(builtin_token);
1209 const info = BuiltinFn.list.get(builtin_name) orelse return null;1209 const info = BuiltinFn.list.get(builtin_name) orelse return null;
1210 switch (info.tag) {1210 switch (info.tag) {
1211 .Enum, .Struct, .Union => {1211 .Restricted, .Enum, .Struct, .Union => {
1212 var buf: [2]Ast.Node.Index = undefined;1212 var buf: [2]Ast.Node.Index = undefined;
1213 const params = tree.builtinCallParams(&buf, node).?;1213 const params = tree.builtinCallParams(&buf, node).?;
1214 return try builtinCall(gz, scope, ri, node, params, false, name_strat);1214 return try builtinCall(gz, scope, ri, node, params, false, name_strat);
...@@ -9320,6 +9320,15 @@ fn builtinCall(...@@ -9320,6 +9320,15 @@ fn builtinCall(
9320 });9320 });
9321 return rvalue(gz, ri, result, node);9321 return rvalue(gz, ri, result, node);
9322 },9322 },
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 },
9323 .Fn => {9332 .Fn => {
9324 const fn_attrs_ty = try gz.addBuiltinValue(node, .fn_attributes);9333 const fn_attrs_ty = try gz.addBuiltinValue(node, .fn_attributes);
9325 const param_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .fn_param_types);9334 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....@@ -903,6 +903,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
903 .error_name,903 .error_name,
904 .set_runtime_safety,904 .set_runtime_safety,
905 .Tuple,905 .Tuple,
906 .Restricted,
906 .wasm_memory_size,907 .wasm_memory_size,
907 .splat,908 .splat,
908 .set_float_mode,909 .set_float_mode,
lib/std/zig/BuiltinFn.zig+8
...@@ -110,6 +110,7 @@ pub const Tag = enum {...@@ -110,6 +110,7 @@ pub const Tag = enum {
110 Int,110 Int,
111 Tuple,111 Tuple,
112 Pointer,112 Pointer,
113 Restricted,
113 Fn,114 Fn,
114 Struct,115 Struct,
115 Union,116 Union,
...@@ -943,6 +944,13 @@ pub const list = list: {...@@ -943,6 +944,13 @@ pub const list = list: {
943 .param_count = 4,944 .param_count = 4,
944 },945 },
945 },946 },
947 .{
948 "@Restricted",
949 .{
950 .tag = .Restricted,
951 .param_count = 1,
952 },
953 },
946 .{954 .{
947 "@Fn",955 "@Fn",
948 .{956 .{
lib/std/zig/Zir.zig+9-3
...@@ -2062,6 +2062,10 @@ pub const Inst = struct {...@@ -2062,6 +2062,10 @@ pub const Inst = struct {
2062 /// Implements builtin `@Pointer`.2062 /// Implements builtin `@Pointer`.
2063 /// `operand` is payload index to `ReifyPointer`.2063 /// `operand` is payload index to `ReifyPointer`.
2064 reify_pointer,2064 reify_pointer,
2065 /// Implements builtin `@Restricted`.
2066 /// `operand` is payload index to `UnNode`.
2067 /// `small` contains `NameStrategy`.
2068 reify_restricted,
2065 /// Implements builtin `@Fn`.2069 /// Implements builtin `@Fn`.
2066 /// `operand` is payload index to `ReifyFn`.2070 /// `operand` is payload index to `ReifyFn`.
2067 reify_fn,2071 reify_fn,
...@@ -4431,15 +4435,16 @@ fn findTrackableInner(...@@ -4431,15 +4435,16 @@ fn findTrackableInner(
4431 },4435 },
44324436
4433 // Reifications need tracking.4437 // Reifications need tracking.
4434 .reify_enum,4438 .reify_restricted,
4435 .reify_struct,4439 .reify_struct,
4436 .reify_union,4440 .reify_union,
4441 .reify_enum,
4437 => return contents.other.append(gpa, inst),4442 => return contents.other.append(gpa, inst),
44384443
4439 // Type declarations need tracking.4444 // Type declarations need tracking.
4440 .struct_decl,4445 .struct_decl,
4441 .union_decl,
4442 .enum_decl,4446 .enum_decl,
4447 .union_decl,
4443 .opaque_decl,4448 .opaque_decl,
4444 => return contents.type_decls.append(gpa, inst),4449 => return contents.type_decls.append(gpa, inst),
4445 }4450 }
...@@ -5232,9 +5237,10 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {...@@ -5232,9 +5237,10 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
5232 .union_decl,5237 .union_decl,
5233 .enum_decl,5238 .enum_decl,
5234 .opaque_decl,5239 .opaque_decl,
5235 .reify_enum,5240 .reify_restricted,
5236 .reify_struct,5241 .reify_struct,
5237 .reify_union,5242 .reify_union,
5243 .reify_enum,
5238 => {}, // tracked in order, as the owner instructions of explicit container types5244 => {}, // tracked in order, as the owner instructions of explicit container types
5239 else => unreachable, // assertion failure; not trackable5245 else => unreachable, // assertion failure; not trackable
5240 },5246 },
src/Air.zig+14
...@@ -633,6 +633,16 @@ pub const Inst = struct {...@@ -633,6 +633,16 @@ pub const Inst = struct {
633 /// wrap from E to E!T633 /// wrap from E to E!T
634 /// Uses the `ty_op` field.634 /// Uses the `ty_op` field.
635 wrap_errunion_err,635 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,
636 /// Given a pointer to a struct or union and a field index, returns a pointer to the field.646 /// Given a pointer to a struct or union and a field index, returns a pointer to the field.
637 /// Uses the `ty_pl` field, payload is `StructField`.647 /// Uses the `ty_pl` field, payload is `StructField`.
638 /// TODO rename to `agg_field_ptr`.648 /// TODO rename to `agg_field_ptr`.
...@@ -1681,6 +1691,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1681,6 +1691,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1681 .unwrap_errunion_err_ptr,1691 .unwrap_errunion_err_ptr,
1682 .wrap_errunion_payload,1692 .wrap_errunion_payload,
1683 .wrap_errunion_err,1693 .wrap_errunion_err,
1694 .unwrap_restricted,
1695 .unwrap_restricted_safe,
1684 .slice_ptr,1696 .slice_ptr,
1685 .ptr_slice_len_ptr,1697 .ptr_slice_len_ptr,
1686 .ptr_slice_ptr_ptr,1698 .ptr_slice_ptr_ptr,
...@@ -1886,6 +1898,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1886,6 +1898,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1886 .unreach,1898 .unreach,
1887 .optional_payload_ptr_set,1899 .optional_payload_ptr_set,
1888 .errunion_payload_ptr_set,1900 .errunion_payload_ptr_set,
1901 .unwrap_restricted_safe,
1889 .set_union_tag,1902 .set_union_tag,
1890 .memset,1903 .memset,
1891 .memset_safe,1904 .memset_safe,
...@@ -2014,6 +2027,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -2014,6 +2027,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
2014 .unwrap_errunion_payload_ptr,2027 .unwrap_errunion_payload_ptr,
2015 .wrap_errunion_payload,2028 .wrap_errunion_payload,
2016 .wrap_errunion_err,2029 .wrap_errunion_err,
2030 .unwrap_restricted,
2017 .struct_field_ptr,2031 .struct_field_ptr,
2018 .struct_field_ptr_index_0,2032 .struct_field_ptr_index_0,
2019 .struct_field_ptr_index_1,2033 .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 {...@@ -741,6 +741,8 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
741 .errunion_payload_ptr_set,741 .errunion_payload_ptr_set,
742 .wrap_errunion_payload,742 .wrap_errunion_payload,
743 .wrap_errunion_err,743 .wrap_errunion_err,
744 .unwrap_restricted,
745 .unwrap_restricted_safe,
744 .struct_field_ptr,746 .struct_field_ptr,
745 .struct_field_ptr_index_0,747 .struct_field_ptr_index_0,
746 .struct_field_ptr_index_1,748 .struct_field_ptr_index_1,
src/Air/Liveness.zig+2
...@@ -506,6 +506,8 @@ fn analyzeInst(...@@ -506,6 +506,8 @@ fn analyzeInst(
506 .unwrap_errunion_err_ptr,506 .unwrap_errunion_err_ptr,
507 .wrap_errunion_payload,507 .wrap_errunion_payload,
508 .wrap_errunion_err,508 .wrap_errunion_err,
509 .unwrap_restricted,
510 .unwrap_restricted_safe,
509 .slice_ptr,511 .slice_ptr,
510 .slice_len,512 .slice_len,
511 .ptr_slice_len_ptr,513 .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 {...@@ -96,6 +96,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
96 .unwrap_errunion_err_ptr,96 .unwrap_errunion_err_ptr,
97 .wrap_errunion_payload,97 .wrap_errunion_payload,
98 .wrap_errunion_err,98 .wrap_errunion_err,
99 .unwrap_restricted,
100 .unwrap_restricted_safe,
99 .slice_ptr,101 .slice_ptr,
100 .slice_len,102 .slice_len,
101 .ptr_slice_len_ptr,103 .ptr_slice_len_ptr,
src/Air/print.zig+2
...@@ -250,6 +250,8 @@ const Writer = struct {...@@ -250,6 +250,8 @@ const Writer = struct {
250 .unwrap_errunion_err_ptr,250 .unwrap_errunion_err_ptr,
251 .wrap_errunion_payload,251 .wrap_errunion_payload,
252 .wrap_errunion_err,252 .wrap_errunion_err,
253 .unwrap_restricted,
254 .unwrap_restricted_safe,
253 .slice_ptr,255 .slice_ptr,
254 .slice_len,256 .slice_len,
255 .ptr_slice_len_ptr,257 .ptr_slice_len_ptr,
src/InternPool.zig+176-54
...@@ -1969,6 +1969,7 @@ pub const CaptureValue = packed struct(u32) {...@@ -1969,6 +1969,7 @@ pub const CaptureValue = packed struct(u32) {
1969pub const Key = union(enum) {1969pub const Key = union(enum) {
1970 int_type: IntType,1970 int_type: IntType,
1971 ptr_type: PtrType,1971 ptr_type: PtrType,
1972 restricted_ptr_type: RestrictedPtrType,
1972 array_type: ArrayType,1973 array_type: ArrayType,
1973 vector_type: VectorType,1974 vector_type: VectorType,
1974 opt_type: Index,1975 opt_type: Index,
...@@ -2094,6 +2095,14 @@ pub const Key = union(enum) {...@@ -2094,6 +2095,14 @@ pub const Key = union(enum) {
2094 pub const AddressSpace = std.builtin.AddressSpace;2095 pub const AddressSpace = std.builtin.AddressSpace;
2095 };2096 };
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
2097 /// Extern so that hashing can be done via memory reinterpreting.2106 /// Extern so that hashing can be done via memory reinterpreting.
2098 pub const ArrayType = extern struct {2107 pub const ArrayType = extern struct {
2099 len: u64,2108 len: u64,
...@@ -2590,6 +2599,7 @@ pub const Key = union(enum) {...@@ -2590,6 +2599,7 @@ pub const Key = union(enum) {
2590 return switch (key) {2599 return switch (key) {
2591 // TODO: assert no padding in these types2600 // TODO: assert no padding in these types
2592 inline .ptr_type,2601 inline .ptr_type,
2602 .restricted_ptr_type,
2593 .array_type,2603 .array_type,
2594 .vector_type,2604 .vector_type,
2595 .opt_type,2605 .opt_type,
...@@ -2606,11 +2616,11 @@ pub const Key = union(enum) {...@@ -2606,11 +2616,11 @@ pub const Key = union(enum) {
2606 .un,2616 .un,
2607 => |x| Hash.hash(seed, asBytes(&x)),2617 => |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
2611 .error_union => |x| switch (x.val) {2621 .error_union => |x| switch (x.val) {
2612 .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),2622 .err_name => |y| Hash.hash(seed | @as(u64, 0 << 63), asBytes(&x.ty) ++ asBytes(&y)),
2613 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),2623 .payload => |y| Hash.hash(seed | @as(u64, 1 << 63), asBytes(&x.ty) ++ asBytes(&y)),
2614 },2624 },
26152625
2616 .opaque_type,2626 .opaque_type,
...@@ -2631,10 +2641,7 @@ pub const Key = union(enum) {...@@ -2631,10 +2641,7 @@ pub const Key = union(enum) {
2631 std.hash.autoHash(&hasher, cv);2641 std.hash.autoHash(&hasher, cv);
2632 }2642 }
2633 },2643 },
2634 .reified => |reified| {2644 .reified => |reified| std.hash.autoHash(&hasher, reified),
2635 std.hash.autoHash(&hasher, reified.zir_index);
2636 std.hash.autoHash(&hasher, reified.type_hash);
2637 },
2638 .generated_union_tag => |union_type| {2645 .generated_union_tag => |union_type| {
2639 std.hash.autoHash(&hasher, union_type);2646 std.hash.autoHash(&hasher, union_type);
2640 },2647 },
...@@ -2672,7 +2679,7 @@ pub const Key = union(enum) {...@@ -2672,7 +2679,7 @@ pub const Key = union(enum) {
2672 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.2679 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
2673 // This is sound due to pointer provenance rules.2680 // This is sound due to pointer provenance rules.
2674 const addr_tag: Key.Ptr.BaseAddr.Tag = ptr.base_addr;2681 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);
2676 const big_offset: i128 = ptr.byte_offset;2683 const big_offset: i128 = ptr.byte_offset;
2677 const common = asBytes(&ptr.ty) ++ asBytes(&big_offset);2684 const common = asBytes(&ptr.ty) ++ asBytes(&big_offset);
2678 return switch (ptr.base_addr) {2685 return switch (ptr.base_addr) {
...@@ -3020,6 +3027,8 @@ pub const Key = union(enum) {...@@ -3020,6 +3027,8 @@ pub const Key = union(enum) {
3020 }3027 }
3021 },3028 },
30223029
3030 .restricted_ptr_type => |a_r| return std.meta.eql(a_r, b.restricted_ptr_type),
3031
3023 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {3032 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {
3024 const b_info = @field(b, @tagName(a_tag_ct));3033 const b_info = @field(b, @tagName(a_tag_ct));
3025 if (std.meta.activeTag(a_info) != b_info) return false;3034 if (std.meta.activeTag(a_info) != b_info) return false;
...@@ -3037,11 +3046,7 @@ pub const Key = union(enum) {...@@ -3037,11 +3046,7 @@ pub const Key = union(enum) {
3037 };3046 };
3038 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));3047 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
3039 },3048 },
3040 .reified => |a_r| {3049 .reified => |a_r| return std.meta.eql(a_r, b_info.reified),
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 },
3045 .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag,3050 .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag,
3046 }3051 }
3047 },3052 },
...@@ -3125,6 +3130,7 @@ pub const Key = union(enum) {...@@ -3125,6 +3130,7 @@ pub const Key = union(enum) {
3125 return switch (key) {3130 return switch (key) {
3126 .int_type,3131 .int_type,
3127 .ptr_type,3132 .ptr_type,
3133 .restricted_ptr_type,
3128 .array_type,3134 .array_type,
3129 .vector_type,3135 .vector_type,
3130 .opt_type,3136 .opt_type,
...@@ -3172,6 +3178,8 @@ pub const Key = union(enum) {...@@ -3172,6 +3178,8 @@ pub const Key = union(enum) {
3172 }3178 }
3173};3179};
31743180
3181pub const LoadedRestrictedType = Tag.TypeRestricted;
3182
3175pub const LoadedStructType = struct {3183pub const LoadedStructType = struct {
3176 /// Index of the `struct_decl` or `reify` ZIR instruction.3184 /// Index of the `struct_decl` or `reify` ZIR instruction.
3177 zir_index: TrackedInst.Index,3185 zir_index: TrackedInst.Index,
...@@ -3499,6 +3507,12 @@ pub const LoadedOpaqueType = struct {...@@ -3499,6 +3507,12 @@ pub const LoadedOpaqueType = struct {
3499 namespace: NamespaceIndex,3507 namespace: NamespaceIndex,
3500};3508};
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
3502pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {3516pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3503 const unwrapped_index = index.unwrap(ip);3517 const unwrapped_index = index.unwrap(ip);
3504 const extra_list = unwrapped_index.getExtra(ip);3518 const extra_list = unwrapped_index.getExtra(ip);
...@@ -4173,6 +4187,7 @@ pub const Index = enum(u32) {...@@ -4173,6 +4187,7 @@ pub const Index = enum(u32) {
4173 type_array_small: struct { data: *Vector },4187 type_array_small: struct { data: *Vector },
4174 type_vector: struct { data: *Vector },4188 type_vector: struct { data: *Vector },
4175 type_pointer: struct { data: *Tag.TypePointer },4189 type_pointer: struct { data: *Tag.TypePointer },
4190 type_restricted: struct { data: *Tag.TypeRestricted },
4176 type_slice: DataIsIndex,4191 type_slice: DataIsIndex,
4177 type_optional: DataIsIndex,4192 type_optional: DataIsIndex,
4178 type_anyframe: DataIsIndex,4193 type_anyframe: DataIsIndex,
...@@ -4771,6 +4786,9 @@ pub const Tag = enum(u8) {...@@ -4771,6 +4786,9 @@ pub const Tag = enum(u8) {
4771 /// A slice type.4786 /// A slice type.
4772 /// data is Index of underlying pointer type.4787 /// data is Index of underlying pointer type.
4773 type_slice,4788 type_slice,
4789 /// A restricted pointer type.
4790 /// data is payload to `TypeRestricted`.
4791 type_restricted,
4774 /// An optional type.4792 /// An optional type.
4775 /// data is the child type.4793 /// data is the child type.
4776 type_optional,4794 type_optional,
...@@ -5024,13 +5042,6 @@ pub const Tag = enum(u8) {...@@ -5024,13 +5042,6 @@ pub const Tag = enum(u8) {
5024 /// data is extra index to `MemoizedCall`5042 /// data is extra index to `MemoizedCall`
5025 memoized_call,5043 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
5034 const struct_packed_encoding = .{5045 const struct_packed_encoding = .{
5035 .summary = .@"{.payload.name%summary#\"}",5046 .summary = .@"{.payload.name%summary#\"}",
5036 .payload = TypeStructPacked,5047 .payload = TypeStructPacked,
...@@ -5116,6 +5127,7 @@ pub const Tag = enum(u8) {...@@ -5116,6 +5127,7 @@ pub const Tag = enum(u8) {
5116 .type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },5127 .type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
5117 .type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },5128 .type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
5118 .type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },5129 .type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
5130 .type_restricted = .{ .summary = .@"@Restricted({.payload.ptr_type%summary})", .payload = TypeRestricted },
5119 .type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },5131 .type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
5120 .type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },5132 .type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
5121 .type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },5133 .type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },
...@@ -5363,6 +5375,25 @@ pub const Tag = enum(u8) {...@@ -5363,6 +5375,25 @@ pub const Tag = enum(u8) {
5363 return @field(encodings, @tagName(tag)).payload;5375 return @field(encodings, @tagName(tag)).payload;
5364 }5376 }
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
5366 pub const Extern = struct {5397 pub const Extern = struct {
5367 // name, is_const, alignment, addrspace come from `owner_nav`.5398 // name, is_const, alignment, addrspace come from `owner_nav`.
5368 ty: Index,5399 ty: Index,
...@@ -6455,6 +6486,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6455,6 +6486,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6455 return .{ .ptr_type = ptr_info };6486 return .{ .ptr_type = ptr_info };
6456 },6487 },
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
6458 .type_optional => .{ .opt_type = @enumFromInt(data) },6497 .type_optional => .{ .opt_type = @enumFromInt(data) },
6459 .type_anyframe => .{ .anyframe_type = @enumFromInt(data) },6498 .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:...@@ -7237,6 +7276,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7237 .data = try addExtra(extra, ptr_type_adjusted),7276 .data = try addExtra(extra, ptr_type_adjusted),
7238 });7277 });
7239 },7278 },
7279 .restricted_ptr_type => unreachable, // instead getReifiedRestrictedType
7240 .array_type => |array_type| {7280 .array_type => |array_type| {
7241 assert(array_type.child != .none);7281 assert(array_type.child != .none);
7242 assert(array_type.sentinel == .none or ip.typeOf(array_type.sentinel) == array_type.child);7282 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:...@@ -7367,7 +7407,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7367 },7407 },
73687408
7369 .ptr => |ptr| {7409 .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 };
7371 assert(ptr_type.flags.size != .slice);7415 assert(ptr_type.flags.size != .slice);
7372 items.appendAssumeCapacity(switch (ptr.base_addr) {7416 items.appendAssumeCapacity(switch (ptr.base_addr) {
7373 .nav => |nav| .{7417 .nav => |nav| .{
...@@ -7959,6 +8003,65 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -7959,6 +8003,65 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7959 return gop.put();8003 return gop.put();
7960}8004}
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
7962pub fn getDeclaredStructType(8065pub fn getDeclaredStructType(
7963 ip: *InternPool,8066 ip: *InternPool,
7964 gpa: Allocator,8067 gpa: Allocator,
...@@ -9925,6 +10028,7 @@ test "basic usage" {...@@ -9925,6 +10028,7 @@ test "basic usage" {
9925pub fn childType(ip: *const InternPool, i: Index) Index {10028pub fn childType(ip: *const InternPool, i: Index) Index {
9926 return switch (ip.indexToKey(i)) {10029 return switch (ip.indexToKey(i)) {
9927 .ptr_type => |ptr_type| ptr_type.child,10030 .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,
9928 .vector_type => |vector_type| vector_type.child,10032 .vector_type => |vector_type| vector_type.child,
9929 .array_type => |array_type| array_type.child,10033 .array_type => |array_type| array_type.child,
9930 .opt_type, .anyframe_type => |child| child,10034 .opt_type, .anyframe_type => |child| child,
...@@ -10007,22 +10111,28 @@ pub fn getCoerced(...@@ -10007,22 +10111,28 @@ pub fn getCoerced(
10007 .val = .none,10111 .val = .none,
10008 } });10112 } });
1000910113
10010 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {10114 new_ty: switch (ip.indexToKey(new_ty)) {
10011 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{10115 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10012 .ty = new_ty,10116 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{
10013 .base_addr = .int,10117 .ty = new_ty,
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),
10020 .base_addr = .int,10118 .base_addr = .int,
10021 .byte_offset = 0,10119 .byte_offset = 0,
10022 } }),10120 } }),
10023 .len = .undef_usize,10121 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
10024 } }),10122 .ty = new_ty,
10025 };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 }
10026 },10136 },
10027 else => {10137 else => {
10028 const unwrapped_val = val.unwrap(ip);10138 const unwrapped_val = val.unwrap(ip);
...@@ -10101,28 +10211,40 @@ pub fn getCoerced(...@@ -10101,28 +10211,40 @@ pub fn getCoerced(
10101 },10211 },
10102 else => {},10212 else => {},
10103 },10213 },
10104 .slice => |slice| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size == .slice)10214 .slice => |slice| new_ty: switch (ip.indexToKey(new_ty)) {
10105 return ip.get(gpa, io, tid, .{ .slice = .{10215 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10106 .ty = new_ty,10216 .one, .many, .c => {},
10107 .ptr = try ip.getCoerced(gpa, io, tid, slice.ptr, ip.slicePtrType(new_ty)),10217 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
10108 .len = slice.len,10218 .ty = new_ty,
10109 } })10219 .ptr = try ip.getCoerced(gpa, io, tid, slice.ptr, ip.slicePtrType(new_ty)),
10110 else if (ip.isIntegerType(new_ty))10220 .len = slice.len,
10111 return ip.getCoerced(gpa, io, tid, slice.ptr, new_ty),10221 } }),
10112 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .slice)10222 },
10113 return ip.get(gpa, io, tid, .{ .ptr = .{10223 .restricted_ptr_type => |restricted_ptr_type| continue :new_ty .{
10114 .ty = new_ty,10224 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
10115 .base_addr = ptr.base_addr,10225 },
10116 .byte_offset = ptr.byte_offset,10226 else => if (ip.isIntegerType(new_ty)) return ip.getCoerced(gpa, io, tid, slice.ptr, new_ty),
10117 } })10227 },
10118 else if (ip.isIntegerType(new_ty))10228 .ptr => |ptr| new_ty: switch (ip.indexToKey(new_ty)) {
10119 switch (ptr.base_addr) {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) {
10120 .int => return ip.get(gpa, io, tid, .{ .int = .{10241 .int => return ip.get(gpa, io, tid, .{ .int = .{
10121 .ty = .usize_type,10242 .ty = .usize_type,
10122 .storage = .{ .u64 = @intCast(ptr.byte_offset) },10243 .storage = .{ .u64 = @intCast(ptr.byte_offset) },
10123 } }),10244 } }),
10124 else => {},10245 else => {},
10125 },10246 },
10247 },
10126 .opt => |opt| switch (ip.indexToKey(new_ty)) {10248 .opt => |opt| switch (ip.indexToKey(new_ty)) {
10127 .ptr_type => |ptr_type| return switch (opt.val) {10249 .ptr_type => |ptr_type| return switch (opt.val) {
10128 .none => switch (ptr_type.flags.size) {10250 .none => switch (ptr_type.flags.size) {
...@@ -10397,10 +10519,6 @@ pub fn isFunctionType(ip: *const InternPool, ty: Index) bool {...@@ -10397,10 +10519,6 @@ pub fn isFunctionType(ip: *const InternPool, ty: Index) bool {
10397 return ip.indexToKey(ty) == .func_type;10519 return ip.indexToKey(ty) == .func_type;
10398}10520}
1039910521
10400pub fn isPointerType(ip: *const InternPool, ty: Index) bool {
10401 return ip.indexToKey(ty) == .ptr_type;
10402}
10403
10404pub fn isOptionalType(ip: *const InternPool, ty: Index) bool {10522pub fn isOptionalType(ip: *const InternPool, ty: Index) bool {
10405 return ip.indexToKey(ty) == .opt_type;10523 return ip.indexToKey(ty) == .opt_type;
10406}10524}
...@@ -10577,6 +10695,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10577,6 +10695,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10577 .type_array_big => @sizeOf(Array),10695 .type_array_big => @sizeOf(Array),
10578 .type_vector => @sizeOf(Vector),10696 .type_vector => @sizeOf(Vector),
10579 .type_pointer => @sizeOf(Tag.TypePointer),10697 .type_pointer => @sizeOf(Tag.TypePointer),
10698 .type_restricted => @sizeOf(Tag.TypeRestricted),
10580 .type_slice => 0,10699 .type_slice => 0,
10581 .type_optional => 0,10700 .type_optional => 0,
10582 .type_anyframe => 0,10701 .type_anyframe => 0,
...@@ -10838,6 +10957,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {...@@ -10838,6 +10957,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
10838 .type_array_big,10957 .type_array_big,
10839 .type_vector,10958 .type_vector,
10840 .type_pointer,10959 .type_pointer,
10960 .type_restricted,
10841 .type_optional,10961 .type_optional,
10842 .type_anyframe,10962 .type_anyframe,
10843 .type_error_union,10963 .type_error_union,
...@@ -11576,6 +11696,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -11576,6 +11696,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
11576 .type_array_small,11696 .type_array_small,
11577 .type_vector,11697 .type_vector,
11578 .type_pointer,11698 .type_pointer,
11699 .type_restricted,
11579 .type_slice,11700 .type_slice,
11580 .type_optional,11701 .type_optional,
11581 .type_anyframe,11702 .type_anyframe,
...@@ -11921,6 +12042,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {...@@ -11921,6 +12042,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1192112042
11922 .type_pointer,12043 .type_pointer,
11923 .type_slice,12044 .type_slice,
12045 .type_restricted,
11924 => .pointer,12046 => .pointer,
1192512047
11926 .type_optional => .optional,12048 .type_optional => .optional,
src/Sema.zig+197-34
...@@ -398,7 +398,7 @@ pub const Block = struct {...@@ -398,7 +398,7 @@ pub const Block = struct {
398 /// The name of the current "context" for naming namespace types.398 /// The name of the current "context" for naming namespace types.
399 /// The interpretation of this depends on the name strategy in ZIR, but the name399 /// The interpretation of this depends on the name strategy in ZIR, but the name
400 /// is always incorporated into the type name somehow.400 /// is always incorporated into the type name somehow.
401 /// See `Sema.setTypeName`.401 /// See `Sema.computeTypeName`.
402 type_name_ctx: InternPool.NullTerminatedString,402 type_name_ctx: InternPool.NullTerminatedString,
403403
404 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.404 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
...@@ -1435,6 +1435,7 @@ fn analyzeBodyInner(...@@ -1435,6 +1435,7 @@ fn analyzeBodyInner(
1435 .reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended),1435 .reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended),
1436 .reify_tuple => try sema.zirReifyTuple( block, extended),1436 .reify_tuple => try sema.zirReifyTuple( block, extended),
1437 .reify_pointer => try sema.zirReifyPointer( block, extended),1437 .reify_pointer => try sema.zirReifyPointer( block, extended),
1438 .reify_restricted => try sema.zirReifyRestricted( block, extended, inst),
1438 .reify_fn => try sema.zirReifyFn( block, extended),1439 .reify_fn => try sema.zirReifyFn( block, extended),
1439 .reify_struct => try sema.zirReifyStruct( block, extended, inst),1440 .reify_struct => try sema.zirReifyStruct( block, extended, inst),
1440 .reify_union => try sema.zirReifyUnion( block, extended, inst),1441 .reify_union => try sema.zirReifyUnion( block, extended, inst),
...@@ -18956,7 +18957,8 @@ fn structInitAnon(...@@ -18956,7 +18957,8 @@ fn structInitAnon(
18956 .existing => |ty| .fromInterned(ty),18957 .existing => |ty| .fromInterned(ty),
18957 .wip => |wip| ty: {18958 .wip => |wip| ty: {
18958 errdefer wip.cancel(ip, pt.tid);18959 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
18961 // Reified structs have field information populated immediately.18963 // Reified structs have field information populated immediately.
18962 @memcpy(wip.field_names.get(ip), names);18964 @memcpy(wip.field_names.get(ip), names);
...@@ -19879,6 +19881,62 @@ fn zirReifyPointer(...@@ -19879,6 +19881,62 @@ fn zirReifyPointer(
19879 }));19881 }));
19880}19882}
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
19882fn zirReifyFn(19940fn zirReifyFn(
19883 sema: *Sema,19941 sema: *Sema,
19884 block: *Block,19942 block: *Block,
...@@ -20194,7 +20252,8 @@ fn zirReifyStruct(...@@ -20194,7 +20252,8 @@ fn zirReifyStruct(
20194 },20252 },
20195 .wip => |wip| {20253 .wip => |wip| {
20196 errdefer wip.cancel(ip, pt.tid);20254 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);
20198 for (0..fields_len) |field_idx| {20257 for (0..fields_len) |field_idx| {
20199 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20258 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20200 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);20259 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
...@@ -20438,7 +20497,8 @@ fn zirReifyUnion(...@@ -20438,7 +20497,8 @@ fn zirReifyUnion(
20438 },20497 },
20439 .wip => |wip| {20498 .wip => |wip| {
20440 errdefer wip.cancel(ip, pt.tid);20499 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
20443 for (0..fields_len) |field_idx| {20503 for (0..fields_len) |field_idx| {
20444 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20504 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
...@@ -20603,8 +20663,8 @@ fn zirReifyEnum(...@@ -20603,8 +20663,8 @@ fn zirReifyEnum(
20603 },20663 },
20604 .wip => |wip| {20664 .wip => |wip| {
20605 errdefer wip.cancel(ip, pt.tid);20665 errdefer wip.cancel(ip, pt.tid);
2060620666 const type_name, const name_nav = try sema.computeTypeName(block, wip.index, name_strategy, "enum", inst);
20607 try sema.setTypeName(block, &wip, name_strategy, "enum", inst);20667 wip.setName(ip, type_name, name_nav);
2060820668
20609 // Populate field names and values. Duplicate checking will be handled by type resolution.20669 // Populate field names and values. Duplicate checking will be handled by type resolution.
20610 for (0..fields_len) |field_index| {20670 for (0..fields_len) |field_index| {
...@@ -27736,6 +27796,22 @@ fn coerceExtra(...@@ -27736,6 +27796,22 @@ fn coerceExtra(
27736 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);27796 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
27737 },27797 },
27738 }27798 }
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 }
27739 },27815 },
27740 .int, .comptime_int => switch (inst_ty.zigTypeTag(zcu)) {27816 .int, .comptime_int => switch (inst_ty.zigTypeTag(zcu)) {
27741 .float, .comptime_float => float: {27817 .float, .comptime_float => float: {
...@@ -28084,6 +28160,7 @@ const InMemoryCoercionResult = union(enum) {...@@ -28084,6 +28160,7 @@ const InMemoryCoercionResult = union(enum) {
28084 ptr_alignment: AlignPair,28160 ptr_alignment: AlignPair,
28085 double_ptr_to_anyopaque: Pair,28161 double_ptr_to_anyopaque: Pair,
28086 slice_to_anyopaque: Pair,28162 slice_to_anyopaque: Pair,
28163 ptr_restricted: Pair,
2808728164
28088 const Pair = struct {28165 const Pair = struct {
28089 actual: Type,28166 actual: Type,
...@@ -28415,6 +28492,15 @@ const InMemoryCoercionResult = union(enum) {...@@ -28415,6 +28492,15 @@ const InMemoryCoercionResult = union(enum) {
28415 try sema.errNote(src, msg, "consider using '.ptr'", .{});28492 try sema.errNote(src, msg, "consider using '.ptr'", .{});
28416 break;28493 break;
28417 },28494 },
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 },
28418 };28504 };
28419 }28505 }
28420};28506};
...@@ -28479,7 +28565,7 @@ pub fn coerceInMemoryAllowed(...@@ -28479,7 +28565,7 @@ pub fn coerceInMemoryAllowed(
28479 (dest_info.signedness == .signed and src_info.signedness == .unsigned and dest_info.bits <= src_info.bits) or28565 (dest_info.signedness == .signed and src_info.signedness == .unsigned and dest_info.bits <= src_info.bits) or
28480 (dest_info.signedness == .unsigned and src_info.signedness == .signed))28566 (dest_info.signedness == .unsigned and src_info.signedness == .signed))
28481 {28567 {
28482 return InMemoryCoercionResult{ .int_not_coercible = .{28568 return .{ .int_not_coercible = .{
28483 .actual_signedness = src_info.signedness,28569 .actual_signedness = src_info.signedness,
28484 .wanted_signedness = dest_info.signedness,28570 .wanted_signedness = dest_info.signedness,
28485 .actual_bits = src_info.bits,28571 .actual_bits = src_info.bits,
...@@ -28913,7 +28999,7 @@ fn coerceInMemoryAllowedPtrs(...@@ -28913,7 +28999,7 @@ fn coerceInMemoryAllowedPtrs(
28913 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or28999 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
28914 src_info.flags.size == .c or dest_info.flags.size == .c;29000 src_info.flags.size == .c or dest_info.flags.size == .c;
28915 if (!ok_ptr_size) {29001 if (!ok_ptr_size) {
28916 return InMemoryCoercionResult{ .ptr_size = .{29002 return .{ .ptr_size = .{
28917 .actual = src_info.flags.size,29003 .actual = src_info.flags.size,
28918 .wanted = dest_info.flags.size,29004 .wanted = dest_info.flags.size,
28919 } };29005 } };
...@@ -29049,13 +29135,19 @@ fn coerceInMemoryAllowedPtrs(...@@ -29049,13 +29135,19 @@ fn coerceInMemoryAllowedPtrs(
29049 break :a dest_child.abiAlignment(zcu);29135 break :a dest_child.abiAlignment(zcu);
29050 } else dest_info.flags.alignment;29136 } else dest_info.flags.alignment;
29051 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {29137 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {
29052 return InMemoryCoercionResult{ .ptr_alignment = .{29138 return .{ .ptr_alignment = .{
29053 .actual = src_align,29139 .actual = src_align,
29054 .wanted = dest_align,29140 .wanted = dest_align,
29055 } };29141 } };
29056 }29142 }
29057 }29143 }
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
29059 return .ok;29151 return .ok;
29060}29152}
2906129153
...@@ -29202,10 +29294,15 @@ fn storePtr2(...@@ -29202,10 +29294,15 @@ fn storePtr2(
2920229294
29203 try sema.requireRuntimeBlock(block, src, runtime_src);29295 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
29205 const store_inst = if (is_ret)29302 const store_inst = if (is_ret)
29206 try block.addBinOp(.store, ptr, operand)29303 try block.addBinOp(.store, unrestricted_ptr, operand)
29207 else29304 else
29208 try block.addBinOp(air_tag, ptr, operand);29305 try block.addBinOp(air_tag, unrestricted_ptr, operand);
2920929306
29210 try sema.checkComptimeKnownStore(block, store_inst, operand_src);29307 try sema.checkComptimeKnownStore(block, store_inst, operand_src);
2921129308
...@@ -30282,7 +30379,12 @@ fn analyzeLoad(...@@ -30282,7 +30379,12 @@ fn analyzeLoad(
30282 break :msg msg;30379 break :msg msg;
30283 });30380 });
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);
30286}30388}
3028730389
30288fn analyzeSlicePtr(30390fn analyzeSlicePtr(
...@@ -31494,6 +31596,19 @@ fn wrapErrorUnionSet(...@@ -31494,6 +31596,19 @@ fn wrapErrorUnionSet(
31494 }31596 }
31495}31597}
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
31497/// Returns the enum tag value for the active tag of a tagged union value.31612/// Returns the enum tag value for the active tag of a tagged union value.
31498///31613///
31499/// Asserts that the type of `un` is a tagged union type.31614/// Asserts that the type of `un` is a tagged union type.
...@@ -34211,13 +34326,59 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C...@@ -34211,13 +34326,59 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C
34211fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Type {34326fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Type {
34212 const pt = sema.pt;34327 const pt = sema.pt;
34213 return switch (decl) {34328 return switch (decl) {
34329 .Signedness,
34330 .AddressSpace,
34331 .CallingConvention,
34332 => unreachable,
34214 // `noinline fn () void`34333 // `noinline fn () void`
34215 .returnError => try pt.funcType(.{34334 .returnError => try pt.funcType(.{
34216 .param_types = &.{},34335 .param_types = &.{},
34217 .return_type = .void_type,34336 .return_type = .void_type,
34218 .is_noinline = true,34337 .is_noinline = true,
34219 }),34338 }),
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,
34221 // `fn ([]const u8, ?usize) noreturn`34382 // `fn ([]const u8, ?usize) noreturn`
34222 .@"panic.call" => try pt.funcType(.{34383 .@"panic.call" => try pt.funcType(.{
34223 .param_types = &.{34384 .param_types = &.{
...@@ -34226,7 +34387,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34226,7 +34387,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34226 },34387 },
34227 .return_type = .noreturn_type,34388 .return_type = .noreturn_type,
34228 }),34389 }),
34229
34230 // `fn (anytype, anytype) noreturn`34390 // `fn (anytype, anytype) noreturn`
34231 .@"panic.sentinelMismatch",34391 .@"panic.sentinelMismatch",
34232 .@"panic.inactiveUnionField",34392 .@"panic.inactiveUnionField",
...@@ -34234,19 +34394,16 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34234,19 +34394,16 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34234 .param_types = &.{ .generic_poison_type, .generic_poison_type },34394 .param_types = &.{ .generic_poison_type, .generic_poison_type },
34235 .return_type = .noreturn_type,34395 .return_type = .noreturn_type,
34236 }),34396 }),
34237
34238 // `fn (anyerror) noreturn`34397 // `fn (anyerror) noreturn`
34239 .@"panic.unwrapError" => try pt.funcType(.{34398 .@"panic.unwrapError" => try pt.funcType(.{
34240 .param_types = &.{.anyerror_type},34399 .param_types = &.{.anyerror_type},
34241 .return_type = .noreturn_type,34400 .return_type = .noreturn_type,
34242 }),34401 }),
34243
34244 // `fn (usize) noreturn`34402 // `fn (usize) noreturn`
34245 .@"panic.sliceCastLenRemainder" => try pt.funcType(.{34403 .@"panic.sliceCastLenRemainder" => try pt.funcType(.{
34246 .param_types = &.{.usize_type},34404 .param_types = &.{.usize_type},
34247 .return_type = .noreturn_type,34405 .return_type = .noreturn_type,
34248 }),34406 }),
34249
34250 // `fn (usize, usize) noreturn`34407 // `fn (usize, usize) noreturn`
34251 .@"panic.outOfBounds",34408 .@"panic.outOfBounds",
34252 .@"panic.startGreaterThanEnd",34409 .@"panic.startGreaterThanEnd",
...@@ -34254,7 +34411,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34254,7 +34411,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34254 .param_types = &.{ .usize_type, .usize_type },34411 .param_types = &.{ .usize_type, .usize_type },
34255 .return_type = .noreturn_type,34412 .return_type = .noreturn_type,
34256 }),34413 }),
34257
34258 // `fn () noreturn`34414 // `fn () noreturn`
34259 .@"panic.reachedUnreachable",34415 .@"panic.reachedUnreachable",
34260 .@"panic.unwrapNull",34416 .@"panic.unwrapNull",
...@@ -34275,23 +34431,28 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34275,23 +34431,28 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34275 .@"panic.copyLenMismatch",34431 .@"panic.copyLenMismatch",
34276 .@"panic.memcpyAlias",34432 .@"panic.memcpyAlias",
34277 .@"panic.noreturnReturned",34433 .@"panic.noreturnReturned",
34434 .@"panic.corruptRestrictedPointer",
34278 => try pt.funcType(.{34435 => try pt.funcType(.{
34279 .param_types = &.{},34436 .param_types = &.{},
34280 .return_type = .noreturn_type,34437 .return_type = .noreturn_type,
34281 }),34438 }),
3428234439
34283 else => unreachable,34440 .VaList => unreachable,
34441
34442 .assembly,
34443 .@"assembly.Clobbers",
34444 => unreachable,
34284 };34445 };
34285}34446}
3428634447
34287pub fn setTypeName(34448pub fn computeTypeName(
34288 sema: *Sema,34449 sema: *Sema,
34289 block: *Block,34450 block: *Block,
34290 wip: *const InternPool.WipContainerType,34451 index: InternPool.Index,
34291 name_strategy: Zir.Inst.NameStrategy,34452 name_strategy: Zir.Inst.NameStrategy,
34292 anon_prefix: []const u8,34453 anon_prefix: []const u8,
34293 inst: Zir.Inst.Index,34454 inst: Zir.Inst.Index,
34294) CompileError!void {34455) CompileError!struct { InternPool.NullTerminatedString, InternPool.Nav.Index.Optional } {
34295 const pt = sema.pt;34456 const pt = sema.pt;
34296 const zcu = pt.zcu;34457 const zcu = pt.zcu;
34297 const comp = zcu.comp;34458 const comp = zcu.comp;
...@@ -34308,16 +34469,16 @@ pub fn setTypeName(...@@ -34308,16 +34469,16 @@ pub fn setTypeName(
34308 // TODO: that would be possible, by detecting line number changes and renaming34469 // TODO: that would be possible, by detecting line number changes and renaming
34309 // types appropriately. However, `@typeName` becomes a problem then. If we remove34470 // types appropriately. However, `@typeName` becomes a problem then. If we remove
34310 // that builtin from the language, we can consider this.34471 // that builtin from the language, we can consider this.
34311 wip.setName(ip, try ip.getOrPutStringFmt(34472 return .{ try ip.getOrPutStringFmt(
34312 gpa,34473 gpa,
34313 io,34474 io,
34314 pt.tid,34475 pt.tid,
34315 "{f}__{s}_{d}",34476 "{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) },
34317 .no_embedded_nulls,34478 .no_embedded_nulls,
34318 ), .none);34479 ), .none };
34319 },34480 },
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() },
34321 .func => {34482 .func => {
34322 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);34483 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
34323 const zir_tags = sema.code.instructions.items(.tag);34484 const zir_tags = sema.code.instructions.items(.tag);
...@@ -34360,8 +34521,7 @@ pub fn setTypeName(...@@ -34360,8 +34521,7 @@ pub fn setTypeName(
34360 };34521 };
3436134522
34362 w.writeByte(')') catch return error.OutOfMemory;34523 w.writeByte(')') catch return error.OutOfMemory;
34363 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);34524 return .{ try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), .none };
34364 wip.setName(ip, name, .none);
34365 },34525 },
34366 .dbg_var => {34526 .dbg_var => {
34367 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.34527 // 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(...@@ -34376,10 +34536,9 @@ pub fn setTypeName(
34376 } else {34536 } else {
34377 continue :strat .anon;34537 continue :strat .anon;
34378 };34538 };
34379 const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{34539 return .{ try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
34380 block.type_name_ctx.fmt(ip), var_name,34540 block.type_name_ctx.fmt(ip), var_name,
34381 }, .no_embedded_nulls);34541 }, .no_embedded_nulls), .none };
34382 wip.setName(ip, name, .none);
34383 },34542 },
34384 }34543 }
34385}34544}
...@@ -34420,7 +34579,8 @@ fn zirStructDecl(...@@ -34420,7 +34579,8 @@ fn zirStructDecl(
34420 .existing => |ty| .fromInterned(ty),34579 .existing => |ty| .fromInterned(ty),
34421 .wip => |wip| ty: {34580 .wip => |wip| ty: {
34422 errdefer wip.cancel(ip, pt.tid);34581 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);
34424 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{34584 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34425 .parent = block.namespace.toOptional(),34585 .parent = block.namespace.toOptional(),
34426 .owner_type = wip.index,34586 .owner_type = wip.index,
...@@ -34493,7 +34653,8 @@ fn zirUnionDecl(...@@ -34493,7 +34653,8 @@ fn zirUnionDecl(
34493 .existing => |ty| .fromInterned(ty),34653 .existing => |ty| .fromInterned(ty),
34494 .wip => |wip| ty: {34654 .wip => |wip| ty: {
34495 errdefer wip.cancel(ip, pt.tid);34655 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);
34497 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{34658 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34498 .parent = block.namespace.toOptional(),34659 .parent = block.namespace.toOptional(),
34499 .owner_type = wip.index,34660 .owner_type = wip.index,
...@@ -34545,7 +34706,8 @@ fn zirEnumDecl(...@@ -34545,7 +34706,8 @@ fn zirEnumDecl(
34545 .existing => |ty| .fromInterned(ty),34706 .existing => |ty| .fromInterned(ty),
34546 .wip => |wip| ty: {34707 .wip => |wip| ty: {
34547 errdefer wip.cancel(ip, pt.tid);34708 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);
34549 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{34711 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34550 .parent = block.namespace.toOptional(),34712 .parent = block.namespace.toOptional(),
34551 .owner_type = wip.index,34713 .owner_type = wip.index,
...@@ -34594,7 +34756,8 @@ fn zirOpaqueDecl(...@@ -34594,7 +34756,8 @@ fn zirOpaqueDecl(
34594 .existing => |ty| .fromInterned(ty),34756 .existing => |ty| .fromInterned(ty),
34595 .wip => |wip| ty: {34757 .wip => |wip| ty: {
34596 errdefer wip.cancel(ip, pt.tid);34758 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);
34598 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{34761 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34599 .parent = block.namespace.toOptional(),34762 .parent = block.namespace.toOptional(),
34600 .owner_type = wip.index,34763 .owner_type = wip.index,
src/Sema/LowerZon.zig+2-1
...@@ -150,7 +150,8 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -150,7 +150,8 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
150 errdefer wip.cancel(ip, pt.tid);150 errdefer wip.cancel(ip, pt.tid);
151 const block = self.block;151 const block = self.block;
152 const zcu = pt.zcu;152 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
155 // Reified structs have field information populated immediately.156 // Reified structs have field information populated immediately.
156 @memcpy(wip.field_values.get(ip), elems);157 @memcpy(wip.field_values.get(ip), elems);
src/Sema/bitcast.zig+1
...@@ -239,6 +239,7 @@ const UnpackValueBits = struct {...@@ -239,6 +239,7 @@ const UnpackValueBits = struct {
239 switch (ip.indexToKey(val.toIntern())) {239 switch (ip.indexToKey(val.toIntern())) {
240 .int_type,240 .int_type,
241 .ptr_type,241 .ptr_type,
242 .restricted_ptr_type,
242 .array_type,243 .array_type,
243 .vector_type,244 .vector_type,
244 .opt_type,245 .opt_type,
src/Sema/type_resolution.zig+1
...@@ -84,6 +84,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons...@@ -84,6 +84,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons
84 switch (ip.indexToKey(ty.toIntern())) {84 switch (ip.indexToKey(ty.toIntern())) {
85 .int_type,85 .int_type,
86 .ptr_type,86 .ptr_type,
87 .restricted_ptr_type,
87 .anyframe_type,88 .anyframe_type,
88 .simple_type,89 .simple_type,
89 .opaque_type,90 .opaque_type,
src/Type.zig+138-70
...@@ -165,6 +165,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class {...@@ -165,6 +165,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class {
165 .error_set_type,165 .error_set_type,
166 .inferred_error_set_type,166 .inferred_error_set_type,
167 .ptr_type,167 .ptr_type,
168 .restricted_ptr_type,
168 .anyframe_type,169 .anyframe_type,
169 => .runtime,170 => .runtime,
170171
...@@ -373,13 +374,28 @@ pub fn arrayInfo(self: Type, zcu: *const Zcu) ArrayInfo {...@@ -373,13 +374,28 @@ pub fn arrayInfo(self: Type, zcu: *const Zcu) ArrayInfo {
373}374}
374375
375pub fn ptrInfo(ty: Type, zcu: *const Zcu) InternPool.Key.PtrType {376pub 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())) {
377 .ptr_type => |p| p,385 .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)) {
379 .ptr_type => |p| p,391 .ptr_type => |p| p,
380 else => unreachable,392 .restricted_ptr_type => |rp| if (opts.allow_restricted)
381 },393 ip.indexToKey(rp.unrestricted_ptr_type).ptr_type
382 else => unreachable,394 else
395 null,
396 else => null, // not a pointer type
397 } else null,
398 else => null, // not a pointer type
383 };399 };
384}400}
385401
...@@ -488,6 +504,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari...@@ -488,6 +504,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
488 try print(Type.fromInterned(info.child), writer, pt, ctx);504 try print(Type.fromInterned(info.child), writer, pt, ctx);
489 return;505 return;
490 },506 },
507 .restricted_ptr_type => {
508 const name = ip.loadRestrictedType(ty.toIntern()).name;
509 try writer.print("{f}", .{name.fmt(ip)});
510 },
491 .array_type => |array_type| {511 .array_type => |array_type| {
492 if (array_type.sentinel == .none) {512 if (array_type.sentinel == .none) {
493 try writer.print("[{d}]", .{array_type.len});513 try writer.print("[{d}]", .{array_type.len});
...@@ -747,6 +767,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {...@@ -747,6 +767,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
747 .vector_type,767 .vector_type,
748 => true,768 => true,
749769
770 .restricted_ptr_type,
750 .error_union_type,771 .error_union_type,
751 .error_set_type,772 .error_set_type,
752 .inferred_error_set_type,773 .inferred_error_set_type,
...@@ -893,22 +914,13 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {...@@ -893,22 +914,13 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
893914
894/// Never returns `none`. Asserts that all necessary type resolution is already done.915/// Never returns `none`. Asserts that all necessary type resolution is already done.
895pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment {916pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment {
896 const ip = &zcu.intern_pool;917 const ptr_key = ptr_ty.ptrInfo(zcu);
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 };
902 if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment;918 if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment;
903 return Type.fromInterned(ptr_key.child).abiAlignment(zcu);919 return Type.fromInterned(ptr_key.child).abiAlignment(zcu);
904}920}
905921
906pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {922pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
907 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {923 return ty.ptrInfo(zcu).flags.address_space;
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 };
912}924}
913925
914/// Never returns `.none`. Asserts that the layout of `ty` is resolved.926/// Never returns `.none`. Asserts that the layout of `ty` is resolved.
...@@ -924,7 +936,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -924,7 +936,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
924 if (int_type.bits == 0) return .@"1";936 if (int_type.bits == 0) return .@"1";
925 return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits));937 return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits));
926 },938 },
927 .ptr_type, .anyframe_type => ptrAbiAlignment(target),939 .ptr_type, .restricted_ptr_type, .anyframe_type => ptrAbiAlignment(target),
928 .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu),940 .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu),
929 .vector_type => |vector_type| {941 .vector_type => |vector_type| {
930 if (vector_type.len == 0) return .@"1";942 if (vector_type.len == 0) return .@"1";
...@@ -1078,7 +1090,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1078,7 +1090,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
1078 .slice => ptrAbiSize(target) * 2,1090 .slice => ptrAbiSize(target) * 2,
1079 .one, .many, .c => ptrAbiSize(target),1091 .one, .many, .c => ptrAbiSize(target),
1080 },1092 },
1081 .anyframe_type => ptrAbiSize(target),1093 .restricted_ptr_type, .anyframe_type => ptrAbiSize(target),
1082 .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu),1094 .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu),
1083 .vector_type => |vec| {1095 .vector_type => |vec| {
1084 const elem_ty: Type = .fromInterned(vec.child);1096 const elem_ty: Type = .fromInterned(vec.child);
...@@ -1231,7 +1243,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1231,7 +1243,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
1231 .slice => target.ptrBitWidth() * 2,1243 .slice => target.ptrBitWidth() * 2,
1232 else => target.ptrBitWidth(),1244 else => target.ptrBitWidth(),
1233 },1245 },
1234 .anyframe_type => target.ptrBitWidth(),1246 .restricted_ptr_type, .anyframe_type => target.ptrBitWidth(),
1235 .array_type => |array_type| {1247 .array_type => |array_type| {
1236 const elem_ty: Type = .fromInterned(array_type.child);1248 const elem_ty: Type = .fromInterned(array_type.child);
1237 const len = array_type.lenIncludingSentinel();1249 const len = array_type.lenIncludingSentinel();
...@@ -1329,13 +1341,31 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1329,13 +1341,31 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
1329 };1341 };
1330}1342}
13311343
1332pub fn isSinglePointer(ty: Type, zcu: *const Zcu) bool {1344/// Returns `null` if `ty` is not a restricted pointer.
1333 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1345pub fn unrestrictedType(ty: Type, zcu: *const Zcu) ?Type {
1334 .ptr_type => |ptr_info| ptr_info.flags.size == .one,1346 const ip = &zcu.intern_pool;
1335 else => false,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,
1336 };1361 };
1337}1362}
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
1339/// Asserts `ty` is a pointer.1369/// Asserts `ty` is a pointer.
1340pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {1370pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {
1341 return ty.ptrSizeOrNull(zcu).?;1371 return ty.ptrSizeOrNull(zcu).?;
...@@ -1343,24 +1373,27 @@ pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {...@@ -1343,24 +1373,27 @@ pub fn ptrSize(ty: Type, zcu: *const Zcu) std.builtin.Type.Pointer.Size {
13431373
1344/// Returns `null` if `ty` is not a pointer.1374/// Returns `null` if `ty` is not a pointer.
1345pub fn ptrSizeOrNull(ty: Type, zcu: *const Zcu) ?std.builtin.Type.Pointer.Size {1375pub fn ptrSizeOrNull(ty: Type, zcu: *const Zcu) ?std.builtin.Type.Pointer.Size {
1346 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1376 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return null;
1347 .ptr_type => |ptr_info| ptr_info.flags.size,1377 return ptr_info.flags.size;
1348 else => null,
1349 };
1350}1378}
13511379
1352pub fn isSlice(ty: Type, zcu: *const Zcu) bool {1380pub fn isSlice(ty: Type, zcu: *const Zcu) bool {
1353 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1381 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1354 .ptr_type => |ptr_type| ptr_type.flags.size == .slice,1382 return ptr_info.flags.size == .slice;
1355 else => false,
1356 };
1357}1383}
13581384
1359pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {1385pub 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())) {
1361 .ptr_type => |ptr_type| ptr_type.flags.size == .slice,1388 .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)) {
1363 .ptr_type => |ptr_type| !ptr_type.flags.is_allowzero and ptr_type.flags.size == .slice,1393 .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 },
1364 else => false,1397 else => false,
1365 },1398 },
1366 else => false,1399 else => false,
...@@ -1372,10 +1405,8 @@ pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {...@@ -1372,10 +1405,8 @@ pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {
1372}1405}
13731406
1374pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {1407pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {
1375 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1408 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1376 .ptr_type => |ptr_type| ptr_type.flags.is_const,1409 return ptr_info.flags.is_const;
1377 else => false,
1378 };
1379}1410}
13801411
1381pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {1412pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {
...@@ -1383,38 +1414,45 @@ pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {...@@ -1383,38 +1414,45 @@ pub fn isVolatilePtr(ty: Type, zcu: *const Zcu) bool {
1383}1414}
13841415
1385pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {1416pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {
1386 return switch (ip.indexToKey(ty.toIntern())) {1417 const ptr_info = ty.ptrInfoOrNull(ip, .{ .allow_optional = false }) orelse return false;
1387 .ptr_type => |ptr_type| ptr_type.flags.is_volatile,1418 return ptr_info.flags.is_volatile;
1388 else => false,
1389 };
1390}1419}
13911420
1392pub fn isAllowzeroPtr(ty: Type, zcu: *const Zcu) bool {1421pub 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())) {
1394 .ptr_type => |ptr_type| ptr_type.flags.is_allowzero,1424 .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 },
1395 .opt_type => true,1428 .opt_type => true,
1396 else => false,1429 else => false,
1397 };1430 };
1398}1431}
13991432
1400pub fn isCPtr(ty: Type, zcu: *const Zcu) bool {1433pub fn isCPtr(ty: Type, zcu: *const Zcu) bool {
1401 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1434 const ptr_info = ty.ptrInfoOrNull(&zcu.intern_pool, .{ .allow_optional = false }) orelse return false;
1402 .ptr_type => |ptr_type| ptr_type.flags.size == .c,1435 return ptr_info.flags.size == .c;
1403 else => false,
1404 };
1405}1436}
14061437
1407pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool {1438pub 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())) {
1409 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1441 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1410 .slice => false,1442 .slice => false,
1411 .one, .many, .c => true,1443 .one, .many, .c => true,
1412 },1444 },
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)) {
1414 .ptr_type => |p| switch (p.flags.size) {1449 .ptr_type => |p| switch (p.flags.size) {
1415 .slice, .c => false,1450 .slice, .c => false,
1416 .many, .one => !p.flags.is_allowzero,1451 .many, .one => !p.flags.is_allowzero,
1417 },1452 },
1453 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1454 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1455 },
1418 else => false,1456 else => false,
1419 },1457 },
1420 else => false,1458 else => false,
...@@ -1429,13 +1467,20 @@ pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {...@@ -1429,13 +1467,20 @@ pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {
14291467
1430/// See also `isPtrLikeOptional`.1468/// See also `isPtrLikeOptional`.
1431pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {1469pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
1432 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1470 const ip = &zcu.intern_pool;
1433 .opt_type => |child_type| child_type == .anyerror_type or switch (zcu.intern_pool.indexToKey(child_type)) {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)) {
1434 .ptr_type => |ptr_type| ptr_type.flags.size != .c and !ptr_type.flags.is_allowzero,1477 .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 },
1435 .error_set_type, .inferred_error_set_type => true,1481 .error_set_type, .inferred_error_set_type => true,
1436 else => false,1482 else => false,
1437 },1483 },
1438 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
1439 else => false,1484 else => false,
1440 };1485 };
1441}1486}
...@@ -1443,13 +1488,20 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {...@@ -1443,13 +1488,20 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
1443/// Returns true if the type is optional and would be lowered to a single pointer1488/// Returns true if the type is optional and would be lowered to a single pointer
1444/// address value, using 0 for null. Note that this returns true for C pointers.1489/// address value, using 0 for null. Note that this returns true for C pointers.
1445pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {1490pub 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())) {
1447 .ptr_type => |ptr_type| ptr_type.flags.size == .c,1493 .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)) {
1449 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1498 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1450 .slice, .c => false,1499 .slice, .c => false,
1451 .many, .one => !ptr_type.flags.is_allowzero,1500 .many, .one => !ptr_type.flags.is_allowzero,
1452 },1501 },
1502 .restricted_ptr_type => |restricted_ptr_type| continue :opt_child .{
1503 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1504 },
1453 else => false,1505 else => false,
1454 },1506 },
1455 else => false,1507 else => false,
...@@ -1486,7 +1538,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {...@@ -1486,7 +1538,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
1486 .pointer => return ty.childType(zcu),1538 .pointer => return ty.childType(zcu),
1487 .optional => {1539 .optional => {
1488 const ptr_ty = ty.childType(zcu);1540 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 }).?;
1490 assert(ptr_info.flags.size != .c);1542 assert(ptr_info.flags.size != .c);
1491 assert(!ptr_info.flags.is_allowzero);1543 assert(!ptr_info.flags.is_allowzero);
1492 return .fromInterned(ptr_info.child);1544 return .fromInterned(ptr_info.child);
...@@ -1508,7 +1560,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {...@@ -1508,7 +1560,7 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
1508/// * `[*c]T`1560/// * `[*c]T`
1509pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {1561pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
1510 const ip = &zcu.intern_pool;1562 const ip = &zcu.intern_pool;
1511 return switch (ip.indexToKey(ty.toIntern())) {1563 return ty: switch (ip.indexToKey(ty.toIntern())) {
1512 inline .array_type, .vector_type => |arr| .fromInterned(arr.child),1564 inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
1513 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1565 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1514 .many, .slice, .c => .fromInterned(ptr_type.child),1566 .many, .slice, .c => .fromInterned(ptr_type.child),
...@@ -1517,6 +1569,9 @@ pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {...@@ -1517,6 +1569,9 @@ pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
1517 else => unreachable,1569 else => unreachable,
1518 },1570 },
1519 },1571 },
1572 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1573 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1574 },
1520 else => unreachable,1575 else => unreachable,
1521 };1576 };
1522}1577}
...@@ -1532,12 +1587,16 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {...@@ -1532,12 +1587,16 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {
1532/// Asserts that the type is an optional, or a C pointer.1587/// Asserts that the type is an optional, or a C pointer.
1533/// For C pointers this returns the type unmodified.1588/// For C pointers this returns the type unmodified.
1534pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {1589pub 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())) {
1536 .opt_type => |child| return .fromInterned(child),1592 .opt_type => |child| return .fromInterned(child),
1537 .ptr_type => |ptr_type| {1593 .ptr_type => |ptr_type| {
1538 assert(ptr_type.flags.size == .c);1594 assert(ptr_type.flags.size == .c);
1539 return ty;1595 return ty;
1540 },1596 },
1597 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1598 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1599 },
1541 else => unreachable,1600 else => unreachable,
1542 }1601 }
1543}1602}
...@@ -1755,7 +1814,8 @@ pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 {...@@ -1755,7 +1814,8 @@ pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 {
17551814
1756/// Asserts the type is an array, pointer or vector.1815/// Asserts the type is an array, pointer or vector.
1757pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {1816pub 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())) {
1759 .vector_type,1819 .vector_type,
1760 .struct_type,1820 .struct_type,
1761 .tuple_type,1821 .tuple_type,
...@@ -1763,6 +1823,9 @@ pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {...@@ -1763,6 +1823,9 @@ pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {
17631823
1764 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,1824 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
1765 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,1825 .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
1767 else => unreachable,1830 else => unreachable,
1768 };1831 };
...@@ -1851,6 +1914,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -1851,6 +1914,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
1851 .tuple_type => unreachable,1914 .tuple_type => unreachable,
18521915
1853 .ptr_type => unreachable,1916 .ptr_type => unreachable,
1917 .restricted_ptr_type => unreachable,
1854 .anyframe_type => unreachable,1918 .anyframe_type => unreachable,
1855 .array_type => unreachable,1919 .array_type => unreachable,
18561920
...@@ -2021,6 +2085,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {...@@ -2021,6 +2085,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
2021 assertHasLayout(ty, zcu);2085 assertHasLayout(ty, zcu);
2022 return switch (ip.indexToKey(ty.toIntern())) {2086 return switch (ip.indexToKey(ty.toIntern())) {
2023 .ptr_type,2087 .ptr_type,
2088 .restricted_ptr_type, // number of possible values is not known until the end of compilation, so never treated as NPV/OPV
2024 .error_union_type,2089 .error_union_type,
2025 .func_type,2090 .func_type,
2026 .anyframe_type,2091 .anyframe_type,
...@@ -2829,7 +2894,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -2829,7 +2894,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
2829pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type {2894pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type {
2830 const zcu = pt.zcu;2895 const zcu = pt.zcu;
2831 const ip = &zcu.intern_pool;2896 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 }).?;
2833 const elem_ty: Type = switch (ptr_info.flags.size) {2898 const elem_ty: Type = switch (ptr_info.flags.size) {
2834 .slice, .many, .c => .fromInterned(ptr_info.child),2899 .slice, .many, .c => .fromInterned(ptr_info.child),
2835 .one => switch (ip.indexToKey(ptr_info.child)) {2900 .one => switch (ip.indexToKey(ptr_info.child)) {
...@@ -2883,7 +2948,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error...@@ -2883,7 +2948,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error
2883pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type {2948pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type {
2884 const zcu = pt.zcu;2949 const zcu = pt.zcu;
2885 const ip = &zcu.intern_pool;2950 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 }).?;
2887 assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c);2952 assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c);
2888 const aggregate_ty: Type = .fromInterned(ptr_info.child);2953 const aggregate_ty: Type = .fromInterned(ptr_info.child);
2889 aggregate_ty.assertHasLayout(zcu);2954 aggregate_ty.assertHasLayout(zcu);
...@@ -3011,7 +3076,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator...@@ -3011,7 +3076,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
3011 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {3076 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {
3012 .tuple_type, .union_type => field_ty.abiAlignment(zcu),3077 .tuple_type, .union_type => field_ty.abiAlignment(zcu),
3013 .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),3078 .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),
3014 .ptr_type => Type.usize.abiAlignment(zcu),3079 .ptr_type, .restricted_ptr_type => ptrAbiAlignment(zcu.getTarget()),
3015 else => unreachable,3080 else => unreachable,
3016 },3081 },
3017 else => |a| a,3082 else => |a| a,
...@@ -3040,6 +3105,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator...@@ -3040,6 +3105,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
30403105
3041pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {3106pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
3042 return switch (ip.indexToKey(ty.toIntern())) {3107 return switch (ip.indexToKey(ty.toIntern())) {
3108 .restricted_ptr_type => ip.loadRestrictedType(ty.toIntern()).name,
3043 .struct_type => ip.loadStructType(ty.toIntern()).name,3109 .struct_type => ip.loadStructType(ty.toIntern()).name,
3044 .union_type => ip.loadUnionType(ty.toIntern()).name,3110 .union_type => ip.loadUnionType(ty.toIntern()).name,
3045 .enum_type => ip.loadEnumType(ty.toIntern()).name,3111 .enum_type => ip.loadEnumType(ty.toIntern()).name,
...@@ -3247,6 +3313,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {...@@ -3247,6 +3313,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
3247 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {3313 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
3248 .int_type,3314 .int_type,
3249 .ptr_type,3315 .ptr_type,
3316 .restricted_ptr_type,
3250 .anyframe_type,3317 .anyframe_type,
3251 .simple_type,3318 .simple_type,
3252 .opaque_type,3319 .opaque_type,
...@@ -3315,34 +3382,34 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn...@@ -3315,34 +3382,34 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
3315 }3382 }
33163383
3317 switch (ip.indexToKey(ty.toIntern())) {3384 switch (ip.indexToKey(ty.toIntern())) {
3318 .ptr_type => try collectSubtypes(Type.fromInterned(ty.ptrInfo(zcu).child), pt, visited),3385 .ptr_type => |ptr_type| try collectSubtypes(.fromInterned(ptr_type.child), pt, visited),
3319 .array_type => |array_type| try collectSubtypes(Type.fromInterned(array_type.child), pt, visited),3386 .array_type => |array_type| try collectSubtypes(.fromInterned(array_type.child), pt, visited),
3320 .vector_type => |vector_type| try collectSubtypes(Type.fromInterned(vector_type.child), pt, visited),3387 .vector_type => |vector_type| try collectSubtypes(.fromInterned(vector_type.child), pt, visited),
3321 .opt_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited),3388 .opt_type => |child| try collectSubtypes(.fromInterned(child), pt, visited),
3322 .error_union_type => |error_union_type| {3389 .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);
3324 if (error_union_type.payload_type != .generic_poison_type) {3391 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);
3326 }3393 }
3327 },3394 },
3328 .tuple_type => |tuple| {3395 .tuple_type => |tuple| {
3329 for (tuple.types.get(ip)) |field_ty| {3396 for (tuple.types.get(ip)) |field_ty| {
3330 try collectSubtypes(Type.fromInterned(field_ty), pt, visited);3397 try collectSubtypes(.fromInterned(field_ty), pt, visited);
3331 }3398 }
3332 },3399 },
3333 .func_type => |fn_info| {3400 .func_type => |fn_info| {
3334 const param_types = fn_info.param_types.get(&zcu.intern_pool);3401 const param_types = fn_info.param_types.get(&zcu.intern_pool);
3335 for (param_types) |param_ty| {3402 for (param_types) |param_ty| {
3336 if (param_ty != .generic_poison_type) {3403 if (param_ty != .generic_poison_type) {
3337 try collectSubtypes(Type.fromInterned(param_ty), pt, visited);3404 try collectSubtypes(.fromInterned(param_ty), pt, visited);
3338 }3405 }
3339 }3406 }
33403407
3341 if (fn_info.return_type != .generic_poison_type) {3408 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);
3343 }3410 }
3344 },3411 },
3345 .anyframe_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited),3412 .anyframe_type => |child| try collectSubtypes(.fromInterned(child), pt, visited),
33463413
3347 // leaf types3414 // leaf types
3348 .undef,3415 .undef,
...@@ -3354,6 +3421,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn...@@ -3354,6 +3421,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
3354 .enum_type,3421 .enum_type,
3355 .simple_type,3422 .simple_type,
3356 .int_type,3423 .int_type,
3424 .restricted_ptr_type,
3357 => {},3425 => {},
33583426
3359 // values, not types3427 // values, not types
src/Zcu.zig+5-1
...@@ -501,6 +501,7 @@ pub const BuiltinDecl = enum {...@@ -501,6 +501,7 @@ pub const BuiltinDecl = enum {
501 @"panic.copyLenMismatch",501 @"panic.copyLenMismatch",
502 @"panic.memcpyAlias",502 @"panic.memcpyAlias",
503 @"panic.noreturnReturned",503 @"panic.noreturnReturned",
504 @"panic.corruptRestrictedPointer",
504505
505 VaList,506 VaList,
506507
...@@ -588,6 +589,7 @@ pub const BuiltinDecl = enum {...@@ -588,6 +589,7 @@ pub const BuiltinDecl = enum {
588 .@"panic.copyLenMismatch",589 .@"panic.copyLenMismatch",
589 .@"panic.memcpyAlias",590 .@"panic.memcpyAlias",
590 .@"panic.noreturnReturned",591 .@"panic.noreturnReturned",
592 .@"panic.corruptRestrictedPointer",
591 => .func,593 => .func,
592 };594 };
593 }595 }
...@@ -661,6 +663,7 @@ pub const SimplePanicId = enum {...@@ -661,6 +663,7 @@ pub const SimplePanicId = enum {
661 copy_len_mismatch,663 copy_len_mismatch,
662 memcpy_alias,664 memcpy_alias,
663 noreturn_returned,665 noreturn_returned,
666 corrupt_restricted_pointer,
664667
665 pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {668 pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
666 return switch (id) {669 return switch (id) {
...@@ -684,6 +687,7 @@ pub const SimplePanicId = enum {...@@ -684,6 +687,7 @@ pub const SimplePanicId = enum {
684 .copy_len_mismatch => .@"panic.copyLenMismatch",687 .copy_len_mismatch => .@"panic.copyLenMismatch",
685 .memcpy_alias => .@"panic.memcpyAlias",688 .memcpy_alias => .@"panic.memcpyAlias",
686 .noreturn_returned => .@"panic.noreturnReturned",689 .noreturn_returned => .@"panic.noreturnReturned",
690 .corrupt_restricted_pointer => .@"panic.corruptRestrictedPointer",
687 // zig fmt: on691 // zig fmt: on
688 };692 };
689 }693 }
...@@ -4215,7 +4219,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag...@@ -4215,7 +4219,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag
42154219
4216 // Queue any decls within this type which would be automatically analyzed.4220 // Queue any decls within this type which would be automatically analyzed.
4217 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.4221 // 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;
4219 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {4223 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {
4220 // `comptime` decls are always analyzed.4224 // `comptime` decls are always analyzed.
4221 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });4225 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
src/codegen.zig+4
...@@ -281,6 +281,9 @@ pub fn generateLazySymbol(...@@ -281,6 +281,9 @@ pub fn generateLazySymbol(
281 w.writeAll(tag_name) catch unreachable;281 w.writeAll(tag_name) catch unreachable;
282 w.writeByte(0) catch unreachable;282 w.writeByte(0) catch unreachable;
283 }283 }
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
284 } else {287 } else {
285 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{288 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{
286 @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt),289 @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt),
...@@ -325,6 +328,7 @@ pub fn generateSymbol(...@@ -325,6 +328,7 @@ pub fn generateSymbol(
325 switch (ip.indexToKey(val.toIntern())) {328 switch (ip.indexToKey(val.toIntern())) {
326 .int_type,329 .int_type,
327 .ptr_type,330 .ptr_type,
331 .restricted_ptr_type,
328 .array_type,332 .array_type,
329 .vector_type,333 .vector_type,
330 .opt_type,334 .opt_type,
src/codegen/aarch64/Select.zig+45
...@@ -658,6 +658,28 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -658,6 +658,28 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
658 air_inst_index = air_body[air_body_index];658 air_inst_index = air_body[air_body_index];
659 continue :air_tag air_tags[@intFromEnum(air_inst_index)];659 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
660 },660 },
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 },
661 .struct_field_ptr, .struct_field_val => {683 .struct_field_ptr, .struct_field_val => {
662 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;684 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
663 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;685 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,...@@ -5737,6 +5759,29 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
5737 }5759 }
5738 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5760 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5739 },5761 },
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 },
5740 .struct_field_ptr => {5785 .struct_field_ptr => {
5741 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {5786 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5742 defer dst_vi.value.deref(isel);5787 defer dst_vi.value.deref(isel);
src/codegen/c.zig+36-1
...@@ -896,6 +896,7 @@ pub const DeclGen = struct {...@@ -896,6 +896,7 @@ pub const DeclGen = struct {
896 // types, not values896 // types, not values
897 .int_type,897 .int_type,
898 .ptr_type,898 .ptr_type,
899 .restricted_ptr_type,
899 .array_type,900 .array_type,
900 .vector_type,901 .vector_type,
901 .opt_type,902 .opt_type,
...@@ -1334,7 +1335,7 @@ pub const DeclGen = struct {...@@ -1334,7 +1335,7 @@ pub const DeclGen = struct {
1334 return w.writeByte(')');1335 return w.writeByte(')');
1335 },1336 },
1336 .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"),1337 .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())) {
1338 .simple_type, // anyerror, c_char (etc), usize, isize1339 .simple_type, // anyerror, c_char (etc), usize, isize
1339 .int_type,1340 .int_type,
1340 .enum_type,1341 .enum_type,
...@@ -1405,6 +1406,9 @@ pub const DeclGen = struct {...@@ -1405,6 +1406,9 @@ pub const DeclGen = struct {
1405 try w.writeByte('}');1406 try w.writeByte('}');
1406 },1407 },
1407 },1408 },
1409 .restricted_ptr_type => |restricted_ptr_type| continue :ty .{
1410 .ptr_type = ip.indexToKey(restricted_ptr_type.unrestricted_ptr_type).ptr_type,
1411 },
1408 .opt_type => |child_type| switch (CType.classifyOptional(ty, zcu)) {1412 .opt_type => |child_type| switch (CType.classifyOptional(ty, zcu)) {
1409 .npv_payload => unreachable, // opv optional1413 .npv_payload => unreachable, // opv optional
14101414
...@@ -2840,6 +2844,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {...@@ -2840,6 +2844,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
2840 .set_err_return_trace => try airSetErrReturnTrace(f, inst),2844 .set_err_return_trace => try airSetErrReturnTrace(f, inst),
2841 .save_err_return_trace_index => try airSaveErrReturnTraceIndex(f, inst),2845 .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
2843 .wasm_memory_size => try airWasmMemorySize(f, inst),2850 .wasm_memory_size => try airWasmMemorySize(f, inst),
2844 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),2851 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
28452852
...@@ -5533,6 +5540,34 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5533,6 +5540,34 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5533 return local;5540 return local;
5534}5541}
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
5536fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {5571fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5537 const pt = f.dg.pt;5572 const pt = f.dg.pt;
5538 const w = &f.code.writer;5573 const w = &f.code.writer;
src/codegen/c/type.zig+19-1
...@@ -284,6 +284,20 @@ pub const CType = union(enum) {...@@ -284,6 +284,20 @@ pub const CType = union(enum) {
284284
285 .pointer => {285 .pointer => {
286 const ptr = cur_ty.ptrInfo(zcu);286 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 };
287 switch (ptr.flags.size) {301 switch (ptr.flags.size) {
288 .slice => {302 .slice => {
289 try deps.addType(gpa, cur_ty, allow_incomplete);303 try deps.addType(gpa, cur_ty, allow_incomplete);
...@@ -912,7 +926,10 @@ pub const CType = union(enum) {...@@ -912,7 +926,10 @@ pub const CType = union(enum) {
912 .optional => try w.print("opt_{f}", .{fmtZigType(ty.optionalChild(zcu), zcu)}),926 .optional => try w.print("opt_{f}", .{fmtZigType(ty.optionalChild(zcu), zcu)}),
913 .error_union => try w.print("errunion_{f}", .{fmtZigType(ty.errorUnionPayload(zcu), zcu)}),927 .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)) {
916 .one, .many, .c => try w.print("ptr_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),933 .one, .many, .c => try w.print("ptr_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
917 .slice => try w.print("slice_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),934 .slice => try w.print("slice_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
918 },935 },
...@@ -985,6 +1002,7 @@ pub const CType = union(enum) {...@@ -985,6 +1002,7 @@ pub const CType = union(enum) {
985 return switch (ip.indexToKey(ty.toIntern())) {1002 return switch (ip.indexToKey(ty.toIntern())) {
986 .int_type,1003 .int_type,
987 .ptr_type,1004 .ptr_type,
1005 .restricted_ptr_type,
988 .anyframe_type,1006 .anyframe_type,
989 .simple_type,1007 .simple_type,
990 .opaque_type,1008 .opaque_type,
src/codegen/llvm.zig+2
...@@ -3061,6 +3061,7 @@ pub const Object = struct {...@@ -3061,6 +3061,7 @@ pub const Object = struct {
3061 }),3061 }),
3062 };3062 };
3063 },3063 },
3064 .restricted_ptr_type => @panic("TODO implement restricted pointers"),
3064 .array_type => |array_type| o.builder.arrayType(3065 .array_type => |array_type| o.builder.arrayType(
3065 array_type.lenIncludingSentinel(),3066 array_type.lenIncludingSentinel(),
3066 try o.lowerType(.fromInterned(array_type.child)),3067 try o.lowerType(.fromInterned(array_type.child)),
...@@ -3443,6 +3444,7 @@ pub const Object = struct {...@@ -3443,6 +3444,7 @@ pub const Object = struct {
3443 return switch (val_key) {3444 return switch (val_key) {
3444 .int_type,3445 .int_type,
3445 .ptr_type,3446 .ptr_type,
3447 .restricted_ptr_type,
3446 .array_type,3448 .array_type,
3447 .vector_type,3449 .vector_type,
3448 .opt_type,3450 .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...@@ -413,6 +413,9 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air
413 .wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]),413 .wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]),
414 .wrap_errunion_err => try self.airWrapErrUnionErr(body[i..]),414 .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
416 .wasm_memory_size => try self.airWasmMemorySize(inst),419 .wasm_memory_size => try self.airWasmMemorySize(inst),
417 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),420 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),
418421
...@@ -3250,6 +3253,22 @@ fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocat...@@ -3250,6 +3253,22 @@ fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocat
3250 return result_ptr;3253 return result_ptr;
3251}3254}
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
3253fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {3272fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
3254 const o = self.object;3273 const o = self.object;
3255 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;3274 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 {...@@ -1614,6 +1614,10 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1614 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),1614 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
1615 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),1615 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16161616
1617 .unwrap_restricted,
1618 .unwrap_restricted_safe,
1619 => return func.fail("TODO implement restricted pointers", .{}),
1620
1617 .runtime_nav_ptr => try func.airRuntimeNavPtr(inst),1621 .runtime_nav_ptr => try func.airRuntimeNavPtr(inst),
16181622
1619 .add_optimized,1623 .add_optimized,
src/codegen/sparc64/CodeGen.zig+4
...@@ -676,6 +676,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -676,6 +676,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
676 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),676 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
677 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),677 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
678678
679 .unwrap_restricted,
680 .unwrap_restricted_safe,
681 => return self.fail("TODO implement restricted pointers", .{}),
682
679 .add_optimized,683 .add_optimized,
680 .sub_optimized,684 .sub_optimized,
681 .mul_optimized,685 .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 {...@@ -774,6 +774,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
774 switch (ip.indexToKey(val.toIntern())) {774 switch (ip.indexToKey(val.toIntern())) {
775 .int_type,775 .int_type,
776 .ptr_type,776 .ptr_type,
777 .restricted_ptr_type,
777 .array_type,778 .array_type,
778 .vector_type,779 .vector_type,
779 .opt_type,780 .opt_type,
...@@ -2774,7 +2775,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {...@@ -2774,7 +2775,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
2774 .unwrap_errunion_err => try cg.airErrUnionErr(inst),2775 .unwrap_errunion_err => try cg.airErrUnionErr(inst),
2775 .unwrap_errunion_payload => try cg.airErrUnionPayload(inst),2776 .unwrap_errunion_payload => try cg.airErrUnionPayload(inst),
2776 .wrap_errunion_err => try cg.airWrapErrUnionErr(inst),2777 .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
2779 .is_null => try cg.airIsNull(inst, false, .is_null),2782 .is_null => try cg.airIsNull(inst, false, .is_null),
2780 .is_non_null => try cg.airIsNull(inst, false, .is_non_null),2783 .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 {...@@ -1815,6 +1815,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1815 .errunion_payload_ptr_set => cg.airErrUnionPayloadPtrSet(inst),1815 .errunion_payload_ptr_set => cg.airErrUnionPayloadPtrSet(inst),
1816 .error_name => cg.airErrorName(inst),1816 .error_name => cg.airErrorName(inst),
18171817
1818 .unwrap_restricted => cg.airUnwrapRestricted(inst, false),
1819 .unwrap_restricted_safe => cg.airUnwrapRestricted(inst, true),
1820
1818 .wasm_memory_size => cg.airWasmMemorySize(inst),1821 .wasm_memory_size => cg.airWasmMemorySize(inst),
1819 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),1822 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),
18201823
...@@ -4676,6 +4679,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {...@@ -4676,6 +4679,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
4676 switch (ip.indexToKey(val.ip_index)) {4679 switch (ip.indexToKey(val.ip_index)) {
4677 .int_type,4680 .int_type,
4678 .ptr_type,4681 .ptr_type,
4682 .restricted_ptr_type,
4679 .array_type,4683 .array_type,
4680 .vector_type,4684 .vector_type,
4681 .opt_type,4685 .opt_type,
...@@ -6719,6 +6723,22 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void...@@ -6719,6 +6723,22 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
6719 return cg.finishAir(inst, result, &.{ty_op.operand});6723 return cg.finishAir(inst, result, &.{ty_op.operand});
6720}6724}
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
6722fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6742fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6723 const pt = cg.pt;6743 const pt = cg.pt;
6724 const zcu = pt.zcu;6744 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 {...@@ -103829,6 +103829,121 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
103829 try eu.write(&ops[0], .{ .disp = eu_err_off }, cg);103829 try eu.write(&ops[0], .{ .disp = eu_err_off }, cg);
103830 try eu.finish(inst, &.{ty_op.operand}, &ops, cg);103830 try eu.finish(inst, &.{ty_op.operand}, &ops, cg);
103831 },103831 },
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 },
103832 .struct_field_ptr => {103947 .struct_field_ptr => {
103833 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;103948 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
103834 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;103949 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
...@@ -176216,20 +176331,22 @@ fn genCall(self: *CodeGen, info: union(enum) {...@@ -176216,20 +176331,22 @@ fn genCall(self: *CodeGen, info: union(enum) {
176216 // Due to incremental compilation, how function calls are generated depends176331 // Due to incremental compilation, how function calls are generated depends
176217 // on linking.176332 // on linking.
176218 switch (info) {176333 switch (info) {
176219 .air => |callee| if (callee.toInterned()) |func_ip_index| {176334 .air => |callee| if (callee.toInterned()) |func_ip_index| try self.asmImmediate(
176220 const func_key = ip.indexToKey(func_ip_index);176335 .{ ._, .call },
176221 switch (switch (func_key) {176336 switch (switch (ip.indexToKey(func_ip_index)) {
176222 else => func_key,176337 else => |func_key| func_key,
176223 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {176338 .ptr => |ptr| switch (ptr.byte_offset) {
176224 .nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),176339 0 => switch (ptr.base_addr) {
176225 else => func_key,176340 .nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),
176226 } else func_key,176341 else => unreachable,
176342 },
176343 else => unreachable,
176344 },
176227 }) {176345 }) {
176228 else => unreachable,176346 else => unreachable,
176229 .func => |func| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = func.owner_nav } }),176347 inline .func, .@"extern" => |func| .{ .nav = .{ .index = func.owner_nav } },
176230 .@"extern" => |@"extern"| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = @"extern".owner_nav } }),176348 },
176231 }176349 ) else {
176232 } else {
176233 assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer);176350 assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer);
176234 const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);176351 const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);
176235 try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{});176352 try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{});
...@@ -188525,6 +188642,7 @@ const Select = struct {...@@ -188525,6 +188642,7 @@ const Select = struct {
188525 splat_float_mem: struct { ref: Select.Operand.Ref, inside: enum { zero } = .zero, outside: f16 },188642 splat_float_mem: struct { ref: Select.Operand.Ref, inside: enum { zero } = .zero, outside: f16 },
188526 frame: FrameIndex,188643 frame: FrameIndex,
188527 lazy_sym: struct { kind: link.File.LazySymbol.Kind, ref: Select.Operand.Ref = .none },188644 lazy_sym: struct { kind: link.File.LazySymbol.Kind, ref: Select.Operand.Ref = .none },
188645 panic_func: Zcu.SimplePanicId,
188528 extern_func: [*:0]const u8,188646 extern_func: [*:0]const u8,
188529188647
188530 const ConstSpec = struct {188648 const ConstSpec = struct {
...@@ -188986,7 +189104,25 @@ const Select = struct {...@@ -188986,7 +189104,25 @@ const Select = struct {
188986 },189104 },
188987 } }), true };189105 } }), true };
188988 },189106 },
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 },
188990 };189126 };
188991 }189127 }
188992189128
...@@ -189036,6 +189172,7 @@ const Select = struct {...@@ -189036,6 +189172,7 @@ const Select = struct {
189036 lhs: enum(u6) {189172 lhs: enum(u6) {
189037 none,189173 none,
189038 ptr_size,189174 ptr_size,
189175 log2_ptr_size,
189039 ptr_bit_size,189176 ptr_bit_size,
189040 size,189177 size,
189041 src0_size,189178 src0_size,
...@@ -189072,7 +189209,9 @@ const Select = struct {...@@ -189072,7 +189209,9 @@ const Select = struct {
189072 rhs: Memory.Scale,189209 rhs: Memory.Scale,
189073189210
189074 const none: Adjust = .{ .sign = .pos, .lhs = .none, .op = .mul, .rhs = .@"1" };189211 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" };
189075 const sub_ptr_size: Adjust = .{ .sign = .neg, .lhs = .ptr_size, .op = .mul, .rhs = .@"1" };189213 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" };
189076 const add_ptr_bit_size: Adjust = .{ .sign = .pos, .lhs = .ptr_bit_size, .op = .mul, .rhs = .@"1" };189215 const add_ptr_bit_size: Adjust = .{ .sign = .pos, .lhs = .ptr_bit_size, .op = .mul, .rhs = .@"1" };
189077 const add_size: Adjust = .{ .sign = .pos, .lhs = .size, .op = .mul, .rhs = .@"1" };189216 const add_size: Adjust = .{ .sign = .pos, .lhs = .size, .op = .mul, .rhs = .@"1" };
189078 const add_size_div_4: Adjust = .{ .sign = .pos, .lhs = .size, .op = .div, .rhs = .@"4" };189217 const add_size_div_4: Adjust = .{ .sign = .pos, .lhs = .size, .op = .div, .rhs = .@"4" };
...@@ -190013,6 +190152,7 @@ const Select = struct {...@@ -190013,6 +190152,7 @@ const Select = struct {
190013 const lhs: SignedImm = lhs: switch (op.flags.adjust.lhs) {190152 const lhs: SignedImm = lhs: switch (op.flags.adjust.lhs) {
190014 .none => 0,190153 .none => 0,
190015 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),190154 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),
190155 .log2_ptr_size => std.math.log2(@divExact(s.cg.target.ptrBitWidth(), 8)),
190016 .ptr_bit_size => s.cg.target.ptrBitWidth(),190156 .ptr_bit_size => s.cg.target.ptrBitWidth(),
190017 .size => @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu)),190157 .size => @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu)),
190018 .src0_size => @intCast(Select.Operand.Ref.src0.typeOf(s).abiSize(s.cg.pt.zcu)),190158 .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...@@ -3060,6 +3060,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3060 } = switch (ip.indexToKey(nav_val.toIntern())) {3060 } = switch (ip.indexToKey(nav_val.toIntern())) {
3061 .int_type,3061 .int_type,
3062 .ptr_type,3062 .ptr_type,
3063 .restricted_ptr_type,
3063 .array_type,3064 .array_type,
3064 .vector_type,3065 .vector_type,
3065 .opt_type,3066 .opt_type,
...@@ -3566,7 +3567,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3566,7 +3567,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
35663567
3567 const diw = &wip_nav.debug_info.writer;3568 const diw = &wip_nav.debug_info.writer;
3568 var big_int_space: Value.BigIntSpace = undefined;3569 var big_int_space: Value.BigIntSpace = undefined;
3569 switch (value_ip_key) {3570 key: switch (value_ip_key) {
3570 .func => unreachable, // handled above3571 .func => unreachable, // handled above
3571 .@"extern" => unreachable, // handled above3572 .@"extern" => unreachable, // handled above
35723573
...@@ -3629,6 +3630,13 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -3629,6 +3630,13 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
3629 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));3630 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
3630 },3631 },
3631 },3632 },
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 },
3632 .array_type => |array_type| {3640 .array_type => |array_type| {
3633 const array_child_type: Type = .fromInterned(array_type.child);3641 const array_child_type: Type = .fromInterned(array_type.child);
3634 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);3642 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(...@@ -49,6 +49,7 @@ pub fn print(
49 switch (ip.indexToKey(val.toIntern())) {49 switch (ip.indexToKey(val.toIntern())) {
50 .int_type,50 .int_type,
51 .ptr_type,51 .ptr_type,
52 .restricted_ptr_type,
52 .array_type,53 .array_type,
53 .vector_type,54 .vector_type,
54 .opt_type,55 .opt_type,
src/print_zir.zig+8
...@@ -622,6 +622,14 @@ const Writer = struct {...@@ -622,6 +622,14 @@ const Writer = struct {
622 try stream.writeAll(")) ");622 try stream.writeAll(")) ");
623 try self.writeSrcNode(stream, extra.node);623 try self.writeSrcNode(stream, extra.node);
624 },624 },
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 },
625 .reify_fn => {633 .reify_fn => {
626 const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;634 const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
627 try self.writeInstRef(stream, extra.param_types);635 try self.writeInstRef(stream, extra.param_types);