authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-22 23:39:44+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-25 14:49:41+00:00
log9c3670fc930d21215e91849ce5a1fc44c9410fd0
treea66f2323f44750129d0229f80f58ce1e6c764fba
parent5c628312b16ce972cc3108ed44eed47960e17af7
signaturelock-open Commit is signed but in an unrecognized format.

compiler: implement analysis-local comptime-mutable memory

This commit changes how we represent comptime-mutable memory (`comptime var`) in the compiler in order to implement the intended behavior that references to such memory can only exist at comptime. It does *not* clean up the representation of mutable values, improve the representation of comptime-known pointers, or fix the many bugs in the comptime pointer access code. These will be future enhancements. Comptime memory lives for the duration of a single Sema, and is not permitted to escape that one analysis, either by becoming runtime-known or by becoming comptime-known to other analyses. These restrictions mean that we can represent comptime allocations not via Decl, but with state local to Sema - specifically, the new `Sema.comptime_allocs` field. All comptime-mutable allocations, as well as any comptime-known const allocs containing references to such memory, live in here. This allows for relatively fast checking of whether a value references any comptime-mtuable memory, since we need only traverse values up to pointers: pointers to Decls can never reference comptime-mutable memory, and pointers into `Sema.comptime_allocs` always do. This change exposed some faulty pointer access logic in `Value.zig`. I've fixed the important cases, but there are some TODOs I've put in which are definitely possible to hit with sufficiently esoteric code. I plan to resolve these by auditing all direct accesses to pointers (most of them ought to use Sema to perform the pointer access!), but for now this is sufficient for all realistic code and to get tests passing. This change eliminates `Zcu.tmp_hack_arena`, instead using the Sema arena for comptime memory mutations, which is possible since comptime memory is now local to the current Sema. This change should allow `Decl` to store only an `InternPool.Index` rather than a full-blown `ty: Type, val: Value`. This commit does not perform this refactor.

28 files changed, 886 insertions(+), 557 deletions(-)

