| ... | ... | @@ -91,14 +91,6 @@ no_partial_func_ty: bool = false, |
| 91 | 91 | /// here so the values can be dropped without any cleanup. |
| 92 | 92 | unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{}, |
| 93 | 93 | |
| 94 | | /// Indices of comptime-mutable decls created by this Sema. These decls' values |
| 95 | | /// should be interned after analysis completes, as they may refer to memory in |
| 96 | | /// the Sema arena. |
| 97 | | /// TODO: this is a workaround for memory bugs triggered by the removal of |
| 98 | | /// Decl.value_arena. A better solution needs to be found. Probably this will |
| 99 | | /// involve transitioning comptime-mutable memory away from using Decls at all. |
| 100 | | comptime_mutable_decls: *std.ArrayList(InternPool.DeclIndex), |
| 101 | | |
| 102 | 94 | /// This is populated when `@setAlignStack` occurs so that if there is a duplicate |
| 103 | 95 | /// one encountered, the conflicting source location can be shown. |
| 104 | 96 | prev_stack_alignment_src: ?LazySrcLoc = null, |
| ... | ... | @@ -123,19 +115,57 @@ base_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, Air.Inst.Index) = .{}, |
| 123 | 115 | /// Backed by gpa. |
| 124 | 116 | maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAlloc) = .{}, |
| 125 | 117 | |
| 118 | /// Comptime-mutable allocs, and any comptime allocs which reference it, are |
| 119 | /// stored as elements of this array. |
| 120 | /// Pointers to such memory are represented via an index into this array. |
| 121 | /// Backed by gpa. |
| 122 | comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{}, |
| 123 | |
| 126 | 124 | const MaybeComptimeAlloc = struct { |
| 127 | 125 | /// The runtime index of the `alloc` instruction. |
| 128 | 126 | runtime_index: Value.RuntimeIndex, |
| 129 | 127 | /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to |
| 130 | 128 | /// RLS, a single comptime-known allocation may have arbitrarily many stores. |
| 131 | 129 | /// This may also contain `set_union_tag` instructions. |
| 132 | | stores: std.ArrayListUnmanaged(Air.Inst.Index) = .{}, |
| 130 | stores: std.MultiArrayList(struct { |
| 131 | inst: Air.Inst.Index, |
| 132 | src_decl: InternPool.DeclIndex, |
| 133 | src: LazySrcLoc, |
| 134 | }) = .{}, |
| 133 | 135 | /// Backed by sema.arena. Contains instructions such as `optional_payload_ptr_set` |
| 134 | 136 | /// which have side effects so will not be elided by Liveness: we must rewrite these |
| 135 | 137 | /// instructions to be nops instead of relying on Liveness. |
| 136 | 138 | non_elideable_pointers: std.ArrayListUnmanaged(Air.Inst.Index) = .{}, |
| 137 | 139 | }; |
| 138 | 140 | |
| 141 | const ComptimeAlloc = struct { |
| 142 | ty: Type, |
| 143 | val: Value, |
| 144 | is_const: bool, |
| 145 | /// `.none` indicates that the alignment is the natural alignment of `val`. |
| 146 | alignment: Alignment, |
| 147 | /// This is the `runtime_index` at the point of this allocation. If an store |
| 148 | /// to this alloc ever occurs with a runtime index greater than this one, it |
| 149 | /// is behind a runtime condition, so a compile error will be emitted. |
| 150 | runtime_index: Value.RuntimeIndex, |
| 151 | }; |
| 152 | |
| 153 | fn newComptimeAlloc(sema: *Sema, block: *Block, ty: Type, alignment: Alignment) !ComptimeAllocIndex { |
| 154 | const idx = sema.comptime_allocs.items.len; |
| 155 | try sema.comptime_allocs.append(sema.gpa, .{ |
| 156 | .ty = ty, |
| 157 | .val = Value.fromInterned(try sema.mod.intern(.{ .undef = ty.toIntern() })), |
| 158 | .is_const = false, |
| 159 | .alignment = alignment, |
| 160 | .runtime_index = block.runtime_index, |
| 161 | }); |
| 162 | return @enumFromInt(idx); |
| 163 | } |
| 164 | |
| 165 | pub fn getComptimeAlloc(sema: *Sema, idx: ComptimeAllocIndex) *ComptimeAlloc { |
| 166 | return &sema.comptime_allocs.items[@intFromEnum(idx)]; |
| 167 | } |
| 168 | |
| 139 | 169 | const std = @import("std"); |
| 140 | 170 | const math = std.math; |
| 141 | 171 | const mem = std.mem; |
| ... | ... | @@ -164,6 +194,7 @@ const build_options = @import("build_options"); |
| 164 | 194 | const Compilation = @import("Compilation.zig"); |
| 165 | 195 | const InternPool = @import("InternPool.zig"); |
| 166 | 196 | const Alignment = InternPool.Alignment; |
| 197 | const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; |
| 167 | 198 | |
| 168 | 199 | pub const default_branch_quota = 1000; |
| 169 | 200 | pub const default_reference_trace_len = 2; |
| ... | ... | @@ -787,40 +818,6 @@ pub const Block = struct { |
| 787 | 818 | const zcu = block.sema.mod; |
| 788 | 819 | return zcu.namespacePtr(block.namespace).file_scope.mod; |
| 789 | 820 | } |
| 790 | | |
| 791 | | pub fn startAnonDecl(block: *Block) !WipAnonDecl { |
| 792 | | return WipAnonDecl{ |
| 793 | | .block = block, |
| 794 | | .finished = false, |
| 795 | | }; |
| 796 | | } |
| 797 | | |
| 798 | | pub const WipAnonDecl = struct { |
| 799 | | block: *Block, |
| 800 | | finished: bool, |
| 801 | | |
| 802 | | pub fn deinit(wad: *WipAnonDecl) void { |
| 803 | | wad.* = undefined; |
| 804 | | } |
| 805 | | |
| 806 | | /// `alignment` value of 0 means to use ABI alignment. |
| 807 | | pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: Alignment) !InternPool.DeclIndex { |
| 808 | | const sema = wad.block.sema; |
| 809 | | // Do this ahead of time because `createAnonymousDecl` depends on calling |
| 810 | | // `type.hasRuntimeBits()`. |
| 811 | | _ = try sema.typeHasRuntimeBits(ty); |
| 812 | | const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{ |
| 813 | | .ty = ty, |
| 814 | | .val = val, |
| 815 | | }); |
| 816 | | const new_decl = sema.mod.declPtr(new_decl_index); |
| 817 | | new_decl.alignment = alignment; |
| 818 | | errdefer sema.mod.abortAnonDecl(new_decl_index); |
| 819 | | wad.finished = true; |
| 820 | | try sema.mod.finalizeAnonDecl(new_decl_index); |
| 821 | | return new_decl_index; |
| 822 | | } |
| 823 | | }; |
| 824 | 821 | }; |
| 825 | 822 | |
| 826 | 823 | const LabeledBlock = struct { |
| ... | ... | @@ -869,6 +866,7 @@ pub fn deinit(sema: *Sema) void { |
| 869 | 866 | sema.unresolved_inferred_allocs.deinit(gpa); |
| 870 | 867 | sema.base_allocs.deinit(gpa); |
| 871 | 868 | sema.maybe_comptime_allocs.deinit(gpa); |
| 869 | sema.comptime_allocs.deinit(gpa); |
| 872 | 870 | sema.* = undefined; |
| 873 | 871 | } |
| 874 | 872 | |
| ... | ... | @@ -1901,7 +1899,7 @@ pub fn resolveConstStringIntern( |
| 1901 | 1899 | const wanted_type = Type.slice_const_u8; |
| 1902 | 1900 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1903 | 1901 | const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); |
| 1904 | | return val.toIpString(wanted_type, sema.mod); |
| 1902 | return sema.sliceToIpString(block, src, val, reason); |
| 1905 | 1903 | } |
| 1906 | 1904 | |
| 1907 | 1905 | pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { |
| ... | ... | @@ -2140,7 +2138,7 @@ fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value |
| 2140 | 2138 | fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { |
| 2141 | 2139 | const val = (try sema.resolveValue(inst)) orelse return null; |
| 2142 | 2140 | if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) { |
| 2143 | | .decl, .anon_decl, .mut_decl, .comptime_field => return null, |
| 2141 | .decl, .anon_decl, .comptime_alloc, .comptime_field => return null, |
| 2144 | 2142 | .int => {}, |
| 2145 | 2143 | .eu_payload, .opt_payload, .elem, .field => unreachable, |
| 2146 | 2144 | }; |
| ... | ... | @@ -2192,17 +2190,21 @@ fn resolveInstConst( |
| 2192 | 2190 | } |
| 2193 | 2191 | |
| 2194 | 2192 | /// Value Tag may be `undef` or `variable`. |
| 2195 | | pub fn resolveConstValueAllowVariables( |
| 2193 | pub fn resolveFinalDeclValue( |
| 2196 | 2194 | sema: *Sema, |
| 2197 | 2195 | block: *Block, |
| 2198 | 2196 | src: LazySrcLoc, |
| 2199 | 2197 | air_ref: Air.Inst.Ref, |
| 2200 | | reason: NeededComptimeReason, |
| 2201 | 2198 | ) CompileError!TypedValue { |
| 2202 | 2199 | const val = try sema.resolveValueAllowVariables(air_ref) orelse { |
| 2203 | | return sema.failWithNeededComptime(block, src, reason); |
| 2200 | return sema.failWithNeededComptime(block, src, .{ |
| 2201 | .needed_comptime_reason = "global variable initializer must be comptime-known", |
| 2202 | }); |
| 2204 | 2203 | }; |
| 2205 | 2204 | if (val.isGenericPoison()) return error.GenericPoison; |
| 2205 | if (val.canMutateComptimeVarState(sema.mod)) { |
| 2206 | return sema.fail(block, src, "global variable contains reference to comptime var", .{}); |
| 2207 | } |
| 2206 | 2208 | return .{ |
| 2207 | 2209 | .ty = sema.typeOf(air_ref), |
| 2208 | 2210 | .val = val, |
| ... | ... | @@ -2671,7 +2673,7 @@ fn analyzeAsInt( |
| 2671 | 2673 | |
| 2672 | 2674 | /// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`, |
| 2673 | 2675 | /// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`. |
| 2674 | | fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue { |
| 2676 | fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue { |
| 2675 | 2677 | const zcu = sema.mod; |
| 2676 | 2678 | const ip = &zcu.intern_pool; |
| 2677 | 2679 | const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu); |
| ... | ... | @@ -2682,9 +2684,29 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32 |
| 2682 | 2684 | const zir_capture: Zir.Inst.Capture = @bitCast(raw); |
| 2683 | 2685 | capture.* = switch (zir_capture.unwrap()) { |
| 2684 | 2686 | .nested => |parent_idx| parent_captures.get(ip)[parent_idx], |
| 2687 | .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: { |
| 2688 | const ptr_ref = try sema.resolveInst(ptr_inst.toRef()); |
| 2689 | const ptr_val = try sema.resolveValue(ptr_ref) orelse { |
| 2690 | break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }; |
| 2691 | }; |
| 2692 | // TODO: better source location |
| 2693 | const unresolved_loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse { |
| 2694 | break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }; |
| 2695 | }; |
| 2696 | const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val); |
| 2697 | if (loaded_val.canMutateComptimeVarState(zcu)) { |
| 2698 | // TODO: source location of captured value |
| 2699 | return sema.fail(block, type_src, "type capture contains reference to comptime var", .{}); |
| 2700 | } |
| 2701 | break :capture .{ .@"comptime" = loaded_val.toIntern() }; |
| 2702 | }), |
| 2685 | 2703 | .instruction => |inst| InternPool.CaptureValue.wrap(capture: { |
| 2686 | 2704 | const air_ref = try sema.resolveInst(inst.toRef()); |
| 2687 | 2705 | if (try sema.resolveValueResolveLazy(air_ref)) |val| { |
| 2706 | if (val.canMutateComptimeVarState(zcu)) { |
| 2707 | // TODO: source location of captured value |
| 2708 | return sema.fail(block, type_src, "type capture contains reference to comptime var", .{}); |
| 2709 | } |
| 2688 | 2710 | break :capture .{ .@"comptime" = val.toIntern() }; |
| 2689 | 2711 | } |
| 2690 | 2712 | break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() }; |
| ... | ... | @@ -2766,7 +2788,7 @@ fn zirStructDecl( |
| 2766 | 2788 | break :blk decls_len; |
| 2767 | 2789 | } else 0; |
| 2768 | 2790 | |
| 2769 | | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 2791 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 2770 | 2792 | extra_index += captures_len; |
| 2771 | 2793 | |
| 2772 | 2794 | if (small.has_backing_int) { |
| ... | ... | @@ -2981,7 +3003,7 @@ fn zirEnumDecl( |
| 2981 | 3003 | break :blk decls_len; |
| 2982 | 3004 | } else 0; |
| 2983 | 3005 | |
| 2984 | | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 3006 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 2985 | 3007 | extra_index += captures_len; |
| 2986 | 3008 | |
| 2987 | 3009 | const decls = sema.code.bodySlice(extra_index, decls_len); |
| ... | ... | @@ -3254,7 +3276,7 @@ fn zirUnionDecl( |
| 3254 | 3276 | break :blk decls_len; |
| 3255 | 3277 | } else 0; |
| 3256 | 3278 | |
| 3257 | | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 3279 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 3258 | 3280 | extra_index += captures_len; |
| 3259 | 3281 | |
| 3260 | 3282 | const union_init: InternPool.UnionTypeInit = .{ |
| ... | ... | @@ -3358,7 +3380,7 @@ fn zirOpaqueDecl( |
| 3358 | 3380 | break :blk decls_len; |
| 3359 | 3381 | } else 0; |
| 3360 | 3382 | |
| 3361 | | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 3383 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 3362 | 3384 | extra_index += captures_len; |
| 3363 | 3385 | |
| 3364 | 3386 | const opaque_init: InternPool.OpaqueTypeInit = .{ |
| ... | ... | @@ -3653,9 +3675,9 @@ fn zirAllocExtended( |
| 3653 | 3675 | try sema.air_instructions.append(gpa, .{ |
| 3654 | 3676 | .tag = .inferred_alloc_comptime, |
| 3655 | 3677 | .data = .{ .inferred_alloc_comptime = .{ |
| 3656 | | .decl_index = undefined, |
| 3657 | 3678 | .alignment = alignment, |
| 3658 | 3679 | .is_const = small.is_const, |
| 3680 | .ptr = undefined, |
| 3659 | 3681 | } }, |
| 3660 | 3682 | }); |
| 3661 | 3683 | return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef(); |
| ... | ... | @@ -3717,36 +3739,51 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3717 | 3739 | const ptr_info = alloc_ty.ptrInfo(mod); |
| 3718 | 3740 | const elem_ty = Type.fromInterned(ptr_info.child); |
| 3719 | 3741 | |
| 3720 | | if (try sema.resolveComptimeKnownAllocValue(block, alloc, null)) |val| { |
| 3721 | | const new_mut_ptr = Air.internedToRef((try mod.intern(.{ .ptr = .{ |
| 3722 | | .ty = alloc_ty.toIntern(), |
| 3723 | | .addr = .{ .anon_decl = .{ |
| 3724 | | .val = val, |
| 3725 | | .orig_ty = alloc_ty.toIntern(), |
| 3726 | | } }, |
| 3727 | | } }))); |
| 3728 | | return sema.makePtrConst(block, new_mut_ptr); |
| 3729 | | } |
| 3730 | | |
| 3731 | | // If this is already a comptime-known allocation, we don't want to emit an error - the stores |
| 3732 | | // were already performed at comptime! Just make the pointer constant as normal. |
| 3733 | | implicit_ct: { |
| 3734 | | const ptr_val = try sema.resolveValue(alloc) orelse break :implicit_ct; |
| 3735 | | if (!ptr_val.isComptimeMutablePtr(mod)) { |
| 3736 | | // It could still be a constant pointer to a decl. |
| 3737 | | switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 3738 | | .anon_decl => |anon_decl| { |
| 3739 | | if (mod.intern_pool.isVariable(anon_decl.val)) |
| 3740 | | break :implicit_ct; |
| 3741 | | }, |
| 3742 | | else => { |
| 3743 | | const decl_index = ptr_val.pointerDecl(mod) orelse break :implicit_ct; |
| 3744 | | const decl_val = mod.declPtr(decl_index).val.toIntern(); |
| 3745 | | if (mod.intern_pool.isVariable(decl_val)) break :implicit_ct; |
| 3742 | // If the alloc was created in a comptime scope, we already created a comptime alloc for it. |
| 3743 | // However, if the final constructed value does not reference comptime-mutable memory, we wish |
| 3744 | // to promote it to an anon decl. |
| 3745 | already_ct: { |
| 3746 | const ptr_val = try sema.resolveValue(alloc) orelse break :already_ct; |
| 3747 | |
| 3748 | // If this was a comptime inferred alloc, then `storeToInferredAllocComptime` |
| 3749 | // might have already done our job and created an anon decl ref. |
| 3750 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 3751 | .ptr => |ptr| switch (ptr.addr) { |
| 3752 | .anon_decl => { |
| 3753 | // The comptime-ification was already done for us. |
| 3754 | // Just make sure the pointer is const. |
| 3755 | return sema.makePtrConst(block, alloc); |
| 3746 | 3756 | }, |
| 3747 | | } |
| 3757 | else => {}, |
| 3758 | }, |
| 3759 | else => {}, |
| 3748 | 3760 | } |
| 3749 | | return sema.makePtrConst(block, alloc); |
| 3761 | |
| 3762 | if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct; |
| 3763 | const alloc_index = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr.comptime_alloc; |
| 3764 | const ct_alloc = sema.getComptimeAlloc(alloc_index); |
| 3765 | const interned = try ct_alloc.val.intern(ct_alloc.ty, mod); |
| 3766 | if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) { |
| 3767 | // Preserve the comptime alloc, just make the pointer const. |
| 3768 | ct_alloc.val = Value.fromInterned(interned); |
| 3769 | ct_alloc.is_const = true; |
| 3770 | return sema.makePtrConst(block, alloc); |
| 3771 | } else { |
| 3772 | // Promote the constant to an anon decl. |
| 3773 | const new_mut_ptr = Air.internedToRef(try mod.intern(.{ .ptr = .{ |
| 3774 | .ty = alloc_ty.toIntern(), |
| 3775 | .addr = .{ .anon_decl = .{ |
| 3776 | .val = interned, |
| 3777 | .orig_ty = alloc_ty.toIntern(), |
| 3778 | } }, |
| 3779 | } })); |
| 3780 | return sema.makePtrConst(block, new_mut_ptr); |
| 3781 | } |
| 3782 | } |
| 3783 | |
| 3784 | // Otherwise, check if the alloc is comptime-known despite being in a runtime scope. |
| 3785 | if (try sema.resolveComptimeKnownAllocPtr(block, alloc, null)) |ptr_val| { |
| 3786 | return sema.makePtrConst(block, Air.internedToRef(ptr_val)); |
| 3750 | 3787 | } |
| 3751 | 3788 | |
| 3752 | 3789 | if (try sema.typeRequiresComptime(elem_ty)) { |
| ... | ... | @@ -3762,7 +3799,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3762 | 3799 | |
| 3763 | 3800 | /// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved |
| 3764 | 3801 | /// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`. |
| 3765 | | fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index { |
| 3802 | fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index { |
| 3766 | 3803 | const mod = sema.mod; |
| 3767 | 3804 | |
| 3768 | 3805 | const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc); |
| ... | ... | @@ -3771,7 +3808,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re |
| 3771 | 3808 | |
| 3772 | 3809 | const alloc_inst = alloc.toIndex() orelse return null; |
| 3773 | 3810 | const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null; |
| 3774 | | const stores = comptime_info.value.stores.items; |
| 3811 | const stores = comptime_info.value.stores.items(.inst); |
| 3775 | 3812 | |
| 3776 | 3813 | // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known. |
| 3777 | 3814 | // We will resolve and return its value. |
| ... | ... | @@ -3779,7 +3816,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re |
| 3779 | 3816 | // We expect to have emitted at least one store, unless the elem type is OPV. |
| 3780 | 3817 | if (stores.len == 0) { |
| 3781 | 3818 | const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern(); |
| 3782 | | return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value); |
| 3819 | return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value); |
| 3783 | 3820 | } |
| 3784 | 3821 | |
| 3785 | 3822 | // In general, we want to create a comptime alloc of the correct type and |
| ... | ... | @@ -3794,28 +3831,23 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re |
| 3794 | 3831 | |
| 3795 | 3832 | const val = store_data.rhs.toInterned().?; |
| 3796 | 3833 | assert(mod.intern_pool.typeOf(val) == elem_ty.toIntern()); |
| 3797 | | return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value); |
| 3834 | return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value); |
| 3798 | 3835 | } |
| 3799 | 3836 | |
| 3800 | 3837 | // The simple strategy failed: we must create a mutable comptime alloc and |
| 3801 | 3838 | // perform all of the runtime store operations at comptime. |
| 3802 | 3839 | |
| 3803 | | var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl |
| 3804 | | defer anon_decl.deinit(); |
| 3805 | | const decl_index = try anon_decl.finish(elem_ty, try mod.undefValue(elem_ty), ptr_info.flags.alignment); |
| 3840 | const ct_alloc = try sema.newComptimeAlloc(block, elem_ty, ptr_info.flags.alignment); |
| 3806 | 3841 | |
| 3807 | | const decl_ptr = try mod.intern(.{ .ptr = .{ |
| 3842 | const alloc_ptr = try mod.intern(.{ .ptr = .{ |
| 3808 | 3843 | .ty = alloc_ty.toIntern(), |
| 3809 | | .addr = .{ .mut_decl = .{ |
| 3810 | | .decl = decl_index, |
| 3811 | | .runtime_index = block.runtime_index, |
| 3812 | | } }, |
| 3844 | .addr = .{ .comptime_alloc = ct_alloc }, |
| 3813 | 3845 | } }); |
| 3814 | 3846 | |
| 3815 | | // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the mut decl. |
| 3847 | // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the comptime alloc |
| 3816 | 3848 | var ptr_mapping = std.AutoHashMap(Air.Inst.Index, InternPool.Index).init(sema.arena); |
| 3817 | 3849 | try ptr_mapping.ensureTotalCapacity(@intCast(stores.len)); |
| 3818 | | ptr_mapping.putAssumeCapacity(alloc_inst, decl_ptr); |
| 3850 | ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr); |
| 3819 | 3851 | |
| 3820 | 3852 | var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len); |
| 3821 | 3853 | for (stores) |store_inst| { |
| ... | ... | @@ -3953,14 +3985,27 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re |
| 3953 | 3985 | } |
| 3954 | 3986 | |
| 3955 | 3987 | // The value is finalized - load it! |
| 3956 | | const val = (try sema.pointerDeref(block, .unneeded, Value.fromInterned(decl_ptr), alloc_ty)).?.toIntern(); |
| 3957 | | return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value); |
| 3988 | const val = (try sema.pointerDeref(block, .unneeded, Value.fromInterned(alloc_ptr), alloc_ty)).?.toIntern(); |
| 3989 | return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, ct_alloc, alloc_inst, comptime_info.value); |
| 3958 | 3990 | } |
| 3959 | 3991 | |
| 3960 | 3992 | /// Given the resolved comptime-known value, rewrites the dead AIR to not |
| 3961 | | /// create a runtime stack allocation. |
| 3962 | | /// Same return type as `resolveComptimeKnownAllocValue` so we can tail call. |
| 3963 | | fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Index, alloc_inst: Air.Inst.Index, comptime_info: MaybeComptimeAlloc) CompileError!?InternPool.Index { |
| 3993 | /// create a runtime stack allocation. Also places the resulting value into |
| 3994 | /// either an anon decl ref or a comptime alloc depending on whether it |
| 3995 | /// references comptime-mutable memory. If `existing_comptime_alloc` is |
| 3996 | /// passed, it is a scratch allocation which already contains `result_val`. |
| 3997 | /// Same return type as `resolveComptimeKnownAllocPtr` so we can tail call. |
| 3998 | fn finishResolveComptimeKnownAllocPtr( |
| 3999 | sema: *Sema, |
| 4000 | block: *Block, |
| 4001 | alloc_ty: Type, |
| 4002 | result_val: InternPool.Index, |
| 4003 | existing_comptime_alloc: ?ComptimeAllocIndex, |
| 4004 | alloc_inst: Air.Inst.Index, |
| 4005 | comptime_info: MaybeComptimeAlloc, |
| 4006 | ) CompileError!?InternPool.Index { |
| 4007 | const zcu = sema.mod; |
| 4008 | |
| 3964 | 4009 | // We're almost done - we have the resolved comptime value. We just need to |
| 3965 | 4010 | // eliminate the now-dead runtime instructions. |
| 3966 | 4011 | |
| ... | ... | @@ -3974,14 +4019,34 @@ fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Inde |
| 3974 | 4019 | const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } }; |
| 3975 | 4020 | |
| 3976 | 4021 | sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst); |
| 3977 | | for (comptime_info.stores.items) |store_inst| { |
| 4022 | for (comptime_info.stores.items(.inst)) |store_inst| { |
| 3978 | 4023 | sema.air_instructions.set(@intFromEnum(store_inst), nop_inst); |
| 3979 | 4024 | } |
| 3980 | 4025 | for (comptime_info.non_elideable_pointers.items) |ptr_inst| { |
| 3981 | 4026 | sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst); |
| 3982 | 4027 | } |
| 3983 | 4028 | |
| 3984 | | return result_val; |
| 4029 | if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) { |
| 4030 | const alloc_index = existing_comptime_alloc orelse a: { |
| 4031 | const idx = try sema.newComptimeAlloc(block, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu)); |
| 4032 | const alloc = sema.getComptimeAlloc(idx); |
| 4033 | alloc.val = Value.fromInterned(result_val); |
| 4034 | break :a idx; |
| 4035 | }; |
| 4036 | sema.getComptimeAlloc(alloc_index).is_const = true; |
| 4037 | return try zcu.intern(.{ .ptr = .{ |
| 4038 | .ty = alloc_ty.toIntern(), |
| 4039 | .addr = .{ .comptime_alloc = alloc_index }, |
| 4040 | } }); |
| 4041 | } else { |
| 4042 | return try zcu.intern(.{ .ptr = .{ |
| 4043 | .ty = alloc_ty.toIntern(), |
| 4044 | .addr = .{ .anon_decl = .{ |
| 4045 | .orig_ty = alloc_ty.toIntern(), |
| 4046 | .val = result_val, |
| 4047 | } }, |
| 4048 | } }); |
| 4049 | } |
| 3985 | 4050 | } |
| 3986 | 4051 | |
| 3987 | 4052 | fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type { |
| ... | ... | @@ -4011,9 +4076,9 @@ fn zirAllocInferredComptime( |
| 4011 | 4076 | try sema.air_instructions.append(gpa, .{ |
| 4012 | 4077 | .tag = .inferred_alloc_comptime, |
| 4013 | 4078 | .data = .{ .inferred_alloc_comptime = .{ |
| 4014 | | .decl_index = undefined, |
| 4015 | 4079 | .alignment = .none, |
| 4016 | 4080 | .is_const = is_const, |
| 4081 | .ptr = undefined, |
| 4017 | 4082 | } }, |
| 4018 | 4083 | }); |
| 4019 | 4084 | return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef(); |
| ... | ... | @@ -4076,9 +4141,9 @@ fn zirAllocInferred( |
| 4076 | 4141 | try sema.air_instructions.append(gpa, .{ |
| 4077 | 4142 | .tag = .inferred_alloc_comptime, |
| 4078 | 4143 | .data = .{ .inferred_alloc_comptime = .{ |
| 4079 | | .decl_index = undefined, |
| 4080 | 4144 | .alignment = .none, |
| 4081 | 4145 | .is_const = is_const, |
| 4146 | .ptr = undefined, |
| 4082 | 4147 | } }, |
| 4083 | 4148 | }); |
| 4084 | 4149 | return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef(); |
| ... | ... | @@ -4092,8 +4157,10 @@ fn zirAllocInferred( |
| 4092 | 4157 | } }, |
| 4093 | 4158 | }); |
| 4094 | 4159 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); |
| 4095 | | try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index }); |
| 4096 | | try sema.base_allocs.put(sema.gpa, result_index, result_index); |
| 4160 | if (is_const) { |
| 4161 | try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index }); |
| 4162 | try sema.base_allocs.put(sema.gpa, result_index, result_index); |
| 4163 | } |
| 4097 | 4164 | return result_index.toRef(); |
| 4098 | 4165 | } |
| 4099 | 4166 | |
| ... | ... | @@ -4112,38 +4179,33 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4112 | 4179 | |
| 4113 | 4180 | switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) { |
| 4114 | 4181 | .inferred_alloc_comptime => { |
| 4182 | // The work was already done for us by `Sema.storeToInferredAllocComptime`. |
| 4183 | // All we need to do is remap the pointer. |
| 4115 | 4184 | const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime; |
| 4116 | | const decl_index = iac.decl_index; |
| 4117 | | |
| 4118 | | const decl = mod.declPtr(decl_index); |
| 4119 | | if (iac.is_const) _ = try decl.internValue(mod); |
| 4120 | | const final_elem_ty = decl.ty; |
| 4121 | | const final_ptr_ty = try sema.ptrType(.{ |
| 4122 | | .child = final_elem_ty.toIntern(), |
| 4123 | | .flags = .{ |
| 4124 | | .is_const = false, |
| 4125 | | .alignment = iac.alignment, |
| 4126 | | .address_space = target_util.defaultAddressSpace(target, .local), |
| 4127 | | }, |
| 4128 | | }); |
| 4185 | const resolved_ptr = iac.ptr; |
| 4129 | 4186 | |
| 4130 | 4187 | if (std.debug.runtime_safety) { |
| 4131 | 4188 | // The inferred_alloc_comptime should never be referenced again |
| 4132 | 4189 | sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined }); |
| 4133 | 4190 | } |
| 4134 | 4191 | |
| 4135 | | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 4136 | | |
| 4137 | | const interned = try mod.intern(.{ .ptr = .{ |
| 4138 | | .ty = final_ptr_ty.toIntern(), |
| 4139 | | .addr = if (!iac.is_const) .{ .mut_decl = .{ |
| 4140 | | .decl = decl_index, |
| 4141 | | .runtime_index = block.runtime_index, |
| 4142 | | } } else .{ .decl = decl_index }, |
| 4143 | | } }); |
| 4192 | const val = switch (mod.intern_pool.indexToKey(resolved_ptr).ptr.addr) { |
| 4193 | .anon_decl => |a| a.val, |
| 4194 | .comptime_alloc => |i| val: { |
| 4195 | const alloc = sema.getComptimeAlloc(i); |
| 4196 | break :val try alloc.val.intern(alloc.ty, mod); |
| 4197 | }, |
| 4198 | else => unreachable, |
| 4199 | }; |
| 4200 | if (mod.intern_pool.isFuncBody(val)) { |
| 4201 | const ty = Type.fromInterned(mod.intern_pool.typeOf(val)); |
| 4202 | if (try sema.fnHasRuntimeBits(ty)) { |
| 4203 | try mod.ensureFuncBodyAnalysisQueued(val); |
| 4204 | } |
| 4205 | } |
| 4144 | 4206 | |
| 4145 | 4207 | // Remap the ZIR operand to the resolved pointer value |
| 4146 | | sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(interned)); |
| 4208 | sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(resolved_ptr)); |
| 4147 | 4209 | }, |
| 4148 | 4210 | .inferred_alloc => { |
| 4149 | 4211 | const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc; |
| ... | ... | @@ -4166,18 +4228,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4166 | 4228 | |
| 4167 | 4229 | if (!ia1.is_const) { |
| 4168 | 4230 | try sema.validateVarType(block, ty_src, final_elem_ty, false); |
| 4169 | | } else if (try sema.resolveComptimeKnownAllocValue(block, ptr, final_ptr_ty)) |val| { |
| 4170 | | const const_ptr_ty = (try sema.makePtrTyConst(final_ptr_ty)).toIntern(); |
| 4171 | | const new_const_ptr = try mod.intern(.{ .ptr = .{ |
| 4172 | | .ty = const_ptr_ty, |
| 4173 | | .addr = .{ .anon_decl = .{ |
| 4174 | | .val = val, |
| 4175 | | .orig_ty = const_ptr_ty, |
| 4176 | | } }, |
| 4177 | | } }); |
| 4231 | } else if (try sema.resolveComptimeKnownAllocPtr(block, ptr, final_ptr_ty)) |ptr_val| { |
| 4232 | const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty); |
| 4233 | const new_const_ptr = try mod.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty); |
| 4178 | 4234 | |
| 4179 | 4235 | // Remap the ZIR oeprand to the resolved pointer value |
| 4180 | | sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(new_const_ptr)); |
| 4236 | sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(new_const_ptr.toIntern())); |
| 4181 | 4237 | |
| 4182 | 4238 | // Unless the block is comptime, `alloc_inferred` always produces |
| 4183 | 4239 | // a runtime constant. The final inferred type needs to be |
| ... | ... | @@ -4387,7 +4443,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL |
| 4387 | 4443 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), |
| 4388 | 4444 | else => break, |
| 4389 | 4445 | }; |
| 4390 | | try sema.checkKnownAllocPtr(ptr, base_ptr); |
| 4446 | try sema.checkKnownAllocPtr(block, ptr, base_ptr); |
| 4391 | 4447 | return base_ptr; |
| 4392 | 4448 | } |
| 4393 | 4449 | |
| ... | ... | @@ -4703,6 +4759,7 @@ fn validateUnionInit( |
| 4703 | 4759 | var first_block_index = block.instructions.items.len; |
| 4704 | 4760 | var block_index = block.instructions.items.len - 1; |
| 4705 | 4761 | var init_val: ?Value = null; |
| 4762 | var init_ref: ?Air.Inst.Ref = null; |
| 4706 | 4763 | while (block_index > 0) : (block_index -= 1) { |
| 4707 | 4764 | const store_inst = block.instructions.items[block_index]; |
| 4708 | 4765 | if (store_inst.toRef() == field_ptr_ref) { |
| ... | ... | @@ -4727,6 +4784,7 @@ fn validateUnionInit( |
| 4727 | 4784 | ).? |
| 4728 | 4785 | else |
| 4729 | 4786 | block_index, first_block_index); |
| 4787 | init_ref = bin_op.rhs; |
| 4730 | 4788 | init_val = try sema.resolveValue(bin_op.rhs); |
| 4731 | 4789 | break; |
| 4732 | 4790 | } |
| ... | ... | @@ -4779,10 +4837,11 @@ fn validateUnionInit( |
| 4779 | 4837 | .needed_comptime_reason = "initializer of comptime only union must be comptime-known", |
| 4780 | 4838 | }); |
| 4781 | 4839 | } |
| 4840 | if (init_ref) |v| try sema.validateRuntimeValue(block, field_ptr_data.src(), v); |
| 4782 | 4841 | |
| 4783 | 4842 | const new_tag = Air.internedToRef(tag_val.toIntern()); |
| 4784 | 4843 | const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag); |
| 4785 | | try sema.checkComptimeKnownStore(block, set_tag_inst); |
| 4844 | try sema.checkComptimeKnownStore(block, set_tag_inst, init_src); |
| 4786 | 4845 | } |
| 4787 | 4846 | |
| 4788 | 4847 | fn validateStructInit( |
| ... | ... | @@ -4887,6 +4946,8 @@ fn validateStructInit( |
| 4887 | 4946 | return; |
| 4888 | 4947 | } |
| 4889 | 4948 | |
| 4949 | var fields_allow_runtime = true; |
| 4950 | |
| 4890 | 4951 | var struct_is_comptime = true; |
| 4891 | 4952 | var first_block_index = block.instructions.items.len; |
| 4892 | 4953 | |
| ... | ... | @@ -4957,6 +5018,7 @@ fn validateStructInit( |
| 4957 | 5018 | ).? |
| 4958 | 5019 | else |
| 4959 | 5020 | block_index, first_block_index); |
| 5021 | if (!sema.checkRuntimeValue(bin_op.rhs)) fields_allow_runtime = false; |
| 4960 | 5022 | if (try sema.resolveValue(bin_op.rhs)) |val| { |
| 4961 | 5023 | field_values[i] = val.toIntern(); |
| 4962 | 5024 | } else if (require_comptime) { |
| ... | ... | @@ -4996,6 +5058,11 @@ fn validateStructInit( |
| 4996 | 5058 | field_values[i] = default_val.toIntern(); |
| 4997 | 5059 | } |
| 4998 | 5060 | |
| 5061 | if (!struct_is_comptime and !fields_allow_runtime and root_msg == null) { |
| 5062 | root_msg = try sema.errMsg(block, init_src, "runtime value contains reference to comptime var", .{}); |
| 5063 | try sema.errNote(block, init_src, root_msg.?, "comptime var pointers are not available at runtime", .{}); |
| 5064 | } |
| 5065 | |
| 4999 | 5066 | if (root_msg) |msg| { |
| 5000 | 5067 | if (mod.typeToStruct(struct_ty)) |struct_type| { |
| 5001 | 5068 | const decl = mod.declPtr(struct_type.decl.unwrap().?); |
| ... | ... | @@ -5067,7 +5134,7 @@ fn validateStructInit( |
| 5067 | 5134 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true) |
| 5068 | 5135 | else |
| 5069 | 5136 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), field_src, struct_ty, true); |
| 5070 | | try sema.checkKnownAllocPtr(struct_ptr, default_field_ptr); |
| 5137 | try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr); |
| 5071 | 5138 | const init = Air.internedToRef(field_values[i]); |
| 5072 | 5139 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| 5073 | 5140 | } |
| ... | ... | @@ -5474,7 +5541,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 5474 | 5541 | }, |
| 5475 | 5542 | .inferred_alloc => { |
| 5476 | 5543 | const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; |
| 5477 | | return sema.storeToInferredAlloc(block, ptr, operand, ia); |
| 5544 | return sema.storeToInferredAlloc(block, src, ptr, operand, ia); |
| 5478 | 5545 | }, |
| 5479 | 5546 | else => unreachable, |
| 5480 | 5547 | } |
| ... | ... | @@ -5483,6 +5550,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 5483 | 5550 | fn storeToInferredAlloc( |
| 5484 | 5551 | sema: *Sema, |
| 5485 | 5552 | block: *Block, |
| 5553 | src: LazySrcLoc, |
| 5486 | 5554 | ptr: Air.Inst.Ref, |
| 5487 | 5555 | operand: Air.Inst.Ref, |
| 5488 | 5556 | inferred_alloc: *InferredAlloc, |
| ... | ... | @@ -5490,7 +5558,7 @@ fn storeToInferredAlloc( |
| 5490 | 5558 | // Create a store instruction as a placeholder. This will be replaced by a |
| 5491 | 5559 | // proper store sequence once we know the stored type. |
| 5492 | 5560 | const dummy_store = try block.addBinOp(.store, ptr, operand); |
| 5493 | | try sema.checkComptimeKnownStore(block, dummy_store); |
| 5561 | try sema.checkComptimeKnownStore(block, dummy_store, src); |
| 5494 | 5562 | // Add the stored instruction to the set we will use to resolve peer types |
| 5495 | 5563 | // for the inferred allocation. |
| 5496 | 5564 | try inferred_alloc.prongs.append(sema.arena, dummy_store.toIndex().?); |
| ... | ... | @@ -5503,20 +5571,38 @@ fn storeToInferredAllocComptime( |
| 5503 | 5571 | operand: Air.Inst.Ref, |
| 5504 | 5572 | iac: *Air.Inst.Data.InferredAllocComptime, |
| 5505 | 5573 | ) CompileError!void { |
| 5574 | const zcu = sema.mod; |
| 5506 | 5575 | const operand_ty = sema.typeOf(operand); |
| 5507 | 5576 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 5508 | | // The alloc will turn into a Decl. |
| 5509 | | if (try sema.resolveValue(operand)) |operand_val| { |
| 5510 | | var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl |
| 5511 | | defer anon_decl.deinit(); |
| 5512 | | iac.decl_index = try anon_decl.finish(operand_ty, operand_val, iac.alignment); |
| 5513 | | try sema.comptime_mutable_decls.append(iac.decl_index); |
| 5514 | | return; |
| 5515 | | } |
| 5516 | | |
| 5517 | | return sema.failWithNeededComptime(block, src, .{ |
| 5518 | | .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known", |
| 5577 | // The alloc will turn into a Decl or a ComptimeAlloc. |
| 5578 | const operand_val = try sema.resolveValue(operand) orelse { |
| 5579 | return sema.failWithNeededComptime(block, src, .{ |
| 5580 | .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known", |
| 5581 | }); |
| 5582 | }; |
| 5583 | const alloc_ty = try sema.ptrType(.{ |
| 5584 | .child = operand_ty.toIntern(), |
| 5585 | .flags = .{ |
| 5586 | .alignment = iac.alignment, |
| 5587 | .is_const = iac.is_const, |
| 5588 | }, |
| 5519 | 5589 | }); |
| 5590 | if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) { |
| 5591 | iac.ptr = try zcu.intern(.{ .ptr = .{ |
| 5592 | .ty = alloc_ty.toIntern(), |
| 5593 | .addr = .{ .anon_decl = .{ |
| 5594 | .val = operand_val.toIntern(), |
| 5595 | .orig_ty = alloc_ty.toIntern(), |
| 5596 | } }, |
| 5597 | } }); |
| 5598 | } else { |
| 5599 | const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment); |
| 5600 | sema.getComptimeAlloc(alloc_index).val = operand_val; |
| 5601 | iac.ptr = try zcu.intern(.{ .ptr = .{ |
| 5602 | .ty = alloc_ty.toIntern(), |
| 5603 | .addr = .{ .comptime_alloc = alloc_index }, |
| 5604 | } }); |
| 5605 | } |
| 5520 | 5606 | } |
| 5521 | 5607 | |
| 5522 | 5608 | fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -6178,6 +6264,9 @@ fn resolveAnalyzedBlock( |
| 6178 | 6264 | }; |
| 6179 | 6265 | return sema.failWithOwnedErrorMsg(child_block, msg); |
| 6180 | 6266 | } |
| 6267 | for (merges.results.items, merges.src_locs.items) |merge_inst, merge_src| { |
| 6268 | try sema.validateRuntimeValue(child_block, merge_src orelse src, merge_inst); |
| 6269 | } |
| 6181 | 6270 | const ty_inst = Air.internedToRef(resolved_ty.toIntern()); |
| 6182 | 6271 | switch (block_tag) { |
| 6183 | 6272 | .block => { |
| ... | ... | @@ -6579,6 +6668,9 @@ fn addDbgVar( |
| 6579 | 6668 | }; |
| 6580 | 6669 | if (try sema.typeRequiresComptime(val_ty)) return; |
| 6581 | 6670 | if (!(try sema.typeHasRuntimeBits(val_ty))) return; |
| 6671 | if (try sema.resolveValue(operand)) |operand_val| { |
| 6672 | if (operand_val.canMutateComptimeVarState(mod)) return; |
| 6673 | } |
| 6582 | 6674 | |
| 6583 | 6675 | // To ensure the lexical scoping is known to backends, this alloc must be |
| 6584 | 6676 | // within a real runtime block. We set a flag which communicates information |
| ... | ... | @@ -7741,20 +7833,24 @@ fn analyzeCall( |
| 7741 | 7833 | break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope); |
| 7742 | 7834 | }; |
| 7743 | 7835 | |
| 7744 | | if (should_memoize and is_comptime_call) { |
| 7836 | if (is_comptime_call) { |
| 7745 | 7837 | const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined); |
| 7746 | 7838 | const result_interned = try result_val.intern2(sema.fn_ret_ty, mod); |
| 7747 | 7839 | |
| 7748 | 7840 | // Transform ad-hoc inferred error set types into concrete error sets. |
| 7749 | 7841 | const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned); |
| 7750 | 7842 | |
| 7843 | // If the result can mutate comptime vars, we must not memoize it, as it contains |
| 7844 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. |
| 7751 | 7845 | // TODO: check whether any external comptime memory was mutated by the |
| 7752 | 7846 | // comptime function call. If so, then do not memoize the call here. |
| 7753 | | _ = try mod.intern(.{ .memoized_call = .{ |
| 7754 | | .func = module_fn_index, |
| 7755 | | .arg_values = memoized_arg_values, |
| 7756 | | .result = result_transformed, |
| 7757 | | } }); |
| 7847 | if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(mod)) { |
| 7848 | _ = try mod.intern(.{ .memoized_call = .{ |
| 7849 | .func = module_fn_index, |
| 7850 | .arg_values = memoized_arg_values, |
| 7851 | .result = result_transformed, |
| 7852 | } }); |
| 7853 | } |
| 7758 | 7854 | |
| 7759 | 7855 | break :res2 Air.internedToRef(result_transformed); |
| 7760 | 7856 | } |
| ... | ... | @@ -7787,6 +7883,7 @@ fn analyzeCall( |
| 7787 | 7883 | } else Type.fromInterned(InternPool.Index.var_args_param_type); |
| 7788 | 7884 | assert(!param_ty.isGenericPoison()); |
| 7789 | 7885 | arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func); |
| 7886 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*); |
| 7790 | 7887 | if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) { |
| 7791 | 7888 | return arg_out.*; |
| 7792 | 7889 | } |
| ... | ... | @@ -8082,7 +8179,6 @@ fn instantiateGenericCall( |
| 8082 | 8179 | .generic_call_decl = block.src_decl.toOptional(), |
| 8083 | 8180 | .branch_quota = sema.branch_quota, |
| 8084 | 8181 | .branch_count = sema.branch_count, |
| 8085 | | .comptime_mutable_decls = sema.comptime_mutable_decls, |
| 8086 | 8182 | .comptime_err_ret_trace = sema.comptime_err_ret_trace, |
| 8087 | 8183 | }; |
| 8088 | 8184 | defer child_sema.deinit(); |
| ... | ... | @@ -8147,6 +8243,7 @@ fn instantiateGenericCall( |
| 8147 | 8243 | }, |
| 8148 | 8244 | }; |
| 8149 | 8245 | const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func); |
| 8246 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_index), arg_ref); |
| 8150 | 8247 | const arg_ty = sema.typeOf(arg_ref); |
| 8151 | 8248 | if (arg_ty.zigTypeTag(mod) == .NoReturn) { |
| 8152 | 8249 | // This terminates argument analysis. |
| ... | ... | @@ -8859,12 +8956,12 @@ fn analyzeOptionalPayloadPtr( |
| 8859 | 8956 | |
| 8860 | 8957 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { |
| 8861 | 8958 | if (initializing) { |
| 8862 | | if (!ptr_val.isComptimeMutablePtr(mod)) { |
| 8959 | if (!sema.isComptimeMutablePtr(ptr_val)) { |
| 8863 | 8960 | // If the pointer resulting from this function was stored at comptime, |
| 8864 | 8961 | // the optional non-null bit would be set that way. But in this case, |
| 8865 | 8962 | // we need to emit a runtime instruction to do it. |
| 8866 | 8963 | const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); |
| 8867 | | try sema.checkKnownAllocPtr(optional_ptr, opt_payload_ptr); |
| 8964 | try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr); |
| 8868 | 8965 | } |
| 8869 | 8966 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ |
| 8870 | 8967 | .ty = child_pointer.toIntern(), |
| ... | ... | @@ -8891,7 +8988,7 @@ fn analyzeOptionalPayloadPtr( |
| 8891 | 8988 | |
| 8892 | 8989 | if (initializing) { |
| 8893 | 8990 | const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); |
| 8894 | | try sema.checkKnownAllocPtr(optional_ptr, opt_payload_ptr); |
| 8991 | try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr); |
| 8895 | 8992 | return opt_payload_ptr; |
| 8896 | 8993 | } else { |
| 8897 | 8994 | return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr); |
| ... | ... | @@ -9050,13 +9147,13 @@ fn analyzeErrUnionPayloadPtr( |
| 9050 | 9147 | |
| 9051 | 9148 | if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { |
| 9052 | 9149 | if (initializing) { |
| 9053 | | if (!ptr_val.isComptimeMutablePtr(mod)) { |
| 9150 | if (!sema.isComptimeMutablePtr(ptr_val)) { |
| 9054 | 9151 | // If the pointer resulting from this function was stored at comptime, |
| 9055 | 9152 | // the error union error code would be set that way. But in this case, |
| 9056 | 9153 | // we need to emit a runtime instruction to do it. |
| 9057 | 9154 | try sema.requireRuntimeBlock(block, src, null); |
| 9058 | 9155 | const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); |
| 9059 | | try sema.checkKnownAllocPtr(operand, eu_payload_ptr); |
| 9156 | try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr); |
| 9060 | 9157 | } |
| 9061 | 9158 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ |
| 9062 | 9159 | .ty = operand_pointer_ty.toIntern(), |
| ... | ... | @@ -9085,7 +9182,7 @@ fn analyzeErrUnionPayloadPtr( |
| 9085 | 9182 | |
| 9086 | 9183 | if (initializing) { |
| 9087 | 9184 | const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); |
| 9088 | | try sema.checkKnownAllocPtr(operand, eu_payload_ptr); |
| 9185 | try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr); |
| 9089 | 9186 | return eu_payload_ptr; |
| 9090 | 9187 | } else { |
| 9091 | 9188 | return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand); |
| ... | ... | @@ -10089,6 +10186,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 10089 | 10186 | } })); |
| 10090 | 10187 | } |
| 10091 | 10188 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); |
| 10189 | try sema.validateRuntimeValue(block, ptr_src, operand); |
| 10092 | 10190 | if (!is_vector) { |
| 10093 | 10191 | return block.addUnOp(.int_from_ptr, operand); |
| 10094 | 10192 | } |
| ... | ... | @@ -14743,7 +14841,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14743 | 14841 | // Optimization for the common pattern of a single element repeated N times, such |
| 14744 | 14842 | // as zero-filling a byte array. |
| 14745 | 14843 | if (lhs_len == 1 and lhs_info.sentinel == null) { |
| 14746 | | const elem_val = try lhs_sub_val.elemValue(mod, 0); |
| 14844 | const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, 0)).?; |
| 14747 | 14845 | break :v try mod.intern(.{ .aggregate = .{ |
| 14748 | 14846 | .ty = result_ty.toIntern(), |
| 14749 | 14847 | .storage = .{ .repeated_elem = elem_val.toIntern() }, |
| ... | ... | @@ -14755,7 +14853,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14755 | 14853 | while (elem_i < result_len) { |
| 14756 | 14854 | var lhs_i: usize = 0; |
| 14757 | 14855 | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 14758 | | const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); |
| 14856 | const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, lhs_i)).?; |
| 14759 | 14857 | element_vals[elem_i] = elem_val.toIntern(); |
| 14760 | 14858 | elem_i += 1; |
| 14761 | 14859 | } |
| ... | ... | @@ -19585,6 +19683,8 @@ fn analyzeRet( |
| 19585 | 19683 | |
| 19586 | 19684 | try sema.resolveTypeLayout(sema.fn_ret_ty); |
| 19587 | 19685 | |
| 19686 | try sema.validateRuntimeValue(block, operand_src, operand); |
| 19687 | |
| 19588 | 19688 | const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret; |
| 19589 | 19689 | if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) { |
| 19590 | 19690 | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| ... | ... | @@ -20013,6 +20113,8 @@ fn zirStructInit( |
| 20013 | 20113 | }); |
| 20014 | 20114 | } |
| 20015 | 20115 | |
| 20116 | try sema.validateRuntimeValue(block, field_src, init_inst); |
| 20117 | |
| 20016 | 20118 | if (is_ref) { |
| 20017 | 20119 | const target = mod.getTarget(); |
| 20018 | 20120 | const alloc_ty = try sema.ptrType(.{ |
| ... | ... | @@ -20187,6 +20289,10 @@ fn finishStructInit( |
| 20187 | 20289 | }); |
| 20188 | 20290 | } |
| 20189 | 20291 | |
| 20292 | for (field_inits) |field_init| { |
| 20293 | try sema.validateRuntimeValue(block, dest_src, field_init); |
| 20294 | } |
| 20295 | |
| 20190 | 20296 | if (is_ref) { |
| 20191 | 20297 | try sema.resolveStructLayout(struct_ty); |
| 20192 | 20298 | const target = sema.mod.getTarget(); |
| ... | ... | @@ -21023,7 +21129,7 @@ fn zirReify( |
| 21023 | 21129 | .needed_comptime_reason = "operand to @Type must be comptime-known", |
| 21024 | 21130 | }); |
| 21025 | 21131 | const union_val = ip.indexToKey(val.toIntern()).un; |
| 21026 | | if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src); |
| 21132 | if (try sema.anyUndef(Value.fromInterned(union_val.val))) return sema.failWithUseOfUndef(block, src); |
| 21027 | 21133 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; |
| 21028 | 21134 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| 21029 | 21135 | .Type => return .type_type, |
| ... | ... | @@ -21268,14 +21374,16 @@ fn zirReify( |
| 21268 | 21374 | var names: InferredErrorSet.NameMap = .{}; |
| 21269 | 21375 | try names.ensureUnusedCapacity(sema.arena, len); |
| 21270 | 21376 | for (0..len) |i| { |
| 21271 | | const elem_val = try payload_val.elemValue(mod, i); |
| 21377 | const elem_val = (try payload_val.maybeElemValueFull(sema, mod, i)).?; |
| 21272 | 21378 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21273 | 21379 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21274 | 21380 | ip, |
| 21275 | 21381 | try ip.getOrPutString(gpa, "name"), |
| 21276 | 21382 | ).?); |
| 21277 | 21383 | |
| 21278 | | const name = try name_val.toIpString(Type.slice_const_u8, mod); |
| 21384 | const name = try sema.sliceToIpString(block, src, name_val, .{ |
| 21385 | .needed_comptime_reason = "error set contents must be comptime-known", |
| 21386 | }); |
| 21279 | 21387 | _ = try mod.getErrorValue(name); |
| 21280 | 21388 | const gop = names.getOrPutAssumeCapacity(name); |
| 21281 | 21389 | if (gop.found_existing) { |
| ... | ... | @@ -21451,7 +21559,7 @@ fn zirReify( |
| 21451 | 21559 | |
| 21452 | 21560 | var noalias_bits: u32 = 0; |
| 21453 | 21561 | for (param_types, 0..) |*param_type, i| { |
| 21454 | | const elem_val = try params_val.elemValue(mod, i); |
| 21562 | const elem_val = (try params_val.maybeElemValueFull(sema, mod, i)).?; |
| 21455 | 21563 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21456 | 21564 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21457 | 21565 | ip, |
| ... | ... | @@ -21526,12 +21634,14 @@ fn reifyEnum( |
| 21526 | 21634 | std.hash.autoHash(&hasher, fields_len); |
| 21527 | 21635 | |
| 21528 | 21636 | for (0..fields_len) |field_idx| { |
| 21529 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21637 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21530 | 21638 | |
| 21531 | 21639 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21532 | 21640 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| 21533 | 21641 | |
| 21534 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 21642 | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ |
| 21643 | .needed_comptime_reason = "enum field name must be comptime-known", |
| 21644 | }); |
| 21535 | 21645 | |
| 21536 | 21646 | std.hash.autoHash(&hasher, .{ |
| 21537 | 21647 | field_name, |
| ... | ... | @@ -21569,12 +21679,13 @@ fn reifyEnum( |
| 21569 | 21679 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21570 | 21680 | |
| 21571 | 21681 | for (0..fields_len) |field_idx| { |
| 21572 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21682 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21573 | 21683 | |
| 21574 | 21684 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21575 | 21685 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| 21576 | 21686 | |
| 21577 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 21687 | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21688 | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21578 | 21689 | |
| 21579 | 21690 | if (!try sema.intFitsInType(field_value_val, tag_ty, null)) { |
| 21580 | 21691 | // TODO: better source location |
| ... | ... | @@ -21646,13 +21757,15 @@ fn reifyUnion( |
| 21646 | 21757 | var any_aligns = false; |
| 21647 | 21758 | |
| 21648 | 21759 | for (0..fields_len) |field_idx| { |
| 21649 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21760 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21650 | 21761 | |
| 21651 | 21762 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21652 | 21763 | const field_type_val = try field_info.fieldValue(mod, 1); |
| 21653 | 21764 | const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2)); |
| 21654 | 21765 | |
| 21655 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 21766 | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ |
| 21767 | .needed_comptime_reason = "union field name must be comptime-known", |
| 21768 | }); |
| 21656 | 21769 | |
| 21657 | 21770 | std.hash.autoHash(&hasher, .{ |
| 21658 | 21771 | field_name, |
| ... | ... | @@ -21720,12 +21833,13 @@ fn reifyUnion( |
| 21720 | 21833 | var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); |
| 21721 | 21834 | |
| 21722 | 21835 | for (field_types, 0..) |*field_ty, field_idx| { |
| 21723 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21836 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21724 | 21837 | |
| 21725 | 21838 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21726 | 21839 | const field_type_val = try field_info.fieldValue(mod, 1); |
| 21727 | 21840 | |
| 21728 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 21841 | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21842 | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21729 | 21843 | |
| 21730 | 21844 | const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse { |
| 21731 | 21845 | // TODO: better source location |
| ... | ... | @@ -21771,12 +21885,13 @@ fn reifyUnion( |
| 21771 | 21885 | try field_names.ensureTotalCapacity(sema.arena, fields_len); |
| 21772 | 21886 | |
| 21773 | 21887 | for (field_types, 0..) |*field_ty, field_idx| { |
| 21774 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21888 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21775 | 21889 | |
| 21776 | 21890 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21777 | 21891 | const field_type_val = try field_info.fieldValue(mod, 1); |
| 21778 | 21892 | |
| 21779 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 21893 | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21894 | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21780 | 21895 | const gop = field_names.getOrPutAssumeCapacity(field_name); |
| 21781 | 21896 | if (gop.found_existing) { |
| 21782 | 21897 | // TODO: better source location |
| ... | ... | @@ -21883,7 +21998,7 @@ fn reifyStruct( |
| 21883 | 21998 | var any_aligned_fields = false; |
| 21884 | 21999 | |
| 21885 | 22000 | for (0..fields_len) |field_idx| { |
| 21886 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 22001 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21887 | 22002 | |
| 21888 | 22003 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21889 | 22004 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -21891,7 +22006,9 @@ fn reifyStruct( |
| 21891 | 22006 | const field_is_comptime_val = try field_info.fieldValue(mod, 3); |
| 21892 | 22007 | const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4)); |
| 21893 | 22008 | |
| 21894 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 22009 | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ |
| 22010 | .needed_comptime_reason = "struct field name must be comptime-known", |
| 22011 | }); |
| 21895 | 22012 | const field_is_comptime = field_is_comptime_val.toBool(); |
| 21896 | 22013 | const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: { |
| 21897 | 22014 | const ptr_ty = try mod.singleConstPtrType(field_type_val.toType()); |
| ... | ... | @@ -21959,7 +22076,7 @@ fn reifyStruct( |
| 21959 | 22076 | const struct_type = ip.loadStructType(wip_ty.index); |
| 21960 | 22077 | |
| 21961 | 22078 | for (0..fields_len) |field_idx| { |
| 21962 | | const field_info = try fields_val.elemValue(mod, field_idx); |
| 22079 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; |
| 21963 | 22080 | |
| 21964 | 22081 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21965 | 22082 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -21968,7 +22085,8 @@ fn reifyStruct( |
| 21968 | 22085 | const field_alignment_val = try field_info.fieldValue(mod, 4); |
| 21969 | 22086 | |
| 21970 | 22087 | const field_ty = field_type_val.toType(); |
| 21971 | | const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod); |
| 22088 | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 22089 | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21972 | 22090 | if (is_tuple) { |
| 21973 | 22091 | const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail( |
| 21974 | 22092 | block, |
| ... | ... | @@ -22914,6 +23032,7 @@ fn ptrCastFull( |
| 22914 | 23032 | } |
| 22915 | 23033 | |
| 22916 | 23034 | try sema.requireRuntimeBlock(block, src, null); |
| 23035 | try sema.validateRuntimeValue(block, operand_src, ptr); |
| 22917 | 23036 | |
| 22918 | 23037 | if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and |
| 22919 | 23038 | (try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)) or Type.fromInterned(dest_info.child).zigTypeTag(mod) == .Fn)) |
| ... | ... | @@ -22986,7 +23105,7 @@ fn ptrCastFull( |
| 22986 | 23105 | }); |
| 22987 | 23106 | } else { |
| 22988 | 23107 | assert(dest_ptr_ty.eql(dest_ty, mod)); |
| 22989 | | try sema.checkKnownAllocPtr(operand, result_ptr); |
| 23108 | try sema.checkKnownAllocPtr(block, operand, result_ptr); |
| 22990 | 23109 | return result_ptr; |
| 22991 | 23110 | } |
| 22992 | 23111 | } |
| ... | ... | @@ -23022,7 +23141,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 23022 | 23141 | |
| 23023 | 23142 | try sema.requireRuntimeBlock(block, src, null); |
| 23024 | 23143 | const new_ptr = try block.addBitCast(dest_ty, operand); |
| 23025 | | try sema.checkKnownAllocPtr(operand, new_ptr); |
| 23144 | try sema.checkKnownAllocPtr(block, operand, new_ptr); |
| 23026 | 23145 | return new_ptr; |
| 23027 | 23146 | } |
| 23028 | 23147 | |
| ... | ... | @@ -23568,7 +23687,7 @@ fn checkPtrIsNotComptimeMutable( |
| 23568 | 23687 | operand_src: LazySrcLoc, |
| 23569 | 23688 | ) CompileError!void { |
| 23570 | 23689 | _ = operand_src; |
| 23571 | | if (ptr_val.isComptimeMutablePtr(sema.mod)) { |
| 23690 | if (sema.isComptimeMutablePtr(ptr_val)) { |
| 23572 | 23691 | return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); |
| 23573 | 23692 | } |
| 23574 | 23693 | } |
| ... | ... | @@ -23577,9 +23696,10 @@ fn checkComptimeVarStore( |
| 23577 | 23696 | sema: *Sema, |
| 23578 | 23697 | block: *Block, |
| 23579 | 23698 | src: LazySrcLoc, |
| 23580 | | decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, |
| 23699 | alloc_index: ComptimeAllocIndex, |
| 23581 | 23700 | ) CompileError!void { |
| 23582 | | if (@intFromEnum(decl_ref_mut.runtime_index) < @intFromEnum(block.runtime_index)) { |
| 23701 | const runtime_index = sema.getComptimeAlloc(alloc_index).runtime_index; |
| 23702 | if (@intFromEnum(runtime_index) < @intFromEnum(block.runtime_index)) { |
| 23583 | 23703 | if (block.runtime_cond) |cond_src| { |
| 23584 | 23704 | const msg = msg: { |
| 23585 | 23705 | const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{}); |
| ... | ... | @@ -24433,7 +24553,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24433 | 24553 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 24434 | 24554 | break :rs operand_src; |
| 24435 | 24555 | }; |
| 24436 | | if (ptr_val.isComptimeMutablePtr(mod)) { |
| 24556 | if (sema.isComptimeMutablePtr(ptr_val)) { |
| 24437 | 24557 | const ptr_ty = sema.typeOf(ptr); |
| 24438 | 24558 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 24439 | 24559 | const new_val = switch (op) { |
| ... | ... | @@ -25149,7 +25269,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25149 | 25269 | } |
| 25150 | 25270 | |
| 25151 | 25271 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { |
| 25152 | | if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; |
| 25272 | if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src; |
| 25153 | 25273 | if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { |
| 25154 | 25274 | const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?; |
| 25155 | 25275 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| ... | ... | @@ -25342,7 +25462,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25342 | 25462 | return; |
| 25343 | 25463 | } |
| 25344 | 25464 | |
| 25345 | | if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; |
| 25465 | if (!sema.isComptimeMutablePtr(ptr_val)) break :rs dest_src; |
| 25346 | 25466 | const elem_val = try sema.resolveValue(elem) orelse break :rs value_src; |
| 25347 | 25467 | const array_ty = try mod.arrayType(.{ |
| 25348 | 25468 | .child = dest_elem_ty.toIntern(), |
| ... | ... | @@ -25588,7 +25708,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 25588 | 25708 | if (val.isGenericPoison()) { |
| 25589 | 25709 | break :blk .generic; |
| 25590 | 25710 | } |
| 25591 | | break :blk .{ .explicit = try val.toIpString(ty, mod) }; |
| 25711 | break :blk .{ .explicit = try sema.sliceToIpString(block, section_src, val, .{ |
| 25712 | .needed_comptime_reason = "linksection must be comptime-known", |
| 25713 | }) }; |
| 25592 | 25714 | } else if (extra.data.bits.has_section_ref) blk: { |
| 25593 | 25715 | const section_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| 25594 | 25716 | extra_index += 1; |
| ... | ... | @@ -27115,7 +27237,7 @@ fn fieldPtr( |
| 27115 | 27237 | try sema.requireRuntimeBlock(block, src, null); |
| 27116 | 27238 | |
| 27117 | 27239 | const field_ptr = try block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); |
| 27118 | | try sema.checkKnownAllocPtr(inner_ptr, field_ptr); |
| 27240 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 27119 | 27241 | return field_ptr; |
| 27120 | 27242 | } else if (ip.stringEqlSlice(field_name, "len")) { |
| 27121 | 27243 | const result_ty = try sema.ptrType(.{ |
| ... | ... | @@ -27139,7 +27261,7 @@ fn fieldPtr( |
| 27139 | 27261 | try sema.requireRuntimeBlock(block, src, null); |
| 27140 | 27262 | |
| 27141 | 27263 | const field_ptr = try block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr); |
| 27142 | | try sema.checkKnownAllocPtr(inner_ptr, field_ptr); |
| 27264 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 27143 | 27265 | return field_ptr; |
| 27144 | 27266 | } else { |
| 27145 | 27267 | return sema.fail( |
| ... | ... | @@ -27238,7 +27360,7 @@ fn fieldPtr( |
| 27238 | 27360 | else |
| 27239 | 27361 | object_ptr; |
| 27240 | 27362 | const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); |
| 27241 | | try sema.checkKnownAllocPtr(inner_ptr, field_ptr); |
| 27363 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 27242 | 27364 | return field_ptr; |
| 27243 | 27365 | }, |
| 27244 | 27366 | .Union => { |
| ... | ... | @@ -27247,7 +27369,7 @@ fn fieldPtr( |
| 27247 | 27369 | else |
| 27248 | 27370 | object_ptr; |
| 27249 | 27371 | const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); |
| 27250 | | try sema.checkKnownAllocPtr(inner_ptr, field_ptr); |
| 27372 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 27251 | 27373 | return field_ptr; |
| 27252 | 27374 | }, |
| 27253 | 27375 | else => {}, |
| ... | ... | @@ -28030,7 +28152,7 @@ fn elemPtr( |
| 28030 | 28152 | }, |
| 28031 | 28153 | }; |
| 28032 | 28154 | |
| 28033 | | try sema.checkKnownAllocPtr(indexable_ptr, elem_ptr); |
| 28155 | try sema.checkKnownAllocPtr(block, indexable_ptr, elem_ptr); |
| 28034 | 28156 | return elem_ptr; |
| 28035 | 28157 | } |
| 28036 | 28158 | |
| ... | ... | @@ -28083,7 +28205,7 @@ fn elemPtrOneLayerOnly( |
| 28083 | 28205 | }, |
| 28084 | 28206 | else => unreachable, // Guaranteed by checkIndexable |
| 28085 | 28207 | }; |
| 28086 | | try sema.checkKnownAllocPtr(indexable, elem_ptr); |
| 28208 | try sema.checkKnownAllocPtr(block, indexable, elem_ptr); |
| 28087 | 28209 | return elem_ptr; |
| 28088 | 28210 | }, |
| 28089 | 28211 | } |
| ... | ... | @@ -28617,7 +28739,7 @@ fn coerceExtra( |
| 28617 | 28739 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28618 | 28740 | try sema.queueFullTypeResolution(dest_ty); |
| 28619 | 28741 | const new_val = try block.addBitCast(dest_ty, inst); |
| 28620 | | try sema.checkKnownAllocPtr(inst, new_val); |
| 28742 | try sema.checkKnownAllocPtr(block, inst, new_val); |
| 28621 | 28743 | return new_val; |
| 28622 | 28744 | } |
| 28623 | 28745 | |
| ... | ... | @@ -30349,7 +30471,7 @@ fn storePtr2( |
| 30349 | 30471 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 30350 | 30472 | break :rs operand_src; |
| 30351 | 30473 | }; |
| 30352 | | if (ptr_val.isComptimeMutablePtr(mod)) { |
| 30474 | if (sema.isComptimeMutablePtr(ptr_val)) { |
| 30353 | 30475 | try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 30354 | 30476 | return; |
| 30355 | 30477 | } else break :rs ptr_src; |
| ... | ... | @@ -30392,7 +30514,7 @@ fn storePtr2( |
| 30392 | 30514 | else |
| 30393 | 30515 | try block.addBinOp(air_tag, ptr, operand); |
| 30394 | 30516 | |
| 30395 | | try sema.checkComptimeKnownStore(block, store_inst); |
| 30517 | try sema.checkComptimeKnownStore(block, store_inst, operand_src); |
| 30396 | 30518 | |
| 30397 | 30519 | return; |
| 30398 | 30520 | } |
| ... | ... | @@ -30400,29 +30522,39 @@ fn storePtr2( |
| 30400 | 30522 | /// Given an AIR store instruction, checks whether we are performing a |
| 30401 | 30523 | /// comptime-known store to a local alloc, and updates `maybe_comptime_allocs` |
| 30402 | 30524 | /// accordingly. |
| 30403 | | fn checkComptimeKnownStore(sema: *Sema, block: *Block, store_inst_ref: Air.Inst.Ref) !void { |
| 30525 | /// Handles calling `validateRuntimeValue` if the store is runtime for any reason. |
| 30526 | fn checkComptimeKnownStore(sema: *Sema, block: *Block, store_inst_ref: Air.Inst.Ref, store_src: LazySrcLoc) !void { |
| 30404 | 30527 | const store_inst = store_inst_ref.toIndex().?; |
| 30405 | 30528 | const inst_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op; |
| 30406 | 30529 | const ptr = inst_data.lhs.toIndex() orelse return; |
| 30407 | 30530 | const operand = inst_data.rhs; |
| 30408 | 30531 | |
| 30409 | | const maybe_base_alloc = sema.base_allocs.get(ptr) orelse return; |
| 30410 | | const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(maybe_base_alloc) orelse return; |
| 30532 | known: { |
| 30533 | const maybe_base_alloc = sema.base_allocs.get(ptr) orelse break :known; |
| 30534 | const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(maybe_base_alloc) orelse break :known; |
| 30411 | 30535 | |
| 30412 | | ct: { |
| 30413 | | if (null == try sema.resolveValue(operand)) break :ct; |
| 30414 | | if (maybe_comptime_alloc.runtime_index != block.runtime_index) break :ct; |
| 30415 | | return maybe_comptime_alloc.stores.append(sema.arena, store_inst); |
| 30536 | if ((try sema.resolveValue(operand)) != null and |
| 30537 | block.runtime_index == maybe_comptime_alloc.runtime_index) |
| 30538 | { |
| 30539 | try maybe_comptime_alloc.stores.append(sema.arena, .{ |
| 30540 | .inst = store_inst, |
| 30541 | .src_decl = block.src_decl, |
| 30542 | .src = store_src, |
| 30543 | }); |
| 30544 | return; |
| 30545 | } |
| 30546 | |
| 30547 | // We're newly discovering that this alloc is runtime-known. |
| 30548 | try sema.markMaybeComptimeAllocRuntime(block, maybe_base_alloc); |
| 30416 | 30549 | } |
| 30417 | 30550 | |
| 30418 | | // Store is runtime-known |
| 30419 | | _ = sema.maybe_comptime_allocs.remove(maybe_base_alloc); |
| 30551 | try sema.validateRuntimeValue(block, store_src, operand); |
| 30420 | 30552 | } |
| 30421 | 30553 | |
| 30422 | 30554 | /// Given an AIR instruction transforming a pointer (struct_field_ptr, |
| 30423 | 30555 | /// ptr_elem_ptr, bitcast, etc), checks whether the base pointer refers to a |
| 30424 | 30556 | /// local alloc, and updates `base_allocs` accordingly. |
| 30425 | | fn checkKnownAllocPtr(sema: *Sema, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref) !void { |
| 30557 | fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref) !void { |
| 30426 | 30558 | const base_ptr_inst = base_ptr.toIndex() orelse return; |
| 30427 | 30559 | const new_ptr_inst = new_ptr.toIndex() orelse return; |
| 30428 | 30560 | const alloc_inst = sema.base_allocs.get(base_ptr_inst) orelse return; |
| ... | ... | @@ -30442,13 +30574,34 @@ fn checkKnownAllocPtr(sema: *Sema, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref |
| 30442 | 30574 | // If the index value is runtime-known, this pointer is also runtime-known, so |
| 30443 | 30575 | // we must in turn make the alloc value runtime-known. |
| 30444 | 30576 | if (null == try sema.resolveValue(index_ref)) { |
| 30445 | | _ = sema.maybe_comptime_allocs.remove(alloc_inst); |
| 30577 | try sema.markMaybeComptimeAllocRuntime(block, alloc_inst); |
| 30446 | 30578 | } |
| 30447 | 30579 | }, |
| 30448 | 30580 | else => {}, |
| 30449 | 30581 | } |
| 30450 | 30582 | } |
| 30451 | 30583 | |
| 30584 | fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Inst.Index) CompileError!void { |
| 30585 | const maybe_comptime_alloc = (sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return).value; |
| 30586 | // Since the alloc has been determined to be runtime, we must check that |
| 30587 | // all other stores to it are permitted to be runtime values. |
| 30588 | const mod = sema.mod; |
| 30589 | const slice = maybe_comptime_alloc.stores.slice(); |
| 30590 | for (slice.items(.inst), slice.items(.src_decl), slice.items(.src)) |other_inst, other_src_decl, other_src| { |
| 30591 | const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op; |
| 30592 | const other_operand = other_data.rhs; |
| 30593 | if (!sema.checkRuntimeValue(other_operand)) { |
| 30594 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 30595 | const other_src_resolved = mod.declPtr(other_src_decl).toSrcLoc(other_src, mod); |
| 30596 | const msg = try Module.ErrorMsg.create(sema.gpa, other_src_resolved, "runtime value contains reference to comptime var", .{}); |
| 30597 | errdefer msg.destroy(sema.gpa); |
| 30598 | try mod.errNoteNonLazy(other_src_resolved, msg, "comptime var pointers are not available at runtime", .{}); |
| 30599 | break :msg msg; |
| 30600 | }); |
| 30601 | } |
| 30602 | } |
| 30603 | } |
| 30604 | |
| 30452 | 30605 | /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector |
| 30453 | 30606 | /// pointer. Only if the final element type matches the vector element type, and the |
| 30454 | 30607 | /// lengths match. |
| ... | ... | @@ -30491,13 +30644,16 @@ fn storePtrVal( |
| 30491 | 30644 | ) !void { |
| 30492 | 30645 | const mod = sema.mod; |
| 30493 | 30646 | var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty); |
| 30494 | | try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl); |
| 30647 | switch (mut_kit.root) { |
| 30648 | .alloc => |a| try sema.checkComptimeVarStore(block, src, a), |
| 30649 | .comptime_field => {}, |
| 30650 | } |
| 30495 | 30651 | |
| 30496 | 30652 | try sema.resolveTypeLayout(operand_ty); |
| 30497 | 30653 | switch (mut_kit.pointee) { |
| 30498 | 30654 | .opv => {}, |
| 30499 | 30655 | .direct => |val_ptr| { |
| 30500 | | if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { |
| 30656 | if (mut_kit.root == .comptime_field) { |
| 30501 | 30657 | val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod))); |
| 30502 | 30658 | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { |
| 30503 | 30659 | // TODO use failWithInvalidComptimeFieldStore |
| ... | ... | @@ -30552,7 +30708,11 @@ fn storePtrVal( |
| 30552 | 30708 | } |
| 30553 | 30709 | |
| 30554 | 30710 | const ComptimePtrMutationKit = struct { |
| 30555 | | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, |
| 30711 | const Root = union(enum) { |
| 30712 | alloc: ComptimeAllocIndex, |
| 30713 | comptime_field, |
| 30714 | }; |
| 30715 | root: Root, |
| 30556 | 30716 | pointee: union(enum) { |
| 30557 | 30717 | opv, |
| 30558 | 30718 | /// The pointer type matches the actual comptime Value so a direct |
| ... | ... | @@ -30591,17 +30751,21 @@ fn beginComptimePtrMutation( |
| 30591 | 30751 | const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 30592 | 30752 | switch (ptr.addr) { |
| 30593 | 30753 | .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already |
| 30594 | | .mut_decl => |mut_decl| { |
| 30595 | | const decl = mod.declPtr(mut_decl.decl); |
| 30596 | | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); |
| 30754 | .comptime_alloc => |alloc_index| { |
| 30755 | const alloc = sema.getComptimeAlloc(alloc_index); |
| 30756 | return sema.beginComptimePtrMutationInner(block, src, alloc.ty, &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index }); |
| 30597 | 30757 | }, |
| 30598 | 30758 | .comptime_field => |comptime_field| { |
| 30599 | 30759 | const duped = try sema.arena.create(Value); |
| 30600 | 30760 | duped.* = Value.fromInterned(comptime_field); |
| 30601 | | return sema.beginComptimePtrMutationInner(block, src, Type.fromInterned(mod.intern_pool.typeOf(comptime_field)), duped, ptr_elem_ty, .{ |
| 30602 | | .decl = undefined, |
| 30603 | | .runtime_index = .comptime_field_ptr, |
| 30604 | | }); |
| 30761 | return sema.beginComptimePtrMutationInner( |
| 30762 | block, |
| 30763 | src, |
| 30764 | Type.fromInterned(mod.intern_pool.typeOf(comptime_field)), |
| 30765 | duped, |
| 30766 | ptr_elem_ty, |
| 30767 | .comptime_field, |
| 30768 | ); |
| 30605 | 30769 | }, |
| 30606 | 30770 | .eu_payload => |eu_ptr| { |
| 30607 | 30771 | const eu_ty = Type.fromInterned(mod.intern_pool.typeOf(eu_ptr)).childType(mod); |
| ... | ... | @@ -30612,7 +30776,7 @@ fn beginComptimePtrMutation( |
| 30612 | 30776 | const payload_ty = parent.ty.errorUnionPayload(mod); |
| 30613 | 30777 | if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { |
| 30614 | 30778 | return ComptimePtrMutationKit{ |
| 30615 | | .mut_decl = parent.mut_decl, |
| 30779 | .root = parent.root, |
| 30616 | 30780 | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, |
| 30617 | 30781 | .ty = payload_ty, |
| 30618 | 30782 | }; |
| ... | ... | @@ -30630,7 +30794,7 @@ fn beginComptimePtrMutation( |
| 30630 | 30794 | val_ptr.* = Value.initPayload(&payload.base); |
| 30631 | 30795 | |
| 30632 | 30796 | return ComptimePtrMutationKit{ |
| 30633 | | .mut_decl = parent.mut_decl, |
| 30797 | .root = parent.root, |
| 30634 | 30798 | .pointee = .{ .direct = &payload.data }, |
| 30635 | 30799 | .ty = payload_ty, |
| 30636 | 30800 | }; |
| ... | ... | @@ -30640,7 +30804,7 @@ fn beginComptimePtrMutation( |
| 30640 | 30804 | // Even though the parent value type has well-defined memory layout, our |
| 30641 | 30805 | // pointer type does not. |
| 30642 | 30806 | .reinterpret => return ComptimePtrMutationKit{ |
| 30643 | | .mut_decl = parent.mut_decl, |
| 30807 | .root = parent.root, |
| 30644 | 30808 | .pointee = .bad_ptr_ty, |
| 30645 | 30809 | .ty = eu_ty, |
| 30646 | 30810 | }, |
| ... | ... | @@ -30655,7 +30819,7 @@ fn beginComptimePtrMutation( |
| 30655 | 30819 | const payload_ty = parent.ty.optionalChild(mod); |
| 30656 | 30820 | switch (val_ptr.ip_index) { |
| 30657 | 30821 | .none => return ComptimePtrMutationKit{ |
| 30658 | | .mut_decl = parent.mut_decl, |
| 30822 | .root = parent.root, |
| 30659 | 30823 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, |
| 30660 | 30824 | .ty = payload_ty, |
| 30661 | 30825 | }, |
| ... | ... | @@ -30682,7 +30846,7 @@ fn beginComptimePtrMutation( |
| 30682 | 30846 | val_ptr.* = Value.initPayload(&payload.base); |
| 30683 | 30847 | |
| 30684 | 30848 | return ComptimePtrMutationKit{ |
| 30685 | | .mut_decl = parent.mut_decl, |
| 30849 | .root = parent.root, |
| 30686 | 30850 | .pointee = .{ .direct = &payload.data }, |
| 30687 | 30851 | .ty = payload_ty, |
| 30688 | 30852 | }; |
| ... | ... | @@ -30693,7 +30857,7 @@ fn beginComptimePtrMutation( |
| 30693 | 30857 | // Even though the parent value type has well-defined memory layout, our |
| 30694 | 30858 | // pointer type does not. |
| 30695 | 30859 | .reinterpret => return ComptimePtrMutationKit{ |
| 30696 | | .mut_decl = parent.mut_decl, |
| 30860 | .root = parent.root, |
| 30697 | 30861 | .pointee = .bad_ptr_ty, |
| 30698 | 30862 | .ty = opt_ty, |
| 30699 | 30863 | }, |
| ... | ... | @@ -30717,7 +30881,7 @@ fn beginComptimePtrMutation( |
| 30717 | 30881 | }); |
| 30718 | 30882 | } |
| 30719 | 30883 | return .{ |
| 30720 | | .mut_decl = parent.mut_decl, |
| 30884 | .root = parent.root, |
| 30721 | 30885 | .pointee = .opv, |
| 30722 | 30886 | .ty = elem_ty, |
| 30723 | 30887 | }; |
| ... | ... | @@ -30742,7 +30906,7 @@ fn beginComptimePtrMutation( |
| 30742 | 30906 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 30743 | 30907 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); |
| 30744 | 30908 | return .{ |
| 30745 | | .mut_decl = parent.mut_decl, |
| 30909 | .root = parent.root, |
| 30746 | 30910 | .pointee = .{ .reinterpret = .{ |
| 30747 | 30911 | .val_ptr = val_ptr, |
| 30748 | 30912 | .byte_offset = elem_abi_size * elem_idx, |
| ... | ... | @@ -30759,7 +30923,7 @@ fn beginComptimePtrMutation( |
| 30759 | 30923 | // If we wanted to avoid this, there would need to be special detection |
| 30760 | 30924 | // elsewhere to identify when writing a value to an array element that is stored |
| 30761 | 30925 | // using the `bytes` tag, and handle it without making a call to this function. |
| 30762 | | const arena = mod.tmp_hack_arena.allocator(); |
| 30926 | const arena = sema.arena; |
| 30763 | 30927 | |
| 30764 | 30928 | const bytes = val_ptr.castTag(.bytes).?.data; |
| 30765 | 30929 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); |
| ... | ... | @@ -30780,7 +30944,7 @@ fn beginComptimePtrMutation( |
| 30780 | 30944 | elem_ty, |
| 30781 | 30945 | &elems[@intCast(elem_ptr.index)], |
| 30782 | 30946 | ptr_elem_ty, |
| 30783 | | parent.mut_decl, |
| 30947 | parent.root, |
| 30784 | 30948 | ); |
| 30785 | 30949 | }, |
| 30786 | 30950 | .repeated => { |
| ... | ... | @@ -30791,7 +30955,7 @@ fn beginComptimePtrMutation( |
| 30791 | 30955 | // need to be special detection elsewhere to identify when writing a value to an |
| 30792 | 30956 | // array element that is stored using the `repeated` tag, and handle it |
| 30793 | 30957 | // without making a call to this function. |
| 30794 | | const arena = mod.tmp_hack_arena.allocator(); |
| 30958 | const arena = sema.arena; |
| 30795 | 30959 | |
| 30796 | 30960 | const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod); |
| 30797 | 30961 | const array_len_including_sentinel = |
| ... | ... | @@ -30808,7 +30972,7 @@ fn beginComptimePtrMutation( |
| 30808 | 30972 | elem_ty, |
| 30809 | 30973 | &elems[@intCast(elem_ptr.index)], |
| 30810 | 30974 | ptr_elem_ty, |
| 30811 | | parent.mut_decl, |
| 30975 | parent.root, |
| 30812 | 30976 | ); |
| 30813 | 30977 | }, |
| 30814 | 30978 | |
| ... | ... | @@ -30819,7 +30983,7 @@ fn beginComptimePtrMutation( |
| 30819 | 30983 | elem_ty, |
| 30820 | 30984 | &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)], |
| 30821 | 30985 | ptr_elem_ty, |
| 30822 | | parent.mut_decl, |
| 30986 | parent.root, |
| 30823 | 30987 | ), |
| 30824 | 30988 | |
| 30825 | 30989 | else => unreachable, |
| ... | ... | @@ -30829,7 +30993,7 @@ fn beginComptimePtrMutation( |
| 30829 | 30993 | // An array has been initialized to undefined at comptime and now we |
| 30830 | 30994 | // are for the first time setting an element. We must change the representation |
| 30831 | 30995 | // of the array from `undef` to `array`. |
| 30832 | | const arena = mod.tmp_hack_arena.allocator(); |
| 30996 | const arena = sema.arena; |
| 30833 | 30997 | |
| 30834 | 30998 | const array_len_including_sentinel = |
| 30835 | 30999 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| ... | ... | @@ -30845,7 +31009,7 @@ fn beginComptimePtrMutation( |
| 30845 | 31009 | elem_ty, |
| 30846 | 31010 | &elems[@intCast(elem_ptr.index)], |
| 30847 | 31011 | ptr_elem_ty, |
| 30848 | | parent.mut_decl, |
| 31012 | parent.root, |
| 30849 | 31013 | ); |
| 30850 | 31014 | }, |
| 30851 | 31015 | else => unreachable, |
| ... | ... | @@ -30866,7 +31030,7 @@ fn beginComptimePtrMutation( |
| 30866 | 31030 | parent.ty, |
| 30867 | 31031 | val_ptr, |
| 30868 | 31032 | ptr_elem_ty, |
| 30869 | | parent.mut_decl, |
| 31033 | parent.root, |
| 30870 | 31034 | ); |
| 30871 | 31035 | }, |
| 30872 | 31036 | }, |
| ... | ... | @@ -30875,7 +31039,7 @@ fn beginComptimePtrMutation( |
| 30875 | 31039 | // Even though the parent value type has well-defined memory layout, our |
| 30876 | 31040 | // pointer type does not. |
| 30877 | 31041 | return ComptimePtrMutationKit{ |
| 30878 | | .mut_decl = parent.mut_decl, |
| 31042 | .root = parent.root, |
| 30879 | 31043 | .pointee = .bad_ptr_ty, |
| 30880 | 31044 | .ty = base_elem_ty, |
| 30881 | 31045 | }; |
| ... | ... | @@ -30885,7 +31049,7 @@ fn beginComptimePtrMutation( |
| 30885 | 31049 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 30886 | 31050 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); |
| 30887 | 31051 | return ComptimePtrMutationKit{ |
| 30888 | | .mut_decl = parent.mut_decl, |
| 31052 | .root = parent.root, |
| 30889 | 31053 | .pointee = .{ .reinterpret = .{ |
| 30890 | 31054 | .val_ptr = reinterpret.val_ptr, |
| 30891 | 31055 | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx, |
| ... | ... | @@ -30914,7 +31078,7 @@ fn beginComptimePtrMutation( |
| 30914 | 31078 | parent.ty.structFieldType(field_index, mod), |
| 30915 | 31079 | duped, |
| 30916 | 31080 | ptr_elem_ty, |
| 30917 | | parent.mut_decl, |
| 31081 | parent.root, |
| 30918 | 31082 | ); |
| 30919 | 31083 | }, |
| 30920 | 31084 | .none => switch (val_ptr.tag()) { |
| ... | ... | @@ -30925,10 +31089,10 @@ fn beginComptimePtrMutation( |
| 30925 | 31089 | parent.ty.structFieldType(field_index, mod), |
| 30926 | 31090 | &val_ptr.castTag(.aggregate).?.data[field_index], |
| 30927 | 31091 | ptr_elem_ty, |
| 30928 | | parent.mut_decl, |
| 31092 | parent.root, |
| 30929 | 31093 | ), |
| 30930 | 31094 | .repeated => { |
| 30931 | | const arena = mod.tmp_hack_arena.allocator(); |
| 31095 | const arena = sema.arena; |
| 30932 | 31096 | |
| 30933 | 31097 | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 30934 | 31098 | @memset(elems, val_ptr.castTag(.repeated).?.data); |
| ... | ... | @@ -30941,7 +31105,7 @@ fn beginComptimePtrMutation( |
| 30941 | 31105 | parent.ty.structFieldType(field_index, mod), |
| 30942 | 31106 | &elems[field_index], |
| 30943 | 31107 | ptr_elem_ty, |
| 30944 | | parent.mut_decl, |
| 31108 | parent.root, |
| 30945 | 31109 | ); |
| 30946 | 31110 | }, |
| 30947 | 31111 | .@"union" => { |
| ... | ... | @@ -30962,7 +31126,7 @@ fn beginComptimePtrMutation( |
| 30962 | 31126 | field_ty, |
| 30963 | 31127 | &payload.val, |
| 30964 | 31128 | ptr_elem_ty, |
| 30965 | | parent.mut_decl, |
| 31129 | parent.root, |
| 30966 | 31130 | ); |
| 30967 | 31131 | } else { |
| 30968 | 31132 | // Writing to a different field (a different or unknown tag is active) requires reinterpreting |
| ... | ... | @@ -30973,7 +31137,7 @@ fn beginComptimePtrMutation( |
| 30973 | 31137 | // The reinterpretation will read it back out as .none. |
| 30974 | 31138 | payload.val = try payload.val.unintern(sema.arena, mod); |
| 30975 | 31139 | return ComptimePtrMutationKit{ |
| 30976 | | .mut_decl = parent.mut_decl, |
| 31140 | .root = parent.root, |
| 30977 | 31141 | .pointee = .{ .reinterpret = .{ |
| 30978 | 31142 | .val_ptr = val_ptr, |
| 30979 | 31143 | .byte_offset = 0, |
| ... | ... | @@ -30991,7 +31155,7 @@ fn beginComptimePtrMutation( |
| 30991 | 31155 | parent.ty.slicePtrFieldType(mod), |
| 30992 | 31156 | &val_ptr.castTag(.slice).?.data.ptr, |
| 30993 | 31157 | ptr_elem_ty, |
| 30994 | | parent.mut_decl, |
| 31158 | parent.root, |
| 30995 | 31159 | ), |
| 30996 | 31160 | |
| 30997 | 31161 | Value.slice_len_index => return beginComptimePtrMutationInner( |
| ... | ... | @@ -31001,7 +31165,7 @@ fn beginComptimePtrMutation( |
| 31001 | 31165 | Type.usize, |
| 31002 | 31166 | &val_ptr.castTag(.slice).?.data.len, |
| 31003 | 31167 | ptr_elem_ty, |
| 31004 | | parent.mut_decl, |
| 31168 | parent.root, |
| 31005 | 31169 | ), |
| 31006 | 31170 | |
| 31007 | 31171 | else => unreachable, |
| ... | ... | @@ -31013,7 +31177,7 @@ fn beginComptimePtrMutation( |
| 31013 | 31177 | // A struct or union has been initialized to undefined at comptime and now we |
| 31014 | 31178 | // are for the first time setting a field. We must change the representation |
| 31015 | 31179 | // of the struct/union from `undef` to `struct`/`union`. |
| 31016 | | const arena = mod.tmp_hack_arena.allocator(); |
| 31180 | const arena = sema.arena; |
| 31017 | 31181 | |
| 31018 | 31182 | switch (parent.ty.zigTypeTag(mod)) { |
| 31019 | 31183 | .Struct => { |
| ... | ... | @@ -31031,7 +31195,7 @@ fn beginComptimePtrMutation( |
| 31031 | 31195 | parent.ty.structFieldType(field_index, mod), |
| 31032 | 31196 | &fields[field_index], |
| 31033 | 31197 | ptr_elem_ty, |
| 31034 | | parent.mut_decl, |
| 31198 | parent.root, |
| 31035 | 31199 | ); |
| 31036 | 31200 | }, |
| 31037 | 31201 | .Union => { |
| ... | ... | @@ -31052,7 +31216,7 @@ fn beginComptimePtrMutation( |
| 31052 | 31216 | payload_ty, |
| 31053 | 31217 | &payload.data.val, |
| 31054 | 31218 | ptr_elem_ty, |
| 31055 | | parent.mut_decl, |
| 31219 | parent.root, |
| 31056 | 31220 | ); |
| 31057 | 31221 | }, |
| 31058 | 31222 | .Pointer => { |
| ... | ... | @@ -31071,7 +31235,7 @@ fn beginComptimePtrMutation( |
| 31071 | 31235 | ptr_ty, |
| 31072 | 31236 | &val_ptr.castTag(.slice).?.data.ptr, |
| 31073 | 31237 | ptr_elem_ty, |
| 31074 | | parent.mut_decl, |
| 31238 | parent.root, |
| 31075 | 31239 | ), |
| 31076 | 31240 | Value.slice_len_index => return beginComptimePtrMutationInner( |
| 31077 | 31241 | sema, |
| ... | ... | @@ -31080,7 +31244,7 @@ fn beginComptimePtrMutation( |
| 31080 | 31244 | Type.usize, |
| 31081 | 31245 | &val_ptr.castTag(.slice).?.data.len, |
| 31082 | 31246 | ptr_elem_ty, |
| 31083 | | parent.mut_decl, |
| 31247 | parent.root, |
| 31084 | 31248 | ), |
| 31085 | 31249 | |
| 31086 | 31250 | else => unreachable, |
| ... | ... | @@ -31096,7 +31260,7 @@ fn beginComptimePtrMutation( |
| 31096 | 31260 | const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); |
| 31097 | 31261 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 31098 | 31262 | return ComptimePtrMutationKit{ |
| 31099 | | .mut_decl = parent.mut_decl, |
| 31263 | .root = parent.root, |
| 31100 | 31264 | .pointee = .{ .reinterpret = .{ |
| 31101 | 31265 | .val_ptr = reinterpret.val_ptr, |
| 31102 | 31266 | .byte_offset = reinterpret.byte_offset + field_offset, |
| ... | ... | @@ -31117,7 +31281,7 @@ fn beginComptimePtrMutationInner( |
| 31117 | 31281 | decl_ty: Type, |
| 31118 | 31282 | decl_val: *Value, |
| 31119 | 31283 | ptr_elem_ty: Type, |
| 31120 | | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, |
| 31284 | root: ComptimePtrMutationKit.Root, |
| 31121 | 31285 | ) CompileError!ComptimePtrMutationKit { |
| 31122 | 31286 | const mod = sema.mod; |
| 31123 | 31287 | const target = mod.getTarget(); |
| ... | ... | @@ -31127,7 +31291,7 @@ fn beginComptimePtrMutationInner( |
| 31127 | 31291 | |
| 31128 | 31292 | if (coerce_ok) { |
| 31129 | 31293 | return ComptimePtrMutationKit{ |
| 31130 | | .mut_decl = mut_decl, |
| 31294 | .root = root, |
| 31131 | 31295 | .pointee = .{ .direct = decl_val }, |
| 31132 | 31296 | .ty = decl_ty, |
| 31133 | 31297 | }; |
| ... | ... | @@ -31138,7 +31302,7 @@ fn beginComptimePtrMutationInner( |
| 31138 | 31302 | const decl_elem_ty = decl_ty.childType(mod); |
| 31139 | 31303 | if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { |
| 31140 | 31304 | return ComptimePtrMutationKit{ |
| 31141 | | .mut_decl = mut_decl, |
| 31305 | .root = root, |
| 31142 | 31306 | .pointee = .{ .direct = decl_val }, |
| 31143 | 31307 | .ty = decl_ty, |
| 31144 | 31308 | }; |
| ... | ... | @@ -31147,20 +31311,20 @@ fn beginComptimePtrMutationInner( |
| 31147 | 31311 | |
| 31148 | 31312 | if (!decl_ty.hasWellDefinedLayout(mod)) { |
| 31149 | 31313 | return ComptimePtrMutationKit{ |
| 31150 | | .mut_decl = mut_decl, |
| 31314 | .root = root, |
| 31151 | 31315 | .pointee = .bad_decl_ty, |
| 31152 | 31316 | .ty = decl_ty, |
| 31153 | 31317 | }; |
| 31154 | 31318 | } |
| 31155 | 31319 | if (!ptr_elem_ty.hasWellDefinedLayout(mod)) { |
| 31156 | 31320 | return ComptimePtrMutationKit{ |
| 31157 | | .mut_decl = mut_decl, |
| 31321 | .root = root, |
| 31158 | 31322 | .pointee = .bad_ptr_ty, |
| 31159 | 31323 | .ty = ptr_elem_ty, |
| 31160 | 31324 | }; |
| 31161 | 31325 | } |
| 31162 | 31326 | return ComptimePtrMutationKit{ |
| 31163 | | .mut_decl = mut_decl, |
| 31327 | .root = root, |
| 31164 | 31328 | .pointee = .{ .reinterpret = .{ |
| 31165 | 31329 | .val_ptr = decl_val, |
| 31166 | 31330 | .byte_offset = 0, |
| ... | ... | @@ -31208,13 +31372,7 @@ fn beginComptimePtrLoad( |
| 31208 | 31372 | |
| 31209 | 31373 | var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) { |
| 31210 | 31374 | .ptr => |ptr| switch (ptr.addr) { |
| 31211 | | .decl, .mut_decl => blk: { |
| 31212 | | const decl_index = switch (ptr.addr) { |
| 31213 | | .decl => |decl| decl, |
| 31214 | | .mut_decl => |mut_decl| mut_decl.decl, |
| 31215 | | else => unreachable, |
| 31216 | | }; |
| 31217 | | const is_mutable = ptr.addr == .mut_decl; |
| 31375 | .decl => |decl_index| blk: { |
| 31218 | 31376 | const decl = mod.declPtr(decl_index); |
| 31219 | 31377 | const decl_tv = try decl.typedValue(); |
| 31220 | 31378 | try sema.declareDependency(.{ .decl_val = decl_index }); |
| ... | ... | @@ -31224,10 +31382,24 @@ fn beginComptimePtrLoad( |
| 31224 | 31382 | break :blk ComptimePtrLoadKit{ |
| 31225 | 31383 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 31226 | 31384 | .pointee = decl_tv, |
| 31227 | | .is_mutable = is_mutable, |
| 31385 | .is_mutable = false, |
| 31228 | 31386 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 31229 | 31387 | }; |
| 31230 | 31388 | }, |
| 31389 | .comptime_alloc => |alloc_index| kit: { |
| 31390 | const alloc = sema.getComptimeAlloc(alloc_index); |
| 31391 | const alloc_tv: TypedValue = .{ |
| 31392 | .ty = alloc.ty, |
| 31393 | .val = alloc.val, |
| 31394 | }; |
| 31395 | const layout_defined = alloc.ty.hasWellDefinedLayout(mod); |
| 31396 | break :kit .{ |
| 31397 | .parent = if (layout_defined) .{ .tv = alloc_tv, .byte_offset = 0 } else null, |
| 31398 | .pointee = alloc_tv, |
| 31399 | .is_mutable = true, |
| 31400 | .ty_without_well_defined_layout = if (!layout_defined) alloc.ty else null, |
| 31401 | }; |
| 31402 | }, |
| 31231 | 31403 | .anon_decl => |anon_decl| blk: { |
| 31232 | 31404 | const decl_val = anon_decl.val; |
| 31233 | 31405 | if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad; |
| ... | ... | @@ -31352,7 +31524,7 @@ fn beginComptimePtrLoad( |
| 31352 | 31524 | .len = len, |
| 31353 | 31525 | .child = elem_ty.toIntern(), |
| 31354 | 31526 | }), |
| 31355 | | .val = try array_tv.val.sliceArray(mod, sema.arena, elem_idx, elem_idx + len), |
| 31527 | .val = try array_tv.val.sliceArray(sema, elem_idx, elem_idx + len), |
| 31356 | 31528 | } else null; |
| 31357 | 31529 | break :blk deref; |
| 31358 | 31530 | } |
| ... | ... | @@ -31481,6 +31653,7 @@ fn bitCast( |
| 31481 | 31653 | } |
| 31482 | 31654 | } |
| 31483 | 31655 | try sema.requireRuntimeBlock(block, inst_src, operand_src); |
| 31656 | try sema.validateRuntimeValue(block, inst_src, inst); |
| 31484 | 31657 | return block.addBitCast(dest_ty, inst); |
| 31485 | 31658 | } |
| 31486 | 31659 | |
| ... | ... | @@ -31693,7 +31866,7 @@ fn coerceCompatiblePtrs( |
| 31693 | 31866 | try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null); |
| 31694 | 31867 | } |
| 31695 | 31868 | const new_ptr = try sema.bitCast(block, dest_ty, inst, inst_src, null); |
| 31696 | | try sema.checkKnownAllocPtr(inst, new_ptr); |
| 31869 | try sema.checkKnownAllocPtr(block, inst, new_ptr); |
| 31697 | 31870 | return new_ptr; |
| 31698 | 31871 | } |
| 31699 | 31872 | |
| ... | ... | @@ -35448,7 +35621,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { |
| 35448 | 35621 | }, |
| 35449 | 35622 | .ptr => |ptr| { |
| 35450 | 35623 | switch (ptr.addr) { |
| 35451 | | .decl, .mut_decl, .anon_decl => return val, |
| 35624 | .decl, .comptime_alloc, .anon_decl => return val, |
| 35452 | 35625 | .comptime_field => |field_val| { |
| 35453 | 35626 | const resolved_field_val = |
| 35454 | 35627 | (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern(); |
| ... | ... | @@ -35803,9 +35976,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co |
| 35803 | 35976 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 35804 | 35977 | defer analysis_arena.deinit(); |
| 35805 | 35978 | |
| 35806 | | var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa); |
| 35807 | | defer comptime_mutable_decls.deinit(); |
| 35808 | | |
| 35809 | 35979 | var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa); |
| 35810 | 35980 | defer comptime_err_ret_trace.deinit(); |
| 35811 | 35981 | |
| ... | ... | @@ -35821,7 +35991,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co |
| 35821 | 35991 | .fn_ret_ty = Type.void, |
| 35822 | 35992 | .fn_ret_ty_ies = null, |
| 35823 | 35993 | .owner_func_index = .none, |
| 35824 | | .comptime_mutable_decls = &comptime_mutable_decls, |
| 35825 | 35994 | .comptime_err_ret_trace = &comptime_err_ret_trace, |
| 35826 | 35995 | }; |
| 35827 | 35996 | defer sema.deinit(); |
| ... | ... | @@ -35887,11 +36056,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co |
| 35887 | 36056 | const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); |
| 35888 | 36057 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); |
| 35889 | 36058 | } |
| 35890 | | |
| 35891 | | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 35892 | | const ct_decl = mod.declPtr(ct_decl_index); |
| 35893 | | _ = try ct_decl.internValue(mod); |
| 35894 | | } |
| 35895 | 36059 | } |
| 35896 | 36060 | |
| 35897 | 36061 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { |
| ... | ... | @@ -36640,9 +36804,6 @@ fn semaStructFields( |
| 36640 | 36804 | }, |
| 36641 | 36805 | }; |
| 36642 | 36806 | |
| 36643 | | var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa); |
| 36644 | | defer comptime_mutable_decls.deinit(); |
| 36645 | | |
| 36646 | 36807 | var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa); |
| 36647 | 36808 | defer comptime_err_ret_trace.deinit(); |
| 36648 | 36809 | |
| ... | ... | @@ -36658,7 +36819,6 @@ fn semaStructFields( |
| 36658 | 36819 | .fn_ret_ty = Type.void, |
| 36659 | 36820 | .fn_ret_ty_ies = null, |
| 36660 | 36821 | .owner_func_index = .none, |
| 36661 | | .comptime_mutable_decls = &comptime_mutable_decls, |
| 36662 | 36822 | .comptime_err_ret_trace = &comptime_err_ret_trace, |
| 36663 | 36823 | }; |
| 36664 | 36824 | defer sema.deinit(); |
| ... | ... | @@ -36872,11 +37032,6 @@ fn semaStructFields( |
| 36872 | 37032 | |
| 36873 | 37033 | struct_type.clearTypesWip(ip); |
| 36874 | 37034 | if (!any_inits) struct_type.setHaveFieldInits(ip); |
| 36875 | | |
| 36876 | | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 36877 | | const ct_decl = mod.declPtr(ct_decl_index); |
| 36878 | | _ = try ct_decl.internValue(mod); |
| 36879 | | } |
| 36880 | 37035 | } |
| 36881 | 37036 | |
| 36882 | 37037 | // This logic must be kept in sync with `semaStructFields` |
| ... | ... | @@ -36897,9 +37052,6 @@ fn semaStructFieldInits( |
| 36897 | 37052 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); |
| 36898 | 37053 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); |
| 36899 | 37054 | |
| 36900 | | var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa); |
| 36901 | | defer comptime_mutable_decls.deinit(); |
| 36902 | | |
| 36903 | 37055 | var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa); |
| 36904 | 37056 | defer comptime_err_ret_trace.deinit(); |
| 36905 | 37057 | |
| ... | ... | @@ -36915,7 +37067,6 @@ fn semaStructFieldInits( |
| 36915 | 37067 | .fn_ret_ty = Type.void, |
| 36916 | 37068 | .fn_ret_ty_ies = null, |
| 36917 | 37069 | .owner_func_index = .none, |
| 36918 | | .comptime_mutable_decls = &comptime_mutable_decls, |
| 36919 | 37070 | .comptime_err_ret_trace = &comptime_err_ret_trace, |
| 36920 | 37071 | }; |
| 36921 | 37072 | defer sema.deinit(); |
| ... | ... | @@ -37024,14 +37175,16 @@ fn semaStructFieldInits( |
| 37024 | 37175 | }; |
| 37025 | 37176 | |
| 37026 | 37177 | const field_init = try default_val.intern(field_ty, mod); |
| 37178 | if (Value.fromInterned(field_init).canMutateComptimeVarState(mod)) { |
| 37179 | const init_src = mod.fieldSrcLoc(decl_index, .{ |
| 37180 | .index = field_i, |
| 37181 | .range = .value, |
| 37182 | }).lazy; |
| 37183 | return sema.fail(&block_scope, init_src, "field default value contains reference to comptime-mutable memory", .{}); |
| 37184 | } |
| 37027 | 37185 | struct_type.field_inits.get(ip)[field_i] = field_init; |
| 37028 | 37186 | } |
| 37029 | 37187 | } |
| 37030 | | |
| 37031 | | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 37032 | | const ct_decl = mod.declPtr(ct_decl_index); |
| 37033 | | _ = try ct_decl.internValue(mod); |
| 37034 | | } |
| 37035 | 37188 | } |
| 37036 | 37189 | |
| 37037 | 37190 | fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void { |
| ... | ... | @@ -37088,9 +37241,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded |
| 37088 | 37241 | |
| 37089 | 37242 | const decl = mod.declPtr(decl_index); |
| 37090 | 37243 | |
| 37091 | | var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa); |
| 37092 | | defer comptime_mutable_decls.deinit(); |
| 37093 | | |
| 37094 | 37244 | var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa); |
| 37095 | 37245 | defer comptime_err_ret_trace.deinit(); |
| 37096 | 37246 | |
| ... | ... | @@ -37106,7 +37256,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded |
| 37106 | 37256 | .fn_ret_ty = Type.void, |
| 37107 | 37257 | .fn_ret_ty_ies = null, |
| 37108 | 37258 | .owner_func_index = .none, |
| 37109 | | .comptime_mutable_decls = &comptime_mutable_decls, |
| 37110 | 37259 | .comptime_err_ret_trace = &comptime_err_ret_trace, |
| 37111 | 37260 | }; |
| 37112 | 37261 | defer sema.deinit(); |
| ... | ... | @@ -37126,11 +37275,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded |
| 37126 | 37275 | _ = try sema.analyzeInlineBody(&block_scope, body, zir_index); |
| 37127 | 37276 | } |
| 37128 | 37277 | |
| 37129 | | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 37130 | | const ct_decl = mod.declPtr(ct_decl_index); |
| 37131 | | _ = try ct_decl.internValue(mod); |
| 37132 | | } |
| 37133 | | |
| 37134 | 37278 | var int_tag_ty: Type = undefined; |
| 37135 | 37279 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; |
| 37136 | 37280 | var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}; |
| ... | ... | @@ -37734,7 +37878,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 37734 | 37878 | .ptr_decl, |
| 37735 | 37879 | .ptr_anon_decl, |
| 37736 | 37880 | .ptr_anon_decl_aligned, |
| 37737 | | .ptr_mut_decl, |
| 37881 | .ptr_comptime_alloc, |
| 37738 | 37882 | .ptr_comptime_field, |
| 37739 | 37883 | .ptr_int, |
| 37740 | 37884 | .ptr_eu_payload, |
| ... | ... | @@ -38017,27 +38161,11 @@ fn analyzeComptimeAlloc( |
| 38017 | 38161 | }, |
| 38018 | 38162 | }); |
| 38019 | 38163 | |
| 38020 | | var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl |
| 38021 | | defer anon_decl.deinit(); |
| 38164 | const alloc = try sema.newComptimeAlloc(block, var_type, alignment); |
| 38022 | 38165 | |
| 38023 | | const decl_index = try anon_decl.finish( |
| 38024 | | var_type, |
| 38025 | | // There will be stores before the first load, but they may be to sub-elements or |
| 38026 | | // sub-fields. So we need to initialize with undef to allow the mechanism to expand |
| 38027 | | // into fields/elements and have those overridden with stored values. |
| 38028 | | Value.fromInterned((try mod.intern(.{ .undef = var_type.toIntern() }))), |
| 38029 | | alignment, |
| 38030 | | ); |
| 38031 | | const decl = mod.declPtr(decl_index); |
| 38032 | | decl.alignment = alignment; |
| 38033 | | |
| 38034 | | try sema.comptime_mutable_decls.append(decl_index); |
| 38035 | 38166 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ |
| 38036 | 38167 | .ty = ptr_type.toIntern(), |
| 38037 | | .addr = .{ .mut_decl = .{ |
| 38038 | | .decl = decl_index, |
| 38039 | | .runtime_index = block.runtime_index, |
| 38040 | | } }, |
| 38168 | .addr = .{ .comptime_alloc = alloc }, |
| 38041 | 38169 | } }))); |
| 38042 | 38170 | } |
| 38043 | 38171 | |
| ... | ... | @@ -39073,3 +39201,130 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 39073 | 39201 | ); |
| 39074 | 39202 | try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee); |
| 39075 | 39203 | } |
| 39204 | |
| 39205 | fn isComptimeMutablePtr(sema: *Sema, val: Value) bool { |
| 39206 | return switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { |
| 39207 | .slice => |slice| sema.isComptimeMutablePtr(Value.fromInterned(slice.ptr)), |
| 39208 | .ptr => |ptr| switch (ptr.addr) { |
| 39209 | .anon_decl, .decl, .int => false, |
| 39210 | .comptime_field => true, |
| 39211 | .comptime_alloc => |alloc_index| !sema.getComptimeAlloc(alloc_index).is_const, |
| 39212 | .eu_payload, .opt_payload => |base| sema.isComptimeMutablePtr(Value.fromInterned(base)), |
| 39213 | .elem, .field => |bi| sema.isComptimeMutablePtr(Value.fromInterned(bi.base)), |
| 39214 | }, |
| 39215 | else => false, |
| 39216 | }; |
| 39217 | } |
| 39218 | |
| 39219 | fn checkRuntimeValue(sema: *Sema, ptr: Air.Inst.Ref) bool { |
| 39220 | const val = ptr.toInterned() orelse return true; |
| 39221 | return !Value.fromInterned(val).canMutateComptimeVarState(sema.mod); |
| 39222 | } |
| 39223 | |
| 39224 | fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Air.Inst.Ref) CompileError!void { |
| 39225 | if (sema.checkRuntimeValue(val)) return; |
| 39226 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 39227 | const msg = try sema.errMsg(block, val_src, "runtime value contains reference to comptime var", .{}); |
| 39228 | errdefer msg.destroy(sema.gpa); |
| 39229 | try sema.errNote(block, val_src, msg, "comptime var pointers are not available at runtime", .{}); |
| 39230 | break :msg msg; |
| 39231 | }); |
| 39232 | } |
| 39233 | |
| 39234 | /// Returns true if any value contained in `val` is undefined. |
| 39235 | fn anyUndef(sema: *Sema, val: Value) !bool { |
| 39236 | const mod = sema.mod; |
| 39237 | if (val.ip_index == .none) return switch (val.tag()) { |
| 39238 | .eu_payload => try sema.anyUndef(val.castTag(.eu_payload).?.data), |
| 39239 | .opt_payload => try sema.anyUndef(val.castTag(.opt_payload).?.data), |
| 39240 | .repeated => try sema.anyUndef(val.castTag(.repeated).?.data), |
| 39241 | .slice => { |
| 39242 | const slice = val.castTag(.slice).?.data; |
| 39243 | for (0..@intCast(slice.len.toUnsignedInt(mod))) |idx| { |
| 39244 | if (try sema.anyUndef((try slice.ptr.maybeElemValueFull(sema, mod, idx)).?)) return true; |
| 39245 | } |
| 39246 | return false; |
| 39247 | }, |
| 39248 | .bytes => false, |
| 39249 | .aggregate => for (val.castTag(.aggregate).?.data) |elem| { |
| 39250 | if (try sema.anyUndef(elem)) break true; |
| 39251 | } else false, |
| 39252 | .@"union" => { |
| 39253 | const un = val.castTag(.@"union").?.data; |
| 39254 | if (un.tag) |t| { |
| 39255 | if (try sema.anyUndef(t)) return true; |
| 39256 | } |
| 39257 | return sema.anyUndef(un.val); |
| 39258 | }, |
| 39259 | }; |
| 39260 | return switch (val.toIntern()) { |
| 39261 | .undef => true, |
| 39262 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 39263 | .undef => true, |
| 39264 | .simple_value => |v| v == .undefined, |
| 39265 | .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| { |
| 39266 | if (try sema.anyUndef((try val.maybeElemValueFull(sema, mod, idx)).?)) break true; |
| 39267 | } else false, |
| 39268 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { |
| 39269 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; |
| 39270 | if (try sema.anyUndef(Value.fromInterned(elem))) break true; |
| 39271 | } else false, |
| 39272 | else => false, |
| 39273 | }, |
| 39274 | }; |
| 39275 | } |
| 39276 | |
| 39277 | /// Asserts that `slice_val` is a slice of `u8`. |
| 39278 | fn sliceToIpString( |
| 39279 | sema: *Sema, |
| 39280 | block: *Block, |
| 39281 | src: LazySrcLoc, |
| 39282 | slice_val: Value, |
| 39283 | reason: NeededComptimeReason, |
| 39284 | ) CompileError!InternPool.NullTerminatedString { |
| 39285 | const zcu = sema.mod; |
| 39286 | const ip = &zcu.intern_pool; |
| 39287 | const slice_ty = Type.fromInterned(ip.typeOf(slice_val.toIntern())); |
| 39288 | assert(slice_ty.isSlice(zcu)); |
| 39289 | assert(slice_ty.childType(zcu).toIntern() == .u8_type); |
| 39290 | const array_val = try sema.derefSliceAsArray(block, src, slice_val, reason); |
| 39291 | const array_ty = Type.fromInterned(ip.typeOf(array_val.toIntern())); |
| 39292 | return array_val.toIpString(array_ty, zcu); |
| 39293 | } |
| 39294 | |
| 39295 | /// Given a slice value, attempts to dereference it into a comptime-known array. |
| 39296 | /// Emits a compile error if the contents of the slice are not comptime-known. |
| 39297 | /// Asserts that `slice_val` is a slice. |
| 39298 | fn derefSliceAsArray( |
| 39299 | sema: *Sema, |
| 39300 | block: *Block, |
| 39301 | src: LazySrcLoc, |
| 39302 | slice_val: Value, |
| 39303 | reason: NeededComptimeReason, |
| 39304 | ) CompileError!Value { |
| 39305 | const zcu = sema.mod; |
| 39306 | const ip = &zcu.intern_pool; |
| 39307 | assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); |
| 39308 | const slice = switch (ip.indexToKey(slice_val.toIntern())) { |
| 39309 | .undef => return sema.failWithUseOfUndef(block, src), |
| 39310 | .slice => |slice| slice, |
| 39311 | else => unreachable, |
| 39312 | }; |
| 39313 | const elem_ty = Type.fromInterned(slice.ty).childType(zcu); |
| 39314 | const len = try Value.fromInterned(slice.len).toUnsignedIntAdvanced(sema); |
| 39315 | const array_ty = try zcu.arrayType(.{ |
| 39316 | .child = elem_ty.toIntern(), |
| 39317 | .len = len, |
| 39318 | }); |
| 39319 | const ptr_ty = try sema.ptrType(p: { |
| 39320 | var p = Type.fromInterned(slice.ty).ptrInfo(zcu); |
| 39321 | p.flags.size = .One; |
| 39322 | p.child = array_ty.toIntern(); |
| 39323 | p.sentinel = .none; |
| 39324 | break :p p; |
| 39325 | }); |
| 39326 | const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty); |
| 39327 | return try sema.pointerDeref(block, src, casted_ptr, ptr_ty) orelse { |
| 39328 | return sema.failWithNeededComptime(block, src, reason); |
| 39329 | }; |
| 39330 | } |