lib/std/Target.zig+2-1
......@@ -1317,7 +1317,8 @@ pub const Cpu = struct {
13171317 for (decls, 0..) |decl, i| {
13181318 array[i] = &@field(cpus, decl.name);
13191319 }
1320 return &array;
1320 const finalized = array;
1321 return &finalized;
13211322 }
13221323 };
13231324
lib/std/enums.zig+2-1
......@@ -41,7 +41,8 @@ pub inline fn valuesFromFields(comptime E: type, comptime fields: []const EnumFi
4141 for (&result, fields) |*r, f| {
4242 r.* = @enumFromInt(f.value);
4343 }
44 return &result;
44 const final = result;
45 return &final;
4546 }
4647}
4748
lib/std/fmt.zig+2-1
......@@ -1829,7 +1829,8 @@ pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [cou
18291829 var buf: [count(fmt, args):0]u8 = undefined;
18301830 _ = bufPrint(&buf, fmt, args) catch unreachable;
18311831 buf[buf.len] = 0;
1832 return &buf;
1832 const final = buf;
1833 return &final;
18331834 }
18341835}
18351836
lib/std/meta.zig+4-2
......@@ -465,7 +465,8 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {
465465 var names: [fieldInfos.len][:0]const u8 = undefined;
466466 // This concat can be removed with the next zig1 update.
467467 for (&names, fieldInfos) |*name, field| name.* = field.name ++ "";
468 break :blk &names;
468 const final = names;
469 break :blk &final;
469470 };
470471}
471472
......@@ -506,7 +507,8 @@ pub fn tags(comptime T: type) *const [fields(T).len]T {
506507 for (fieldInfos, 0..) |field, i| {
507508 res[i] = @field(T, field.name);
508509 }
509 break :blk &res;
510 const final = res;
511 break :blk &final;
510512 };
511513}
512514
lib/std/unicode.zig+2-1
......@@ -1358,7 +1358,8 @@ pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16Le
13581358 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
13591359 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
13601360 assert(len == utf16le_len);
1361 break :blk &utf16le;
1361 const final = utf16le;
1362 break :blk &final;
13621363 };
13631364}
13641365
lib/std/zig/AstGen.zig+19-11
......@@ -8296,22 +8296,27 @@ fn localVarRef(
82968296 });
82978297 }
82988298
8299 const ptr_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8300 gz,
8301 ident,
8302 num_namespaces_out,
8303 .{ .ref = local_ptr.ptr },
8304 .{ .token = local_ptr.token_src },
8305 ) else local_ptr.ptr;
8306
83078299 switch (ri.rl) {
83088300 .ref, .ref_coerced_ty => {
8301 const ptr_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8302 gz,
8303 ident,
8304 num_namespaces_out,
8305 .{ .ref = local_ptr.ptr },
8306 .{ .token = local_ptr.token_src },
8307 ) else local_ptr.ptr;
83098308 local_ptr.used_as_lvalue = true;
83108309 return ptr_inst;
83118310 },
83128311 else => {
8313 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
8314 return rvalueNoCoercePreRef(gz, ri, loaded, ident);
8312 const val_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8313 gz,
8314 ident,
8315 num_namespaces_out,
8316 .{ .ref_load = local_ptr.ptr },
8317 .{ .token = local_ptr.token_src },
8318 ) else try gz.addUnNode(.load, local_ptr.ptr, ident);
8319 return rvalueNoCoercePreRef(gz, ri, val_inst, ident);
83158320 },
83168321 }
83178322 }
......@@ -8390,6 +8395,7 @@ fn tunnelThroughClosure(
83908395 /// The value being captured.
83918396 value: union(enum) {
83928397 ref: Zir.Inst.Ref,
8398 ref_load: Zir.Inst.Ref,
83938399 decl_val: Zir.NullTerminatedString,
83948400 decl_ref: Zir.NullTerminatedString,
83958401 },
......@@ -8400,7 +8406,8 @@ fn tunnelThroughClosure(
84008406 },
84018407) !Zir.Inst.Ref {
84028408 switch (value) {
8403 .ref => |v| if (v.toIndex() == null) return v, // trivia value; do not need tunnel
8409 .ref => |v| if (v.toIndex() == null) return v, // trivial value; do not need tunnel
8410 .ref_load => |v| assert(v.toIndex() != null), // there are no constant pointer refs
84048411 .decl_val, .decl_ref => {},
84058412 }
84068413
......@@ -8433,6 +8440,7 @@ fn tunnelThroughClosure(
84338440 // captures as required, starting with the outermost namespace.
84348441 const root_capture = Zir.Inst.Capture.wrap(switch (value) {
84358442 .ref => |v| .{ .instruction = v.toIndex().? },
8443 .ref_load => |v| .{ .instruction_load = v.toIndex().? },
84368444 .decl_val => |str| .{ .decl_val = str },
84378445 .decl_ref => |str| .{ .decl_ref = str },
84388446 });
lib/std/zig/Zir.zig+10-2
......@@ -3058,20 +3058,23 @@ pub const Inst = struct {
30583058
30593059 /// Represents a single value being captured in a type declaration's closure.
30603060 pub const Capture = packed struct(u32) {
3061 tag: enum(u2) {
3061 tag: enum(u3) {
30623062 /// `data` is a `u16` index into the parent closure.
30633063 nested,
30643064 /// `data` is a `Zir.Inst.Index` to an instruction whose value is being captured.
30653065 instruction,
3066 /// `data` is a `Zir.Inst.Index` to an instruction representing an alloc whose contents is being captured.
3067 instruction_load,
30663068 /// `data` is a `NullTerminatedString` to a decl name.
30673069 decl_val,
30683070 /// `data` is a `NullTerminatedString` to a decl name.
30693071 decl_ref,
30703072 },
3071 data: u30,
3073 data: u29,
30723074 pub const Unwrapped = union(enum) {
30733075 nested: u16,
30743076 instruction: Zir.Inst.Index,
3077 instruction_load: Zir.Inst.Index,
30753078 decl_val: NullTerminatedString,
30763079 decl_ref: NullTerminatedString,
30773080 };
......@@ -3085,6 +3088,10 @@ pub const Inst = struct {
30853088 .tag = .instruction,
30863089 .data = @intCast(@intFromEnum(inst)),
30873090 },
3091 .instruction_load => |inst| .{
3092 .tag = .instruction_load,
3093 .data = @intCast(@intFromEnum(inst)),
3094 },
30883095 .decl_val => |str| .{
30893096 .tag = .decl_val,
30903097 .data = @intCast(@intFromEnum(str)),
......@@ -3099,6 +3106,7 @@ pub const Inst = struct {
30993106 return switch (cap.tag) {
31003107 .nested => .{ .nested = @intCast(cap.data) },
31013108 .instruction => .{ .instruction = @enumFromInt(cap.data) },
3109 .instruction_load => .{ .instruction_load = @enumFromInt(cap.data) },
31023110 .decl_val => .{ .decl_val = @enumFromInt(cap.data) },
31033111 .decl_ref => .{ .decl_ref = @enumFromInt(cap.data) },
31043112 };
src/Air.zig+3-1
......@@ -1084,9 +1084,11 @@ pub const Inst = struct {
10841084 inferred_alloc: InferredAlloc,
10851085
10861086 pub const InferredAllocComptime = struct {
1087 decl_index: InternPool.DeclIndex,
10881087 alignment: InternPool.Alignment,
10891088 is_const: bool,
1089 /// This is `undefined` until we encounter a `store_to_inferred_alloc`,
1090 /// at which point the pointer is created and stored here.
1091 ptr: InternPool.Index,
10901092 };
10911093
10921094 pub const InferredAlloc = struct {
src/Compilation.zig-1
......@@ -1382,7 +1382,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13821382 .global_zir_cache = global_zir_cache,
13831383 .local_zir_cache = local_zir_cache,
13841384 .emit_h = emit_h,
1385 .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa),
13861385 .error_limit = error_limit,
13871386 .llvm_object = null,
13881387 };
src/InternPool.zig+32-41
......@@ -389,6 +389,8 @@ pub const RuntimeIndex = enum(u32) {
389389 }
390390};
391391
392pub const ComptimeAllocIndex = enum(u32) { _ };
393
392394pub const DeclIndex = std.zig.DeclIndex;
393395pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;
394396
......@@ -979,7 +981,7 @@ pub const Key = union(enum) {
979981 const Tag = @typeInfo(Addr).Union.tag_type.?;
980982
981983 decl: DeclIndex,
982 mut_decl: MutDecl,
984 comptime_alloc: ComptimeAllocIndex,
983985 anon_decl: AnonDecl,
984986 comptime_field: Index,
985987 int: Index,
......@@ -1172,20 +1174,14 @@ pub const Key = union(enum) {
11721174 const seed2 = seed + @intFromEnum(addr);
11731175 const common = asBytes(&ptr.ty);
11741176 return switch (ptr.addr) {
1175 .decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
1176
1177 .mut_decl => |x| Hash.hash(
1178 seed2,
1179 common ++ asBytes(&x.decl) ++ asBytes(&x.runtime_index),
1180 ),
1181
1182 .anon_decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
1183
1177 inline .decl,
1178 .comptime_alloc,
1179 .anon_decl,
11841180 .int,
11851181 .eu_payload,
11861182 .opt_payload,
11871183 .comptime_field,
1188 => |int| Hash.hash(seed2, common ++ asBytes(&int)),
1184 => |x| Hash.hash(seed2, common ++ asBytes(&x)),
11891185
11901186 .elem, .field => |x| Hash.hash(
11911187 seed2,
......@@ -1452,7 +1448,7 @@ pub const Key = union(enum) {
14521448
14531449 return switch (a_info.addr) {
14541450 .decl => |a_decl| a_decl == b_info.addr.decl,
1455 .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl),
1451 .comptime_alloc => |a_alloc| a_alloc == b_info.addr.comptime_alloc,
14561452 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and
14571453 ad.orig_ty == b_info.addr.anon_decl.orig_ty,
14581454 .int => |a_int| a_int == b_info.addr.int,
......@@ -2787,7 +2783,7 @@ pub const Index = enum(u32) {
27872783 undef: DataIsIndex,
27882784 simple_value: struct { data: SimpleValue },
27892785 ptr_decl: struct { data: *PtrDecl },
2790 ptr_mut_decl: struct { data: *PtrMutDecl },
2786 ptr_comptime_alloc: struct { data: *PtrComptimeAlloc },
27912787 ptr_anon_decl: struct { data: *PtrAnonDecl },
27922788 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
27932789 ptr_comptime_field: struct { data: *PtrComptimeField },
......@@ -3243,8 +3239,8 @@ pub const Tag = enum(u8) {
32433239 /// data is extra index of `PtrDecl`, which contains the type and address.
32443240 ptr_decl,
32453241 /// A pointer to a decl that can be mutated at comptime.
3246 /// data is extra index of `PtrMutDecl`, which contains the type and address.
3247 ptr_mut_decl,
3242 /// data is extra index of `PtrComptimeAlloc`, which contains the type and address.
3243 ptr_comptime_alloc,
32483244 /// A pointer to an anonymous decl.
32493245 /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value.
32503246 /// The alignment of the anonymous decl is communicated via the pointer type.
......@@ -3448,7 +3444,7 @@ pub const Tag = enum(u8) {
34483444 .undef => unreachable,
34493445 .simple_value => unreachable,
34503446 .ptr_decl => PtrDecl,
3451 .ptr_mut_decl => PtrMutDecl,
3447 .ptr_comptime_alloc => PtrComptimeAlloc,
34523448 .ptr_anon_decl => PtrAnonDecl,
34533449 .ptr_anon_decl_aligned => PtrAnonDeclAligned,
34543450 .ptr_comptime_field => PtrComptimeField,
......@@ -4129,10 +4125,9 @@ pub const PtrAnonDeclAligned = struct {
41294125 orig_ty: Index,
41304126};
41314127
4132pub const PtrMutDecl = struct {
4128pub const PtrComptimeAlloc = struct {
41334129 ty: Index,
4134 decl: DeclIndex,
4135 runtime_index: RuntimeIndex,
4130 index: ComptimeAllocIndex,
41364131};
41374132
41384133pub const PtrComptimeField = struct {
......@@ -4537,14 +4532,11 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
45374532 .addr = .{ .decl = info.decl },
45384533 } };
45394534 },
4540 .ptr_mut_decl => {
4541 const info = ip.extraData(PtrMutDecl, data);
4535 .ptr_comptime_alloc => {
4536 const info = ip.extraData(PtrComptimeAlloc, data);
45424537 return .{ .ptr = .{
45434538 .ty = info.ty,
4544 .addr = .{ .mut_decl = .{
4545 .decl = info.decl,
4546 .runtime_index = info.runtime_index,
4547 } },
4539 .addr = .{ .comptime_alloc = info.index },
45484540 } };
45494541 },
45504542 .ptr_anon_decl => {
......@@ -5186,12 +5178,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
51865178 .decl = decl,
51875179 }),
51885180 }),
5189 .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{
5190 .tag = .ptr_mut_decl,
5191 .data = try ip.addExtra(gpa, PtrMutDecl{
5181 .comptime_alloc => |alloc_index| ip.items.appendAssumeCapacity(.{
5182 .tag = .ptr_comptime_alloc,
5183 .data = try ip.addExtra(gpa, PtrComptimeAlloc{
51925184 .ty = ptr.ty,
5193 .decl = mut_decl.decl,
5194 .runtime_index = mut_decl.runtime_index,
5185 .index = alloc_index,
51955186 }),
51965187 }),
51975188 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
......@@ -7265,6 +7256,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
72657256 Tag.TypePointer.VectorIndex,
72667257 TrackedInst.Index,
72677258 TrackedInst.Index.Optional,
7259 ComptimeAllocIndex,
72687260 => @intFromEnum(@field(extra, field.name)),
72697261
72707262 u32,
......@@ -7342,6 +7334,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
73427334 Tag.TypePointer.VectorIndex,
73437335 TrackedInst.Index,
73447336 TrackedInst.Index.Optional,
7337 ComptimeAllocIndex,
73457338 => @enumFromInt(int32),
73467339
73477340 u32,
......@@ -8144,7 +8137,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
81448137 .simple_type => 0,
81458138 .simple_value => 0,
81468139 .ptr_decl => @sizeOf(PtrDecl),
8147 .ptr_mut_decl => @sizeOf(PtrMutDecl),
8140 .ptr_comptime_alloc => @sizeOf(PtrComptimeAlloc),
81488141 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
81498142 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
81508143 .ptr_comptime_field => @sizeOf(PtrComptimeField),
......@@ -8275,7 +8268,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
82758268 .type_function,
82768269 .undef,
82778270 .ptr_decl,
8278 .ptr_mut_decl,
8271 .ptr_comptime_alloc,
82798272 .ptr_anon_decl,
82808273 .ptr_anon_decl_aligned,
82818274 .ptr_comptime_field,
......@@ -8690,7 +8683,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
86908683 .simple_value => unreachable, // handled via Index above
86918684
86928685 inline .ptr_decl,
8693 .ptr_mut_decl,
8686 .ptr_comptime_alloc,
86948687 .ptr_anon_decl,
86958688 .ptr_anon_decl_aligned,
86968689 .ptr_comptime_field,
......@@ -8822,10 +8815,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
88228815 var base = @intFromEnum(val);
88238816 while (true) {
88248817 switch (ip.items.items(.tag)[base]) {
8825 inline .ptr_decl,
8826 .ptr_mut_decl,
8827 => |tag| return @enumFromInt(ip.extra.items[
8828 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "decl").?
8818 .ptr_decl => return @enumFromInt(ip.extra.items[
8819 ip.items.items(.data)[base] + std.meta.fieldIndex(PtrDecl, "decl").?
88298820 ]),
88308821 inline .ptr_eu_payload,
88318822 .ptr_opt_payload,
......@@ -8834,8 +8825,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
88348825 => |tag| base = ip.extra.items[
88358826 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "base").?
88368827 ],
8837 inline .ptr_slice => |tag| base = ip.extra.items[
8838 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "ptr").?
8828 .ptr_slice => base = ip.extra.items[
8829 ip.items.items(.data)[base] + std.meta.fieldIndex(PtrSlice, "ptr").?
88398830 ],
88408831 else => return .none,
88418832 }
......@@ -8847,7 +8838,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
88478838 while (true) {
88488839 switch (ip.items.items(.tag)[base]) {
88498840 .ptr_decl => return .decl,
8850 .ptr_mut_decl => return .mut_decl,
8841 .ptr_comptime_alloc => return .comptime_alloc,
88518842 .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,
88528843 .ptr_comptime_field => return .comptime_field,
88538844 .ptr_int => return .int,
......@@ -9023,7 +9014,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
90239014 .undef,
90249015 .simple_value,
90259016 .ptr_decl,
9026 .ptr_mut_decl,
9017 .ptr_comptime_alloc,
90279018 .ptr_anon_decl,
90289019 .ptr_anon_decl_aligned,
90299020 .ptr_comptime_field,
src/Module.zig+2-29
......@@ -101,12 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
101101/// is not yet implemented.
102102intern_pool: InternPool = .{},
103103
104/// To be eliminated in a future commit by moving more data into InternPool.
105/// Current uses that must be eliminated:
106/// * comptime pointer mutation
107/// This memory lives until the Module is destroyed.
108tmp_hack_arena: std.heap.ArenaAllocator,
109
110104/// We optimize memory usage for a compilation with no compile errors by storing the
111105/// error messages and mapping outside of `Decl`.
112106/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
......@@ -2099,7 +2093,6 @@ pub fn deinit(zcu: *Zcu) void {
20992093 }
21002094
21012095 zcu.intern_pool.deinit(gpa);
2102 zcu.tmp_hack_arena.deinit();
21032096}
21042097
21052098pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
......@@ -3656,9 +3649,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
36563649 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
36573650 defer analysis_arena.deinit();
36583651
3659 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3660 defer comptime_mutable_decls.deinit();
3661
36623652 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
36633653 defer comptime_err_ret_trace.deinit();
36643654
......@@ -3674,7 +3664,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
36743664 .fn_ret_ty = Type.void,
36753665 .fn_ret_ty_ies = null,
36763666 .owner_func_index = .none,
3677 .comptime_mutable_decls = &comptime_mutable_decls,
36783667 .comptime_err_ret_trace = &comptime_err_ret_trace,
36793668 .builtin_type_target_index = builtin_type_target_index,
36803669 };
......@@ -3704,18 +3693,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
37043693 // We'll do some other bits with the Sema. Clear the type target index just
37053694 // in case they analyze any type.
37063695 sema.builtin_type_target_index = .none;
3707 for (comptime_mutable_decls.items) |ct_decl_index| {
3708 const ct_decl = mod.declPtr(ct_decl_index);
3709 _ = try ct_decl.internValue(mod);
3710 }
37113696 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
37123697 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
37133698 const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
37143699 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
37153700 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
3716 const decl_tv = try sema.resolveConstValueAllowVariables(&block_scope, init_src, result_ref, .{
3717 .needed_comptime_reason = "global variable initializer must be comptime-known",
3718 });
3701 const decl_tv = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
37193702
37203703 // Note this resolves the type of the Decl, not the value; if this Decl
37213704 // is a struct, for example, this resolves `type` (which needs no resolution),
......@@ -4572,9 +4555,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
45724555
45734556 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
45744557
4575 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
4576 defer comptime_mutable_decls.deinit();
4577
45784558 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
45794559 defer comptime_err_ret_trace.deinit();
45804560
......@@ -4599,7 +4579,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
45994579 .fn_ret_ty_ies = null,
46004580 .owner_func_index = func_index,
46014581 .branch_quota = @max(func.branchQuota(ip).*, Sema.default_branch_quota),
4602 .comptime_mutable_decls = &comptime_mutable_decls,
46034582 .comptime_err_ret_trace = &comptime_err_ret_trace,
46044583 };
46054584 defer sema.deinit();
......@@ -4736,11 +4715,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
47364715 };
47374716 }
47384717
4739 for (comptime_mutable_decls.items) |ct_decl_index| {
4740 const ct_decl = mod.declPtr(ct_decl_index);
4741 _ = try ct_decl.internValue(mod);
4742 }
4743
47444718 // Copy the block into place and mark that as the main block.
47454719 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
47464720 inner_block.instructions.items.len);
......@@ -5632,8 +5606,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
56325606 .ptr => |ptr| switch (ptr.addr) {
56335607 .decl => |decl| try mod.markDeclIndexAlive(decl),
56345608 .anon_decl => {},
5635 .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),
5636 .int, .comptime_field => {},
5609 .int, .comptime_field, .comptime_alloc => {},
56375610 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),
56385611 .elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),
56395612 },
src/Sema.zig+587-332
......@@ -91,14 +91,6 @@ no_partial_func_ty: bool = false,
9191/// here so the values can be dropped without any cleanup.
9292unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},
9393
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.
100comptime_mutable_decls: *std.ArrayList(InternPool.DeclIndex),
101
10294/// This is populated when `@setAlignStack` occurs so that if there is a duplicate
10395/// one encountered, the conflicting source location can be shown.
10496prev_stack_alignment_src: ?LazySrcLoc = null,
......@@ -123,19 +115,57 @@ base_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, Air.Inst.Index) = .{},
123115/// Backed by gpa.
124116maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAlloc) = .{},
125117
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.
122comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{},
123
126124const MaybeComptimeAlloc = struct {
127125 /// The runtime index of the `alloc` instruction.
128126 runtime_index: Value.RuntimeIndex,
129127 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to
130128 /// RLS, a single comptime-known allocation may have arbitrarily many stores.
131129 /// 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 }) = .{},
133135 /// Backed by sema.arena. Contains instructions such as `optional_payload_ptr_set`
134136 /// which have side effects so will not be elided by Liveness: we must rewrite these
135137 /// instructions to be nops instead of relying on Liveness.
136138 non_elideable_pointers: std.ArrayListUnmanaged(Air.Inst.Index) = .{},
137139};
138140
141const 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
153fn 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
165pub fn getComptimeAlloc(sema: *Sema, idx: ComptimeAllocIndex) *ComptimeAlloc {
166 return &sema.comptime_allocs.items[@intFromEnum(idx)];
167}
168
139169const std = @import("std");
140170const math = std.math;
141171const mem = std.mem;
......@@ -164,6 +194,7 @@ const build_options = @import("build_options");
164194const Compilation = @import("Compilation.zig");
165195const InternPool = @import("InternPool.zig");
166196const Alignment = InternPool.Alignment;
197const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
167198
168199pub const default_branch_quota = 1000;
169200pub const default_reference_trace_len = 2;
......@@ -787,40 +818,6 @@ pub const Block = struct {
787818 const zcu = block.sema.mod;
788819 return zcu.namespacePtr(block.namespace).file_scope.mod;
789820 }
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 };
824821};
825822
826823const LabeledBlock = struct {
......@@ -869,6 +866,7 @@ pub fn deinit(sema: *Sema) void {
869866 sema.unresolved_inferred_allocs.deinit(gpa);
870867 sema.base_allocs.deinit(gpa);
871868 sema.maybe_comptime_allocs.deinit(gpa);
869 sema.comptime_allocs.deinit(gpa);
872870 sema.* = undefined;
873871}
874872
......@@ -1901,7 +1899,7 @@ pub fn resolveConstStringIntern(
19011899 const wanted_type = Type.slice_const_u8;
19021900 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
19031901 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);
19051903}
19061904
19071905pub 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
21402138fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
21412139 const val = (try sema.resolveValue(inst)) orelse return null;
21422140 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,
21442142 .int => {},
21452143 .eu_payload, .opt_payload, .elem, .field => unreachable,
21462144 };
......@@ -2192,17 +2190,21 @@ fn resolveInstConst(
21922190}
21932191
21942192/// Value Tag may be `undef` or `variable`.
2195pub fn resolveConstValueAllowVariables(
2193pub fn resolveFinalDeclValue(
21962194 sema: *Sema,
21972195 block: *Block,
21982196 src: LazySrcLoc,
21992197 air_ref: Air.Inst.Ref,
2200 reason: NeededComptimeReason,
22012198) CompileError!TypedValue {
22022199 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 });
22042203 };
22052204 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 }
22062208 return .{
22072209 .ty = sema.typeOf(air_ref),
22082210 .val = val,
......@@ -2671,7 +2673,7 @@ fn analyzeAsInt(
26712673
26722674/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
26732675/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
2674fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
2676fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
26752677 const zcu = sema.mod;
26762678 const ip = &zcu.intern_pool;
26772679 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
26822684 const zir_capture: Zir.Inst.Capture = @bitCast(raw);
26832685 capture.* = switch (zir_capture.unwrap()) {
26842686 .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 }),
26852703 .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
26862704 const air_ref = try sema.resolveInst(inst.toRef());
26872705 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 }
26882710 break :capture .{ .@"comptime" = val.toIntern() };
26892711 }
26902712 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
......@@ -2766,7 +2788,7 @@ fn zirStructDecl(
27662788 break :blk decls_len;
27672789 } else 0;
27682790
2769 const captures = try sema.getCaptures(block, extra_index, captures_len);
2791 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
27702792 extra_index += captures_len;
27712793
27722794 if (small.has_backing_int) {
......@@ -2981,7 +3003,7 @@ fn zirEnumDecl(
29813003 break :blk decls_len;
29823004 } else 0;
29833005
2984 const captures = try sema.getCaptures(block, extra_index, captures_len);
3006 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
29853007 extra_index += captures_len;
29863008
29873009 const decls = sema.code.bodySlice(extra_index, decls_len);
......@@ -3254,7 +3276,7 @@ fn zirUnionDecl(
32543276 break :blk decls_len;
32553277 } else 0;
32563278
3257 const captures = try sema.getCaptures(block, extra_index, captures_len);
3279 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
32583280 extra_index += captures_len;
32593281
32603282 const union_init: InternPool.UnionTypeInit = .{
......@@ -3358,7 +3380,7 @@ fn zirOpaqueDecl(
33583380 break :blk decls_len;
33593381 } else 0;
33603382
3361 const captures = try sema.getCaptures(block, extra_index, captures_len);
3383 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
33623384 extra_index += captures_len;
33633385
33643386 const opaque_init: InternPool.OpaqueTypeInit = .{
......@@ -3653,9 +3675,9 @@ fn zirAllocExtended(
36533675 try sema.air_instructions.append(gpa, .{
36543676 .tag = .inferred_alloc_comptime,
36553677 .data = .{ .inferred_alloc_comptime = .{
3656 .decl_index = undefined,
36573678 .alignment = alignment,
36583679 .is_const = small.is_const,
3680 .ptr = undefined,
36593681 } },
36603682 });
36613683 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
37173739 const ptr_info = alloc_ty.ptrInfo(mod);
37183740 const elem_ty = Type.fromInterned(ptr_info.child);
37193741
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);
37463756 },
3747 }
3757 else => {},
3758 },
3759 else => {},
37483760 }
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));
37503787 }
37513788
37523789 if (try sema.typeRequiresComptime(elem_ty)) {
......@@ -3762,7 +3799,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
37623799
37633800/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved
37643801/// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`.
3765fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index {
3802fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index {
37663803 const mod = sema.mod;
37673804
37683805 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
......@@ -3771,7 +3808,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
37713808
37723809 const alloc_inst = alloc.toIndex() orelse return null;
37733810 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);
37753812
37763813 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.
37773814 // We will resolve and return its value.
......@@ -3779,7 +3816,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
37793816 // We expect to have emitted at least one store, unless the elem type is OPV.
37803817 if (stores.len == 0) {
37813818 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);
37833820 }
37843821
37853822 // 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
37943831
37953832 const val = store_data.rhs.toInterned().?;
37963833 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);
37983835 }
37993836
38003837 // The simple strategy failed: we must create a mutable comptime alloc and
38013838 // perform all of the runtime store operations at comptime.
38023839
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);
38063841
3807 const decl_ptr = try mod.intern(.{ .ptr = .{
3842 const alloc_ptr = try mod.intern(.{ .ptr = .{
38083843 .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 },
38133845 } });
38143846
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
38163848 var ptr_mapping = std.AutoHashMap(Air.Inst.Index, InternPool.Index).init(sema.arena);
38173849 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));
3818 ptr_mapping.putAssumeCapacity(alloc_inst, decl_ptr);
3850 ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr);
38193851
38203852 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);
38213853 for (stores) |store_inst| {
......@@ -3953,14 +3985,27 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
39533985 }
39543986
39553987 // 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);
39583990}
39593991
39603992/// 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.
3963fn 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.
3998fn 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
39644009 // We're almost done - we have the resolved comptime value. We just need to
39654010 // eliminate the now-dead runtime instructions.
39664011
......@@ -3974,14 +4019,34 @@ fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Inde
39744019 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };
39754020
39764021 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| {
39784023 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);
39794024 }
39804025 for (comptime_info.non_elideable_pointers.items) |ptr_inst| {
39814026 sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst);
39824027 }
39834028
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 }
39854050}
39864051
39874052fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {
......@@ -4011,9 +4076,9 @@ fn zirAllocInferredComptime(
40114076 try sema.air_instructions.append(gpa, .{
40124077 .tag = .inferred_alloc_comptime,
40134078 .data = .{ .inferred_alloc_comptime = .{
4014 .decl_index = undefined,
40154079 .alignment = .none,
40164080 .is_const = is_const,
4081 .ptr = undefined,
40174082 } },
40184083 });
40194084 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
......@@ -4076,9 +4141,9 @@ fn zirAllocInferred(
40764141 try sema.air_instructions.append(gpa, .{
40774142 .tag = .inferred_alloc_comptime,
40784143 .data = .{ .inferred_alloc_comptime = .{
4079 .decl_index = undefined,
40804144 .alignment = .none,
40814145 .is_const = is_const,
4146 .ptr = undefined,
40824147 } },
40834148 });
40844149 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
......@@ -4092,8 +4157,10 @@ fn zirAllocInferred(
40924157 } },
40934158 });
40944159 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 }
40974164 return result_index.toRef();
40984165}
40994166
......@@ -4112,38 +4179,33 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
41124179
41134180 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
41144181 .inferred_alloc_comptime => {
4182 // The work was already done for us by `Sema.storeToInferredAllocComptime`.
4183 // All we need to do is remap the pointer.
41154184 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;
41294186
41304187 if (std.debug.runtime_safety) {
41314188 // The inferred_alloc_comptime should never be referenced again
41324189 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });
41334190 }
41344191
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 }
41444206
41454207 // 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));
41474209 },
41484210 .inferred_alloc => {
41494211 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
41664228
41674229 if (!ia1.is_const) {
41684230 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);
41784234
41794235 // 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()));
41814237
41824238 // Unless the block is comptime, `alloc_inferred` always produces
41834239 // 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
43874443 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
43884444 else => break,
43894445 };
4390 try sema.checkKnownAllocPtr(ptr, base_ptr);
4446 try sema.checkKnownAllocPtr(block, ptr, base_ptr);
43914447 return base_ptr;
43924448}
43934449
......@@ -4703,6 +4759,7 @@ fn validateUnionInit(
47034759 var first_block_index = block.instructions.items.len;
47044760 var block_index = block.instructions.items.len - 1;
47054761 var init_val: ?Value = null;
4762 var init_ref: ?Air.Inst.Ref = null;
47064763 while (block_index > 0) : (block_index -= 1) {
47074764 const store_inst = block.instructions.items[block_index];
47084765 if (store_inst.toRef() == field_ptr_ref) {
......@@ -4727,6 +4784,7 @@ fn validateUnionInit(
47274784 ).?
47284785 else
47294786 block_index, first_block_index);
4787 init_ref = bin_op.rhs;
47304788 init_val = try sema.resolveValue(bin_op.rhs);
47314789 break;
47324790 }
......@@ -4779,10 +4837,11 @@ fn validateUnionInit(
47794837 .needed_comptime_reason = "initializer of comptime only union must be comptime-known",
47804838 });
47814839 }
4840 if (init_ref) |v| try sema.validateRuntimeValue(block, field_ptr_data.src(), v);
47824841
47834842 const new_tag = Air.internedToRef(tag_val.toIntern());
47844843 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);
47864845}
47874846
47884847fn validateStructInit(
......@@ -4887,6 +4946,8 @@ fn validateStructInit(
48874946 return;
48884947 }
48894948
4949 var fields_allow_runtime = true;
4950
48904951 var struct_is_comptime = true;
48914952 var first_block_index = block.instructions.items.len;
48924953
......@@ -4957,6 +5018,7 @@ fn validateStructInit(
49575018 ).?
49585019 else
49595020 block_index, first_block_index);
5021 if (!sema.checkRuntimeValue(bin_op.rhs)) fields_allow_runtime = false;
49605022 if (try sema.resolveValue(bin_op.rhs)) |val| {
49615023 field_values[i] = val.toIntern();
49625024 } else if (require_comptime) {
......@@ -4996,6 +5058,11 @@ fn validateStructInit(
49965058 field_values[i] = default_val.toIntern();
49975059 }
49985060
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
49995066 if (root_msg) |msg| {
50005067 if (mod.typeToStruct(struct_ty)) |struct_type| {
50015068 const decl = mod.declPtr(struct_type.decl.unwrap().?);
......@@ -5067,7 +5134,7 @@ fn validateStructInit(
50675134 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)
50685135 else
50695136 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);
50715138 const init = Air.internedToRef(field_values[i]);
50725139 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
50735140 }
......@@ -5474,7 +5541,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
54745541 },
54755542 .inferred_alloc => {
54765543 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);
54785545 },
54795546 else => unreachable,
54805547 }
......@@ -5483,6 +5550,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
54835550fn storeToInferredAlloc(
54845551 sema: *Sema,
54855552 block: *Block,
5553 src: LazySrcLoc,
54865554 ptr: Air.Inst.Ref,
54875555 operand: Air.Inst.Ref,
54885556 inferred_alloc: *InferredAlloc,
......@@ -5490,7 +5558,7 @@ fn storeToInferredAlloc(
54905558 // Create a store instruction as a placeholder. This will be replaced by a
54915559 // proper store sequence once we know the stored type.
54925560 const dummy_store = try block.addBinOp(.store, ptr, operand);
5493 try sema.checkComptimeKnownStore(block, dummy_store);
5561 try sema.checkComptimeKnownStore(block, dummy_store, src);
54945562 // Add the stored instruction to the set we will use to resolve peer types
54955563 // for the inferred allocation.
54965564 try inferred_alloc.prongs.append(sema.arena, dummy_store.toIndex().?);
......@@ -5503,20 +5571,38 @@ fn storeToInferredAllocComptime(
55035571 operand: Air.Inst.Ref,
55045572 iac: *Air.Inst.Data.InferredAllocComptime,
55055573) CompileError!void {
5574 const zcu = sema.mod;
55065575 const operand_ty = sema.typeOf(operand);
55075576 // 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 },
55195589 });
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 }
55205606}
55215607
55225608fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
......@@ -6178,6 +6264,9 @@ fn resolveAnalyzedBlock(
61786264 };
61796265 return sema.failWithOwnedErrorMsg(child_block, msg);
61806266 }
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 }
61816270 const ty_inst = Air.internedToRef(resolved_ty.toIntern());
61826271 switch (block_tag) {
61836272 .block => {
......@@ -6579,6 +6668,9 @@ fn addDbgVar(
65796668 };
65806669 if (try sema.typeRequiresComptime(val_ty)) return;
65816670 if (!(try sema.typeHasRuntimeBits(val_ty))) return;
6671 if (try sema.resolveValue(operand)) |operand_val| {
6672 if (operand_val.canMutateComptimeVarState(mod)) return;
6673 }
65826674
65836675 // To ensure the lexical scoping is known to backends, this alloc must be
65846676 // within a real runtime block. We set a flag which communicates information
......@@ -7741,20 +7833,24 @@ fn analyzeCall(
77417833 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
77427834 };
77437835
7744 if (should_memoize and is_comptime_call) {
7836 if (is_comptime_call) {
77457837 const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined);
77467838 const result_interned = try result_val.intern2(sema.fn_ret_ty, mod);
77477839
77487840 // Transform ad-hoc inferred error set types into concrete error sets.
77497841 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
77507842
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`.
77517845 // TODO: check whether any external comptime memory was mutated by the
77527846 // 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 }
77587854
77597855 break :res2 Air.internedToRef(result_transformed);
77607856 }
......@@ -7787,6 +7883,7 @@ fn analyzeCall(
77877883 } else Type.fromInterned(InternPool.Index.var_args_param_type);
77887884 assert(!param_ty.isGenericPoison());
77897885 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.*);
77907887 if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) {
77917888 return arg_out.*;
77927889 }
......@@ -8082,7 +8179,6 @@ fn instantiateGenericCall(
80828179 .generic_call_decl = block.src_decl.toOptional(),
80838180 .branch_quota = sema.branch_quota,
80848181 .branch_count = sema.branch_count,
8085 .comptime_mutable_decls = sema.comptime_mutable_decls,
80868182 .comptime_err_ret_trace = sema.comptime_err_ret_trace,
80878183 };
80888184 defer child_sema.deinit();
......@@ -8147,6 +8243,7 @@ fn instantiateGenericCall(
81478243 },
81488244 };
81498245 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);
81508247 const arg_ty = sema.typeOf(arg_ref);
81518248 if (arg_ty.zigTypeTag(mod) == .NoReturn) {
81528249 // This terminates argument analysis.
......@@ -8859,12 +8956,12 @@ fn analyzeOptionalPayloadPtr(
88598956
88608957 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
88618958 if (initializing) {
8862 if (!ptr_val.isComptimeMutablePtr(mod)) {
8959 if (!sema.isComptimeMutablePtr(ptr_val)) {
88638960 // If the pointer resulting from this function was stored at comptime,
88648961 // the optional non-null bit would be set that way. But in this case,
88658962 // we need to emit a runtime instruction to do it.
88668963 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);
88688965 }
88698966 return Air.internedToRef((try mod.intern(.{ .ptr = .{
88708967 .ty = child_pointer.toIntern(),
......@@ -8891,7 +8988,7 @@ fn analyzeOptionalPayloadPtr(
88918988
88928989 if (initializing) {
88938990 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);
88958992 return opt_payload_ptr;
88968993 } else {
88978994 return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr);
......@@ -9050,13 +9147,13 @@ fn analyzeErrUnionPayloadPtr(
90509147
90519148 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
90529149 if (initializing) {
9053 if (!ptr_val.isComptimeMutablePtr(mod)) {
9150 if (!sema.isComptimeMutablePtr(ptr_val)) {
90549151 // If the pointer resulting from this function was stored at comptime,
90559152 // the error union error code would be set that way. But in this case,
90569153 // we need to emit a runtime instruction to do it.
90579154 try sema.requireRuntimeBlock(block, src, null);
90589155 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);
90609157 }
90619158 return Air.internedToRef((try mod.intern(.{ .ptr = .{
90629159 .ty = operand_pointer_ty.toIntern(),
......@@ -9085,7 +9182,7 @@ fn analyzeErrUnionPayloadPtr(
90859182
90869183 if (initializing) {
90879184 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);
90899186 return eu_payload_ptr;
90909187 } else {
90919188 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!
1008910186 } }));
1009010187 }
1009110188 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
10189 try sema.validateRuntimeValue(block, ptr_src, operand);
1009210190 if (!is_vector) {
1009310191 return block.addUnOp(.int_from_ptr, operand);
1009410192 }
......@@ -14743,7 +14841,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1474314841 // Optimization for the common pattern of a single element repeated N times, such
1474414842 // as zero-filling a byte array.
1474514843 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)).?;
1474714845 break :v try mod.intern(.{ .aggregate = .{
1474814846 .ty = result_ty.toIntern(),
1474914847 .storage = .{ .repeated_elem = elem_val.toIntern() },
......@@ -14755,7 +14853,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1475514853 while (elem_i < result_len) {
1475614854 var lhs_i: usize = 0;
1475714855 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)).?;
1475914857 element_vals[elem_i] = elem_val.toIntern();
1476014858 elem_i += 1;
1476114859 }
......@@ -19585,6 +19683,8 @@ fn analyzeRet(
1958519683
1958619684 try sema.resolveTypeLayout(sema.fn_ret_ty);
1958719685
19686 try sema.validateRuntimeValue(block, operand_src, operand);
19687
1958819688 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;
1958919689 if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
1959019690 // Avoid adding a frame to the error return trace in case the value is comptime-known
......@@ -20013,6 +20113,8 @@ fn zirStructInit(
2001320113 });
2001420114 }
2001520115
20116 try sema.validateRuntimeValue(block, field_src, init_inst);
20117
2001620118 if (is_ref) {
2001720119 const target = mod.getTarget();
2001820120 const alloc_ty = try sema.ptrType(.{
......@@ -20187,6 +20289,10 @@ fn finishStructInit(
2018720289 });
2018820290 }
2018920291
20292 for (field_inits) |field_init| {
20293 try sema.validateRuntimeValue(block, dest_src, field_init);
20294 }
20295
2019020296 if (is_ref) {
2019120297 try sema.resolveStructLayout(struct_ty);
2019220298 const target = sema.mod.getTarget();
......@@ -21023,7 +21129,7 @@ fn zirReify(
2102321129 .needed_comptime_reason = "operand to @Type must be comptime-known",
2102421130 });
2102521131 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);
2102721133 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
2102821134 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
2102921135 .Type => return .type_type,
......@@ -21268,14 +21374,16 @@ fn zirReify(
2126821374 var names: InferredErrorSet.NameMap = .{};
2126921375 try names.ensureUnusedCapacity(sema.arena, len);
2127021376 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)).?;
2127221378 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
2127321379 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
2127421380 ip,
2127521381 try ip.getOrPutString(gpa, "name"),
2127621382 ).?);
2127721383
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 });
2127921387 _ = try mod.getErrorValue(name);
2128021388 const gop = names.getOrPutAssumeCapacity(name);
2128121389 if (gop.found_existing) {
......@@ -21451,7 +21559,7 @@ fn zirReify(
2145121559
2145221560 var noalias_bits: u32 = 0;
2145321561 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)).?;
2145521563 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
2145621564 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
2145721565 ip,
......@@ -21526,12 +21634,14 @@ fn reifyEnum(
2152621634 std.hash.autoHash(&hasher, fields_len);
2152721635
2152821636 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)).?;
2153021638
2153121639 const field_name_val = try field_info.fieldValue(mod, 0);
2153221640 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
2153321641
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 });
2153521645
2153621646 std.hash.autoHash(&hasher, .{
2153721647 field_name,
......@@ -21569,12 +21679,13 @@ fn reifyEnum(
2156921679 wip_ty.setTagTy(ip, tag_ty.toIntern());
2157021680
2157121681 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)).?;
2157321683
2157421684 const field_name_val = try field_info.fieldValue(mod, 0);
2157521685 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
2157621686
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);
2157821689
2157921690 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
2158021691 // TODO: better source location
......@@ -21646,13 +21757,15 @@ fn reifyUnion(
2164621757 var any_aligns = false;
2164721758
2164821759 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)).?;
2165021761
2165121762 const field_name_val = try field_info.fieldValue(mod, 0);
2165221763 const field_type_val = try field_info.fieldValue(mod, 1);
2165321764 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2));
2165421765
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 });
2165621769
2165721770 std.hash.autoHash(&hasher, .{
2165821771 field_name,
......@@ -21720,12 +21833,13 @@ fn reifyUnion(
2172021833 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
2172121834
2172221835 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)).?;
2172421837
2172521838 const field_name_val = try field_info.fieldValue(mod, 0);
2172621839 const field_type_val = try field_info.fieldValue(mod, 1);
2172721840
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);
2172921843
2173021844 const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {
2173121845 // TODO: better source location
......@@ -21771,12 +21885,13 @@ fn reifyUnion(
2177121885 try field_names.ensureTotalCapacity(sema.arena, fields_len);
2177221886
2177321887 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)).?;
2177521889
2177621890 const field_name_val = try field_info.fieldValue(mod, 0);
2177721891 const field_type_val = try field_info.fieldValue(mod, 1);
2177821892
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);
2178021895 const gop = field_names.getOrPutAssumeCapacity(field_name);
2178121896 if (gop.found_existing) {
2178221897 // TODO: better source location
......@@ -21883,7 +21998,7 @@ fn reifyStruct(
2188321998 var any_aligned_fields = false;
2188421999
2188522000 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)).?;
2188722002
2188822003 const field_name_val = try field_info.fieldValue(mod, 0);
2188922004 const field_type_val = try field_info.fieldValue(mod, 1);
......@@ -21891,7 +22006,9 @@ fn reifyStruct(
2189122006 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
2189222007 const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4));
2189322008
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 });
2189522012 const field_is_comptime = field_is_comptime_val.toBool();
2189622013 const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {
2189722014 const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());
......@@ -21959,7 +22076,7 @@ fn reifyStruct(
2195922076 const struct_type = ip.loadStructType(wip_ty.index);
2196022077
2196122078 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)).?;
2196322080
2196422081 const field_name_val = try field_info.fieldValue(mod, 0);
2196522082 const field_type_val = try field_info.fieldValue(mod, 1);
......@@ -21968,7 +22085,8 @@ fn reifyStruct(
2196822085 const field_alignment_val = try field_info.fieldValue(mod, 4);
2196922086
2197022087 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);
2197222090 if (is_tuple) {
2197322091 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
2197422092 block,
......@@ -22914,6 +23032,7 @@ fn ptrCastFull(
2291423032 }
2291523033
2291623034 try sema.requireRuntimeBlock(block, src, null);
23035 try sema.validateRuntimeValue(block, operand_src, ptr);
2291723036
2291823037 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and
2291923038 (try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)) or Type.fromInterned(dest_info.child).zigTypeTag(mod) == .Fn))
......@@ -22986,7 +23105,7 @@ fn ptrCastFull(
2298623105 });
2298723106 } else {
2298823107 assert(dest_ptr_ty.eql(dest_ty, mod));
22989 try sema.checkKnownAllocPtr(operand, result_ptr);
23108 try sema.checkKnownAllocPtr(block, operand, result_ptr);
2299023109 return result_ptr;
2299123110 }
2299223111}
......@@ -23022,7 +23141,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
2302223141
2302323142 try sema.requireRuntimeBlock(block, src, null);
2302423143 const new_ptr = try block.addBitCast(dest_ty, operand);
23025 try sema.checkKnownAllocPtr(operand, new_ptr);
23144 try sema.checkKnownAllocPtr(block, operand, new_ptr);
2302623145 return new_ptr;
2302723146}
2302823147
......@@ -23568,7 +23687,7 @@ fn checkPtrIsNotComptimeMutable(
2356823687 operand_src: LazySrcLoc,
2356923688) CompileError!void {
2357023689 _ = operand_src;
23571 if (ptr_val.isComptimeMutablePtr(sema.mod)) {
23690 if (sema.isComptimeMutablePtr(ptr_val)) {
2357223691 return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});
2357323692 }
2357423693}
......@@ -23577,9 +23696,10 @@ fn checkComptimeVarStore(
2357723696 sema: *Sema,
2357823697 block: *Block,
2357923698 src: LazySrcLoc,
23580 decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl,
23699 alloc_index: ComptimeAllocIndex,
2358123700) 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)) {
2358323703 if (block.runtime_cond) |cond_src| {
2358423704 const msg = msg: {
2358523705 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
2443324553 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
2443424554 break :rs operand_src;
2443524555 };
24436 if (ptr_val.isComptimeMutablePtr(mod)) {
24556 if (sema.isComptimeMutablePtr(ptr_val)) {
2443724557 const ptr_ty = sema.typeOf(ptr);
2443824558 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
2443924559 const new_val = switch (op) {
......@@ -25149,7 +25269,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2514925269 }
2515025270
2515125271 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;
2515325273 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
2515425274 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;
2515525275 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
2534225462 return;
2534325463 }
2534425464
25345 if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
25465 if (!sema.isComptimeMutablePtr(ptr_val)) break :rs dest_src;
2534625466 const elem_val = try sema.resolveValue(elem) orelse break :rs value_src;
2534725467 const array_ty = try mod.arrayType(.{
2534825468 .child = dest_elem_ty.toIntern(),
......@@ -25588,7 +25708,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2558825708 if (val.isGenericPoison()) {
2558925709 break :blk .generic;
2559025710 }
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 }) };
2559225714 } else if (extra.data.bits.has_section_ref) blk: {
2559325715 const section_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
2559425716 extra_index += 1;
......@@ -27115,7 +27237,7 @@ fn fieldPtr(
2711527237 try sema.requireRuntimeBlock(block, src, null);
2711627238
2711727239 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);
2711927241 return field_ptr;
2712027242 } else if (ip.stringEqlSlice(field_name, "len")) {
2712127243 const result_ty = try sema.ptrType(.{
......@@ -27139,7 +27261,7 @@ fn fieldPtr(
2713927261 try sema.requireRuntimeBlock(block, src, null);
2714027262
2714127263 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);
2714327265 return field_ptr;
2714427266 } else {
2714527267 return sema.fail(
......@@ -27238,7 +27360,7 @@ fn fieldPtr(
2723827360 else
2723927361 object_ptr;
2724027362 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);
2724227364 return field_ptr;
2724327365 },
2724427366 .Union => {
......@@ -27247,7 +27369,7 @@ fn fieldPtr(
2724727369 else
2724827370 object_ptr;
2724927371 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);
2725127373 return field_ptr;
2725227374 },
2725327375 else => {},
......@@ -28030,7 +28152,7 @@ fn elemPtr(
2803028152 },
2803128153 };
2803228154
28033 try sema.checkKnownAllocPtr(indexable_ptr, elem_ptr);
28155 try sema.checkKnownAllocPtr(block, indexable_ptr, elem_ptr);
2803428156 return elem_ptr;
2803528157}
2803628158
......@@ -28083,7 +28205,7 @@ fn elemPtrOneLayerOnly(
2808328205 },
2808428206 else => unreachable, // Guaranteed by checkIndexable
2808528207 };
28086 try sema.checkKnownAllocPtr(indexable, elem_ptr);
28208 try sema.checkKnownAllocPtr(block, indexable, elem_ptr);
2808728209 return elem_ptr;
2808828210 },
2808928211 }
......@@ -28617,7 +28739,7 @@ fn coerceExtra(
2861728739 try sema.requireRuntimeBlock(block, inst_src, null);
2861828740 try sema.queueFullTypeResolution(dest_ty);
2861928741 const new_val = try block.addBitCast(dest_ty, inst);
28620 try sema.checkKnownAllocPtr(inst, new_val);
28742 try sema.checkKnownAllocPtr(block, inst, new_val);
2862128743 return new_val;
2862228744 }
2862328745
......@@ -30349,7 +30471,7 @@ fn storePtr2(
3034930471 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
3035030472 break :rs operand_src;
3035130473 };
30352 if (ptr_val.isComptimeMutablePtr(mod)) {
30474 if (sema.isComptimeMutablePtr(ptr_val)) {
3035330475 try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
3035430476 return;
3035530477 } else break :rs ptr_src;
......@@ -30392,7 +30514,7 @@ fn storePtr2(
3039230514 else
3039330515 try block.addBinOp(air_tag, ptr, operand);
3039430516
30395 try sema.checkComptimeKnownStore(block, store_inst);
30517 try sema.checkComptimeKnownStore(block, store_inst, operand_src);
3039630518
3039730519 return;
3039830520}
......@@ -30400,29 +30522,39 @@ fn storePtr2(
3040030522/// Given an AIR store instruction, checks whether we are performing a
3040130523/// comptime-known store to a local alloc, and updates `maybe_comptime_allocs`
3040230524/// accordingly.
30403fn checkComptimeKnownStore(sema: *Sema, block: *Block, store_inst_ref: Air.Inst.Ref) !void {
30525/// Handles calling `validateRuntimeValue` if the store is runtime for any reason.
30526fn checkComptimeKnownStore(sema: *Sema, block: *Block, store_inst_ref: Air.Inst.Ref, store_src: LazySrcLoc) !void {
3040430527 const store_inst = store_inst_ref.toIndex().?;
3040530528 const inst_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
3040630529 const ptr = inst_data.lhs.toIndex() orelse return;
3040730530 const operand = inst_data.rhs;
3040830531
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;
3041130535
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);
3041630549 }
3041730550
30418 // Store is runtime-known
30419 _ = sema.maybe_comptime_allocs.remove(maybe_base_alloc);
30551 try sema.validateRuntimeValue(block, store_src, operand);
3042030552}
3042130553
3042230554/// Given an AIR instruction transforming a pointer (struct_field_ptr,
3042330555/// ptr_elem_ptr, bitcast, etc), checks whether the base pointer refers to a
3042430556/// local alloc, and updates `base_allocs` accordingly.
30425fn checkKnownAllocPtr(sema: *Sema, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref) !void {
30557fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref) !void {
3042630558 const base_ptr_inst = base_ptr.toIndex() orelse return;
3042730559 const new_ptr_inst = new_ptr.toIndex() orelse return;
3042830560 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
3044230574 // If the index value is runtime-known, this pointer is also runtime-known, so
3044330575 // we must in turn make the alloc value runtime-known.
3044430576 if (null == try sema.resolveValue(index_ref)) {
30445 _ = sema.maybe_comptime_allocs.remove(alloc_inst);
30577 try sema.markMaybeComptimeAllocRuntime(block, alloc_inst);
3044630578 }
3044730579 },
3044830580 else => {},
3044930581 }
3045030582}
3045130583
30584fn 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
3045230605/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
3045330606/// pointer. Only if the final element type matches the vector element type, and the
3045430607/// lengths match.
......@@ -30491,13 +30644,16 @@ fn storePtrVal(
3049130644) !void {
3049230645 const mod = sema.mod;
3049330646 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 }
3049530651
3049630652 try sema.resolveTypeLayout(operand_ty);
3049730653 switch (mut_kit.pointee) {
3049830654 .opv => {},
3049930655 .direct => |val_ptr| {
30500 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
30656 if (mut_kit.root == .comptime_field) {
3050130657 val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod)));
3050230658 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
3050330659 // TODO use failWithInvalidComptimeFieldStore
......@@ -30552,7 +30708,11 @@ fn storePtrVal(
3055230708}
3055330709
3055430710const 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,
3055630716 pointee: union(enum) {
3055730717 opv,
3055830718 /// The pointer type matches the actual comptime Value so a direct
......@@ -30591,17 +30751,21 @@ fn beginComptimePtrMutation(
3059130751 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
3059230752 switch (ptr.addr) {
3059330753 .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 });
3059730757 },
3059830758 .comptime_field => |comptime_field| {
3059930759 const duped = try sema.arena.create(Value);
3060030760 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 );
3060530769 },
3060630770 .eu_payload => |eu_ptr| {
3060730771 const eu_ty = Type.fromInterned(mod.intern_pool.typeOf(eu_ptr)).childType(mod);
......@@ -30612,7 +30776,7 @@ fn beginComptimePtrMutation(
3061230776 const payload_ty = parent.ty.errorUnionPayload(mod);
3061330777 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
3061430778 return ComptimePtrMutationKit{
30615 .mut_decl = parent.mut_decl,
30779 .root = parent.root,
3061630780 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
3061730781 .ty = payload_ty,
3061830782 };
......@@ -30630,7 +30794,7 @@ fn beginComptimePtrMutation(
3063030794 val_ptr.* = Value.initPayload(&payload.base);
3063130795
3063230796 return ComptimePtrMutationKit{
30633 .mut_decl = parent.mut_decl,
30797 .root = parent.root,
3063430798 .pointee = .{ .direct = &payload.data },
3063530799 .ty = payload_ty,
3063630800 };
......@@ -30640,7 +30804,7 @@ fn beginComptimePtrMutation(
3064030804 // Even though the parent value type has well-defined memory layout, our
3064130805 // pointer type does not.
3064230806 .reinterpret => return ComptimePtrMutationKit{
30643 .mut_decl = parent.mut_decl,
30807 .root = parent.root,
3064430808 .pointee = .bad_ptr_ty,
3064530809 .ty = eu_ty,
3064630810 },
......@@ -30655,7 +30819,7 @@ fn beginComptimePtrMutation(
3065530819 const payload_ty = parent.ty.optionalChild(mod);
3065630820 switch (val_ptr.ip_index) {
3065730821 .none => return ComptimePtrMutationKit{
30658 .mut_decl = parent.mut_decl,
30822 .root = parent.root,
3065930823 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
3066030824 .ty = payload_ty,
3066130825 },
......@@ -30682,7 +30846,7 @@ fn beginComptimePtrMutation(
3068230846 val_ptr.* = Value.initPayload(&payload.base);
3068330847
3068430848 return ComptimePtrMutationKit{
30685 .mut_decl = parent.mut_decl,
30849 .root = parent.root,
3068630850 .pointee = .{ .direct = &payload.data },
3068730851 .ty = payload_ty,
3068830852 };
......@@ -30693,7 +30857,7 @@ fn beginComptimePtrMutation(
3069330857 // Even though the parent value type has well-defined memory layout, our
3069430858 // pointer type does not.
3069530859 .reinterpret => return ComptimePtrMutationKit{
30696 .mut_decl = parent.mut_decl,
30860 .root = parent.root,
3069730861 .pointee = .bad_ptr_ty,
3069830862 .ty = opt_ty,
3069930863 },
......@@ -30717,7 +30881,7 @@ fn beginComptimePtrMutation(
3071730881 });
3071830882 }
3071930883 return .{
30720 .mut_decl = parent.mut_decl,
30884 .root = parent.root,
3072130885 .pointee = .opv,
3072230886 .ty = elem_ty,
3072330887 };
......@@ -30742,7 +30906,7 @@ fn beginComptimePtrMutation(
3074230906 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
3074330907 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
3074430908 return .{
30745 .mut_decl = parent.mut_decl,
30909 .root = parent.root,
3074630910 .pointee = .{ .reinterpret = .{
3074730911 .val_ptr = val_ptr,
3074830912 .byte_offset = elem_abi_size * elem_idx,
......@@ -30759,7 +30923,7 @@ fn beginComptimePtrMutation(
3075930923 // If we wanted to avoid this, there would need to be special detection
3076030924 // elsewhere to identify when writing a value to an array element that is stored
3076130925 // 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;
3076330927
3076430928 const bytes = val_ptr.castTag(.bytes).?.data;
3076530929 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
......@@ -30780,7 +30944,7 @@ fn beginComptimePtrMutation(
3078030944 elem_ty,
3078130945 &elems[@intCast(elem_ptr.index)],
3078230946 ptr_elem_ty,
30783 parent.mut_decl,
30947 parent.root,
3078430948 );
3078530949 },
3078630950 .repeated => {
......@@ -30791,7 +30955,7 @@ fn beginComptimePtrMutation(
3079130955 // need to be special detection elsewhere to identify when writing a value to an
3079230956 // array element that is stored using the `repeated` tag, and handle it
3079330957 // without making a call to this function.
30794 const arena = mod.tmp_hack_arena.allocator();
30958 const arena = sema.arena;
3079530959
3079630960 const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod);
3079730961 const array_len_including_sentinel =
......@@ -30808,7 +30972,7 @@ fn beginComptimePtrMutation(
3080830972 elem_ty,
3080930973 &elems[@intCast(elem_ptr.index)],
3081030974 ptr_elem_ty,
30811 parent.mut_decl,
30975 parent.root,
3081230976 );
3081330977 },
3081430978
......@@ -30819,7 +30983,7 @@ fn beginComptimePtrMutation(
3081930983 elem_ty,
3082030984 &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)],
3082130985 ptr_elem_ty,
30822 parent.mut_decl,
30986 parent.root,
3082330987 ),
3082430988
3082530989 else => unreachable,
......@@ -30829,7 +30993,7 @@ fn beginComptimePtrMutation(
3082930993 // An array has been initialized to undefined at comptime and now we
3083030994 // are for the first time setting an element. We must change the representation
3083130995 // of the array from `undef` to `array`.
30832 const arena = mod.tmp_hack_arena.allocator();
30996 const arena = sema.arena;
3083330997
3083430998 const array_len_including_sentinel =
3083530999 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
......@@ -30845,7 +31009,7 @@ fn beginComptimePtrMutation(
3084531009 elem_ty,
3084631010 &elems[@intCast(elem_ptr.index)],
3084731011 ptr_elem_ty,
30848 parent.mut_decl,
31012 parent.root,
3084931013 );
3085031014 },
3085131015 else => unreachable,
......@@ -30866,7 +31030,7 @@ fn beginComptimePtrMutation(
3086631030 parent.ty,
3086731031 val_ptr,
3086831032 ptr_elem_ty,
30869 parent.mut_decl,
31033 parent.root,
3087031034 );
3087131035 },
3087231036 },
......@@ -30875,7 +31039,7 @@ fn beginComptimePtrMutation(
3087531039 // Even though the parent value type has well-defined memory layout, our
3087631040 // pointer type does not.
3087731041 return ComptimePtrMutationKit{
30878 .mut_decl = parent.mut_decl,
31042 .root = parent.root,
3087931043 .pointee = .bad_ptr_ty,
3088031044 .ty = base_elem_ty,
3088131045 };
......@@ -30885,7 +31049,7 @@ fn beginComptimePtrMutation(
3088531049 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
3088631050 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
3088731051 return ComptimePtrMutationKit{
30888 .mut_decl = parent.mut_decl,
31052 .root = parent.root,
3088931053 .pointee = .{ .reinterpret = .{
3089031054 .val_ptr = reinterpret.val_ptr,
3089131055 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx,
......@@ -30914,7 +31078,7 @@ fn beginComptimePtrMutation(
3091431078 parent.ty.structFieldType(field_index, mod),
3091531079 duped,
3091631080 ptr_elem_ty,
30917 parent.mut_decl,
31081 parent.root,
3091831082 );
3091931083 },
3092031084 .none => switch (val_ptr.tag()) {
......@@ -30925,10 +31089,10 @@ fn beginComptimePtrMutation(
3092531089 parent.ty.structFieldType(field_index, mod),
3092631090 &val_ptr.castTag(.aggregate).?.data[field_index],
3092731091 ptr_elem_ty,
30928 parent.mut_decl,
31092 parent.root,
3092931093 ),
3093031094 .repeated => {
30931 const arena = mod.tmp_hack_arena.allocator();
31095 const arena = sema.arena;
3093231096
3093331097 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
3093431098 @memset(elems, val_ptr.castTag(.repeated).?.data);
......@@ -30941,7 +31105,7 @@ fn beginComptimePtrMutation(
3094131105 parent.ty.structFieldType(field_index, mod),
3094231106 &elems[field_index],
3094331107 ptr_elem_ty,
30944 parent.mut_decl,
31108 parent.root,
3094531109 );
3094631110 },
3094731111 .@"union" => {
......@@ -30962,7 +31126,7 @@ fn beginComptimePtrMutation(
3096231126 field_ty,
3096331127 &payload.val,
3096431128 ptr_elem_ty,
30965 parent.mut_decl,
31129 parent.root,
3096631130 );
3096731131 } else {
3096831132 // Writing to a different field (a different or unknown tag is active) requires reinterpreting
......@@ -30973,7 +31137,7 @@ fn beginComptimePtrMutation(
3097331137 // The reinterpretation will read it back out as .none.
3097431138 payload.val = try payload.val.unintern(sema.arena, mod);
3097531139 return ComptimePtrMutationKit{
30976 .mut_decl = parent.mut_decl,
31140 .root = parent.root,
3097731141 .pointee = .{ .reinterpret = .{
3097831142 .val_ptr = val_ptr,
3097931143 .byte_offset = 0,
......@@ -30991,7 +31155,7 @@ fn beginComptimePtrMutation(
3099131155 parent.ty.slicePtrFieldType(mod),
3099231156 &val_ptr.castTag(.slice).?.data.ptr,
3099331157 ptr_elem_ty,
30994 parent.mut_decl,
31158 parent.root,
3099531159 ),
3099631160
3099731161 Value.slice_len_index => return beginComptimePtrMutationInner(
......@@ -31001,7 +31165,7 @@ fn beginComptimePtrMutation(
3100131165 Type.usize,
3100231166 &val_ptr.castTag(.slice).?.data.len,
3100331167 ptr_elem_ty,
31004 parent.mut_decl,
31168 parent.root,
3100531169 ),
3100631170
3100731171 else => unreachable,
......@@ -31013,7 +31177,7 @@ fn beginComptimePtrMutation(
3101331177 // A struct or union has been initialized to undefined at comptime and now we
3101431178 // are for the first time setting a field. We must change the representation
3101531179 // of the struct/union from `undef` to `struct`/`union`.
31016 const arena = mod.tmp_hack_arena.allocator();
31180 const arena = sema.arena;
3101731181
3101831182 switch (parent.ty.zigTypeTag(mod)) {
3101931183 .Struct => {
......@@ -31031,7 +31195,7 @@ fn beginComptimePtrMutation(
3103131195 parent.ty.structFieldType(field_index, mod),
3103231196 &fields[field_index],
3103331197 ptr_elem_ty,
31034 parent.mut_decl,
31198 parent.root,
3103531199 );
3103631200 },
3103731201 .Union => {
......@@ -31052,7 +31216,7 @@ fn beginComptimePtrMutation(
3105231216 payload_ty,
3105331217 &payload.data.val,
3105431218 ptr_elem_ty,
31055 parent.mut_decl,
31219 parent.root,
3105631220 );
3105731221 },
3105831222 .Pointer => {
......@@ -31071,7 +31235,7 @@ fn beginComptimePtrMutation(
3107131235 ptr_ty,
3107231236 &val_ptr.castTag(.slice).?.data.ptr,
3107331237 ptr_elem_ty,
31074 parent.mut_decl,
31238 parent.root,
3107531239 ),
3107631240 Value.slice_len_index => return beginComptimePtrMutationInner(
3107731241 sema,
......@@ -31080,7 +31244,7 @@ fn beginComptimePtrMutation(
3108031244 Type.usize,
3108131245 &val_ptr.castTag(.slice).?.data.len,
3108231246 ptr_elem_ty,
31083 parent.mut_decl,
31247 parent.root,
3108431248 ),
3108531249
3108631250 else => unreachable,
......@@ -31096,7 +31260,7 @@ fn beginComptimePtrMutation(
3109631260 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
3109731261 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
3109831262 return ComptimePtrMutationKit{
31099 .mut_decl = parent.mut_decl,
31263 .root = parent.root,
3110031264 .pointee = .{ .reinterpret = .{
3110131265 .val_ptr = reinterpret.val_ptr,
3110231266 .byte_offset = reinterpret.byte_offset + field_offset,
......@@ -31117,7 +31281,7 @@ fn beginComptimePtrMutationInner(
3111731281 decl_ty: Type,
3111831282 decl_val: *Value,
3111931283 ptr_elem_ty: Type,
31120 mut_decl: InternPool.Key.Ptr.Addr.MutDecl,
31284 root: ComptimePtrMutationKit.Root,
3112131285) CompileError!ComptimePtrMutationKit {
3112231286 const mod = sema.mod;
3112331287 const target = mod.getTarget();
......@@ -31127,7 +31291,7 @@ fn beginComptimePtrMutationInner(
3112731291
3112831292 if (coerce_ok) {
3112931293 return ComptimePtrMutationKit{
31130 .mut_decl = mut_decl,
31294 .root = root,
3113131295 .pointee = .{ .direct = decl_val },
3113231296 .ty = decl_ty,
3113331297 };
......@@ -31138,7 +31302,7 @@ fn beginComptimePtrMutationInner(
3113831302 const decl_elem_ty = decl_ty.childType(mod);
3113931303 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
3114031304 return ComptimePtrMutationKit{
31141 .mut_decl = mut_decl,
31305 .root = root,
3114231306 .pointee = .{ .direct = decl_val },
3114331307 .ty = decl_ty,
3114431308 };
......@@ -31147,20 +31311,20 @@ fn beginComptimePtrMutationInner(
3114731311
3114831312 if (!decl_ty.hasWellDefinedLayout(mod)) {
3114931313 return ComptimePtrMutationKit{
31150 .mut_decl = mut_decl,
31314 .root = root,
3115131315 .pointee = .bad_decl_ty,
3115231316 .ty = decl_ty,
3115331317 };
3115431318 }
3115531319 if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {
3115631320 return ComptimePtrMutationKit{
31157 .mut_decl = mut_decl,
31321 .root = root,
3115831322 .pointee = .bad_ptr_ty,
3115931323 .ty = ptr_elem_ty,
3116031324 };
3116131325 }
3116231326 return ComptimePtrMutationKit{
31163 .mut_decl = mut_decl,
31327 .root = root,
3116431328 .pointee = .{ .reinterpret = .{
3116531329 .val_ptr = decl_val,
3116631330 .byte_offset = 0,
......@@ -31208,13 +31372,7 @@ fn beginComptimePtrLoad(
3120831372
3120931373 var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) {
3121031374 .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: {
3121831376 const decl = mod.declPtr(decl_index);
3121931377 const decl_tv = try decl.typedValue();
3122031378 try sema.declareDependency(.{ .decl_val = decl_index });
......@@ -31224,10 +31382,24 @@ fn beginComptimePtrLoad(
3122431382 break :blk ComptimePtrLoadKit{
3122531383 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
3122631384 .pointee = decl_tv,
31227 .is_mutable = is_mutable,
31385 .is_mutable = false,
3122831386 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
3122931387 };
3123031388 },
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 },
3123131403 .anon_decl => |anon_decl| blk: {
3123231404 const decl_val = anon_decl.val;
3123331405 if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad;
......@@ -31352,7 +31524,7 @@ fn beginComptimePtrLoad(
3135231524 .len = len,
3135331525 .child = elem_ty.toIntern(),
3135431526 }),
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),
3135631528 } else null;
3135731529 break :blk deref;
3135831530 }
......@@ -31481,6 +31653,7 @@ fn bitCast(
3148131653 }
3148231654 }
3148331655 try sema.requireRuntimeBlock(block, inst_src, operand_src);
31656 try sema.validateRuntimeValue(block, inst_src, inst);
3148431657 return block.addBitCast(dest_ty, inst);
3148531658}
3148631659
......@@ -31693,7 +31866,7 @@ fn coerceCompatiblePtrs(
3169331866 try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);
3169431867 }
3169531868 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);
3169731870 return new_ptr;
3169831871}
3169931872
......@@ -35448,7 +35621,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3544835621 },
3544935622 .ptr => |ptr| {
3545035623 switch (ptr.addr) {
35451 .decl, .mut_decl, .anon_decl => return val,
35624 .decl, .comptime_alloc, .anon_decl => return val,
3545235625 .comptime_field => |field_val| {
3545335626 const resolved_field_val =
3545435627 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
......@@ -35803,9 +35976,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3580335976 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3580435977 defer analysis_arena.deinit();
3580535978
35806 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
35807 defer comptime_mutable_decls.deinit();
35808
3580935979 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
3581035980 defer comptime_err_ret_trace.deinit();
3581135981
......@@ -35821,7 +35991,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3582135991 .fn_ret_ty = Type.void,
3582235992 .fn_ret_ty_ies = null,
3582335993 .owner_func_index = .none,
35824 .comptime_mutable_decls = &comptime_mutable_decls,
3582535994 .comptime_err_ret_trace = &comptime_err_ret_trace,
3582635995 };
3582735996 defer sema.deinit();
......@@ -35887,11 +36056,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3588736056 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
3588836057 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
3588936058 }
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 }
3589536059}
3589636060
3589736061fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
......@@ -36640,9 +36804,6 @@ fn semaStructFields(
3664036804 },
3664136805 };
3664236806
36643 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
36644 defer comptime_mutable_decls.deinit();
36645
3664636807 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
3664736808 defer comptime_err_ret_trace.deinit();
3664836809
......@@ -36658,7 +36819,6 @@ fn semaStructFields(
3665836819 .fn_ret_ty = Type.void,
3665936820 .fn_ret_ty_ies = null,
3666036821 .owner_func_index = .none,
36661 .comptime_mutable_decls = &comptime_mutable_decls,
3666236822 .comptime_err_ret_trace = &comptime_err_ret_trace,
3666336823 };
3666436824 defer sema.deinit();
......@@ -36872,11 +37032,6 @@ fn semaStructFields(
3687237032
3687337033 struct_type.clearTypesWip(ip);
3687437034 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 }
3688037035}
3688137036
3688237037// This logic must be kept in sync with `semaStructFields`
......@@ -36897,9 +37052,6 @@ fn semaStructFieldInits(
3689737052 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
3689837053 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3689937054
36900 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
36901 defer comptime_mutable_decls.deinit();
36902
3690337055 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
3690437056 defer comptime_err_ret_trace.deinit();
3690537057
......@@ -36915,7 +37067,6 @@ fn semaStructFieldInits(
3691537067 .fn_ret_ty = Type.void,
3691637068 .fn_ret_ty_ies = null,
3691737069 .owner_func_index = .none,
36918 .comptime_mutable_decls = &comptime_mutable_decls,
3691937070 .comptime_err_ret_trace = &comptime_err_ret_trace,
3692037071 };
3692137072 defer sema.deinit();
......@@ -37024,14 +37175,16 @@ fn semaStructFieldInits(
3702437175 };
3702537176
3702637177 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 }
3702737185 struct_type.field_inits.get(ip)[field_i] = field_init;
3702837186 }
3702937187 }
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 }
3703537188}
3703637189
3703737190fn 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
3708837241
3708937242 const decl = mod.declPtr(decl_index);
3709037243
37091 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
37092 defer comptime_mutable_decls.deinit();
37093
3709437244 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
3709537245 defer comptime_err_ret_trace.deinit();
3709637246
......@@ -37106,7 +37256,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3710637256 .fn_ret_ty = Type.void,
3710737257 .fn_ret_ty_ies = null,
3710837258 .owner_func_index = .none,
37109 .comptime_mutable_decls = &comptime_mutable_decls,
3711037259 .comptime_err_ret_trace = &comptime_err_ret_trace,
3711137260 };
3711237261 defer sema.deinit();
......@@ -37126,11 +37275,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3712637275 _ = try sema.analyzeInlineBody(&block_scope, body, zir_index);
3712737276 }
3712837277
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
3713437278 var int_tag_ty: Type = undefined;
3713537279 var enum_field_names: []InternPool.NullTerminatedString = &.{};
3713637280 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
......@@ -37734,7 +37878,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3773437878 .ptr_decl,
3773537879 .ptr_anon_decl,
3773637880 .ptr_anon_decl_aligned,
37737 .ptr_mut_decl,
37881 .ptr_comptime_alloc,
3773837882 .ptr_comptime_field,
3773937883 .ptr_int,
3774037884 .ptr_eu_payload,
......@@ -38017,27 +38161,11 @@ fn analyzeComptimeAlloc(
3801738161 },
3801838162 });
3801938163
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);
3802238165
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);
3803538166 return Air.internedToRef((try mod.intern(.{ .ptr = .{
3803638167 .ty = ptr_type.toIntern(),
38037 .addr = .{ .mut_decl = .{
38038 .decl = decl_index,
38039 .runtime_index = block.runtime_index,
38040 } },
38168 .addr = .{ .comptime_alloc = alloc },
3804138169 } })));
3804238170}
3804338171
......@@ -39073,3 +39201,130 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3907339201 );
3907439202 try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee);
3907539203}
39204
39205fn 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
39219fn 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
39224fn 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.
39235fn 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`.
39278fn 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.
39298fn 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}
src/TypedValue.zig+3-7
......@@ -329,13 +329,9 @@ pub fn print(
329329 .val = Value.fromInterned(decl_val),
330330 }, writer, level - 1, mod);
331331 },
332 .mut_decl => |mut_decl| {
333 const decl = mod.declPtr(mut_decl.decl);
334 if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)});
335 return print(.{
336 .ty = decl.ty,
337 .val = decl.val,
338 }, writer, level - 1, mod);
332 .comptime_alloc => {
333 // TODO: we need a Sema to print this!
334 return writer.writeAll("(comptime alloc)");
339335 },
340336 .comptime_field => |field_val_ip| {
341337 return print(.{
src/Value.zig+64-95
......@@ -6,7 +6,8 @@ const BigIntConst = std.math.big.int.Const;
66const BigIntMutable = std.math.big.int.Mutable;
77const Target = std.Target;
88const Allocator = std.mem.Allocator;
9const Module = @import("Module.zig");
9const Zcu = @import("Module.zig");
10const Module = Zcu;
1011const TypedValue = @import("TypedValue.zig");
1112const Sema = @import("Sema.zig");
1213const InternPool = @import("InternPool.zig");
......@@ -187,24 +188,21 @@ pub fn fmtValue(val: Value, ty: Type, mod: *Module) std.fmt.Formatter(TypedValue
187188 } };
188189}
189190
190/// Asserts that the value is representable as an array of bytes.
191/// Returns the value as a null-terminated string stored in the InternPool.
191/// Converts `val` to a null-terminated string stored in the InternPool.
192/// Asserts `val` is an array of `u8`
192193pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString {
194 assert(ty.zigTypeTag(mod) == .Array);
195 assert(ty.childType(mod).toIntern() == .u8_type);
193196 const ip = &mod.intern_pool;
194 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
195 .enum_literal => |enum_literal| enum_literal,
196 .slice => |slice| try arrayToIpString(val, Value.fromInterned(slice.len).toUnsignedInt(mod), mod),
197 .aggregate => |aggregate| switch (aggregate.storage) {
198 .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),
199 .elems => try arrayToIpString(val, ty.arrayLen(mod), mod),
200 .repeated_elem => |elem| {
201 const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));
202 const len = @as(usize, @intCast(ty.arrayLen(mod)));
203 try ip.string_bytes.appendNTimes(mod.gpa, byte, len);
204 return ip.getOrPutTrailingString(mod.gpa, len);
205 },
197 return switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
198 .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),
199 .elems => try arrayToIpString(val, ty.arrayLen(mod), mod),
200 .repeated_elem => |elem| {
201 const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));
202 const len = @as(usize, @intCast(ty.arrayLen(mod)));
203 try ip.string_bytes.appendNTimes(mod.gpa, byte, len);
204 return ip.getOrPutTrailingString(mod.gpa, len);
206205 },
207 else => unreachable,
208206 };
209207}
210208
......@@ -606,7 +604,7 @@ fn isDeclRef(val: Value, mod: *Module) bool {
606604 var check = val;
607605 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
608606 .ptr => |ptr| switch (ptr.addr) {
609 .decl, .mut_decl, .comptime_field, .anon_decl => return true,
607 .decl, .comptime_alloc, .comptime_field, .anon_decl => return true,
610608 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),
611609 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),
612610 .int => return false,
......@@ -1343,7 +1341,7 @@ pub fn orderAgainstZeroAdvanced(
13431341 .bool_true => .gt,
13441342 else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) {
13451343 .ptr => |ptr| switch (ptr.addr) {
1346 .decl, .mut_decl, .comptime_field => .gt,
1344 .decl, .comptime_alloc, .comptime_field => .gt,
13471345 .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema),
13481346 .elem => |elem| switch (try Value.fromInterned(elem.base).orderAgainstZeroAdvanced(mod, opt_sema)) {
13491347 .lt => unreachable,
......@@ -1532,45 +1530,34 @@ pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
15321530 return a.toIntern() == b.toIntern();
15331531}
15341532
1535pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool {
1536 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1537 .slice => |slice| return Value.fromInterned(slice.ptr).isComptimeMutablePtr(mod),
1533pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
1534 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
1535 .error_union => |error_union| switch (error_union.val) {
1536 .err_name => false,
1537 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
1538 },
15381539 .ptr => |ptr| switch (ptr.addr) {
1539 .mut_decl, .comptime_field => true,
1540 .eu_payload, .opt_payload => |base_ptr| Value.fromInterned(base_ptr).isComptimeMutablePtr(mod),
1541 .elem, .field => |base_index| Value.fromInterned(base_index.base).isComptimeMutablePtr(mod),
1542 else => false,
1540 .decl => false, // The value of a Decl can never reference a comptime alloc.
1541 .int => false,
1542 .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.
1543 .comptime_field => true, // Comptime field pointers are comptime-mutable, albeit only to the "correct" value.
1544 .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu),
1545 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu),
1546 .elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu),
1547 },
1548 .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu),
1549 .opt => |opt| switch (opt.val) {
1550 .none => false,
1551 else => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
15431552 },
1553 .aggregate => |aggregate| for (aggregate.storage.values()) |elem| {
1554 if (Value.fromInterned(elem).canMutateComptimeVarState(zcu)) break true;
1555 } else false,
1556 .un => |un| Value.fromInterned(un.val).canMutateComptimeVarState(zcu),
15441557 else => false,
15451558 };
15461559}
15471560
1548pub fn canMutateComptimeVarState(val: Value, mod: *Module) bool {
1549 return val.isComptimeMutablePtr(mod) or switch (val.toIntern()) {
1550 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1551 .error_union => |error_union| switch (error_union.val) {
1552 .err_name => false,
1553 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(mod),
1554 },
1555 .ptr => |ptr| switch (ptr.addr) {
1556 .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(mod),
1557 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(mod),
1558 .elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(mod),
1559 else => false,
1560 },
1561 .opt => |opt| switch (opt.val) {
1562 .none => false,
1563 else => |payload| Value.fromInterned(payload).canMutateComptimeVarState(mod),
1564 },
1565 .aggregate => |aggregate| for (aggregate.storage.values()) |elem| {
1566 if (Value.fromInterned(elem).canMutateComptimeVarState(mod)) break true;
1567 } else false,
1568 .un => |un| Value.fromInterned(un.val).canMutateComptimeVarState(mod),
1569 else => false,
1570 },
1571 };
1572}
1573
15741561/// Gets the decl referenced by this pointer. If the pointer does not point
15751562/// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),
15761563/// this function returns null.
......@@ -1581,7 +1568,6 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {
15811568 .func => |func| func.owner_decl,
15821569 .ptr => |ptr| switch (ptr.addr) {
15831570 .decl => |decl| decl,
1584 .mut_decl => |mut_decl| mut_decl.decl,
15851571 else => null,
15861572 },
15871573 else => null,
......@@ -1600,7 +1586,7 @@ pub fn sliceLen(val: Value, mod: *Module) u64 {
16001586 return switch (ip.indexToKey(val.toIntern())) {
16011587 .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) {
16021588 .decl => |decl| mod.declPtr(decl).ty.toIntern(),
1603 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
1589 .comptime_alloc => @panic("TODO"),
16041590 .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
16051591 .comptime_field => |comptime_field| ip.typeOf(comptime_field),
16061592 else => unreachable,
......@@ -1621,34 +1607,38 @@ pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
16211607
16221608/// Like `elemValue`, but returns `null` instead of asserting on failure.
16231609pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value {
1610 return val.maybeElemValueFull(null, mod, index);
1611}
1612
1613pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value {
16241614 return switch (val.ip_index) {
16251615 .none => switch (val.tag()) {
16261616 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
16271617 .repeated => val.castTag(.repeated).?.data,
16281618 .aggregate => val.castTag(.aggregate).?.data[index],
1629 .slice => val.castTag(.slice).?.data.ptr.maybeElemValue(mod, index),
1619 .slice => val.castTag(.slice).?.data.ptr.maybeElemValueFull(sema, mod, index),
16301620 else => null,
16311621 },
16321622 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
16331623 .undef => |ty| Value.fromInterned((try mod.intern(.{
16341624 .undef = Type.fromInterned(ty).elemType2(mod).toIntern(),
16351625 }))),
1636 .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValue(mod, index),
1626 .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index),
16371627 .ptr => |ptr| switch (ptr.addr) {
1638 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
1639 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValue(mod, index),
1640 .mut_decl => |mut_decl| Value.fromInterned((try mod.declPtr(mut_decl.decl).internValue(mod))).maybeElemValue(mod, index),
1628 .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index),
1629 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index),
1630 .comptime_alloc => |idx| if (sema) |s| s.getComptimeAlloc(idx).val.maybeElemValueFull(sema, mod, index) else null,
16411631 .int, .eu_payload => null,
1642 .opt_payload => |base| Value.fromInterned(base).maybeElemValue(mod, index),
1643 .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValue(mod, index),
1644 .elem => |elem| Value.fromInterned(elem.base).maybeElemValue(mod, index + @as(usize, @intCast(elem.index))),
1632 .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index),
1633 .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index),
1634 .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))),
16451635 .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| {
16461636 const base_decl = mod.declPtr(decl_index);
16471637 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));
1648 return field_val.maybeElemValue(mod, index);
1638 return field_val.maybeElemValueFull(sema, mod, index);
16491639 } else null,
16501640 },
1651 .opt => |opt| Value.fromInterned(opt.val).maybeElemValue(mod, index),
1641 .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index),
16521642 .aggregate => |aggregate| {
16531643 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
16541644 if (index < len) return Value.fromInterned(switch (aggregate.storage) {
......@@ -1690,29 +1680,28 @@ pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
16901680// Asserts that the provided start/end are in-bounds.
16911681pub fn sliceArray(
16921682 val: Value,
1693 mod: *Module,
1694 arena: Allocator,
1683 sema: *Sema,
16951684 start: usize,
16961685 end: usize,
16971686) error{OutOfMemory}!Value {
16981687 // TODO: write something like getCoercedInts to avoid needing to dupe
1688 const mod = sema.mod;
16991689 return switch (val.ip_index) {
17001690 .none => switch (val.tag()) {
1701 .slice => val.castTag(.slice).?.data.ptr.sliceArray(mod, arena, start, end),
1702 .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),
1691 .slice => val.castTag(.slice).?.data.ptr.sliceArray(sema, start, end),
1692 .bytes => Tag.bytes.create(sema.arena, val.castTag(.bytes).?.data[start..end]),
17031693 .repeated => val,
1704 .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]),
1694 .aggregate => Tag.aggregate.create(sema.arena, val.castTag(.aggregate).?.data[start..end]),
17051695 else => unreachable,
17061696 },
17071697 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
17081698 .ptr => |ptr| switch (ptr.addr) {
1709 .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end),
1710 .mut_decl => |mut_decl| Value.fromInterned((try mod.declPtr(mut_decl.decl).internValue(mod)))
1711 .sliceArray(mod, arena, start, end),
1699 .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end),
1700 .comptime_alloc => |idx| sema.getComptimeAlloc(idx).val.sliceArray(sema, start, end),
17121701 .comptime_field => |comptime_field| Value.fromInterned(comptime_field)
1713 .sliceArray(mod, arena, start, end),
1702 .sliceArray(sema, start, end),
17141703 .elem => |elem| Value.fromInterned(elem.base)
1715 .sliceArray(mod, arena, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))),
1704 .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))),
17161705 else => unreachable,
17171706 },
17181707 .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{
......@@ -1729,8 +1718,8 @@ pub fn sliceArray(
17291718 else => unreachable,
17301719 }.toIntern(),
17311720 .storage = switch (aggregate.storage) {
1732 .bytes => .{ .bytes = try arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
1733 .elems => .{ .elems = try arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
1721 .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
1722 .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
17341723 .repeated_elem => |elem| .{ .repeated_elem = elem },
17351724 },
17361725 } }))),
......@@ -1838,26 +1827,6 @@ pub fn isUndefDeep(val: Value, mod: *Module) bool {
18381827 return val.isUndef(mod);
18391828}
18401829
1841/// Returns true if any value contained in `self` is undefined.
1842pub fn anyUndef(val: Value, mod: *Module) !bool {
1843 if (val.ip_index == .none) return false;
1844 return switch (val.toIntern()) {
1845 .undef => true,
1846 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1847 .undef => true,
1848 .simple_value => |v| v == .undefined,
1849 .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| {
1850 if (try (try val.elemValue(mod, idx)).anyUndef(mod)) break true;
1851 } else false,
1852 .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| {
1853 const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i];
1854 if (try anyUndef(Value.fromInterned(elem), mod)) break true;
1855 } else false,
1856 else => false,
1857 },
1858 };
1859}
1860
18611830/// Asserts the value is not undefined and not unreachable.
18621831/// C pointers with an integer value of 0 are also considered null.
18631832pub fn isNull(val: Value, mod: *Module) bool {
src/arch/wasm/CodeGen.zig+3-8
......@@ -3067,14 +3067,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
30673067 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
30683068 },
30693069 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
3070 .mut_decl => |mut_decl| {
3071 const decl_index = mut_decl.decl;
3072 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
3073 },
30743070 .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}),
30753071 .int => |base| return func.lowerConstant(Value.fromInterned(base), Type.usize),
30763072 .opt_payload => |base_ptr| return func.lowerParentPtr(Value.fromInterned(base_ptr), offset),
3077 .comptime_field => unreachable,
3073 .comptime_field, .comptime_alloc => unreachable,
30783074 .elem => |elem| {
30793075 const index = elem.index;
30803076 const elem_type = Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod);
......@@ -3320,20 +3316,19 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33203316 var ptr = ip.indexToKey(slice.ptr).ptr;
33213317 const owner_decl = while (true) switch (ptr.addr) {
33223318 .decl => |decl| break decl,
3323 .mut_decl => |mut_decl| break mut_decl.decl,
33243319 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),
33253320 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,
33263321 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
3327 .comptime_field => unreachable,
3322 .comptime_field, .comptime_alloc => unreachable,
33283323 };
33293324 return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) };
33303325 },
33313326 .ptr => |ptr| switch (ptr.addr) {
33323327 .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),
3333 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
33343328 .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))),
33353329 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
33363330 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
3331 .comptime_field, .comptime_alloc => unreachable,
33373332 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
33383333 },
33393334 .opt => if (ty.optionalReprIsPayload(mod)) {
src/arch/x86_64/Encoding.zig+10-2
......@@ -818,7 +818,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
818818}
819819
820820const mnemonic_to_encodings_map = init: {
821 @setEvalBranchQuota(4_000);
821 @setEvalBranchQuota(5_000);
822822 const mnemonic_count = @typeInfo(Mnemonic).Enum.fields.len;
823823 var mnemonic_map: [mnemonic_count][]Data = .{&.{}} ** mnemonic_count;
824824 const encodings = @import("encodings.zig");
......@@ -845,5 +845,13 @@ const mnemonic_to_encodings_map = init: {
845845 };
846846 i.* += 1;
847847 }
848 break :init mnemonic_map;
848 const final_storage = data_storage;
849 var final_map: [mnemonic_count][]const Data = .{&.{}} ** mnemonic_count;
850 storage_i = 0;
851 for (&final_map, mnemonic_map) |*value, wip_value| {
852 value.ptr = final_storage[storage_i..].ptr;
853 value.len = wip_value.len;
854 storage_i += value.len;
855 }
856 break :init final_map;
849857};
src/codegen.zig+1-3
......@@ -680,7 +680,6 @@ fn lowerParentPtr(
680680 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
681681 return switch (ptr.addr) {
682682 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
683 .mut_decl => |md| try lowerDeclRef(bin_file, src_loc, md.decl, code, debug_output, reloc_info),
684683 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
685684 .int => |int| try generateSymbol(bin_file, src_loc, .{
686685 .ty = Type.usize,
......@@ -756,7 +755,7 @@ fn lowerParentPtr(
756755 }),
757756 );
758757 },
759 .comptime_field => unreachable,
758 .comptime_field, .comptime_alloc => unreachable,
760759 };
761760}
762761
......@@ -1089,7 +1088,6 @@ pub fn genTypedValue(
10891088 if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) {
10901089 .ptr => |ptr| switch (ptr.addr) {
10911090 .decl => |decl| return genDeclRef(lf, src_loc, typed_value, decl),
1092 .mut_decl => |mut_decl| return genDeclRef(lf, src_loc, typed_value, mut_decl.decl),
10931091 else => {},
10941092 },
10951093 else => {},
src/codegen/c.zig+2-4
......@@ -698,7 +698,6 @@ pub const DeclGen = struct {
698698 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;
699699 switch (ptr.addr) {
700700 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), d, location),
701 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), md.decl, location),
702701 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), anon_decl, location),
703702 .int => |int| {
704703 try writer.writeByte('(');
......@@ -795,7 +794,7 @@ pub const DeclGen = struct {
795794 },
796795 }
797796 },
798 .comptime_field => unreachable,
797 .comptime_field, .comptime_alloc => unreachable,
799798 }
800799 }
801800
......@@ -1229,7 +1228,6 @@ pub const DeclGen = struct {
12291228 },
12301229 .ptr => |ptr| switch (ptr.addr) {
12311230 .decl => |d| try dg.renderDeclValue(writer, ty, val, d, location),
1232 .mut_decl => |md| try dg.renderDeclValue(writer, ty, val, md.decl, location),
12331231 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ty, val, decl_val, location),
12341232 .int => |int| {
12351233 try writer.writeAll("((");
......@@ -1243,7 +1241,7 @@ pub const DeclGen = struct {
12431241 .elem,
12441242 .field,
12451243 => try dg.renderParentPtr(writer, val.ip_index, location),
1246 .comptime_field => unreachable,
1244 .comptime_field, .comptime_alloc => unreachable,
12471245 },
12481246 .opt => |opt| {
12491247 const payload_ty = ty.optionalChild(mod);
src/codegen/llvm.zig+2-4
......@@ -3808,7 +3808,6 @@ pub const Object = struct {
38083808 },
38093809 .ptr => |ptr| return switch (ptr.addr) {
38103810 .decl => |decl| try o.lowerDeclRefValue(ty, decl),
3811 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ty, mut_decl.decl),
38123811 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ty, anon_decl),
38133812 .int => |int| try o.lowerIntAsPtr(int),
38143813 .eu_payload,
......@@ -3816,7 +3815,7 @@ pub const Object = struct {
38163815 .elem,
38173816 .field,
38183817 => try o.lowerParentPtr(val),
3819 .comptime_field => unreachable,
3818 .comptime_field, .comptime_alloc => unreachable,
38203819 },
38213820 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
38223821 try o.lowerValue(slice.ptr),
......@@ -4274,7 +4273,6 @@ pub const Object = struct {
42744273 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;
42754274 return switch (ptr.addr) {
42764275 .decl => |decl| try o.lowerParentPtrDecl(decl),
4277 .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl),
42784276 .anon_decl => |ad| try o.lowerAnonDeclRef(Type.fromInterned(ad.orig_ty), ad),
42794277 .int => |int| try o.lowerIntAsPtr(int),
42804278 .eu_payload => |eu_ptr| {
......@@ -4311,7 +4309,7 @@ pub const Object = struct {
43114309
43124310 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{ .@"0", .@"0" });
43134311 },
4314 .comptime_field => unreachable,
4312 .comptime_field, .comptime_alloc => unreachable,
43154313 .elem => |elem_ptr| {
43164314 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(elem_ptr.base));
43174315 const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod);
src/codegen/spirv.zig+1-2
......@@ -1105,7 +1105,6 @@ const DeclGen = struct {
11051105 const mod = self.module;
11061106 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
11071107 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
1108 .mut_decl => |decl_mut| return try self.constantDeclRef(ptr_ty, decl_mut.decl),
11091108 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),
11101109 .int => |int| {
11111110 const ptr_id = self.spv.allocId();
......@@ -1121,7 +1120,7 @@ const DeclGen = struct {
11211120 },
11221121 .eu_payload => unreachable, // TODO
11231122 .opt_payload => unreachable, // TODO
1124 .comptime_field => unreachable,
1123 .comptime_field, .comptime_alloc => unreachable,
11251124 .elem => |elem_ptr| {
11261125 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
11271126 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
src/link/Elf/LdScript.zig+8-5
......@@ -109,11 +109,14 @@ const Command = enum {
109109
110110 fn fromString(s: []const u8) ?Command {
111111 inline for (@typeInfo(Command).Enum.fields) |field| {
112 comptime var buf: [field.name.len]u8 = undefined;
113 inline for (field.name, 0..) |c, i| {
114 buf[i] = comptime std.ascii.toUpper(c);
115 }
116 if (std.mem.eql(u8, &buf, s)) return @field(Command, field.name);
112 const upper_name = n: {
113 comptime var buf: [field.name.len]u8 = undefined;
114 inline for (field.name, 0..) |c, i| {
115 buf[i] = comptime std.ascii.toUpper(c);
116 }
117 break :n buf;
118 };
119 if (std.mem.eql(u8, &upper_name, s)) return @field(Command, field.name);
117120 }
118121 return null;
119122 }
src/print_zir.zig+4
......@@ -2810,6 +2810,10 @@ const Writer = struct {
28102810 switch (capture.unwrap()) {
28112811 .nested => |i| return stream.print("[{d}]", .{i}),
28122812 .instruction => |inst| return self.writeInstIndex(stream, inst),
2813 .instruction_load => |ptr_inst| {
2814 try stream.writeAll("load ");
2815 try self.writeInstIndex(stream, ptr_inst);
2816 },
28132817 .decl_val => |str| try stream.print("decl_val \"{}\"", .{
28142818 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
28152819 }),
test/behavior/align.zig+2
......@@ -586,6 +586,8 @@ fn overaligned_fn() align(0x1000) i32 {
586586}
587587
588588test "comptime alloc alignment" {
589 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.
590 if (true) return error.SkipZigTest;
589591 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
590592 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
591593 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/comptime_memory.zig+1-1
......@@ -461,7 +461,7 @@ test "write empty array to end" {
461461 array[5..5].* = .{};
462462 array[5..5].* = [0]u8{};
463463 array[5..5].* = [_]u8{};
464 try testing.expectEqualStrings("hello", &array);
464 comptime std.debug.assert(std.mem.eql(u8, "hello", &array));
465465}
466466
467467fn doublePtrTest() !void {
test/behavior/eval.zig+1-1
......@@ -1211,7 +1211,7 @@ test "storing an array of type in a field" {
12111211
12121212 const S = struct {
12131213 fn doTheTest() void {
1214 comptime var foobar = Foobar.foo();
1214 const foobar = Foobar.foo();
12151215 foo(foobar.str[0..10]);
12161216 }
12171217 const Foobar = struct {
test/cases/compile_errors/comptime_var_referenced_at_runtime.zig created+65
......@@ -0,0 +1,65 @@
1var runtime_int: u32 = 123;
2
3export fn foo() void {
4 comptime var x: u32 = 123;
5 var runtime = &x;
6 _ = &runtime;
7}
8
9export fn bar() void {
10 const S = struct { u32, *const u32 };
11 comptime var x: u32 = 123;
12 const runtime: S = .{ runtime_int, &x };
13 _ = runtime;
14}
15
16export fn qux() void {
17 const S = struct { a: u32, b: *const u32 };
18 comptime var x: u32 = 123;
19 const runtime: S = .{ .a = runtime_int, .b = &x };
20 _ = runtime;
21}
22
23export fn baz() void {
24 const S = struct {
25 fn f(_: *const u32) void {}
26 };
27 comptime var x: u32 = 123;
28 S.f(&x);
29}
30
31export fn faz() void {
32 const S = struct {
33 fn f(_: anytype) void {}
34 };
35 comptime var x: u32 = 123;
36 S.f(&x);
37}
38
39export fn boo() *const u32 {
40 comptime var x: u32 = 123;
41 return &x;
42}
43
44export fn qar() void {
45 comptime var x: u32 = 123;
46 const y = if (runtime_int == 123) &x else undefined;
47 _ = y;
48}
49
50// error
51//
52// :5:19: error: runtime value contains reference to comptime var
53// :5:19: note: comptime var pointers are not available at runtime
54// :12:40: error: runtime value contains reference to comptime var
55// :12:40: note: comptime var pointers are not available at runtime
56// :19:50: error: runtime value contains reference to comptime var
57// :19:50: note: comptime var pointers are not available at runtime
58// :28:9: error: runtime value contains reference to comptime var
59// :28:9: note: comptime var pointers are not available at runtime
60// :36:9: error: runtime value contains reference to comptime var
61// :36:9: note: comptime var pointers are not available at runtime
62// :41:12: error: runtime value contains reference to comptime var
63// :41:12: note: comptime var pointers are not available at runtime
64// :46:39: error: runtime value contains reference to comptime var
65// :46:39: note: comptime var pointers are not available at runtime
test/cases/compile_errors/comptime_var_referenced_by_decl.zig created+49
......@@ -0,0 +1,49 @@
1export const a: *u32 = a: {
2 var x: u32 = 123;
3 break :a &x;
4};
5
6export const b: [1]*u32 = b: {
7 var x: u32 = 123;
8 break :b .{&x};
9};
10
11export const c: *[1]u32 = c: {
12 var x: u32 = 123;
13 break :c (&x)[0..1];
14};
15
16export const d: *anyopaque = d: {
17 var x: u32 = 123;
18 break :d &x;
19};
20
21const S = extern struct { ptr: *u32 };
22export const e: S = e: {
23 var x: u32 = 123;
24 break :e .{ .ptr = &x };
25};
26
27// The pointer constness shouldn't matter - *any* reference to a comptime var is illegal in a global's value.
28export const f: *const u32 = f: {
29 var x: u32 = 123;
30 break :f &x;
31};
32
33// The pointer itself doesn't refer to a comptime var, but from it you can derive a pointer which does.
34export const g: *const *const u32 = g: {
35 const valid: u32 = 123;
36 var invalid: u32 = 123;
37 const aggregate: [2]*const u32 = .{ &valid, &invalid };
38 break :g &aggregate[0];
39};
40
41// error
42//
43// :1:27: error: global variable contains reference to comptime var
44// :6:30: error: global variable contains reference to comptime var
45// :11:30: error: global variable contains reference to comptime var
46// :16:33: error: global variable contains reference to comptime var
47// :22:24: error: global variable contains reference to comptime var
48// :28:33: error: global variable contains reference to comptime var
49// :34:40: error: global variable contains reference to comptime var
test/cases/comptime_aggregate_print.zig+5-2
......@@ -23,10 +23,13 @@ comptime {
2323
2424pub fn main() !void {}
2525
26// TODO: the output here has been regressed by #19414.
27// Restoring useful output here will require providing a Sema to TypedValue.print.
28
2629// error
2730//
2831// :20:5: error: found compile log statement
2932//
3033// Compile Log Output:
31// @as([]i32, .{ 1, 2 })
32// @as([]i32, .{ 3, 4 })
34// @as([]i32, .{ (reinterpreted data) })
35// @as([]i32, .{ (reinterpreted data) })