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 {...@@ -1317,7 +1317,8 @@ pub const Cpu = struct {
1317 for (decls, 0..) |decl, i| {1317 for (decls, 0..) |decl, i| {
1318 array[i] = &@field(cpus, decl.name);1318 array[i] = &@field(cpus, decl.name);
1319 }1319 }
1320 return &array;1320 const finalized = array;
1321 return &finalized;
1321 }1322 }
1322 };1323 };
13231324
lib/std/enums.zig+2-1
...@@ -41,7 +41,8 @@ pub inline fn valuesFromFields(comptime E: type, comptime fields: []const EnumFi...@@ -41,7 +41,8 @@ pub inline fn valuesFromFields(comptime E: type, comptime fields: []const EnumFi
41 for (&result, fields) |*r, f| {41 for (&result, fields) |*r, f| {
42 r.* = @enumFromInt(f.value);42 r.* = @enumFromInt(f.value);
43 }43 }
44 return &result;44 const final = result;
45 return &final;
45 }46 }
46}47}
4748
lib/std/fmt.zig+2-1
...@@ -1829,7 +1829,8 @@ pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [cou...@@ -1829,7 +1829,8 @@ pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [cou
1829 var buf: [count(fmt, args):0]u8 = undefined;1829 var buf: [count(fmt, args):0]u8 = undefined;
1830 _ = bufPrint(&buf, fmt, args) catch unreachable;1830 _ = bufPrint(&buf, fmt, args) catch unreachable;
1831 buf[buf.len] = 0;1831 buf[buf.len] = 0;
1832 return &buf;1832 const final = buf;
1833 return &final;
1833 }1834 }
1834}1835}
18351836
lib/std/meta.zig+4-2
...@@ -465,7 +465,8 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {...@@ -465,7 +465,8 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {
465 var names: [fieldInfos.len][:0]const u8 = undefined;465 var names: [fieldInfos.len][:0]const u8 = undefined;
466 // This concat can be removed with the next zig1 update.466 // This concat can be removed with the next zig1 update.
467 for (&names, fieldInfos) |*name, field| name.* = field.name ++ "";467 for (&names, fieldInfos) |*name, field| name.* = field.name ++ "";
468 break :blk &names;468 const final = names;
469 break :blk &final;
469 };470 };
470}471}
471472
...@@ -506,7 +507,8 @@ pub fn tags(comptime T: type) *const [fields(T).len]T {...@@ -506,7 +507,8 @@ pub fn tags(comptime T: type) *const [fields(T).len]T {
506 for (fieldInfos, 0..) |field, i| {507 for (fieldInfos, 0..) |field, i| {
507 res[i] = @field(T, field.name);508 res[i] = @field(T, field.name);
508 }509 }
509 break :blk &res;510 const final = res;
511 break :blk &final;
510 };512 };
511}513}
512514
lib/std/unicode.zig+2-1
...@@ -1358,7 +1358,8 @@ pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16Le...@@ -1358,7 +1358,8 @@ pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16Le
1358 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;1358 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
1359 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);1359 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
1360 assert(len == utf16le_len);1360 assert(len == utf16le_len);
1361 break :blk &utf16le;1361 const final = utf16le;
1362 break :blk &final;
1362 };1363 };
1363}1364}
13641365
lib/std/zig/AstGen.zig+19-11
...@@ -8296,22 +8296,27 @@ fn localVarRef(...@@ -8296,22 +8296,27 @@ fn localVarRef(
8296 });8296 });
8297 }8297 }
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
8307 switch (ri.rl) {8299 switch (ri.rl) {
8308 .ref, .ref_coerced_ty => {8300 .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;
8309 local_ptr.used_as_lvalue = true;8308 local_ptr.used_as_lvalue = true;
8310 return ptr_inst;8309 return ptr_inst;
8311 },8310 },
8312 else => {8311 else => {
8313 const loaded = try gz.addUnNode(.load, ptr_inst, ident);8312 const val_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8314 return rvalueNoCoercePreRef(gz, ri, loaded, ident);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);
8315 },8320 },
8316 }8321 }
8317 }8322 }
...@@ -8390,6 +8395,7 @@ fn tunnelThroughClosure(...@@ -8390,6 +8395,7 @@ fn tunnelThroughClosure(
8390 /// The value being captured.8395 /// The value being captured.
8391 value: union(enum) {8396 value: union(enum) {
8392 ref: Zir.Inst.Ref,8397 ref: Zir.Inst.Ref,
8398 ref_load: Zir.Inst.Ref,
8393 decl_val: Zir.NullTerminatedString,8399 decl_val: Zir.NullTerminatedString,
8394 decl_ref: Zir.NullTerminatedString,8400 decl_ref: Zir.NullTerminatedString,
8395 },8401 },
...@@ -8400,7 +8406,8 @@ fn tunnelThroughClosure(...@@ -8400,7 +8406,8 @@ fn tunnelThroughClosure(
8400 },8406 },
8401) !Zir.Inst.Ref {8407) !Zir.Inst.Ref {
8402 switch (value) {8408 switch (value) {
8403 .ref => |v| if (v.toIndex() == null) return v, // trivia value; do not need tunnel8409 .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
8404 .decl_val, .decl_ref => {},8411 .decl_val, .decl_ref => {},
8405 }8412 }
84068413
...@@ -8433,6 +8440,7 @@ fn tunnelThroughClosure(...@@ -8433,6 +8440,7 @@ fn tunnelThroughClosure(
8433 // captures as required, starting with the outermost namespace.8440 // captures as required, starting with the outermost namespace.
8434 const root_capture = Zir.Inst.Capture.wrap(switch (value) {8441 const root_capture = Zir.Inst.Capture.wrap(switch (value) {
8435 .ref => |v| .{ .instruction = v.toIndex().? },8442 .ref => |v| .{ .instruction = v.toIndex().? },
8443 .ref_load => |v| .{ .instruction_load = v.toIndex().? },
8436 .decl_val => |str| .{ .decl_val = str },8444 .decl_val => |str| .{ .decl_val = str },
8437 .decl_ref => |str| .{ .decl_ref = str },8445 .decl_ref => |str| .{ .decl_ref = str },
8438 });8446 });
lib/std/zig/Zir.zig+10-2
...@@ -3058,20 +3058,23 @@ pub const Inst = struct {...@@ -3058,20 +3058,23 @@ pub const Inst = struct {
30583058
3059 /// Represents a single value being captured in a type declaration's closure.3059 /// Represents a single value being captured in a type declaration's closure.
3060 pub const Capture = packed struct(u32) {3060 pub const Capture = packed struct(u32) {
3061 tag: enum(u2) {3061 tag: enum(u3) {
3062 /// `data` is a `u16` index into the parent closure.3062 /// `data` is a `u16` index into the parent closure.
3063 nested,3063 nested,
3064 /// `data` is a `Zir.Inst.Index` to an instruction whose value is being captured.3064 /// `data` is a `Zir.Inst.Index` to an instruction whose value is being captured.
3065 instruction,3065 instruction,
3066 /// `data` is a `Zir.Inst.Index` to an instruction representing an alloc whose contents is being captured.
3067 instruction_load,
3066 /// `data` is a `NullTerminatedString` to a decl name.3068 /// `data` is a `NullTerminatedString` to a decl name.
3067 decl_val,3069 decl_val,
3068 /// `data` is a `NullTerminatedString` to a decl name.3070 /// `data` is a `NullTerminatedString` to a decl name.
3069 decl_ref,3071 decl_ref,
3070 },3072 },
3071 data: u30,3073 data: u29,
3072 pub const Unwrapped = union(enum) {3074 pub const Unwrapped = union(enum) {
3073 nested: u16,3075 nested: u16,
3074 instruction: Zir.Inst.Index,3076 instruction: Zir.Inst.Index,
3077 instruction_load: Zir.Inst.Index,
3075 decl_val: NullTerminatedString,3078 decl_val: NullTerminatedString,
3076 decl_ref: NullTerminatedString,3079 decl_ref: NullTerminatedString,
3077 };3080 };
...@@ -3085,6 +3088,10 @@ pub const Inst = struct {...@@ -3085,6 +3088,10 @@ pub const Inst = struct {
3085 .tag = .instruction,3088 .tag = .instruction,
3086 .data = @intCast(@intFromEnum(inst)),3089 .data = @intCast(@intFromEnum(inst)),
3087 },3090 },
3091 .instruction_load => |inst| .{
3092 .tag = .instruction_load,
3093 .data = @intCast(@intFromEnum(inst)),
3094 },
3088 .decl_val => |str| .{3095 .decl_val => |str| .{
3089 .tag = .decl_val,3096 .tag = .decl_val,
3090 .data = @intCast(@intFromEnum(str)),3097 .data = @intCast(@intFromEnum(str)),
...@@ -3099,6 +3106,7 @@ pub const Inst = struct {...@@ -3099,6 +3106,7 @@ pub const Inst = struct {
3099 return switch (cap.tag) {3106 return switch (cap.tag) {
3100 .nested => .{ .nested = @intCast(cap.data) },3107 .nested => .{ .nested = @intCast(cap.data) },
3101 .instruction => .{ .instruction = @enumFromInt(cap.data) },3108 .instruction => .{ .instruction = @enumFromInt(cap.data) },
3109 .instruction_load => .{ .instruction_load = @enumFromInt(cap.data) },
3102 .decl_val => .{ .decl_val = @enumFromInt(cap.data) },3110 .decl_val => .{ .decl_val = @enumFromInt(cap.data) },
3103 .decl_ref => .{ .decl_ref = @enumFromInt(cap.data) },3111 .decl_ref => .{ .decl_ref = @enumFromInt(cap.data) },
3104 };3112 };
src/Air.zig+3-1
...@@ -1084,9 +1084,11 @@ pub const Inst = struct {...@@ -1084,9 +1084,11 @@ pub const Inst = struct {
1084 inferred_alloc: InferredAlloc,1084 inferred_alloc: InferredAlloc,
10851085
1086 pub const InferredAllocComptime = struct {1086 pub const InferredAllocComptime = struct {
1087 decl_index: InternPool.DeclIndex,
1088 alignment: InternPool.Alignment,1087 alignment: InternPool.Alignment,
1089 is_const: bool,1088 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,
1090 };1092 };
10911093
1092 pub const InferredAlloc = struct {1094 pub const InferredAlloc = struct {
src/Compilation.zig-1
...@@ -1382,7 +1382,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1382,7 +1382,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1382 .global_zir_cache = global_zir_cache,1382 .global_zir_cache = global_zir_cache,
1383 .local_zir_cache = local_zir_cache,1383 .local_zir_cache = local_zir_cache,
1384 .emit_h = emit_h,1384 .emit_h = emit_h,
1385 .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa),
1386 .error_limit = error_limit,1385 .error_limit = error_limit,
1387 .llvm_object = null,1386 .llvm_object = null,
1388 };1387 };
src/InternPool.zig+32-41
...@@ -389,6 +389,8 @@ pub const RuntimeIndex = enum(u32) {...@@ -389,6 +389,8 @@ pub const RuntimeIndex = enum(u32) {
389 }389 }
390};390};
391391
392pub const ComptimeAllocIndex = enum(u32) { _ };
393
392pub const DeclIndex = std.zig.DeclIndex;394pub const DeclIndex = std.zig.DeclIndex;
393pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;395pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;
394396
...@@ -979,7 +981,7 @@ pub const Key = union(enum) {...@@ -979,7 +981,7 @@ pub const Key = union(enum) {
979 const Tag = @typeInfo(Addr).Union.tag_type.?;981 const Tag = @typeInfo(Addr).Union.tag_type.?;
980982
981 decl: DeclIndex,983 decl: DeclIndex,
982 mut_decl: MutDecl,984 comptime_alloc: ComptimeAllocIndex,
983 anon_decl: AnonDecl,985 anon_decl: AnonDecl,
984 comptime_field: Index,986 comptime_field: Index,
985 int: Index,987 int: Index,
...@@ -1172,20 +1174,14 @@ pub const Key = union(enum) {...@@ -1172,20 +1174,14 @@ pub const Key = union(enum) {
1172 const seed2 = seed + @intFromEnum(addr);1174 const seed2 = seed + @intFromEnum(addr);
1173 const common = asBytes(&ptr.ty);1175 const common = asBytes(&ptr.ty);
1174 return switch (ptr.addr) {1176 return switch (ptr.addr) {
1175 .decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),1177 inline .decl,
11761178 .comptime_alloc,
1177 .mut_decl => |x| Hash.hash(1179 .anon_decl,
1178 seed2,
1179 common ++ asBytes(&x.decl) ++ asBytes(&x.runtime_index),
1180 ),
1181
1182 .anon_decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
1183
1184 .int,1180 .int,
1185 .eu_payload,1181 .eu_payload,
1186 .opt_payload,1182 .opt_payload,
1187 .comptime_field,1183 .comptime_field,
1188 => |int| Hash.hash(seed2, common ++ asBytes(&int)),1184 => |x| Hash.hash(seed2, common ++ asBytes(&x)),
11891185
1190 .elem, .field => |x| Hash.hash(1186 .elem, .field => |x| Hash.hash(
1191 seed2,1187 seed2,
...@@ -1452,7 +1448,7 @@ pub const Key = union(enum) {...@@ -1452,7 +1448,7 @@ pub const Key = union(enum) {
14521448
1453 return switch (a_info.addr) {1449 return switch (a_info.addr) {
1454 .decl => |a_decl| a_decl == b_info.addr.decl,1450 .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,
1456 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and1452 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and
1457 ad.orig_ty == b_info.addr.anon_decl.orig_ty,1453 ad.orig_ty == b_info.addr.anon_decl.orig_ty,
1458 .int => |a_int| a_int == b_info.addr.int,1454 .int => |a_int| a_int == b_info.addr.int,
...@@ -2787,7 +2783,7 @@ pub const Index = enum(u32) {...@@ -2787,7 +2783,7 @@ pub const Index = enum(u32) {
2787 undef: DataIsIndex,2783 undef: DataIsIndex,
2788 simple_value: struct { data: SimpleValue },2784 simple_value: struct { data: SimpleValue },
2789 ptr_decl: struct { data: *PtrDecl },2785 ptr_decl: struct { data: *PtrDecl },
2790 ptr_mut_decl: struct { data: *PtrMutDecl },2786 ptr_comptime_alloc: struct { data: *PtrComptimeAlloc },
2791 ptr_anon_decl: struct { data: *PtrAnonDecl },2787 ptr_anon_decl: struct { data: *PtrAnonDecl },
2792 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },2788 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
2793 ptr_comptime_field: struct { data: *PtrComptimeField },2789 ptr_comptime_field: struct { data: *PtrComptimeField },
...@@ -3243,8 +3239,8 @@ pub const Tag = enum(u8) {...@@ -3243,8 +3239,8 @@ pub const Tag = enum(u8) {
3243 /// data is extra index of `PtrDecl`, which contains the type and address.3239 /// data is extra index of `PtrDecl`, which contains the type and address.
3244 ptr_decl,3240 ptr_decl,
3245 /// A pointer to a decl that can be mutated at comptime.3241 /// A pointer to a decl that can be mutated at comptime.
3246 /// data is extra index of `PtrMutDecl`, which contains the type and address.3242 /// data is extra index of `PtrComptimeAlloc`, which contains the type and address.
3247 ptr_mut_decl,3243 ptr_comptime_alloc,
3248 /// A pointer to an anonymous decl.3244 /// A pointer to an anonymous decl.
3249 /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value.3245 /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value.
3250 /// The alignment of the anonymous decl is communicated via the pointer type.3246 /// The alignment of the anonymous decl is communicated via the pointer type.
...@@ -3448,7 +3444,7 @@ pub const Tag = enum(u8) {...@@ -3448,7 +3444,7 @@ pub const Tag = enum(u8) {
3448 .undef => unreachable,3444 .undef => unreachable,
3449 .simple_value => unreachable,3445 .simple_value => unreachable,
3450 .ptr_decl => PtrDecl,3446 .ptr_decl => PtrDecl,
3451 .ptr_mut_decl => PtrMutDecl,3447 .ptr_comptime_alloc => PtrComptimeAlloc,
3452 .ptr_anon_decl => PtrAnonDecl,3448 .ptr_anon_decl => PtrAnonDecl,
3453 .ptr_anon_decl_aligned => PtrAnonDeclAligned,3449 .ptr_anon_decl_aligned => PtrAnonDeclAligned,
3454 .ptr_comptime_field => PtrComptimeField,3450 .ptr_comptime_field => PtrComptimeField,
...@@ -4129,10 +4125,9 @@ pub const PtrAnonDeclAligned = struct {...@@ -4129,10 +4125,9 @@ pub const PtrAnonDeclAligned = struct {
4129 orig_ty: Index,4125 orig_ty: Index,
4130};4126};
41314127
4132pub const PtrMutDecl = struct {4128pub const PtrComptimeAlloc = struct {
4133 ty: Index,4129 ty: Index,
4134 decl: DeclIndex,4130 index: ComptimeAllocIndex,
4135 runtime_index: RuntimeIndex,
4136};4131};
41374132
4138pub const PtrComptimeField = struct {4133pub const PtrComptimeField = struct {
...@@ -4537,14 +4532,11 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4537,14 +4532,11 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4537 .addr = .{ .decl = info.decl },4532 .addr = .{ .decl = info.decl },
4538 } };4533 } };
4539 },4534 },
4540 .ptr_mut_decl => {4535 .ptr_comptime_alloc => {
4541 const info = ip.extraData(PtrMutDecl, data);4536 const info = ip.extraData(PtrComptimeAlloc, data);
4542 return .{ .ptr = .{4537 return .{ .ptr = .{
4543 .ty = info.ty,4538 .ty = info.ty,
4544 .addr = .{ .mut_decl = .{4539 .addr = .{ .comptime_alloc = info.index },
4545 .decl = info.decl,
4546 .runtime_index = info.runtime_index,
4547 } },
4548 } };4540 } };
4549 },4541 },
4550 .ptr_anon_decl => {4542 .ptr_anon_decl => {
...@@ -5186,12 +5178,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5186,12 +5178,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5186 .decl = decl,5178 .decl = decl,
5187 }),5179 }),
5188 }),5180 }),
5189 .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{5181 .comptime_alloc => |alloc_index| ip.items.appendAssumeCapacity(.{
5190 .tag = .ptr_mut_decl,5182 .tag = .ptr_comptime_alloc,
5191 .data = try ip.addExtra(gpa, PtrMutDecl{5183 .data = try ip.addExtra(gpa, PtrComptimeAlloc{
5192 .ty = ptr.ty,5184 .ty = ptr.ty,
5193 .decl = mut_decl.decl,5185 .index = alloc_index,
5194 .runtime_index = mut_decl.runtime_index,
5195 }),5186 }),
5196 }),5187 }),
5197 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(5188 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
...@@ -7265,6 +7256,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -7265,6 +7256,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
7265 Tag.TypePointer.VectorIndex,7256 Tag.TypePointer.VectorIndex,
7266 TrackedInst.Index,7257 TrackedInst.Index,
7267 TrackedInst.Index.Optional,7258 TrackedInst.Index.Optional,
7259 ComptimeAllocIndex,
7268 => @intFromEnum(@field(extra, field.name)),7260 => @intFromEnum(@field(extra, field.name)),
72697261
7270 u32,7262 u32,
...@@ -7342,6 +7334,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct...@@ -7342,6 +7334,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
7342 Tag.TypePointer.VectorIndex,7334 Tag.TypePointer.VectorIndex,
7343 TrackedInst.Index,7335 TrackedInst.Index,
7344 TrackedInst.Index.Optional,7336 TrackedInst.Index.Optional,
7337 ComptimeAllocIndex,
7345 => @enumFromInt(int32),7338 => @enumFromInt(int32),
73467339
7347 u32,7340 u32,
...@@ -8144,7 +8137,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -8144,7 +8137,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
8144 .simple_type => 0,8137 .simple_type => 0,
8145 .simple_value => 0,8138 .simple_value => 0,
8146 .ptr_decl => @sizeOf(PtrDecl),8139 .ptr_decl => @sizeOf(PtrDecl),
8147 .ptr_mut_decl => @sizeOf(PtrMutDecl),8140 .ptr_comptime_alloc => @sizeOf(PtrComptimeAlloc),
8148 .ptr_anon_decl => @sizeOf(PtrAnonDecl),8141 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
8149 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),8142 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
8150 .ptr_comptime_field => @sizeOf(PtrComptimeField),8143 .ptr_comptime_field => @sizeOf(PtrComptimeField),
...@@ -8275,7 +8268,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -8275,7 +8268,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
8275 .type_function,8268 .type_function,
8276 .undef,8269 .undef,
8277 .ptr_decl,8270 .ptr_decl,
8278 .ptr_mut_decl,8271 .ptr_comptime_alloc,
8279 .ptr_anon_decl,8272 .ptr_anon_decl,
8280 .ptr_anon_decl_aligned,8273 .ptr_anon_decl_aligned,
8281 .ptr_comptime_field,8274 .ptr_comptime_field,
...@@ -8690,7 +8683,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -8690,7 +8683,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
8690 .simple_value => unreachable, // handled via Index above8683 .simple_value => unreachable, // handled via Index above
86918684
8692 inline .ptr_decl,8685 inline .ptr_decl,
8693 .ptr_mut_decl,8686 .ptr_comptime_alloc,
8694 .ptr_anon_decl,8687 .ptr_anon_decl,
8695 .ptr_anon_decl_aligned,8688 .ptr_anon_decl_aligned,
8696 .ptr_comptime_field,8689 .ptr_comptime_field,
...@@ -8822,10 +8815,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {...@@ -8822,10 +8815,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
8822 var base = @intFromEnum(val);8815 var base = @intFromEnum(val);
8823 while (true) {8816 while (true) {
8824 switch (ip.items.items(.tag)[base]) {8817 switch (ip.items.items(.tag)[base]) {
8825 inline .ptr_decl,8818 .ptr_decl => return @enumFromInt(ip.extra.items[
8826 .ptr_mut_decl,8819 ip.items.items(.data)[base] + std.meta.fieldIndex(PtrDecl, "decl").?
8827 => |tag| return @enumFromInt(ip.extra.items[
8828 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "decl").?
8829 ]),8820 ]),
8830 inline .ptr_eu_payload,8821 inline .ptr_eu_payload,
8831 .ptr_opt_payload,8822 .ptr_opt_payload,
...@@ -8834,8 +8825,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {...@@ -8834,8 +8825,8 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
8834 => |tag| base = ip.extra.items[8825 => |tag| base = ip.extra.items[
8835 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "base").?8826 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "base").?
8836 ],8827 ],
8837 inline .ptr_slice => |tag| base = ip.extra.items[8828 .ptr_slice => base = ip.extra.items[
8838 ip.items.items(.data)[base] + std.meta.fieldIndex(tag.Payload(), "ptr").?8829 ip.items.items(.data)[base] + std.meta.fieldIndex(PtrSlice, "ptr").?
8839 ],8830 ],
8840 else => return .none,8831 else => return .none,
8841 }8832 }
...@@ -8847,7 +8838,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {...@@ -8847,7 +8838,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
8847 while (true) {8838 while (true) {
8848 switch (ip.items.items(.tag)[base]) {8839 switch (ip.items.items(.tag)[base]) {
8849 .ptr_decl => return .decl,8840 .ptr_decl => return .decl,
8850 .ptr_mut_decl => return .mut_decl,8841 .ptr_comptime_alloc => return .comptime_alloc,
8851 .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,8842 .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,
8852 .ptr_comptime_field => return .comptime_field,8843 .ptr_comptime_field => return .comptime_field,
8853 .ptr_int => return .int,8844 .ptr_int => return .int,
...@@ -9023,7 +9014,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -9023,7 +9014,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
9023 .undef,9014 .undef,
9024 .simple_value,9015 .simple_value,
9025 .ptr_decl,9016 .ptr_decl,
9026 .ptr_mut_decl,9017 .ptr_comptime_alloc,
9027 .ptr_anon_decl,9018 .ptr_anon_decl,
9028 .ptr_anon_decl_aligned,9019 .ptr_anon_decl_aligned,
9029 .ptr_comptime_field,9020 .ptr_comptime_field,
src/Module.zig+2-29
...@@ -101,12 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},...@@ -101,12 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
101/// is not yet implemented.101/// is not yet implemented.
102intern_pool: InternPool = .{},102intern_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
110/// We optimize memory usage for a compilation with no compile errors by storing the104/// We optimize memory usage for a compilation with no compile errors by storing the
111/// error messages and mapping outside of `Decl`.105/// error messages and mapping outside of `Decl`.
112/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.106/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
...@@ -2099,7 +2093,6 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2099,7 +2093,6 @@ pub fn deinit(zcu: *Zcu) void {
2099 }2093 }
21002094
2101 zcu.intern_pool.deinit(gpa);2095 zcu.intern_pool.deinit(gpa);
2102 zcu.tmp_hack_arena.deinit();
2103}2096}
21042097
2105pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {2098pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
...@@ -3656,9 +3649,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3656,9 +3649,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3656 var analysis_arena = std.heap.ArenaAllocator.init(gpa);3649 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3657 defer analysis_arena.deinit();3650 defer analysis_arena.deinit();
36583651
3659 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3660 defer comptime_mutable_decls.deinit();
3661
3662 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);3652 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
3663 defer comptime_err_ret_trace.deinit();3653 defer comptime_err_ret_trace.deinit();
36643654
...@@ -3674,7 +3664,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3674,7 +3664,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3674 .fn_ret_ty = Type.void,3664 .fn_ret_ty = Type.void,
3675 .fn_ret_ty_ies = null,3665 .fn_ret_ty_ies = null,
3676 .owner_func_index = .none,3666 .owner_func_index = .none,
3677 .comptime_mutable_decls = &comptime_mutable_decls,
3678 .comptime_err_ret_trace = &comptime_err_ret_trace,3667 .comptime_err_ret_trace = &comptime_err_ret_trace,
3679 .builtin_type_target_index = builtin_type_target_index,3668 .builtin_type_target_index = builtin_type_target_index,
3680 };3669 };
...@@ -3704,18 +3693,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3704,18 +3693,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3704 // We'll do some other bits with the Sema. Clear the type target index just3693 // We'll do some other bits with the Sema. Clear the type target index just
3705 // in case they analyze any type.3694 // in case they analyze any type.
3706 sema.builtin_type_target_index = .none;3695 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 }
3711 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };3696 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
3712 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };3697 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
3713 const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };3698 const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
3714 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };3699 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
3715 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };3700 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
3716 const decl_tv = try sema.resolveConstValueAllowVariables(&block_scope, init_src, result_ref, .{3701 const decl_tv = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
3717 .needed_comptime_reason = "global variable initializer must be comptime-known",
3718 });
37193702
3720 // Note this resolves the type of the Decl, not the value; if this Decl3703 // Note this resolves the type of the Decl, not the value; if this Decl
3721 // is a struct, for example, this resolves `type` (which needs no resolution),3704 // 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...@@ -4572,9 +4555,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
45724555
4573 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));4556 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
4578 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);4558 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
4579 defer comptime_err_ret_trace.deinit();4559 defer comptime_err_ret_trace.deinit();
45804560
...@@ -4599,7 +4579,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4599,7 +4579,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4599 .fn_ret_ty_ies = null,4579 .fn_ret_ty_ies = null,
4600 .owner_func_index = func_index,4580 .owner_func_index = func_index,
4601 .branch_quota = @max(func.branchQuota(ip).*, Sema.default_branch_quota),4581 .branch_quota = @max(func.branchQuota(ip).*, Sema.default_branch_quota),
4602 .comptime_mutable_decls = &comptime_mutable_decls,
4603 .comptime_err_ret_trace = &comptime_err_ret_trace,4582 .comptime_err_ret_trace = &comptime_err_ret_trace,
4604 };4583 };
4605 defer sema.deinit();4584 defer sema.deinit();
...@@ -4736,11 +4715,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4736,11 +4715,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4736 };4715 };
4737 }4716 }
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
4744 // Copy the block into place and mark that as the main block.4718 // Copy the block into place and mark that as the main block.
4745 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +4719 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
4746 inner_block.instructions.items.len);4720 inner_block.instructions.items.len);
...@@ -5632,8 +5606,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {...@@ -5632,8 +5606,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
5632 .ptr => |ptr| switch (ptr.addr) {5606 .ptr => |ptr| switch (ptr.addr) {
5633 .decl => |decl| try mod.markDeclIndexAlive(decl),5607 .decl => |decl| try mod.markDeclIndexAlive(decl),
5634 .anon_decl => {},5608 .anon_decl => {},
5635 .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),5609 .int, .comptime_field, .comptime_alloc => {},
5636 .int, .comptime_field => {},
5637 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),5610 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),
5638 .elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),5611 .elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),
5639 },5612 },
src/Sema.zig+587-332
...@@ -91,14 +91,6 @@ no_partial_func_ty: bool = false,...@@ -91,14 +91,6 @@ no_partial_func_ty: bool = false,
91/// here so the values can be dropped without any cleanup.91/// here so the values can be dropped without any cleanup.
92unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},92unresolved_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
102/// This is populated when `@setAlignStack` occurs so that if there is a duplicate94/// This is populated when `@setAlignStack` occurs so that if there is a duplicate
103/// one encountered, the conflicting source location can be shown.95/// one encountered, the conflicting source location can be shown.
104prev_stack_alignment_src: ?LazySrcLoc = null,96prev_stack_alignment_src: ?LazySrcLoc = null,
...@@ -123,19 +115,57 @@ base_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, Air.Inst.Index) = .{},...@@ -123,19 +115,57 @@ base_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, Air.Inst.Index) = .{},
123/// Backed by gpa.115/// Backed by gpa.
124maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAlloc) = .{},116maybe_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
126const MaybeComptimeAlloc = struct {124const MaybeComptimeAlloc = struct {
127 /// The runtime index of the `alloc` instruction.125 /// The runtime index of the `alloc` instruction.
128 runtime_index: Value.RuntimeIndex,126 runtime_index: Value.RuntimeIndex,
129 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to127 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to
130 /// RLS, a single comptime-known allocation may have arbitrarily many stores.128 /// RLS, a single comptime-known allocation may have arbitrarily many stores.
131 /// This may also contain `set_union_tag` instructions.129 /// This may also contain `set_union_tag` instructions.
132 stores: std.ArrayListUnmanaged(Air.Inst.Index) = .{},130 stores: std.MultiArrayList(struct {
131 inst: Air.Inst.Index,
132 src_decl: InternPool.DeclIndex,
133 src: LazySrcLoc,
134 }) = .{},
133 /// Backed by sema.arena. Contains instructions such as `optional_payload_ptr_set`135 /// Backed by sema.arena. Contains instructions such as `optional_payload_ptr_set`
134 /// which have side effects so will not be elided by Liveness: we must rewrite these136 /// which have side effects so will not be elided by Liveness: we must rewrite these
135 /// instructions to be nops instead of relying on Liveness.137 /// instructions to be nops instead of relying on Liveness.
136 non_elideable_pointers: std.ArrayListUnmanaged(Air.Inst.Index) = .{},138 non_elideable_pointers: std.ArrayListUnmanaged(Air.Inst.Index) = .{},
137};139};
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
139const std = @import("std");169const std = @import("std");
140const math = std.math;170const math = std.math;
141const mem = std.mem;171const mem = std.mem;
...@@ -164,6 +194,7 @@ const build_options = @import("build_options");...@@ -164,6 +194,7 @@ const build_options = @import("build_options");
164const Compilation = @import("Compilation.zig");194const Compilation = @import("Compilation.zig");
165const InternPool = @import("InternPool.zig");195const InternPool = @import("InternPool.zig");
166const Alignment = InternPool.Alignment;196const Alignment = InternPool.Alignment;
197const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
167198
168pub const default_branch_quota = 1000;199pub const default_branch_quota = 1000;
169pub const default_reference_trace_len = 2;200pub const default_reference_trace_len = 2;
...@@ -787,40 +818,6 @@ pub const Block = struct {...@@ -787,40 +818,6 @@ pub const Block = struct {
787 const zcu = block.sema.mod;818 const zcu = block.sema.mod;
788 return zcu.namespacePtr(block.namespace).file_scope.mod;819 return zcu.namespacePtr(block.namespace).file_scope.mod;
789 }820 }
790
791 pub fn startAnonDecl(block: *Block) !WipAnonDecl {
792 return WipAnonDecl{
793 .block = block,
794 .finished = false,
795 };
796 }
797
798 pub const WipAnonDecl = struct {
799 block: *Block,
800 finished: bool,
801
802 pub fn deinit(wad: *WipAnonDecl) void {
803 wad.* = undefined;
804 }
805
806 /// `alignment` value of 0 means to use ABI alignment.
807 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: Alignment) !InternPool.DeclIndex {
808 const sema = wad.block.sema;
809 // Do this ahead of time because `createAnonymousDecl` depends on calling
810 // `type.hasRuntimeBits()`.
811 _ = try sema.typeHasRuntimeBits(ty);
812 const new_decl_index = try sema.mod.createAnonymousDecl(wad.block, .{
813 .ty = ty,
814 .val = val,
815 });
816 const new_decl = sema.mod.declPtr(new_decl_index);
817 new_decl.alignment = alignment;
818 errdefer sema.mod.abortAnonDecl(new_decl_index);
819 wad.finished = true;
820 try sema.mod.finalizeAnonDecl(new_decl_index);
821 return new_decl_index;
822 }
823 };
824};821};
825822
826const LabeledBlock = struct {823const LabeledBlock = struct {
...@@ -869,6 +866,7 @@ pub fn deinit(sema: *Sema) void {...@@ -869,6 +866,7 @@ pub fn deinit(sema: *Sema) void {
869 sema.unresolved_inferred_allocs.deinit(gpa);866 sema.unresolved_inferred_allocs.deinit(gpa);
870 sema.base_allocs.deinit(gpa);867 sema.base_allocs.deinit(gpa);
871 sema.maybe_comptime_allocs.deinit(gpa);868 sema.maybe_comptime_allocs.deinit(gpa);
869 sema.comptime_allocs.deinit(gpa);
872 sema.* = undefined;870 sema.* = undefined;
873}871}
874872
...@@ -1901,7 +1899,7 @@ pub fn resolveConstStringIntern(...@@ -1901,7 +1899,7 @@ pub fn resolveConstStringIntern(
1901 const wanted_type = Type.slice_const_u8;1899 const wanted_type = Type.slice_const_u8;
1902 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);1900 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
1903 const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);1901 const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);
1904 return val.toIpString(wanted_type, sema.mod);1902 return sema.sliceToIpString(block, src, val, reason);
1905}1903}
19061904
1907pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type {1905pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type {
...@@ -2140,7 +2138,7 @@ fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value...@@ -2140,7 +2138,7 @@ fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value
2140fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {2138fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2141 const val = (try sema.resolveValue(inst)) orelse return null;2139 const val = (try sema.resolveValue(inst)) orelse return null;
2142 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {2140 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {
2143 .decl, .anon_decl, .mut_decl, .comptime_field => return null,2141 .decl, .anon_decl, .comptime_alloc, .comptime_field => return null,
2144 .int => {},2142 .int => {},
2145 .eu_payload, .opt_payload, .elem, .field => unreachable,2143 .eu_payload, .opt_payload, .elem, .field => unreachable,
2146 };2144 };
...@@ -2192,17 +2190,21 @@ fn resolveInstConst(...@@ -2192,17 +2190,21 @@ fn resolveInstConst(
2192}2190}
21932191
2194/// Value Tag may be `undef` or `variable`.2192/// Value Tag may be `undef` or `variable`.
2195pub fn resolveConstValueAllowVariables(2193pub fn resolveFinalDeclValue(
2196 sema: *Sema,2194 sema: *Sema,
2197 block: *Block,2195 block: *Block,
2198 src: LazySrcLoc,2196 src: LazySrcLoc,
2199 air_ref: Air.Inst.Ref,2197 air_ref: Air.Inst.Ref,
2200 reason: NeededComptimeReason,
2201) CompileError!TypedValue {2198) CompileError!TypedValue {
2202 const val = try sema.resolveValueAllowVariables(air_ref) orelse {2199 const val = try sema.resolveValueAllowVariables(air_ref) orelse {
2203 return sema.failWithNeededComptime(block, src, reason);2200 return sema.failWithNeededComptime(block, src, .{
2201 .needed_comptime_reason = "global variable initializer must be comptime-known",
2202 });
2204 };2203 };
2205 if (val.isGenericPoison()) return error.GenericPoison;2204 if (val.isGenericPoison()) return error.GenericPoison;
2205 if (val.canMutateComptimeVarState(sema.mod)) {
2206 return sema.fail(block, src, "global variable contains reference to comptime var", .{});
2207 }
2206 return .{2208 return .{
2207 .ty = sema.typeOf(air_ref),2209 .ty = sema.typeOf(air_ref),
2208 .val = val,2210 .val = val,
...@@ -2671,7 +2673,7 @@ fn analyzeAsInt(...@@ -2671,7 +2673,7 @@ fn analyzeAsInt(
26712673
2672/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,2674/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
2673/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.2675/// 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 {
2675 const zcu = sema.mod;2677 const zcu = sema.mod;
2676 const ip = &zcu.intern_pool;2678 const ip = &zcu.intern_pool;
2677 const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu);2679 const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu);
...@@ -2682,9 +2684,29 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32...@@ -2682,9 +2684,29 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32
2682 const zir_capture: Zir.Inst.Capture = @bitCast(raw);2684 const zir_capture: Zir.Inst.Capture = @bitCast(raw);
2683 capture.* = switch (zir_capture.unwrap()) {2685 capture.* = switch (zir_capture.unwrap()) {
2684 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],2686 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
2687 .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {
2688 const ptr_ref = try sema.resolveInst(ptr_inst.toRef());
2689 const ptr_val = try sema.resolveValue(ptr_ref) orelse {
2690 break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };
2691 };
2692 // TODO: better source location
2693 const unresolved_loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse {
2694 break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };
2695 };
2696 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
2697 if (loaded_val.canMutateComptimeVarState(zcu)) {
2698 // TODO: source location of captured value
2699 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});
2700 }
2701 break :capture .{ .@"comptime" = loaded_val.toIntern() };
2702 }),
2685 .instruction => |inst| InternPool.CaptureValue.wrap(capture: {2703 .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
2686 const air_ref = try sema.resolveInst(inst.toRef());2704 const air_ref = try sema.resolveInst(inst.toRef());
2687 if (try sema.resolveValueResolveLazy(air_ref)) |val| {2705 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
2706 if (val.canMutateComptimeVarState(zcu)) {
2707 // TODO: source location of captured value
2708 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});
2709 }
2688 break :capture .{ .@"comptime" = val.toIntern() };2710 break :capture .{ .@"comptime" = val.toIntern() };
2689 }2711 }
2690 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };2712 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
...@@ -2766,7 +2788,7 @@ fn zirStructDecl(...@@ -2766,7 +2788,7 @@ fn zirStructDecl(
2766 break :blk decls_len;2788 break :blk decls_len;
2767 } else 0;2789 } 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);
2770 extra_index += captures_len;2792 extra_index += captures_len;
27712793
2772 if (small.has_backing_int) {2794 if (small.has_backing_int) {
...@@ -2981,7 +3003,7 @@ fn zirEnumDecl(...@@ -2981,7 +3003,7 @@ fn zirEnumDecl(
2981 break :blk decls_len;3003 break :blk decls_len;
2982 } else 0;3004 } 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);
2985 extra_index += captures_len;3007 extra_index += captures_len;
29863008
2987 const decls = sema.code.bodySlice(extra_index, decls_len);3009 const decls = sema.code.bodySlice(extra_index, decls_len);
...@@ -3254,7 +3276,7 @@ fn zirUnionDecl(...@@ -3254,7 +3276,7 @@ fn zirUnionDecl(
3254 break :blk decls_len;3276 break :blk decls_len;
3255 } else 0;3277 } 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);
3258 extra_index += captures_len;3280 extra_index += captures_len;
32593281
3260 const union_init: InternPool.UnionTypeInit = .{3282 const union_init: InternPool.UnionTypeInit = .{
...@@ -3358,7 +3380,7 @@ fn zirOpaqueDecl(...@@ -3358,7 +3380,7 @@ fn zirOpaqueDecl(
3358 break :blk decls_len;3380 break :blk decls_len;
3359 } else 0;3381 } 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);
3362 extra_index += captures_len;3384 extra_index += captures_len;
33633385
3364 const opaque_init: InternPool.OpaqueTypeInit = .{3386 const opaque_init: InternPool.OpaqueTypeInit = .{
...@@ -3653,9 +3675,9 @@ fn zirAllocExtended(...@@ -3653,9 +3675,9 @@ fn zirAllocExtended(
3653 try sema.air_instructions.append(gpa, .{3675 try sema.air_instructions.append(gpa, .{
3654 .tag = .inferred_alloc_comptime,3676 .tag = .inferred_alloc_comptime,
3655 .data = .{ .inferred_alloc_comptime = .{3677 .data = .{ .inferred_alloc_comptime = .{
3656 .decl_index = undefined,
3657 .alignment = alignment,3678 .alignment = alignment,
3658 .is_const = small.is_const,3679 .is_const = small.is_const,
3680 .ptr = undefined,
3659 } },3681 } },
3660 });3682 });
3661 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();3683 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
...@@ -3717,36 +3739,51 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3717,36 +3739,51 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3717 const ptr_info = alloc_ty.ptrInfo(mod);3739 const ptr_info = alloc_ty.ptrInfo(mod);
3718 const elem_ty = Type.fromInterned(ptr_info.child);3740 const elem_ty = Type.fromInterned(ptr_info.child);
37193741
3720 if (try sema.resolveComptimeKnownAllocValue(block, alloc, null)) |val| {3742 // If the alloc was created in a comptime scope, we already created a comptime alloc for it.
3721 const new_mut_ptr = Air.internedToRef((try mod.intern(.{ .ptr = .{3743 // However, if the final constructed value does not reference comptime-mutable memory, we wish
3722 .ty = alloc_ty.toIntern(),3744 // to promote it to an anon decl.
3723 .addr = .{ .anon_decl = .{3745 already_ct: {
3724 .val = val,3746 const ptr_val = try sema.resolveValue(alloc) orelse break :already_ct;
3725 .orig_ty = alloc_ty.toIntern(),3747
3726 } },3748 // If this was a comptime inferred alloc, then `storeToInferredAllocComptime`
3727 } })));3749 // might have already done our job and created an anon decl ref.
3728 return sema.makePtrConst(block, new_mut_ptr);3750 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
3729 }3751 .ptr => |ptr| switch (ptr.addr) {
37303752 .anon_decl => {
3731 // If this is already a comptime-known allocation, we don't want to emit an error - the stores3753 // The comptime-ification was already done for us.
3732 // were already performed at comptime! Just make the pointer constant as normal.3754 // Just make sure the pointer is const.
3733 implicit_ct: {3755 return sema.makePtrConst(block, alloc);
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;
3746 },3756 },
3747 }3757 else => {},
3758 },
3759 else => {},
3748 }3760 }
3749 return sema.makePtrConst(block, alloc);3761
3762 if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct;
3763 const alloc_index = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr.comptime_alloc;
3764 const ct_alloc = sema.getComptimeAlloc(alloc_index);
3765 const interned = try ct_alloc.val.intern(ct_alloc.ty, mod);
3766 if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) {
3767 // Preserve the comptime alloc, just make the pointer const.
3768 ct_alloc.val = Value.fromInterned(interned);
3769 ct_alloc.is_const = true;
3770 return sema.makePtrConst(block, alloc);
3771 } else {
3772 // Promote the constant to an anon decl.
3773 const new_mut_ptr = Air.internedToRef(try mod.intern(.{ .ptr = .{
3774 .ty = alloc_ty.toIntern(),
3775 .addr = .{ .anon_decl = .{
3776 .val = interned,
3777 .orig_ty = alloc_ty.toIntern(),
3778 } },
3779 } }));
3780 return sema.makePtrConst(block, new_mut_ptr);
3781 }
3782 }
3783
3784 // Otherwise, check if the alloc is comptime-known despite being in a runtime scope.
3785 if (try sema.resolveComptimeKnownAllocPtr(block, alloc, null)) |ptr_val| {
3786 return sema.makePtrConst(block, Air.internedToRef(ptr_val));
3750 }3787 }
37513788
3752 if (try sema.typeRequiresComptime(elem_ty)) {3789 if (try sema.typeRequiresComptime(elem_ty)) {
...@@ -3762,7 +3799,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3762,7 +3799,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
37623799
3763/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved3800/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved
3764/// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`.3801/// 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 {
3766 const mod = sema.mod;3803 const mod = sema.mod;
37673804
3768 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);3805 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
...@@ -3771,7 +3808,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re...@@ -3771,7 +3808,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
37713808
3772 const alloc_inst = alloc.toIndex() orelse return null;3809 const alloc_inst = alloc.toIndex() orelse return null;
3773 const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null;3810 const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null;
3774 const stores = comptime_info.value.stores.items;3811 const stores = comptime_info.value.stores.items(.inst);
37753812
3776 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.3813 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.
3777 // We will resolve and return its value.3814 // We will resolve and return its value.
...@@ -3779,7 +3816,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re...@@ -3779,7 +3816,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
3779 // We expect to have emitted at least one store, unless the elem type is OPV.3816 // We expect to have emitted at least one store, unless the elem type is OPV.
3780 if (stores.len == 0) {3817 if (stores.len == 0) {
3781 const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern();3818 const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern();
3782 return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value);3819 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
3783 }3820 }
37843821
3785 // In general, we want to create a comptime alloc of the correct type and3822 // In general, we want to create a comptime alloc of the correct type and
...@@ -3794,28 +3831,23 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re...@@ -3794,28 +3831,23 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
37943831
3795 const val = store_data.rhs.toInterned().?;3832 const val = store_data.rhs.toInterned().?;
3796 assert(mod.intern_pool.typeOf(val) == elem_ty.toIntern());3833 assert(mod.intern_pool.typeOf(val) == elem_ty.toIntern());
3797 return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value);3834 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
3798 }3835 }
37993836
3800 // The simple strategy failed: we must create a mutable comptime alloc and3837 // The simple strategy failed: we must create a mutable comptime alloc and
3801 // perform all of the runtime store operations at comptime.3838 // perform all of the runtime store operations at comptime.
38023839
3803 var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl3840 const ct_alloc = try sema.newComptimeAlloc(block, elem_ty, ptr_info.flags.alignment);
3804 defer anon_decl.deinit();
3805 const decl_index = try anon_decl.finish(elem_ty, try mod.undefValue(elem_ty), ptr_info.flags.alignment);
38063841
3807 const decl_ptr = try mod.intern(.{ .ptr = .{3842 const alloc_ptr = try mod.intern(.{ .ptr = .{
3808 .ty = alloc_ty.toIntern(),3843 .ty = alloc_ty.toIntern(),
3809 .addr = .{ .mut_decl = .{3844 .addr = .{ .comptime_alloc = ct_alloc },
3810 .decl = decl_index,
3811 .runtime_index = block.runtime_index,
3812 } },
3813 } });3845 } });
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
3816 var ptr_mapping = std.AutoHashMap(Air.Inst.Index, InternPool.Index).init(sema.arena);3848 var ptr_mapping = std.AutoHashMap(Air.Inst.Index, InternPool.Index).init(sema.arena);
3817 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));3849 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));
3818 ptr_mapping.putAssumeCapacity(alloc_inst, decl_ptr);3850 ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr);
38193851
3820 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);3852 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);
3821 for (stores) |store_inst| {3853 for (stores) |store_inst| {
...@@ -3953,14 +3985,27 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re...@@ -3953,14 +3985,27 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
3953 }3985 }
39543986
3955 // The value is finalized - load it!3987 // The value is finalized - load it!
3956 const val = (try sema.pointerDeref(block, .unneeded, Value.fromInterned(decl_ptr), alloc_ty)).?.toIntern();3988 const val = (try sema.pointerDeref(block, .unneeded, Value.fromInterned(alloc_ptr), alloc_ty)).?.toIntern();
3957 return sema.finishResolveComptimeKnownAllocValue(val, alloc_inst, comptime_info.value);3989 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, ct_alloc, alloc_inst, comptime_info.value);
3958}3990}
39593991
3960/// Given the resolved comptime-known value, rewrites the dead AIR to not3992/// Given the resolved comptime-known value, rewrites the dead AIR to not
3961/// create a runtime stack allocation.3993/// create a runtime stack allocation. Also places the resulting value into
3962/// Same return type as `resolveComptimeKnownAllocValue` so we can tail call.3994/// either an anon decl ref or a comptime alloc depending on whether it
3963fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Index, alloc_inst: Air.Inst.Index, comptime_info: MaybeComptimeAlloc) CompileError!?InternPool.Index {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
3964 // We're almost done - we have the resolved comptime value. We just need to4009 // We're almost done - we have the resolved comptime value. We just need to
3965 // eliminate the now-dead runtime instructions.4010 // eliminate the now-dead runtime instructions.
39664011
...@@ -3974,14 +4019,34 @@ fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Inde...@@ -3974,14 +4019,34 @@ fn finishResolveComptimeKnownAllocValue(sema: *Sema, result_val: InternPool.Inde
3974 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };4019 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };
39754020
3976 sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);4021 sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);
3977 for (comptime_info.stores.items) |store_inst| {4022 for (comptime_info.stores.items(.inst)) |store_inst| {
3978 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);4023 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);
3979 }4024 }
3980 for (comptime_info.non_elideable_pointers.items) |ptr_inst| {4025 for (comptime_info.non_elideable_pointers.items) |ptr_inst| {
3981 sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst);4026 sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst);
3982 }4027 }
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 }
3985}4050}
39864051
3987fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {4052fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {
...@@ -4011,9 +4076,9 @@ fn zirAllocInferredComptime(...@@ -4011,9 +4076,9 @@ fn zirAllocInferredComptime(
4011 try sema.air_instructions.append(gpa, .{4076 try sema.air_instructions.append(gpa, .{
4012 .tag = .inferred_alloc_comptime,4077 .tag = .inferred_alloc_comptime,
4013 .data = .{ .inferred_alloc_comptime = .{4078 .data = .{ .inferred_alloc_comptime = .{
4014 .decl_index = undefined,
4015 .alignment = .none,4079 .alignment = .none,
4016 .is_const = is_const,4080 .is_const = is_const,
4081 .ptr = undefined,
4017 } },4082 } },
4018 });4083 });
4019 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();4084 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
...@@ -4076,9 +4141,9 @@ fn zirAllocInferred(...@@ -4076,9 +4141,9 @@ fn zirAllocInferred(
4076 try sema.air_instructions.append(gpa, .{4141 try sema.air_instructions.append(gpa, .{
4077 .tag = .inferred_alloc_comptime,4142 .tag = .inferred_alloc_comptime,
4078 .data = .{ .inferred_alloc_comptime = .{4143 .data = .{ .inferred_alloc_comptime = .{
4079 .decl_index = undefined,
4080 .alignment = .none,4144 .alignment = .none,
4081 .is_const = is_const,4145 .is_const = is_const,
4146 .ptr = undefined,
4082 } },4147 } },
4083 });4148 });
4084 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();4149 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
...@@ -4092,8 +4157,10 @@ fn zirAllocInferred(...@@ -4092,8 +4157,10 @@ fn zirAllocInferred(
4092 } },4157 } },
4093 });4158 });
4094 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});4159 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});
4095 try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index });4160 if (is_const) {
4096 try sema.base_allocs.put(sema.gpa, result_index, result_index);4161 try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index });
4162 try sema.base_allocs.put(sema.gpa, result_index, result_index);
4163 }
4097 return result_index.toRef();4164 return result_index.toRef();
4098}4165}
40994166
...@@ -4112,38 +4179,33 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4112,38 +4179,33 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
41124179
4113 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {4180 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
4114 .inferred_alloc_comptime => {4181 .inferred_alloc_comptime => {
4182 // The work was already done for us by `Sema.storeToInferredAllocComptime`.
4183 // All we need to do is remap the pointer.
4115 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;4184 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;
4116 const decl_index = iac.decl_index;4185 const resolved_ptr = iac.ptr;
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 });
41294186
4130 if (std.debug.runtime_safety) {4187 if (std.debug.runtime_safety) {
4131 // The inferred_alloc_comptime should never be referenced again4188 // The inferred_alloc_comptime should never be referenced again
4132 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });4189 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });
4133 }4190 }
41344191
4135 try sema.maybeQueueFuncBodyAnalysis(decl_index);4192 const val = switch (mod.intern_pool.indexToKey(resolved_ptr).ptr.addr) {
41364193 .anon_decl => |a| a.val,
4137 const interned = try mod.intern(.{ .ptr = .{4194 .comptime_alloc => |i| val: {
4138 .ty = final_ptr_ty.toIntern(),4195 const alloc = sema.getComptimeAlloc(i);
4139 .addr = if (!iac.is_const) .{ .mut_decl = .{4196 break :val try alloc.val.intern(alloc.ty, mod);
4140 .decl = decl_index,4197 },
4141 .runtime_index = block.runtime_index,4198 else => unreachable,
4142 } } else .{ .decl = decl_index },4199 };
4143 } });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
4145 // Remap the ZIR operand to the resolved pointer value4207 // Remap the ZIR operand to the resolved pointer value
4146 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(interned));4208 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(resolved_ptr));
4147 },4209 },
4148 .inferred_alloc => {4210 .inferred_alloc => {
4149 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;4211 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;
...@@ -4166,18 +4228,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4166,18 +4228,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
41664228
4167 if (!ia1.is_const) {4229 if (!ia1.is_const) {
4168 try sema.validateVarType(block, ty_src, final_elem_ty, false);4230 try sema.validateVarType(block, ty_src, final_elem_ty, false);
4169 } else if (try sema.resolveComptimeKnownAllocValue(block, ptr, final_ptr_ty)) |val| {4231 } else if (try sema.resolveComptimeKnownAllocPtr(block, ptr, final_ptr_ty)) |ptr_val| {
4170 const const_ptr_ty = (try sema.makePtrTyConst(final_ptr_ty)).toIntern();4232 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);
4171 const new_const_ptr = try mod.intern(.{ .ptr = .{4233 const new_const_ptr = try mod.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);
4172 .ty = const_ptr_ty,
4173 .addr = .{ .anon_decl = .{
4174 .val = val,
4175 .orig_ty = const_ptr_ty,
4176 } },
4177 } });
41784234
4179 // Remap the ZIR oeprand to the resolved pointer value4235 // 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
4182 // Unless the block is comptime, `alloc_inferred` always produces4238 // Unless the block is comptime, `alloc_inferred` always produces
4183 // a runtime constant. The final inferred type needs to be4239 // a runtime constant. The final inferred type needs to be
...@@ -4387,7 +4443,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL...@@ -4387,7 +4443,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL
4387 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),4443 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
4388 else => break,4444 else => break,
4389 };4445 };
4390 try sema.checkKnownAllocPtr(ptr, base_ptr);4446 try sema.checkKnownAllocPtr(block, ptr, base_ptr);
4391 return base_ptr;4447 return base_ptr;
4392}4448}
43934449
...@@ -4703,6 +4759,7 @@ fn validateUnionInit(...@@ -4703,6 +4759,7 @@ fn validateUnionInit(
4703 var first_block_index = block.instructions.items.len;4759 var first_block_index = block.instructions.items.len;
4704 var block_index = block.instructions.items.len - 1;4760 var block_index = block.instructions.items.len - 1;
4705 var init_val: ?Value = null;4761 var init_val: ?Value = null;
4762 var init_ref: ?Air.Inst.Ref = null;
4706 while (block_index > 0) : (block_index -= 1) {4763 while (block_index > 0) : (block_index -= 1) {
4707 const store_inst = block.instructions.items[block_index];4764 const store_inst = block.instructions.items[block_index];
4708 if (store_inst.toRef() == field_ptr_ref) {4765 if (store_inst.toRef() == field_ptr_ref) {
...@@ -4727,6 +4784,7 @@ fn validateUnionInit(...@@ -4727,6 +4784,7 @@ fn validateUnionInit(
4727 ).?4784 ).?
4728 else4785 else
4729 block_index, first_block_index);4786 block_index, first_block_index);
4787 init_ref = bin_op.rhs;
4730 init_val = try sema.resolveValue(bin_op.rhs);4788 init_val = try sema.resolveValue(bin_op.rhs);
4731 break;4789 break;
4732 }4790 }
...@@ -4779,10 +4837,11 @@ fn validateUnionInit(...@@ -4779,10 +4837,11 @@ fn validateUnionInit(
4779 .needed_comptime_reason = "initializer of comptime only union must be comptime-known",4837 .needed_comptime_reason = "initializer of comptime only union must be comptime-known",
4780 });4838 });
4781 }4839 }
4840 if (init_ref) |v| try sema.validateRuntimeValue(block, field_ptr_data.src(), v);
47824841
4783 const new_tag = Air.internedToRef(tag_val.toIntern());4842 const new_tag = Air.internedToRef(tag_val.toIntern());
4784 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);4843 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
4785 try sema.checkComptimeKnownStore(block, set_tag_inst);4844 try sema.checkComptimeKnownStore(block, set_tag_inst, init_src);
4786}4845}
47874846
4788fn validateStructInit(4847fn validateStructInit(
...@@ -4887,6 +4946,8 @@ fn validateStructInit(...@@ -4887,6 +4946,8 @@ fn validateStructInit(
4887 return;4946 return;
4888 }4947 }
48894948
4949 var fields_allow_runtime = true;
4950
4890 var struct_is_comptime = true;4951 var struct_is_comptime = true;
4891 var first_block_index = block.instructions.items.len;4952 var first_block_index = block.instructions.items.len;
48924953
...@@ -4957,6 +5018,7 @@ fn validateStructInit(...@@ -4957,6 +5018,7 @@ fn validateStructInit(
4957 ).?5018 ).?
4958 else5019 else
4959 block_index, first_block_index);5020 block_index, first_block_index);
5021 if (!sema.checkRuntimeValue(bin_op.rhs)) fields_allow_runtime = false;
4960 if (try sema.resolveValue(bin_op.rhs)) |val| {5022 if (try sema.resolveValue(bin_op.rhs)) |val| {
4961 field_values[i] = val.toIntern();5023 field_values[i] = val.toIntern();
4962 } else if (require_comptime) {5024 } else if (require_comptime) {
...@@ -4996,6 +5058,11 @@ fn validateStructInit(...@@ -4996,6 +5058,11 @@ fn validateStructInit(
4996 field_values[i] = default_val.toIntern();5058 field_values[i] = default_val.toIntern();
4997 }5059 }
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
4999 if (root_msg) |msg| {5066 if (root_msg) |msg| {
5000 if (mod.typeToStruct(struct_ty)) |struct_type| {5067 if (mod.typeToStruct(struct_ty)) |struct_type| {
5001 const decl = mod.declPtr(struct_type.decl.unwrap().?);5068 const decl = mod.declPtr(struct_type.decl.unwrap().?);
...@@ -5067,7 +5134,7 @@ fn validateStructInit(...@@ -5067,7 +5134,7 @@ fn validateStructInit(
5067 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)5134 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)
5068 else5135 else
5069 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), field_src, struct_ty, true);5136 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), field_src, struct_ty, true);
5070 try sema.checkKnownAllocPtr(struct_ptr, default_field_ptr);5137 try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);
5071 const init = Air.internedToRef(field_values[i]);5138 const init = Air.internedToRef(field_values[i]);
5072 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);5139 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
5073 }5140 }
...@@ -5474,7 +5541,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -5474,7 +5541,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
5474 },5541 },
5475 .inferred_alloc => {5542 .inferred_alloc => {
5476 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;5543 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
5477 return sema.storeToInferredAlloc(block, ptr, operand, ia);5544 return sema.storeToInferredAlloc(block, src, ptr, operand, ia);
5478 },5545 },
5479 else => unreachable,5546 else => unreachable,
5480 }5547 }
...@@ -5483,6 +5550,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -5483,6 +5550,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
5483fn storeToInferredAlloc(5550fn storeToInferredAlloc(
5484 sema: *Sema,5551 sema: *Sema,
5485 block: *Block,5552 block: *Block,
5553 src: LazySrcLoc,
5486 ptr: Air.Inst.Ref,5554 ptr: Air.Inst.Ref,
5487 operand: Air.Inst.Ref,5555 operand: Air.Inst.Ref,
5488 inferred_alloc: *InferredAlloc,5556 inferred_alloc: *InferredAlloc,
...@@ -5490,7 +5558,7 @@ fn storeToInferredAlloc(...@@ -5490,7 +5558,7 @@ fn storeToInferredAlloc(
5490 // Create a store instruction as a placeholder. This will be replaced by a5558 // Create a store instruction as a placeholder. This will be replaced by a
5491 // proper store sequence once we know the stored type.5559 // proper store sequence once we know the stored type.
5492 const dummy_store = try block.addBinOp(.store, ptr, operand);5560 const dummy_store = try block.addBinOp(.store, ptr, operand);
5493 try sema.checkComptimeKnownStore(block, dummy_store);5561 try sema.checkComptimeKnownStore(block, dummy_store, src);
5494 // Add the stored instruction to the set we will use to resolve peer types5562 // Add the stored instruction to the set we will use to resolve peer types
5495 // for the inferred allocation.5563 // for the inferred allocation.
5496 try inferred_alloc.prongs.append(sema.arena, dummy_store.toIndex().?);5564 try inferred_alloc.prongs.append(sema.arena, dummy_store.toIndex().?);
...@@ -5503,20 +5571,38 @@ fn storeToInferredAllocComptime(...@@ -5503,20 +5571,38 @@ fn storeToInferredAllocComptime(
5503 operand: Air.Inst.Ref,5571 operand: Air.Inst.Ref,
5504 iac: *Air.Inst.Data.InferredAllocComptime,5572 iac: *Air.Inst.Data.InferredAllocComptime,
5505) CompileError!void {5573) CompileError!void {
5574 const zcu = sema.mod;
5506 const operand_ty = sema.typeOf(operand);5575 const operand_ty = sema.typeOf(operand);
5507 // There will be only one store_to_inferred_ptr because we are running at comptime.5576 // There will be only one store_to_inferred_ptr because we are running at comptime.
5508 // The alloc will turn into a Decl.5577 // The alloc will turn into a Decl or a ComptimeAlloc.
5509 if (try sema.resolveValue(operand)) |operand_val| {5578 const operand_val = try sema.resolveValue(operand) orelse {
5510 var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl5579 return sema.failWithNeededComptime(block, src, .{
5511 defer anon_decl.deinit();5580 .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known",
5512 iac.decl_index = try anon_decl.finish(operand_ty, operand_val, iac.alignment);5581 });
5513 try sema.comptime_mutable_decls.append(iac.decl_index);5582 };
5514 return;5583 const alloc_ty = try sema.ptrType(.{
5515 }5584 .child = operand_ty.toIntern(),
55165585 .flags = .{
5517 return sema.failWithNeededComptime(block, src, .{5586 .alignment = iac.alignment,
5518 .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known",5587 .is_const = iac.is_const,
5588 },
5519 });5589 });
5590 if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {
5591 iac.ptr = try zcu.intern(.{ .ptr = .{
5592 .ty = alloc_ty.toIntern(),
5593 .addr = .{ .anon_decl = .{
5594 .val = operand_val.toIntern(),
5595 .orig_ty = alloc_ty.toIntern(),
5596 } },
5597 } });
5598 } else {
5599 const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment);
5600 sema.getComptimeAlloc(alloc_index).val = operand_val;
5601 iac.ptr = try zcu.intern(.{ .ptr = .{
5602 .ty = alloc_ty.toIntern(),
5603 .addr = .{ .comptime_alloc = alloc_index },
5604 } });
5605 }
5520}5606}
55215607
5522fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5608fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
...@@ -6178,6 +6264,9 @@ fn resolveAnalyzedBlock(...@@ -6178,6 +6264,9 @@ fn resolveAnalyzedBlock(
6178 };6264 };
6179 return sema.failWithOwnedErrorMsg(child_block, msg);6265 return sema.failWithOwnedErrorMsg(child_block, msg);
6180 }6266 }
6267 for (merges.results.items, merges.src_locs.items) |merge_inst, merge_src| {
6268 try sema.validateRuntimeValue(child_block, merge_src orelse src, merge_inst);
6269 }
6181 const ty_inst = Air.internedToRef(resolved_ty.toIntern());6270 const ty_inst = Air.internedToRef(resolved_ty.toIntern());
6182 switch (block_tag) {6271 switch (block_tag) {
6183 .block => {6272 .block => {
...@@ -6579,6 +6668,9 @@ fn addDbgVar(...@@ -6579,6 +6668,9 @@ fn addDbgVar(
6579 };6668 };
6580 if (try sema.typeRequiresComptime(val_ty)) return;6669 if (try sema.typeRequiresComptime(val_ty)) return;
6581 if (!(try sema.typeHasRuntimeBits(val_ty))) return;6670 if (!(try sema.typeHasRuntimeBits(val_ty))) return;
6671 if (try sema.resolveValue(operand)) |operand_val| {
6672 if (operand_val.canMutateComptimeVarState(mod)) return;
6673 }
65826674
6583 // To ensure the lexical scoping is known to backends, this alloc must be6675 // To ensure the lexical scoping is known to backends, this alloc must be
6584 // within a real runtime block. We set a flag which communicates information6676 // within a real runtime block. We set a flag which communicates information
...@@ -7741,20 +7833,24 @@ fn analyzeCall(...@@ -7741,20 +7833,24 @@ fn analyzeCall(
7741 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);7833 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
7742 };7834 };
77437835
7744 if (should_memoize and is_comptime_call) {7836 if (is_comptime_call) {
7745 const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined);7837 const result_val = try sema.resolveConstValue(block, .unneeded, result, undefined);
7746 const result_interned = try result_val.intern2(sema.fn_ret_ty, mod);7838 const result_interned = try result_val.intern2(sema.fn_ret_ty, mod);
77477839
7748 // Transform ad-hoc inferred error set types into concrete error sets.7840 // Transform ad-hoc inferred error set types into concrete error sets.
7749 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);7841 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`.
7751 // TODO: check whether any external comptime memory was mutated by the7845 // TODO: check whether any external comptime memory was mutated by the
7752 // comptime function call. If so, then do not memoize the call here.7846 // comptime function call. If so, then do not memoize the call here.
7753 _ = try mod.intern(.{ .memoized_call = .{7847 if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(mod)) {
7754 .func = module_fn_index,7848 _ = try mod.intern(.{ .memoized_call = .{
7755 .arg_values = memoized_arg_values,7849 .func = module_fn_index,
7756 .result = result_transformed,7850 .arg_values = memoized_arg_values,
7757 } });7851 .result = result_transformed,
7852 } });
7853 }
77587854
7759 break :res2 Air.internedToRef(result_transformed);7855 break :res2 Air.internedToRef(result_transformed);
7760 }7856 }
...@@ -7787,6 +7883,7 @@ fn analyzeCall(...@@ -7787,6 +7883,7 @@ fn analyzeCall(
7787 } else Type.fromInterned(InternPool.Index.var_args_param_type);7883 } else Type.fromInterned(InternPool.Index.var_args_param_type);
7788 assert(!param_ty.isGenericPoison());7884 assert(!param_ty.isGenericPoison());
7789 arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func);7885 arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func);
7886 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*);
7790 if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) {7887 if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) {
7791 return arg_out.*;7888 return arg_out.*;
7792 }7889 }
...@@ -8082,7 +8179,6 @@ fn instantiateGenericCall(...@@ -8082,7 +8179,6 @@ fn instantiateGenericCall(
8082 .generic_call_decl = block.src_decl.toOptional(),8179 .generic_call_decl = block.src_decl.toOptional(),
8083 .branch_quota = sema.branch_quota,8180 .branch_quota = sema.branch_quota,
8084 .branch_count = sema.branch_count,8181 .branch_count = sema.branch_count,
8085 .comptime_mutable_decls = sema.comptime_mutable_decls,
8086 .comptime_err_ret_trace = sema.comptime_err_ret_trace,8182 .comptime_err_ret_trace = sema.comptime_err_ret_trace,
8087 };8183 };
8088 defer child_sema.deinit();8184 defer child_sema.deinit();
...@@ -8147,6 +8243,7 @@ fn instantiateGenericCall(...@@ -8147,6 +8243,7 @@ fn instantiateGenericCall(
8147 },8243 },
8148 };8244 };
8149 const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);8245 const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);
8246 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_index), arg_ref);
8150 const arg_ty = sema.typeOf(arg_ref);8247 const arg_ty = sema.typeOf(arg_ref);
8151 if (arg_ty.zigTypeTag(mod) == .NoReturn) {8248 if (arg_ty.zigTypeTag(mod) == .NoReturn) {
8152 // This terminates argument analysis.8249 // This terminates argument analysis.
...@@ -8859,12 +8956,12 @@ fn analyzeOptionalPayloadPtr(...@@ -8859,12 +8956,12 @@ fn analyzeOptionalPayloadPtr(
88598956
8860 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {8957 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
8861 if (initializing) {8958 if (initializing) {
8862 if (!ptr_val.isComptimeMutablePtr(mod)) {8959 if (!sema.isComptimeMutablePtr(ptr_val)) {
8863 // If the pointer resulting from this function was stored at comptime,8960 // If the pointer resulting from this function was stored at comptime,
8864 // the optional non-null bit would be set that way. But in this case,8961 // the optional non-null bit would be set that way. But in this case,
8865 // we need to emit a runtime instruction to do it.8962 // we need to emit a runtime instruction to do it.
8866 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);8963 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
8867 try sema.checkKnownAllocPtr(optional_ptr, opt_payload_ptr);8964 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);
8868 }8965 }
8869 return Air.internedToRef((try mod.intern(.{ .ptr = .{8966 return Air.internedToRef((try mod.intern(.{ .ptr = .{
8870 .ty = child_pointer.toIntern(),8967 .ty = child_pointer.toIntern(),
...@@ -8891,7 +8988,7 @@ fn analyzeOptionalPayloadPtr(...@@ -8891,7 +8988,7 @@ fn analyzeOptionalPayloadPtr(
88918988
8892 if (initializing) {8989 if (initializing) {
8893 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);8990 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
8894 try sema.checkKnownAllocPtr(optional_ptr, opt_payload_ptr);8991 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);
8895 return opt_payload_ptr;8992 return opt_payload_ptr;
8896 } else {8993 } else {
8897 return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr);8994 return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr);
...@@ -9050,13 +9147,13 @@ fn analyzeErrUnionPayloadPtr(...@@ -9050,13 +9147,13 @@ fn analyzeErrUnionPayloadPtr(
90509147
9051 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {9148 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
9052 if (initializing) {9149 if (initializing) {
9053 if (!ptr_val.isComptimeMutablePtr(mod)) {9150 if (!sema.isComptimeMutablePtr(ptr_val)) {
9054 // If the pointer resulting from this function was stored at comptime,9151 // If the pointer resulting from this function was stored at comptime,
9055 // the error union error code would be set that way. But in this case,9152 // the error union error code would be set that way. But in this case,
9056 // we need to emit a runtime instruction to do it.9153 // we need to emit a runtime instruction to do it.
9057 try sema.requireRuntimeBlock(block, src, null);9154 try sema.requireRuntimeBlock(block, src, null);
9058 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);9155 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
9059 try sema.checkKnownAllocPtr(operand, eu_payload_ptr);9156 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);
9060 }9157 }
9061 return Air.internedToRef((try mod.intern(.{ .ptr = .{9158 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9062 .ty = operand_pointer_ty.toIntern(),9159 .ty = operand_pointer_ty.toIntern(),
...@@ -9085,7 +9182,7 @@ fn analyzeErrUnionPayloadPtr(...@@ -9085,7 +9182,7 @@ fn analyzeErrUnionPayloadPtr(
90859182
9086 if (initializing) {9183 if (initializing) {
9087 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);9184 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
9088 try sema.checkKnownAllocPtr(operand, eu_payload_ptr);9185 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);
9089 return eu_payload_ptr;9186 return eu_payload_ptr;
9090 } else {9187 } else {
9091 return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand);9188 return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand);
...@@ -10089,6 +10186,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -10089,6 +10186,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
10089 } }));10186 } }));
10090 }10187 }
10091 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);10188 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
10189 try sema.validateRuntimeValue(block, ptr_src, operand);
10092 if (!is_vector) {10190 if (!is_vector) {
10093 return block.addUnOp(.int_from_ptr, operand);10191 return block.addUnOp(.int_from_ptr, operand);
10094 }10192 }
...@@ -14743,7 +14841,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14743,7 +14841,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14743 // Optimization for the common pattern of a single element repeated N times, such14841 // Optimization for the common pattern of a single element repeated N times, such
14744 // as zero-filling a byte array.14842 // as zero-filling a byte array.
14745 if (lhs_len == 1 and lhs_info.sentinel == null) {14843 if (lhs_len == 1 and lhs_info.sentinel == null) {
14746 const elem_val = try lhs_sub_val.elemValue(mod, 0);14844 const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, 0)).?;
14747 break :v try mod.intern(.{ .aggregate = .{14845 break :v try mod.intern(.{ .aggregate = .{
14748 .ty = result_ty.toIntern(),14846 .ty = result_ty.toIntern(),
14749 .storage = .{ .repeated_elem = elem_val.toIntern() },14847 .storage = .{ .repeated_elem = elem_val.toIntern() },
...@@ -14755,7 +14853,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14755,7 +14853,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14755 while (elem_i < result_len) {14853 while (elem_i < result_len) {
14756 var lhs_i: usize = 0;14854 var lhs_i: usize = 0;
14757 while (lhs_i < lhs_len) : (lhs_i += 1) {14855 while (lhs_i < lhs_len) : (lhs_i += 1) {
14758 const elem_val = try lhs_sub_val.elemValue(mod, lhs_i);14856 const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, lhs_i)).?;
14759 element_vals[elem_i] = elem_val.toIntern();14857 element_vals[elem_i] = elem_val.toIntern();
14760 elem_i += 1;14858 elem_i += 1;
14761 }14859 }
...@@ -19585,6 +19683,8 @@ fn analyzeRet(...@@ -19585,6 +19683,8 @@ fn analyzeRet(
1958519683
19586 try sema.resolveTypeLayout(sema.fn_ret_ty);19684 try sema.resolveTypeLayout(sema.fn_ret_ty);
1958719685
19686 try sema.validateRuntimeValue(block, operand_src, operand);
19687
19588 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;19688 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;
19589 if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {19689 if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
19590 // Avoid adding a frame to the error return trace in case the value is comptime-known19690 // Avoid adding a frame to the error return trace in case the value is comptime-known
...@@ -20013,6 +20113,8 @@ fn zirStructInit(...@@ -20013,6 +20113,8 @@ fn zirStructInit(
20013 });20113 });
20014 }20114 }
2001520115
20116 try sema.validateRuntimeValue(block, field_src, init_inst);
20117
20016 if (is_ref) {20118 if (is_ref) {
20017 const target = mod.getTarget();20119 const target = mod.getTarget();
20018 const alloc_ty = try sema.ptrType(.{20120 const alloc_ty = try sema.ptrType(.{
...@@ -20187,6 +20289,10 @@ fn finishStructInit(...@@ -20187,6 +20289,10 @@ fn finishStructInit(
20187 });20289 });
20188 }20290 }
2018920291
20292 for (field_inits) |field_init| {
20293 try sema.validateRuntimeValue(block, dest_src, field_init);
20294 }
20295
20190 if (is_ref) {20296 if (is_ref) {
20191 try sema.resolveStructLayout(struct_ty);20297 try sema.resolveStructLayout(struct_ty);
20192 const target = sema.mod.getTarget();20298 const target = sema.mod.getTarget();
...@@ -21023,7 +21129,7 @@ fn zirReify(...@@ -21023,7 +21129,7 @@ fn zirReify(
21023 .needed_comptime_reason = "operand to @Type must be comptime-known",21129 .needed_comptime_reason = "operand to @Type must be comptime-known",
21024 });21130 });
21025 const union_val = ip.indexToKey(val.toIntern()).un;21131 const union_val = ip.indexToKey(val.toIntern()).un;
21026 if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src);21132 if (try sema.anyUndef(Value.fromInterned(union_val.val))) return sema.failWithUseOfUndef(block, src);
21027 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;21133 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
21028 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {21134 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
21029 .Type => return .type_type,21135 .Type => return .type_type,
...@@ -21268,14 +21374,16 @@ fn zirReify(...@@ -21268,14 +21374,16 @@ fn zirReify(
21268 var names: InferredErrorSet.NameMap = .{};21374 var names: InferredErrorSet.NameMap = .{};
21269 try names.ensureUnusedCapacity(sema.arena, len);21375 try names.ensureUnusedCapacity(sema.arena, len);
21270 for (0..len) |i| {21376 for (0..len) |i| {
21271 const elem_val = try payload_val.elemValue(mod, i);21377 const elem_val = (try payload_val.maybeElemValueFull(sema, mod, i)).?;
21272 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));21378 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21273 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21379 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21274 ip,21380 ip,
21275 try ip.getOrPutString(gpa, "name"),21381 try ip.getOrPutString(gpa, "name"),
21276 ).?);21382 ).?);
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 });
21279 _ = try mod.getErrorValue(name);21387 _ = try mod.getErrorValue(name);
21280 const gop = names.getOrPutAssumeCapacity(name);21388 const gop = names.getOrPutAssumeCapacity(name);
21281 if (gop.found_existing) {21389 if (gop.found_existing) {
...@@ -21451,7 +21559,7 @@ fn zirReify(...@@ -21451,7 +21559,7 @@ fn zirReify(
2145121559
21452 var noalias_bits: u32 = 0;21560 var noalias_bits: u32 = 0;
21453 for (param_types, 0..) |*param_type, i| {21561 for (param_types, 0..) |*param_type, i| {
21454 const elem_val = try params_val.elemValue(mod, i);21562 const elem_val = (try params_val.maybeElemValueFull(sema, mod, i)).?;
21455 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));21563 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21456 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21564 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21457 ip,21565 ip,
...@@ -21526,12 +21634,14 @@ fn reifyEnum(...@@ -21526,12 +21634,14 @@ fn reifyEnum(
21526 std.hash.autoHash(&hasher, fields_len);21634 std.hash.autoHash(&hasher, fields_len);
2152721635
21528 for (0..fields_len) |field_idx| {21636 for (0..fields_len) |field_idx| {
21529 const field_info = try fields_val.elemValue(mod, field_idx);21637 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2153021638
21531 const field_name_val = try field_info.fieldValue(mod, 0);21639 const field_name_val = try field_info.fieldValue(mod, 0);
21532 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));21640 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
21536 std.hash.autoHash(&hasher, .{21646 std.hash.autoHash(&hasher, .{
21537 field_name,21647 field_name,
...@@ -21569,12 +21679,13 @@ fn reifyEnum(...@@ -21569,12 +21679,13 @@ fn reifyEnum(
21569 wip_ty.setTagTy(ip, tag_ty.toIntern());21679 wip_ty.setTagTy(ip, tag_ty.toIntern());
2157021680
21571 for (0..fields_len) |field_idx| {21681 for (0..fields_len) |field_idx| {
21572 const field_info = try fields_val.elemValue(mod, field_idx);21682 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2157321683
21574 const field_name_val = try field_info.fieldValue(mod, 0);21684 const field_name_val = try field_info.fieldValue(mod, 0);
21575 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));21685 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
21579 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {21690 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
21580 // TODO: better source location21691 // TODO: better source location
...@@ -21646,13 +21757,15 @@ fn reifyUnion(...@@ -21646,13 +21757,15 @@ fn reifyUnion(
21646 var any_aligns = false;21757 var any_aligns = false;
2164721758
21648 for (0..fields_len) |field_idx| {21759 for (0..fields_len) |field_idx| {
21649 const field_info = try fields_val.elemValue(mod, field_idx);21760 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2165021761
21651 const field_name_val = try field_info.fieldValue(mod, 0);21762 const field_name_val = try field_info.fieldValue(mod, 0);
21652 const field_type_val = try field_info.fieldValue(mod, 1);21763 const field_type_val = try field_info.fieldValue(mod, 1);
21653 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2));21764 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
21657 std.hash.autoHash(&hasher, .{21770 std.hash.autoHash(&hasher, .{
21658 field_name,21771 field_name,
...@@ -21720,12 +21833,13 @@ fn reifyUnion(...@@ -21720,12 +21833,13 @@ fn reifyUnion(
21720 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);21833 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
2172121834
21722 for (field_types, 0..) |*field_ty, field_idx| {21835 for (field_types, 0..) |*field_ty, field_idx| {
21723 const field_info = try fields_val.elemValue(mod, field_idx);21836 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2172421837
21725 const field_name_val = try field_info.fieldValue(mod, 0);21838 const field_name_val = try field_info.fieldValue(mod, 0);
21726 const field_type_val = try field_info.fieldValue(mod, 1);21839 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
21730 const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {21844 const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {
21731 // TODO: better source location21845 // TODO: better source location
...@@ -21771,12 +21885,13 @@ fn reifyUnion(...@@ -21771,12 +21885,13 @@ fn reifyUnion(
21771 try field_names.ensureTotalCapacity(sema.arena, fields_len);21885 try field_names.ensureTotalCapacity(sema.arena, fields_len);
2177221886
21773 for (field_types, 0..) |*field_ty, field_idx| {21887 for (field_types, 0..) |*field_ty, field_idx| {
21774 const field_info = try fields_val.elemValue(mod, field_idx);21888 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2177521889
21776 const field_name_val = try field_info.fieldValue(mod, 0);21890 const field_name_val = try field_info.fieldValue(mod, 0);
21777 const field_type_val = try field_info.fieldValue(mod, 1);21891 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);
21780 const gop = field_names.getOrPutAssumeCapacity(field_name);21895 const gop = field_names.getOrPutAssumeCapacity(field_name);
21781 if (gop.found_existing) {21896 if (gop.found_existing) {
21782 // TODO: better source location21897 // TODO: better source location
...@@ -21883,7 +21998,7 @@ fn reifyStruct(...@@ -21883,7 +21998,7 @@ fn reifyStruct(
21883 var any_aligned_fields = false;21998 var any_aligned_fields = false;
2188421999
21885 for (0..fields_len) |field_idx| {22000 for (0..fields_len) |field_idx| {
21886 const field_info = try fields_val.elemValue(mod, field_idx);22001 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2188722002
21888 const field_name_val = try field_info.fieldValue(mod, 0);22003 const field_name_val = try field_info.fieldValue(mod, 0);
21889 const field_type_val = try field_info.fieldValue(mod, 1);22004 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -21891,7 +22006,9 @@ fn reifyStruct(...@@ -21891,7 +22006,9 @@ fn reifyStruct(
21891 const field_is_comptime_val = try field_info.fieldValue(mod, 3);22006 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
21892 const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4));22007 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 });
21895 const field_is_comptime = field_is_comptime_val.toBool();22012 const field_is_comptime = field_is_comptime_val.toBool();
21896 const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {22013 const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {
21897 const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());22014 const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());
...@@ -21959,7 +22076,7 @@ fn reifyStruct(...@@ -21959,7 +22076,7 @@ fn reifyStruct(
21959 const struct_type = ip.loadStructType(wip_ty.index);22076 const struct_type = ip.loadStructType(wip_ty.index);
2196022077
21961 for (0..fields_len) |field_idx| {22078 for (0..fields_len) |field_idx| {
21962 const field_info = try fields_val.elemValue(mod, field_idx);22079 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;
2196322080
21964 const field_name_val = try field_info.fieldValue(mod, 0);22081 const field_name_val = try field_info.fieldValue(mod, 0);
21965 const field_type_val = try field_info.fieldValue(mod, 1);22082 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -21968,7 +22085,8 @@ fn reifyStruct(...@@ -21968,7 +22085,8 @@ fn reifyStruct(
21968 const field_alignment_val = try field_info.fieldValue(mod, 4);22085 const field_alignment_val = try field_info.fieldValue(mod, 4);
2196922086
21970 const field_ty = field_type_val.toType();22087 const field_ty = field_type_val.toType();
21971 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);22088 // Don't pass a reason; first loop acts as an assertion that this is valid.
22089 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
21972 if (is_tuple) {22090 if (is_tuple) {
21973 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(22091 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
21974 block,22092 block,
...@@ -22914,6 +23032,7 @@ fn ptrCastFull(...@@ -22914,6 +23032,7 @@ fn ptrCastFull(
22914 }23032 }
2291523033
22916 try sema.requireRuntimeBlock(block, src, null);23034 try sema.requireRuntimeBlock(block, src, null);
23035 try sema.validateRuntimeValue(block, operand_src, ptr);
2291723036
22918 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and23037 if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and
22919 (try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)) or Type.fromInterned(dest_info.child).zigTypeTag(mod) == .Fn))23038 (try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)) or Type.fromInterned(dest_info.child).zigTypeTag(mod) == .Fn))
...@@ -22986,7 +23105,7 @@ fn ptrCastFull(...@@ -22986,7 +23105,7 @@ fn ptrCastFull(
22986 });23105 });
22987 } else {23106 } else {
22988 assert(dest_ptr_ty.eql(dest_ty, mod));23107 assert(dest_ptr_ty.eql(dest_ty, mod));
22989 try sema.checkKnownAllocPtr(operand, result_ptr);23108 try sema.checkKnownAllocPtr(block, operand, result_ptr);
22990 return result_ptr;23109 return result_ptr;
22991 }23110 }
22992}23111}
...@@ -23022,7 +23141,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst...@@ -23022,7 +23141,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
2302223141
23023 try sema.requireRuntimeBlock(block, src, null);23142 try sema.requireRuntimeBlock(block, src, null);
23024 const new_ptr = try block.addBitCast(dest_ty, operand);23143 const new_ptr = try block.addBitCast(dest_ty, operand);
23025 try sema.checkKnownAllocPtr(operand, new_ptr);23144 try sema.checkKnownAllocPtr(block, operand, new_ptr);
23026 return new_ptr;23145 return new_ptr;
23027}23146}
2302823147
...@@ -23568,7 +23687,7 @@ fn checkPtrIsNotComptimeMutable(...@@ -23568,7 +23687,7 @@ fn checkPtrIsNotComptimeMutable(
23568 operand_src: LazySrcLoc,23687 operand_src: LazySrcLoc,
23569) CompileError!void {23688) CompileError!void {
23570 _ = operand_src;23689 _ = operand_src;
23571 if (ptr_val.isComptimeMutablePtr(sema.mod)) {23690 if (sema.isComptimeMutablePtr(ptr_val)) {
23572 return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});23691 return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});
23573 }23692 }
23574}23693}
...@@ -23577,9 +23696,10 @@ fn checkComptimeVarStore(...@@ -23577,9 +23696,10 @@ fn checkComptimeVarStore(
23577 sema: *Sema,23696 sema: *Sema,
23578 block: *Block,23697 block: *Block,
23579 src: LazySrcLoc,23698 src: LazySrcLoc,
23580 decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl,23699 alloc_index: ComptimeAllocIndex,
23581) CompileError!void {23700) CompileError!void {
23582 if (@intFromEnum(decl_ref_mut.runtime_index) < @intFromEnum(block.runtime_index)) {23701 const runtime_index = sema.getComptimeAlloc(alloc_index).runtime_index;
23702 if (@intFromEnum(runtime_index) < @intFromEnum(block.runtime_index)) {
23583 if (block.runtime_cond) |cond_src| {23703 if (block.runtime_cond) |cond_src| {
23584 const msg = msg: {23704 const msg = msg: {
23585 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});23705 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});
...@@ -24433,7 +24553,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -24433,7 +24553,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
24433 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);24553 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
24434 break :rs operand_src;24554 break :rs operand_src;
24435 };24555 };
24436 if (ptr_val.isComptimeMutablePtr(mod)) {24556 if (sema.isComptimeMutablePtr(ptr_val)) {
24437 const ptr_ty = sema.typeOf(ptr);24557 const ptr_ty = sema.typeOf(ptr);
24438 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;24558 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
24439 const new_val = switch (op) {24559 const new_val = switch (op) {
...@@ -25149,7 +25269,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -25149,7 +25269,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
25149 }25269 }
2515025270
25151 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {25271 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
25152 if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;25272 if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src;
25153 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {25273 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
25154 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;25274 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;
25155 const len = try sema.usizeCast(block, dest_src, len_u64);25275 const len = try sema.usizeCast(block, dest_src, len_u64);
...@@ -25342,7 +25462,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -25342,7 +25462,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
25342 return;25462 return;
25343 }25463 }
2534425464
25345 if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;25465 if (!sema.isComptimeMutablePtr(ptr_val)) break :rs dest_src;
25346 const elem_val = try sema.resolveValue(elem) orelse break :rs value_src;25466 const elem_val = try sema.resolveValue(elem) orelse break :rs value_src;
25347 const array_ty = try mod.arrayType(.{25467 const array_ty = try mod.arrayType(.{
25348 .child = dest_elem_ty.toIntern(),25468 .child = dest_elem_ty.toIntern(),
...@@ -25588,7 +25708,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -25588,7 +25708,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
25588 if (val.isGenericPoison()) {25708 if (val.isGenericPoison()) {
25589 break :blk .generic;25709 break :blk .generic;
25590 }25710 }
25591 break :blk .{ .explicit = try val.toIpString(ty, mod) };25711 break :blk .{ .explicit = try sema.sliceToIpString(block, section_src, val, .{
25712 .needed_comptime_reason = "linksection must be comptime-known",
25713 }) };
25592 } else if (extra.data.bits.has_section_ref) blk: {25714 } else if (extra.data.bits.has_section_ref) blk: {
25593 const section_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);25715 const section_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
25594 extra_index += 1;25716 extra_index += 1;
...@@ -27115,7 +27237,7 @@ fn fieldPtr(...@@ -27115,7 +27237,7 @@ fn fieldPtr(
27115 try sema.requireRuntimeBlock(block, src, null);27237 try sema.requireRuntimeBlock(block, src, null);
2711627238
27117 const field_ptr = try block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);27239 const field_ptr = try block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
27118 try sema.checkKnownAllocPtr(inner_ptr, field_ptr);27240 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
27119 return field_ptr;27241 return field_ptr;
27120 } else if (ip.stringEqlSlice(field_name, "len")) {27242 } else if (ip.stringEqlSlice(field_name, "len")) {
27121 const result_ty = try sema.ptrType(.{27243 const result_ty = try sema.ptrType(.{
...@@ -27139,7 +27261,7 @@ fn fieldPtr(...@@ -27139,7 +27261,7 @@ fn fieldPtr(
27139 try sema.requireRuntimeBlock(block, src, null);27261 try sema.requireRuntimeBlock(block, src, null);
2714027262
27141 const field_ptr = try block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);27263 const field_ptr = try block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
27142 try sema.checkKnownAllocPtr(inner_ptr, field_ptr);27264 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
27143 return field_ptr;27265 return field_ptr;
27144 } else {27266 } else {
27145 return sema.fail(27267 return sema.fail(
...@@ -27238,7 +27360,7 @@ fn fieldPtr(...@@ -27238,7 +27360,7 @@ fn fieldPtr(
27238 else27360 else
27239 object_ptr;27361 object_ptr;
27240 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);27362 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
27241 try sema.checkKnownAllocPtr(inner_ptr, field_ptr);27363 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
27242 return field_ptr;27364 return field_ptr;
27243 },27365 },
27244 .Union => {27366 .Union => {
...@@ -27247,7 +27369,7 @@ fn fieldPtr(...@@ -27247,7 +27369,7 @@ fn fieldPtr(
27247 else27369 else
27248 object_ptr;27370 object_ptr;
27249 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);27371 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
27250 try sema.checkKnownAllocPtr(inner_ptr, field_ptr);27372 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
27251 return field_ptr;27373 return field_ptr;
27252 },27374 },
27253 else => {},27375 else => {},
...@@ -28030,7 +28152,7 @@ fn elemPtr(...@@ -28030,7 +28152,7 @@ fn elemPtr(
28030 },28152 },
28031 };28153 };
2803228154
28033 try sema.checkKnownAllocPtr(indexable_ptr, elem_ptr);28155 try sema.checkKnownAllocPtr(block, indexable_ptr, elem_ptr);
28034 return elem_ptr;28156 return elem_ptr;
28035}28157}
2803628158
...@@ -28083,7 +28205,7 @@ fn elemPtrOneLayerOnly(...@@ -28083,7 +28205,7 @@ fn elemPtrOneLayerOnly(
28083 },28205 },
28084 else => unreachable, // Guaranteed by checkIndexable28206 else => unreachable, // Guaranteed by checkIndexable
28085 };28207 };
28086 try sema.checkKnownAllocPtr(indexable, elem_ptr);28208 try sema.checkKnownAllocPtr(block, indexable, elem_ptr);
28087 return elem_ptr;28209 return elem_ptr;
28088 },28210 },
28089 }28211 }
...@@ -28617,7 +28739,7 @@ fn coerceExtra(...@@ -28617,7 +28739,7 @@ fn coerceExtra(
28617 try sema.requireRuntimeBlock(block, inst_src, null);28739 try sema.requireRuntimeBlock(block, inst_src, null);
28618 try sema.queueFullTypeResolution(dest_ty);28740 try sema.queueFullTypeResolution(dest_ty);
28619 const new_val = try block.addBitCast(dest_ty, inst);28741 const new_val = try block.addBitCast(dest_ty, inst);
28620 try sema.checkKnownAllocPtr(inst, new_val);28742 try sema.checkKnownAllocPtr(block, inst, new_val);
28621 return new_val;28743 return new_val;
28622 }28744 }
2862328745
...@@ -30349,7 +30471,7 @@ fn storePtr2(...@@ -30349,7 +30471,7 @@ fn storePtr2(
30349 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);30471 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
30350 break :rs operand_src;30472 break :rs operand_src;
30351 };30473 };
30352 if (ptr_val.isComptimeMutablePtr(mod)) {30474 if (sema.isComptimeMutablePtr(ptr_val)) {
30353 try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);30475 try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
30354 return;30476 return;
30355 } else break :rs ptr_src;30477 } else break :rs ptr_src;
...@@ -30392,7 +30514,7 @@ fn storePtr2(...@@ -30392,7 +30514,7 @@ fn storePtr2(
30392 else30514 else
30393 try block.addBinOp(air_tag, ptr, operand);30515 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
30397 return;30519 return;
30398}30520}
...@@ -30400,29 +30522,39 @@ fn storePtr2(...@@ -30400,29 +30522,39 @@ fn storePtr2(
30400/// Given an AIR store instruction, checks whether we are performing a30522/// Given an AIR store instruction, checks whether we are performing a
30401/// comptime-known store to a local alloc, and updates `maybe_comptime_allocs`30523/// comptime-known store to a local alloc, and updates `maybe_comptime_allocs`
30402/// accordingly.30524/// 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 {
30404 const store_inst = store_inst_ref.toIndex().?;30527 const store_inst = store_inst_ref.toIndex().?;
30405 const inst_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;30528 const inst_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
30406 const ptr = inst_data.lhs.toIndex() orelse return;30529 const ptr = inst_data.lhs.toIndex() orelse return;
30407 const operand = inst_data.rhs;30530 const operand = inst_data.rhs;
3040830531
30409 const maybe_base_alloc = sema.base_allocs.get(ptr) orelse return;30532 known: {
30410 const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(maybe_base_alloc) orelse return;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: {30536 if ((try sema.resolveValue(operand)) != null and
30413 if (null == try sema.resolveValue(operand)) break :ct;30537 block.runtime_index == maybe_comptime_alloc.runtime_index)
30414 if (maybe_comptime_alloc.runtime_index != block.runtime_index) break :ct;30538 {
30415 return maybe_comptime_alloc.stores.append(sema.arena, store_inst);30539 try maybe_comptime_alloc.stores.append(sema.arena, .{
30540 .inst = store_inst,
30541 .src_decl = block.src_decl,
30542 .src = store_src,
30543 });
30544 return;
30545 }
30546
30547 // We're newly discovering that this alloc is runtime-known.
30548 try sema.markMaybeComptimeAllocRuntime(block, maybe_base_alloc);
30416 }30549 }
3041730550
30418 // Store is runtime-known30551 try sema.validateRuntimeValue(block, store_src, operand);
30419 _ = sema.maybe_comptime_allocs.remove(maybe_base_alloc);
30420}30552}
3042130553
30422/// Given an AIR instruction transforming a pointer (struct_field_ptr,30554/// Given an AIR instruction transforming a pointer (struct_field_ptr,
30423/// ptr_elem_ptr, bitcast, etc), checks whether the base pointer refers to a30555/// ptr_elem_ptr, bitcast, etc), checks whether the base pointer refers to a
30424/// local alloc, and updates `base_allocs` accordingly.30556/// 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 {
30426 const base_ptr_inst = base_ptr.toIndex() orelse return;30558 const base_ptr_inst = base_ptr.toIndex() orelse return;
30427 const new_ptr_inst = new_ptr.toIndex() orelse return;30559 const new_ptr_inst = new_ptr.toIndex() orelse return;
30428 const alloc_inst = sema.base_allocs.get(base_ptr_inst) orelse return;30560 const alloc_inst = sema.base_allocs.get(base_ptr_inst) orelse return;
...@@ -30442,13 +30574,34 @@ fn checkKnownAllocPtr(sema: *Sema, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref...@@ -30442,13 +30574,34 @@ fn checkKnownAllocPtr(sema: *Sema, base_ptr: Air.Inst.Ref, new_ptr: Air.Inst.Ref
30442 // If the index value is runtime-known, this pointer is also runtime-known, so30574 // If the index value is runtime-known, this pointer is also runtime-known, so
30443 // we must in turn make the alloc value runtime-known.30575 // we must in turn make the alloc value runtime-known.
30444 if (null == try sema.resolveValue(index_ref)) {30576 if (null == try sema.resolveValue(index_ref)) {
30445 _ = sema.maybe_comptime_allocs.remove(alloc_inst);30577 try sema.markMaybeComptimeAllocRuntime(block, alloc_inst);
30446 }30578 }
30447 },30579 },
30448 else => {},30580 else => {},
30449 }30581 }
30450}30582}
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
30452/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector30605/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
30453/// pointer. Only if the final element type matches the vector element type, and the30606/// pointer. Only if the final element type matches the vector element type, and the
30454/// lengths match.30607/// lengths match.
...@@ -30491,13 +30644,16 @@ fn storePtrVal(...@@ -30491,13 +30644,16 @@ fn storePtrVal(
30491) !void {30644) !void {
30492 const mod = sema.mod;30645 const mod = sema.mod;
30493 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);30646 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
30494 try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);30647 switch (mut_kit.root) {
30648 .alloc => |a| try sema.checkComptimeVarStore(block, src, a),
30649 .comptime_field => {},
30650 }
3049530651
30496 try sema.resolveTypeLayout(operand_ty);30652 try sema.resolveTypeLayout(operand_ty);
30497 switch (mut_kit.pointee) {30653 switch (mut_kit.pointee) {
30498 .opv => {},30654 .opv => {},
30499 .direct => |val_ptr| {30655 .direct => |val_ptr| {
30500 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {30656 if (mut_kit.root == .comptime_field) {
30501 val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod)));30657 val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod)));
30502 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {30658 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
30503 // TODO use failWithInvalidComptimeFieldStore30659 // TODO use failWithInvalidComptimeFieldStore
...@@ -30552,7 +30708,11 @@ fn storePtrVal(...@@ -30552,7 +30708,11 @@ fn storePtrVal(
30552}30708}
3055330709
30554const ComptimePtrMutationKit = struct {30710const ComptimePtrMutationKit = struct {
30555 mut_decl: InternPool.Key.Ptr.Addr.MutDecl,30711 const Root = union(enum) {
30712 alloc: ComptimeAllocIndex,
30713 comptime_field,
30714 };
30715 root: Root,
30556 pointee: union(enum) {30716 pointee: union(enum) {
30557 opv,30717 opv,
30558 /// The pointer type matches the actual comptime Value so a direct30718 /// The pointer type matches the actual comptime Value so a direct
...@@ -30591,17 +30751,21 @@ fn beginComptimePtrMutation(...@@ -30591,17 +30751,21 @@ fn beginComptimePtrMutation(
30591 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;30751 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
30592 switch (ptr.addr) {30752 switch (ptr.addr) {
30593 .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already30753 .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already
30594 .mut_decl => |mut_decl| {30754 .comptime_alloc => |alloc_index| {
30595 const decl = mod.declPtr(mut_decl.decl);30755 const alloc = sema.getComptimeAlloc(alloc_index);
30596 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);30756 return sema.beginComptimePtrMutationInner(block, src, alloc.ty, &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index });
30597 },30757 },
30598 .comptime_field => |comptime_field| {30758 .comptime_field => |comptime_field| {
30599 const duped = try sema.arena.create(Value);30759 const duped = try sema.arena.create(Value);
30600 duped.* = Value.fromInterned(comptime_field);30760 duped.* = Value.fromInterned(comptime_field);
30601 return sema.beginComptimePtrMutationInner(block, src, Type.fromInterned(mod.intern_pool.typeOf(comptime_field)), duped, ptr_elem_ty, .{30761 return sema.beginComptimePtrMutationInner(
30602 .decl = undefined,30762 block,
30603 .runtime_index = .comptime_field_ptr,30763 src,
30604 });30764 Type.fromInterned(mod.intern_pool.typeOf(comptime_field)),
30765 duped,
30766 ptr_elem_ty,
30767 .comptime_field,
30768 );
30605 },30769 },
30606 .eu_payload => |eu_ptr| {30770 .eu_payload => |eu_ptr| {
30607 const eu_ty = Type.fromInterned(mod.intern_pool.typeOf(eu_ptr)).childType(mod);30771 const eu_ty = Type.fromInterned(mod.intern_pool.typeOf(eu_ptr)).childType(mod);
...@@ -30612,7 +30776,7 @@ fn beginComptimePtrMutation(...@@ -30612,7 +30776,7 @@ fn beginComptimePtrMutation(
30612 const payload_ty = parent.ty.errorUnionPayload(mod);30776 const payload_ty = parent.ty.errorUnionPayload(mod);
30613 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {30777 if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
30614 return ComptimePtrMutationKit{30778 return ComptimePtrMutationKit{
30615 .mut_decl = parent.mut_decl,30779 .root = parent.root,
30616 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },30780 .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
30617 .ty = payload_ty,30781 .ty = payload_ty,
30618 };30782 };
...@@ -30630,7 +30794,7 @@ fn beginComptimePtrMutation(...@@ -30630,7 +30794,7 @@ fn beginComptimePtrMutation(
30630 val_ptr.* = Value.initPayload(&payload.base);30794 val_ptr.* = Value.initPayload(&payload.base);
3063130795
30632 return ComptimePtrMutationKit{30796 return ComptimePtrMutationKit{
30633 .mut_decl = parent.mut_decl,30797 .root = parent.root,
30634 .pointee = .{ .direct = &payload.data },30798 .pointee = .{ .direct = &payload.data },
30635 .ty = payload_ty,30799 .ty = payload_ty,
30636 };30800 };
...@@ -30640,7 +30804,7 @@ fn beginComptimePtrMutation(...@@ -30640,7 +30804,7 @@ fn beginComptimePtrMutation(
30640 // Even though the parent value type has well-defined memory layout, our30804 // Even though the parent value type has well-defined memory layout, our
30641 // pointer type does not.30805 // pointer type does not.
30642 .reinterpret => return ComptimePtrMutationKit{30806 .reinterpret => return ComptimePtrMutationKit{
30643 .mut_decl = parent.mut_decl,30807 .root = parent.root,
30644 .pointee = .bad_ptr_ty,30808 .pointee = .bad_ptr_ty,
30645 .ty = eu_ty,30809 .ty = eu_ty,
30646 },30810 },
...@@ -30655,7 +30819,7 @@ fn beginComptimePtrMutation(...@@ -30655,7 +30819,7 @@ fn beginComptimePtrMutation(
30655 const payload_ty = parent.ty.optionalChild(mod);30819 const payload_ty = parent.ty.optionalChild(mod);
30656 switch (val_ptr.ip_index) {30820 switch (val_ptr.ip_index) {
30657 .none => return ComptimePtrMutationKit{30821 .none => return ComptimePtrMutationKit{
30658 .mut_decl = parent.mut_decl,30822 .root = parent.root,
30659 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },30823 .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
30660 .ty = payload_ty,30824 .ty = payload_ty,
30661 },30825 },
...@@ -30682,7 +30846,7 @@ fn beginComptimePtrMutation(...@@ -30682,7 +30846,7 @@ fn beginComptimePtrMutation(
30682 val_ptr.* = Value.initPayload(&payload.base);30846 val_ptr.* = Value.initPayload(&payload.base);
3068330847
30684 return ComptimePtrMutationKit{30848 return ComptimePtrMutationKit{
30685 .mut_decl = parent.mut_decl,30849 .root = parent.root,
30686 .pointee = .{ .direct = &payload.data },30850 .pointee = .{ .direct = &payload.data },
30687 .ty = payload_ty,30851 .ty = payload_ty,
30688 };30852 };
...@@ -30693,7 +30857,7 @@ fn beginComptimePtrMutation(...@@ -30693,7 +30857,7 @@ fn beginComptimePtrMutation(
30693 // Even though the parent value type has well-defined memory layout, our30857 // Even though the parent value type has well-defined memory layout, our
30694 // pointer type does not.30858 // pointer type does not.
30695 .reinterpret => return ComptimePtrMutationKit{30859 .reinterpret => return ComptimePtrMutationKit{
30696 .mut_decl = parent.mut_decl,30860 .root = parent.root,
30697 .pointee = .bad_ptr_ty,30861 .pointee = .bad_ptr_ty,
30698 .ty = opt_ty,30862 .ty = opt_ty,
30699 },30863 },
...@@ -30717,7 +30881,7 @@ fn beginComptimePtrMutation(...@@ -30717,7 +30881,7 @@ fn beginComptimePtrMutation(
30717 });30881 });
30718 }30882 }
30719 return .{30883 return .{
30720 .mut_decl = parent.mut_decl,30884 .root = parent.root,
30721 .pointee = .opv,30885 .pointee = .opv,
30722 .ty = elem_ty,30886 .ty = elem_ty,
30723 };30887 };
...@@ -30742,7 +30906,7 @@ fn beginComptimePtrMutation(...@@ -30742,7 +30906,7 @@ fn beginComptimePtrMutation(
30742 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);30906 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
30743 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);30907 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
30744 return .{30908 return .{
30745 .mut_decl = parent.mut_decl,30909 .root = parent.root,
30746 .pointee = .{ .reinterpret = .{30910 .pointee = .{ .reinterpret = .{
30747 .val_ptr = val_ptr,30911 .val_ptr = val_ptr,
30748 .byte_offset = elem_abi_size * elem_idx,30912 .byte_offset = elem_abi_size * elem_idx,
...@@ -30759,7 +30923,7 @@ fn beginComptimePtrMutation(...@@ -30759,7 +30923,7 @@ fn beginComptimePtrMutation(
30759 // If we wanted to avoid this, there would need to be special detection30923 // If we wanted to avoid this, there would need to be special detection
30760 // elsewhere to identify when writing a value to an array element that is stored30924 // elsewhere to identify when writing a value to an array element that is stored
30761 // using the `bytes` tag, and handle it without making a call to this function.30925 // using the `bytes` tag, and handle it without making a call to this function.
30762 const arena = mod.tmp_hack_arena.allocator();30926 const arena = sema.arena;
3076330927
30764 const bytes = val_ptr.castTag(.bytes).?.data;30928 const bytes = val_ptr.castTag(.bytes).?.data;
30765 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);30929 const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
...@@ -30780,7 +30944,7 @@ fn beginComptimePtrMutation(...@@ -30780,7 +30944,7 @@ fn beginComptimePtrMutation(
30780 elem_ty,30944 elem_ty,
30781 &elems[@intCast(elem_ptr.index)],30945 &elems[@intCast(elem_ptr.index)],
30782 ptr_elem_ty,30946 ptr_elem_ty,
30783 parent.mut_decl,30947 parent.root,
30784 );30948 );
30785 },30949 },
30786 .repeated => {30950 .repeated => {
...@@ -30791,7 +30955,7 @@ fn beginComptimePtrMutation(...@@ -30791,7 +30955,7 @@ fn beginComptimePtrMutation(
30791 // need to be special detection elsewhere to identify when writing a value to an30955 // need to be special detection elsewhere to identify when writing a value to an
30792 // array element that is stored using the `repeated` tag, and handle it30956 // array element that is stored using the `repeated` tag, and handle it
30793 // without making a call to this function.30957 // without making a call to this function.
30794 const arena = mod.tmp_hack_arena.allocator();30958 const arena = sema.arena;
3079530959
30796 const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod);30960 const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod);
30797 const array_len_including_sentinel =30961 const array_len_including_sentinel =
...@@ -30808,7 +30972,7 @@ fn beginComptimePtrMutation(...@@ -30808,7 +30972,7 @@ fn beginComptimePtrMutation(
30808 elem_ty,30972 elem_ty,
30809 &elems[@intCast(elem_ptr.index)],30973 &elems[@intCast(elem_ptr.index)],
30810 ptr_elem_ty,30974 ptr_elem_ty,
30811 parent.mut_decl,30975 parent.root,
30812 );30976 );
30813 },30977 },
3081430978
...@@ -30819,7 +30983,7 @@ fn beginComptimePtrMutation(...@@ -30819,7 +30983,7 @@ fn beginComptimePtrMutation(
30819 elem_ty,30983 elem_ty,
30820 &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)],30984 &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)],
30821 ptr_elem_ty,30985 ptr_elem_ty,
30822 parent.mut_decl,30986 parent.root,
30823 ),30987 ),
3082430988
30825 else => unreachable,30989 else => unreachable,
...@@ -30829,7 +30993,7 @@ fn beginComptimePtrMutation(...@@ -30829,7 +30993,7 @@ fn beginComptimePtrMutation(
30829 // An array has been initialized to undefined at comptime and now we30993 // An array has been initialized to undefined at comptime and now we
30830 // are for the first time setting an element. We must change the representation30994 // are for the first time setting an element. We must change the representation
30831 // of the array from `undef` to `array`.30995 // of the array from `undef` to `array`.
30832 const arena = mod.tmp_hack_arena.allocator();30996 const arena = sema.arena;
3083330997
30834 const array_len_including_sentinel =30998 const array_len_including_sentinel =
30835 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));30999 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
...@@ -30845,7 +31009,7 @@ fn beginComptimePtrMutation(...@@ -30845,7 +31009,7 @@ fn beginComptimePtrMutation(
30845 elem_ty,31009 elem_ty,
30846 &elems[@intCast(elem_ptr.index)],31010 &elems[@intCast(elem_ptr.index)],
30847 ptr_elem_ty,31011 ptr_elem_ty,
30848 parent.mut_decl,31012 parent.root,
30849 );31013 );
30850 },31014 },
30851 else => unreachable,31015 else => unreachable,
...@@ -30866,7 +31030,7 @@ fn beginComptimePtrMutation(...@@ -30866,7 +31030,7 @@ fn beginComptimePtrMutation(
30866 parent.ty,31030 parent.ty,
30867 val_ptr,31031 val_ptr,
30868 ptr_elem_ty,31032 ptr_elem_ty,
30869 parent.mut_decl,31033 parent.root,
30870 );31034 );
30871 },31035 },
30872 },31036 },
...@@ -30875,7 +31039,7 @@ fn beginComptimePtrMutation(...@@ -30875,7 +31039,7 @@ fn beginComptimePtrMutation(
30875 // Even though the parent value type has well-defined memory layout, our31039 // Even though the parent value type has well-defined memory layout, our
30876 // pointer type does not.31040 // pointer type does not.
30877 return ComptimePtrMutationKit{31041 return ComptimePtrMutationKit{
30878 .mut_decl = parent.mut_decl,31042 .root = parent.root,
30879 .pointee = .bad_ptr_ty,31043 .pointee = .bad_ptr_ty,
30880 .ty = base_elem_ty,31044 .ty = base_elem_ty,
30881 };31045 };
...@@ -30885,7 +31049,7 @@ fn beginComptimePtrMutation(...@@ -30885,7 +31049,7 @@ fn beginComptimePtrMutation(
30885 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);31049 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
30886 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);31050 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
30887 return ComptimePtrMutationKit{31051 return ComptimePtrMutationKit{
30888 .mut_decl = parent.mut_decl,31052 .root = parent.root,
30889 .pointee = .{ .reinterpret = .{31053 .pointee = .{ .reinterpret = .{
30890 .val_ptr = reinterpret.val_ptr,31054 .val_ptr = reinterpret.val_ptr,
30891 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx,31055 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx,
...@@ -30914,7 +31078,7 @@ fn beginComptimePtrMutation(...@@ -30914,7 +31078,7 @@ fn beginComptimePtrMutation(
30914 parent.ty.structFieldType(field_index, mod),31078 parent.ty.structFieldType(field_index, mod),
30915 duped,31079 duped,
30916 ptr_elem_ty,31080 ptr_elem_ty,
30917 parent.mut_decl,31081 parent.root,
30918 );31082 );
30919 },31083 },
30920 .none => switch (val_ptr.tag()) {31084 .none => switch (val_ptr.tag()) {
...@@ -30925,10 +31089,10 @@ fn beginComptimePtrMutation(...@@ -30925,10 +31089,10 @@ fn beginComptimePtrMutation(
30925 parent.ty.structFieldType(field_index, mod),31089 parent.ty.structFieldType(field_index, mod),
30926 &val_ptr.castTag(.aggregate).?.data[field_index],31090 &val_ptr.castTag(.aggregate).?.data[field_index],
30927 ptr_elem_ty,31091 ptr_elem_ty,
30928 parent.mut_decl,31092 parent.root,
30929 ),31093 ),
30930 .repeated => {31094 .repeated => {
30931 const arena = mod.tmp_hack_arena.allocator();31095 const arena = sema.arena;
3093231096
30933 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));31097 const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
30934 @memset(elems, val_ptr.castTag(.repeated).?.data);31098 @memset(elems, val_ptr.castTag(.repeated).?.data);
...@@ -30941,7 +31105,7 @@ fn beginComptimePtrMutation(...@@ -30941,7 +31105,7 @@ fn beginComptimePtrMutation(
30941 parent.ty.structFieldType(field_index, mod),31105 parent.ty.structFieldType(field_index, mod),
30942 &elems[field_index],31106 &elems[field_index],
30943 ptr_elem_ty,31107 ptr_elem_ty,
30944 parent.mut_decl,31108 parent.root,
30945 );31109 );
30946 },31110 },
30947 .@"union" => {31111 .@"union" => {
...@@ -30962,7 +31126,7 @@ fn beginComptimePtrMutation(...@@ -30962,7 +31126,7 @@ fn beginComptimePtrMutation(
30962 field_ty,31126 field_ty,
30963 &payload.val,31127 &payload.val,
30964 ptr_elem_ty,31128 ptr_elem_ty,
30965 parent.mut_decl,31129 parent.root,
30966 );31130 );
30967 } else {31131 } else {
30968 // Writing to a different field (a different or unknown tag is active) requires reinterpreting31132 // Writing to a different field (a different or unknown tag is active) requires reinterpreting
...@@ -30973,7 +31137,7 @@ fn beginComptimePtrMutation(...@@ -30973,7 +31137,7 @@ fn beginComptimePtrMutation(
30973 // The reinterpretation will read it back out as .none.31137 // The reinterpretation will read it back out as .none.
30974 payload.val = try payload.val.unintern(sema.arena, mod);31138 payload.val = try payload.val.unintern(sema.arena, mod);
30975 return ComptimePtrMutationKit{31139 return ComptimePtrMutationKit{
30976 .mut_decl = parent.mut_decl,31140 .root = parent.root,
30977 .pointee = .{ .reinterpret = .{31141 .pointee = .{ .reinterpret = .{
30978 .val_ptr = val_ptr,31142 .val_ptr = val_ptr,
30979 .byte_offset = 0,31143 .byte_offset = 0,
...@@ -30991,7 +31155,7 @@ fn beginComptimePtrMutation(...@@ -30991,7 +31155,7 @@ fn beginComptimePtrMutation(
30991 parent.ty.slicePtrFieldType(mod),31155 parent.ty.slicePtrFieldType(mod),
30992 &val_ptr.castTag(.slice).?.data.ptr,31156 &val_ptr.castTag(.slice).?.data.ptr,
30993 ptr_elem_ty,31157 ptr_elem_ty,
30994 parent.mut_decl,31158 parent.root,
30995 ),31159 ),
3099631160
30997 Value.slice_len_index => return beginComptimePtrMutationInner(31161 Value.slice_len_index => return beginComptimePtrMutationInner(
...@@ -31001,7 +31165,7 @@ fn beginComptimePtrMutation(...@@ -31001,7 +31165,7 @@ fn beginComptimePtrMutation(
31001 Type.usize,31165 Type.usize,
31002 &val_ptr.castTag(.slice).?.data.len,31166 &val_ptr.castTag(.slice).?.data.len,
31003 ptr_elem_ty,31167 ptr_elem_ty,
31004 parent.mut_decl,31168 parent.root,
31005 ),31169 ),
3100631170
31007 else => unreachable,31171 else => unreachable,
...@@ -31013,7 +31177,7 @@ fn beginComptimePtrMutation(...@@ -31013,7 +31177,7 @@ fn beginComptimePtrMutation(
31013 // A struct or union has been initialized to undefined at comptime and now we31177 // A struct or union has been initialized to undefined at comptime and now we
31014 // are for the first time setting a field. We must change the representation31178 // are for the first time setting a field. We must change the representation
31015 // of the struct/union from `undef` to `struct`/`union`.31179 // of the struct/union from `undef` to `struct`/`union`.
31016 const arena = mod.tmp_hack_arena.allocator();31180 const arena = sema.arena;
3101731181
31018 switch (parent.ty.zigTypeTag(mod)) {31182 switch (parent.ty.zigTypeTag(mod)) {
31019 .Struct => {31183 .Struct => {
...@@ -31031,7 +31195,7 @@ fn beginComptimePtrMutation(...@@ -31031,7 +31195,7 @@ fn beginComptimePtrMutation(
31031 parent.ty.structFieldType(field_index, mod),31195 parent.ty.structFieldType(field_index, mod),
31032 &fields[field_index],31196 &fields[field_index],
31033 ptr_elem_ty,31197 ptr_elem_ty,
31034 parent.mut_decl,31198 parent.root,
31035 );31199 );
31036 },31200 },
31037 .Union => {31201 .Union => {
...@@ -31052,7 +31216,7 @@ fn beginComptimePtrMutation(...@@ -31052,7 +31216,7 @@ fn beginComptimePtrMutation(
31052 payload_ty,31216 payload_ty,
31053 &payload.data.val,31217 &payload.data.val,
31054 ptr_elem_ty,31218 ptr_elem_ty,
31055 parent.mut_decl,31219 parent.root,
31056 );31220 );
31057 },31221 },
31058 .Pointer => {31222 .Pointer => {
...@@ -31071,7 +31235,7 @@ fn beginComptimePtrMutation(...@@ -31071,7 +31235,7 @@ fn beginComptimePtrMutation(
31071 ptr_ty,31235 ptr_ty,
31072 &val_ptr.castTag(.slice).?.data.ptr,31236 &val_ptr.castTag(.slice).?.data.ptr,
31073 ptr_elem_ty,31237 ptr_elem_ty,
31074 parent.mut_decl,31238 parent.root,
31075 ),31239 ),
31076 Value.slice_len_index => return beginComptimePtrMutationInner(31240 Value.slice_len_index => return beginComptimePtrMutationInner(
31077 sema,31241 sema,
...@@ -31080,7 +31244,7 @@ fn beginComptimePtrMutation(...@@ -31080,7 +31244,7 @@ fn beginComptimePtrMutation(
31080 Type.usize,31244 Type.usize,
31081 &val_ptr.castTag(.slice).?.data.len,31245 &val_ptr.castTag(.slice).?.data.len,
31082 ptr_elem_ty,31246 ptr_elem_ty,
31083 parent.mut_decl,31247 parent.root,
31084 ),31248 ),
3108531249
31086 else => unreachable,31250 else => unreachable,
...@@ -31096,7 +31260,7 @@ fn beginComptimePtrMutation(...@@ -31096,7 +31260,7 @@ fn beginComptimePtrMutation(
31096 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);31260 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
31097 const field_offset = try sema.usizeCast(block, src, field_offset_u64);31261 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
31098 return ComptimePtrMutationKit{31262 return ComptimePtrMutationKit{
31099 .mut_decl = parent.mut_decl,31263 .root = parent.root,
31100 .pointee = .{ .reinterpret = .{31264 .pointee = .{ .reinterpret = .{
31101 .val_ptr = reinterpret.val_ptr,31265 .val_ptr = reinterpret.val_ptr,
31102 .byte_offset = reinterpret.byte_offset + field_offset,31266 .byte_offset = reinterpret.byte_offset + field_offset,
...@@ -31117,7 +31281,7 @@ fn beginComptimePtrMutationInner(...@@ -31117,7 +31281,7 @@ fn beginComptimePtrMutationInner(
31117 decl_ty: Type,31281 decl_ty: Type,
31118 decl_val: *Value,31282 decl_val: *Value,
31119 ptr_elem_ty: Type,31283 ptr_elem_ty: Type,
31120 mut_decl: InternPool.Key.Ptr.Addr.MutDecl,31284 root: ComptimePtrMutationKit.Root,
31121) CompileError!ComptimePtrMutationKit {31285) CompileError!ComptimePtrMutationKit {
31122 const mod = sema.mod;31286 const mod = sema.mod;
31123 const target = mod.getTarget();31287 const target = mod.getTarget();
...@@ -31127,7 +31291,7 @@ fn beginComptimePtrMutationInner(...@@ -31127,7 +31291,7 @@ fn beginComptimePtrMutationInner(
3112731291
31128 if (coerce_ok) {31292 if (coerce_ok) {
31129 return ComptimePtrMutationKit{31293 return ComptimePtrMutationKit{
31130 .mut_decl = mut_decl,31294 .root = root,
31131 .pointee = .{ .direct = decl_val },31295 .pointee = .{ .direct = decl_val },
31132 .ty = decl_ty,31296 .ty = decl_ty,
31133 };31297 };
...@@ -31138,7 +31302,7 @@ fn beginComptimePtrMutationInner(...@@ -31138,7 +31302,7 @@ fn beginComptimePtrMutationInner(
31138 const decl_elem_ty = decl_ty.childType(mod);31302 const decl_elem_ty = decl_ty.childType(mod);
31139 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {31303 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
31140 return ComptimePtrMutationKit{31304 return ComptimePtrMutationKit{
31141 .mut_decl = mut_decl,31305 .root = root,
31142 .pointee = .{ .direct = decl_val },31306 .pointee = .{ .direct = decl_val },
31143 .ty = decl_ty,31307 .ty = decl_ty,
31144 };31308 };
...@@ -31147,20 +31311,20 @@ fn beginComptimePtrMutationInner(...@@ -31147,20 +31311,20 @@ fn beginComptimePtrMutationInner(
3114731311
31148 if (!decl_ty.hasWellDefinedLayout(mod)) {31312 if (!decl_ty.hasWellDefinedLayout(mod)) {
31149 return ComptimePtrMutationKit{31313 return ComptimePtrMutationKit{
31150 .mut_decl = mut_decl,31314 .root = root,
31151 .pointee = .bad_decl_ty,31315 .pointee = .bad_decl_ty,
31152 .ty = decl_ty,31316 .ty = decl_ty,
31153 };31317 };
31154 }31318 }
31155 if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {31319 if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {
31156 return ComptimePtrMutationKit{31320 return ComptimePtrMutationKit{
31157 .mut_decl = mut_decl,31321 .root = root,
31158 .pointee = .bad_ptr_ty,31322 .pointee = .bad_ptr_ty,
31159 .ty = ptr_elem_ty,31323 .ty = ptr_elem_ty,
31160 };31324 };
31161 }31325 }
31162 return ComptimePtrMutationKit{31326 return ComptimePtrMutationKit{
31163 .mut_decl = mut_decl,31327 .root = root,
31164 .pointee = .{ .reinterpret = .{31328 .pointee = .{ .reinterpret = .{
31165 .val_ptr = decl_val,31329 .val_ptr = decl_val,
31166 .byte_offset = 0,31330 .byte_offset = 0,
...@@ -31208,13 +31372,7 @@ fn beginComptimePtrLoad(...@@ -31208,13 +31372,7 @@ fn beginComptimePtrLoad(
3120831372
31209 var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) {31373 var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) {
31210 .ptr => |ptr| switch (ptr.addr) {31374 .ptr => |ptr| switch (ptr.addr) {
31211 .decl, .mut_decl => blk: {31375 .decl => |decl_index| 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;
31218 const decl = mod.declPtr(decl_index);31376 const decl = mod.declPtr(decl_index);
31219 const decl_tv = try decl.typedValue();31377 const decl_tv = try decl.typedValue();
31220 try sema.declareDependency(.{ .decl_val = decl_index });31378 try sema.declareDependency(.{ .decl_val = decl_index });
...@@ -31224,10 +31382,24 @@ fn beginComptimePtrLoad(...@@ -31224,10 +31382,24 @@ fn beginComptimePtrLoad(
31224 break :blk ComptimePtrLoadKit{31382 break :blk ComptimePtrLoadKit{
31225 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,31383 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
31226 .pointee = decl_tv,31384 .pointee = decl_tv,
31227 .is_mutable = is_mutable,31385 .is_mutable = false,
31228 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,31386 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
31229 };31387 };
31230 },31388 },
31389 .comptime_alloc => |alloc_index| kit: {
31390 const alloc = sema.getComptimeAlloc(alloc_index);
31391 const alloc_tv: TypedValue = .{
31392 .ty = alloc.ty,
31393 .val = alloc.val,
31394 };
31395 const layout_defined = alloc.ty.hasWellDefinedLayout(mod);
31396 break :kit .{
31397 .parent = if (layout_defined) .{ .tv = alloc_tv, .byte_offset = 0 } else null,
31398 .pointee = alloc_tv,
31399 .is_mutable = true,
31400 .ty_without_well_defined_layout = if (!layout_defined) alloc.ty else null,
31401 };
31402 },
31231 .anon_decl => |anon_decl| blk: {31403 .anon_decl => |anon_decl| blk: {
31232 const decl_val = anon_decl.val;31404 const decl_val = anon_decl.val;
31233 if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad;31405 if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad;
...@@ -31352,7 +31524,7 @@ fn beginComptimePtrLoad(...@@ -31352,7 +31524,7 @@ fn beginComptimePtrLoad(
31352 .len = len,31524 .len = len,
31353 .child = elem_ty.toIntern(),31525 .child = elem_ty.toIntern(),
31354 }),31526 }),
31355 .val = try array_tv.val.sliceArray(mod, sema.arena, elem_idx, elem_idx + len),31527 .val = try array_tv.val.sliceArray(sema, elem_idx, elem_idx + len),
31356 } else null;31528 } else null;
31357 break :blk deref;31529 break :blk deref;
31358 }31530 }
...@@ -31481,6 +31653,7 @@ fn bitCast(...@@ -31481,6 +31653,7 @@ fn bitCast(
31481 }31653 }
31482 }31654 }
31483 try sema.requireRuntimeBlock(block, inst_src, operand_src);31655 try sema.requireRuntimeBlock(block, inst_src, operand_src);
31656 try sema.validateRuntimeValue(block, inst_src, inst);
31484 return block.addBitCast(dest_ty, inst);31657 return block.addBitCast(dest_ty, inst);
31485}31658}
3148631659
...@@ -31693,7 +31866,7 @@ fn coerceCompatiblePtrs(...@@ -31693,7 +31866,7 @@ fn coerceCompatiblePtrs(
31693 try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);31866 try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);
31694 }31867 }
31695 const new_ptr = try sema.bitCast(block, dest_ty, inst, inst_src, null);31868 const new_ptr = try sema.bitCast(block, dest_ty, inst, inst_src, null);
31696 try sema.checkKnownAllocPtr(inst, new_ptr);31869 try sema.checkKnownAllocPtr(block, inst, new_ptr);
31697 return new_ptr;31870 return new_ptr;
31698}31871}
3169931872
...@@ -35448,7 +35621,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35448,7 +35621,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35448 },35621 },
35449 .ptr => |ptr| {35622 .ptr => |ptr| {
35450 switch (ptr.addr) {35623 switch (ptr.addr) {
35451 .decl, .mut_decl, .anon_decl => return val,35624 .decl, .comptime_alloc, .anon_decl => return val,
35452 .comptime_field => |field_val| {35625 .comptime_field => |field_val| {
35453 const resolved_field_val =35626 const resolved_field_val =
35454 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();35627 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
...@@ -35803,9 +35976,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co...@@ -35803,9 +35976,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
35803 var analysis_arena = std.heap.ArenaAllocator.init(gpa);35976 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
35804 defer analysis_arena.deinit();35977 defer analysis_arena.deinit();
3580535978
35806 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
35807 defer comptime_mutable_decls.deinit();
35808
35809 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);35979 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
35810 defer comptime_err_ret_trace.deinit();35980 defer comptime_err_ret_trace.deinit();
3581135981
...@@ -35821,7 +35991,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co...@@ -35821,7 +35991,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
35821 .fn_ret_ty = Type.void,35991 .fn_ret_ty = Type.void,
35822 .fn_ret_ty_ies = null,35992 .fn_ret_ty_ies = null,
35823 .owner_func_index = .none,35993 .owner_func_index = .none,
35824 .comptime_mutable_decls = &comptime_mutable_decls,
35825 .comptime_err_ret_trace = &comptime_err_ret_trace,35994 .comptime_err_ret_trace = &comptime_err_ret_trace,
35826 };35995 };
35827 defer sema.deinit();35996 defer sema.deinit();
...@@ -35887,11 +36056,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co...@@ -35887,11 +36056,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
35887 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));36056 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
35888 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();36057 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
35889 }36058 }
35890
35891 for (comptime_mutable_decls.items) |ct_decl_index| {
35892 const ct_decl = mod.declPtr(ct_decl_index);
35893 _ = try ct_decl.internValue(mod);
35894 }
35895}36059}
3589636060
35897fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {36061fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
...@@ -36640,9 +36804,6 @@ fn semaStructFields(...@@ -36640,9 +36804,6 @@ fn semaStructFields(
36640 },36804 },
36641 };36805 };
3664236806
36643 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
36644 defer comptime_mutable_decls.deinit();
36645
36646 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);36807 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
36647 defer comptime_err_ret_trace.deinit();36808 defer comptime_err_ret_trace.deinit();
3664836809
...@@ -36658,7 +36819,6 @@ fn semaStructFields(...@@ -36658,7 +36819,6 @@ fn semaStructFields(
36658 .fn_ret_ty = Type.void,36819 .fn_ret_ty = Type.void,
36659 .fn_ret_ty_ies = null,36820 .fn_ret_ty_ies = null,
36660 .owner_func_index = .none,36821 .owner_func_index = .none,
36661 .comptime_mutable_decls = &comptime_mutable_decls,
36662 .comptime_err_ret_trace = &comptime_err_ret_trace,36822 .comptime_err_ret_trace = &comptime_err_ret_trace,
36663 };36823 };
36664 defer sema.deinit();36824 defer sema.deinit();
...@@ -36872,11 +37032,6 @@ fn semaStructFields(...@@ -36872,11 +37032,6 @@ fn semaStructFields(
3687237032
36873 struct_type.clearTypesWip(ip);37033 struct_type.clearTypesWip(ip);
36874 if (!any_inits) struct_type.setHaveFieldInits(ip);37034 if (!any_inits) struct_type.setHaveFieldInits(ip);
36875
36876 for (comptime_mutable_decls.items) |ct_decl_index| {
36877 const ct_decl = mod.declPtr(ct_decl_index);
36878 _ = try ct_decl.internValue(mod);
36879 }
36880}37035}
3688137036
36882// This logic must be kept in sync with `semaStructFields`37037// This logic must be kept in sync with `semaStructFields`
...@@ -36897,9 +37052,6 @@ fn semaStructFieldInits(...@@ -36897,9 +37052,6 @@ fn semaStructFieldInits(
36897 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);37052 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
36898 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);37053 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
36903 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);37055 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
36904 defer comptime_err_ret_trace.deinit();37056 defer comptime_err_ret_trace.deinit();
3690537057
...@@ -36915,7 +37067,6 @@ fn semaStructFieldInits(...@@ -36915,7 +37067,6 @@ fn semaStructFieldInits(
36915 .fn_ret_ty = Type.void,37067 .fn_ret_ty = Type.void,
36916 .fn_ret_ty_ies = null,37068 .fn_ret_ty_ies = null,
36917 .owner_func_index = .none,37069 .owner_func_index = .none,
36918 .comptime_mutable_decls = &comptime_mutable_decls,
36919 .comptime_err_ret_trace = &comptime_err_ret_trace,37070 .comptime_err_ret_trace = &comptime_err_ret_trace,
36920 };37071 };
36921 defer sema.deinit();37072 defer sema.deinit();
...@@ -37024,14 +37175,16 @@ fn semaStructFieldInits(...@@ -37024,14 +37175,16 @@ fn semaStructFieldInits(
37024 };37175 };
3702537176
37026 const field_init = try default_val.intern(field_ty, mod);37177 const field_init = try default_val.intern(field_ty, mod);
37178 if (Value.fromInterned(field_init).canMutateComptimeVarState(mod)) {
37179 const init_src = mod.fieldSrcLoc(decl_index, .{
37180 .index = field_i,
37181 .range = .value,
37182 }).lazy;
37183 return sema.fail(&block_scope, init_src, "field default value contains reference to comptime-mutable memory", .{});
37184 }
37027 struct_type.field_inits.get(ip)[field_i] = field_init;37185 struct_type.field_inits.get(ip)[field_i] = field_init;
37028 }37186 }
37029 }37187 }
37030
37031 for (comptime_mutable_decls.items) |ct_decl_index| {
37032 const ct_decl = mod.declPtr(ct_decl_index);
37033 _ = try ct_decl.internValue(mod);
37034 }
37035}37188}
3703637189
37037fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {37190fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {
...@@ -37088,9 +37241,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded...@@ -37088,9 +37241,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3708837241
37089 const decl = mod.declPtr(decl_index);37242 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
37094 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);37244 var comptime_err_ret_trace = std.ArrayList(Module.SrcLoc).init(gpa);
37095 defer comptime_err_ret_trace.deinit();37245 defer comptime_err_ret_trace.deinit();
3709637246
...@@ -37106,7 +37256,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded...@@ -37106,7 +37256,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
37106 .fn_ret_ty = Type.void,37256 .fn_ret_ty = Type.void,
37107 .fn_ret_ty_ies = null,37257 .fn_ret_ty_ies = null,
37108 .owner_func_index = .none,37258 .owner_func_index = .none,
37109 .comptime_mutable_decls = &comptime_mutable_decls,
37110 .comptime_err_ret_trace = &comptime_err_ret_trace,37259 .comptime_err_ret_trace = &comptime_err_ret_trace,
37111 };37260 };
37112 defer sema.deinit();37261 defer sema.deinit();
...@@ -37126,11 +37275,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded...@@ -37126,11 +37275,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
37126 _ = try sema.analyzeInlineBody(&block_scope, body, zir_index);37275 _ = try sema.analyzeInlineBody(&block_scope, body, zir_index);
37127 }37276 }
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
37134 var int_tag_ty: Type = undefined;37278 var int_tag_ty: Type = undefined;
37135 var enum_field_names: []InternPool.NullTerminatedString = &.{};37279 var enum_field_names: []InternPool.NullTerminatedString = &.{};
37136 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};37280 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
...@@ -37734,7 +37878,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37734,7 +37878,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37734 .ptr_decl,37878 .ptr_decl,
37735 .ptr_anon_decl,37879 .ptr_anon_decl,
37736 .ptr_anon_decl_aligned,37880 .ptr_anon_decl_aligned,
37737 .ptr_mut_decl,37881 .ptr_comptime_alloc,
37738 .ptr_comptime_field,37882 .ptr_comptime_field,
37739 .ptr_int,37883 .ptr_int,
37740 .ptr_eu_payload,37884 .ptr_eu_payload,
...@@ -38017,27 +38161,11 @@ fn analyzeComptimeAlloc(...@@ -38017,27 +38161,11 @@ fn analyzeComptimeAlloc(
38017 },38161 },
38018 });38162 });
3801938163
38020 var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl38164 const alloc = try sema.newComptimeAlloc(block, var_type, alignment);
38021 defer anon_decl.deinit();
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);
38035 return Air.internedToRef((try mod.intern(.{ .ptr = .{38166 return Air.internedToRef((try mod.intern(.{ .ptr = .{
38036 .ty = ptr_type.toIntern(),38167 .ty = ptr_type.toIntern(),
38037 .addr = .{ .mut_decl = .{38168 .addr = .{ .comptime_alloc = alloc },
38038 .decl = decl_index,
38039 .runtime_index = block.runtime_index,
38040 } },
38041 } })));38169 } })));
38042}38170}
3804338171
...@@ -39073,3 +39201,130 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {...@@ -39073,3 +39201,130 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
39073 );39201 );
39074 try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee);39202 try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee);
39075}39203}
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(...@@ -329,13 +329,9 @@ pub fn print(
329 .val = Value.fromInterned(decl_val),329 .val = Value.fromInterned(decl_val),
330 }, writer, level - 1, mod);330 }, writer, level - 1, mod);
331 },331 },
332 .mut_decl => |mut_decl| {332 .comptime_alloc => {
333 const decl = mod.declPtr(mut_decl.decl);333 // TODO: we need a Sema to print this!
334 if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)});334 return writer.writeAll("(comptime alloc)");
335 return print(.{
336 .ty = decl.ty,
337 .val = decl.val,
338 }, writer, level - 1, mod);
339 },335 },
340 .comptime_field => |field_val_ip| {336 .comptime_field => |field_val_ip| {
341 return print(.{337 return print(.{
src/Value.zig+64-95
...@@ -6,7 +6,8 @@ const BigIntConst = std.math.big.int.Const;...@@ -6,7 +6,8 @@ const BigIntConst = std.math.big.int.Const;
6const BigIntMutable = std.math.big.int.Mutable;6const BigIntMutable = std.math.big.int.Mutable;
7const Target = std.Target;7const Target = std.Target;
8const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
9const Module = @import("Module.zig");9const Zcu = @import("Module.zig");
10const Module = Zcu;
10const TypedValue = @import("TypedValue.zig");11const TypedValue = @import("TypedValue.zig");
11const Sema = @import("Sema.zig");12const Sema = @import("Sema.zig");
12const InternPool = @import("InternPool.zig");13const InternPool = @import("InternPool.zig");
...@@ -187,24 +188,21 @@ pub fn fmtValue(val: Value, ty: Type, mod: *Module) std.fmt.Formatter(TypedValue...@@ -187,24 +188,21 @@ pub fn fmtValue(val: Value, ty: Type, mod: *Module) std.fmt.Formatter(TypedValue
187 } };188 } };
188}189}
189190
190/// Asserts that the value is representable as an array of bytes.191/// Converts `val` to a null-terminated string stored in the InternPool.
191/// Returns the value as a null-terminated string stored in the InternPool.192/// Asserts `val` is an array of `u8`
192pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString {193pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString {
194 assert(ty.zigTypeTag(mod) == .Array);
195 assert(ty.childType(mod).toIntern() == .u8_type);
193 const ip = &mod.intern_pool;196 const ip = &mod.intern_pool;
194 return switch (mod.intern_pool.indexToKey(val.toIntern())) {197 return switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
195 .enum_literal => |enum_literal| enum_literal,198 .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),
196 .slice => |slice| try arrayToIpString(val, Value.fromInterned(slice.len).toUnsignedInt(mod), mod),199 .elems => try arrayToIpString(val, ty.arrayLen(mod), mod),
197 .aggregate => |aggregate| switch (aggregate.storage) {200 .repeated_elem => |elem| {
198 .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),201 const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));
199 .elems => try arrayToIpString(val, ty.arrayLen(mod), mod),202 const len = @as(usize, @intCast(ty.arrayLen(mod)));
200 .repeated_elem => |elem| {203 try ip.string_bytes.appendNTimes(mod.gpa, byte, len);
201 const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));204 return ip.getOrPutTrailingString(mod.gpa, len);
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 },
206 },205 },
207 else => unreachable,
208 };206 };
209}207}
210208
...@@ -606,7 +604,7 @@ fn isDeclRef(val: Value, mod: *Module) bool {...@@ -606,7 +604,7 @@ fn isDeclRef(val: Value, mod: *Module) bool {
606 var check = val;604 var check = val;
607 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {605 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
608 .ptr => |ptr| switch (ptr.addr) {606 .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,
610 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),608 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),
611 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),609 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),
612 .int => return false,610 .int => return false,
...@@ -1343,7 +1341,7 @@ pub fn orderAgainstZeroAdvanced(...@@ -1343,7 +1341,7 @@ pub fn orderAgainstZeroAdvanced(
1343 .bool_true => .gt,1341 .bool_true => .gt,
1344 else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) {1342 else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) {
1345 .ptr => |ptr| switch (ptr.addr) {1343 .ptr => |ptr| switch (ptr.addr) {
1346 .decl, .mut_decl, .comptime_field => .gt,1344 .decl, .comptime_alloc, .comptime_field => .gt,
1347 .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema),1345 .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema),
1348 .elem => |elem| switch (try Value.fromInterned(elem.base).orderAgainstZeroAdvanced(mod, opt_sema)) {1346 .elem => |elem| switch (try Value.fromInterned(elem.base).orderAgainstZeroAdvanced(mod, opt_sema)) {
1349 .lt => unreachable,1347 .lt => unreachable,
...@@ -1532,45 +1530,34 @@ pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {...@@ -1532,45 +1530,34 @@ pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
1532 return a.toIntern() == b.toIntern();1530 return a.toIntern() == b.toIntern();
1533}1531}
15341532
1535pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool {1533pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
1536 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1534 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
1537 .slice => |slice| return Value.fromInterned(slice.ptr).isComptimeMutablePtr(mod),1535 .error_union => |error_union| switch (error_union.val) {
1536 .err_name => false,
1537 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
1538 },
1538 .ptr => |ptr| switch (ptr.addr) {1539 .ptr => |ptr| switch (ptr.addr) {
1539 .mut_decl, .comptime_field => true,1540 .decl => false, // The value of a Decl can never reference a comptime alloc.
1540 .eu_payload, .opt_payload => |base_ptr| Value.fromInterned(base_ptr).isComptimeMutablePtr(mod),1541 .int => false,
1541 .elem, .field => |base_index| Value.fromInterned(base_index.base).isComptimeMutablePtr(mod),1542 .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.
1542 else => false,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),
1543 },1552 },
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),
1544 else => false,1557 else => false,
1545 };1558 };
1546}1559}
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
1574/// Gets the decl referenced by this pointer. If the pointer does not point1561/// Gets the decl referenced by this pointer. If the pointer does not point
1575/// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),1562/// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),
1576/// this function returns null.1563/// this function returns null.
...@@ -1581,7 +1568,6 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {...@@ -1581,7 +1568,6 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {
1581 .func => |func| func.owner_decl,1568 .func => |func| func.owner_decl,
1582 .ptr => |ptr| switch (ptr.addr) {1569 .ptr => |ptr| switch (ptr.addr) {
1583 .decl => |decl| decl,1570 .decl => |decl| decl,
1584 .mut_decl => |mut_decl| mut_decl.decl,
1585 else => null,1571 else => null,
1586 },1572 },
1587 else => null,1573 else => null,
...@@ -1600,7 +1586,7 @@ pub fn sliceLen(val: Value, mod: *Module) u64 {...@@ -1600,7 +1586,7 @@ pub fn sliceLen(val: Value, mod: *Module) u64 {
1600 return switch (ip.indexToKey(val.toIntern())) {1586 return switch (ip.indexToKey(val.toIntern())) {
1601 .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) {1587 .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) {
1602 .decl => |decl| mod.declPtr(decl).ty.toIntern(),1588 .decl => |decl| mod.declPtr(decl).ty.toIntern(),
1603 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),1589 .comptime_alloc => @panic("TODO"),
1604 .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),1590 .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
1605 .comptime_field => |comptime_field| ip.typeOf(comptime_field),1591 .comptime_field => |comptime_field| ip.typeOf(comptime_field),
1606 else => unreachable,1592 else => unreachable,
...@@ -1621,34 +1607,38 @@ pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {...@@ -1621,34 +1607,38 @@ pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
16211607
1622/// Like `elemValue`, but returns `null` instead of asserting on failure.1608/// Like `elemValue`, but returns `null` instead of asserting on failure.
1623pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value {1609pub 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 {
1624 return switch (val.ip_index) {1614 return switch (val.ip_index) {
1625 .none => switch (val.tag()) {1615 .none => switch (val.tag()) {
1626 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),1616 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
1627 .repeated => val.castTag(.repeated).?.data,1617 .repeated => val.castTag(.repeated).?.data,
1628 .aggregate => val.castTag(.aggregate).?.data[index],1618 .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),
1630 else => null,1620 else => null,
1631 },1621 },
1632 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {1622 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1633 .undef => |ty| Value.fromInterned((try mod.intern(.{1623 .undef => |ty| Value.fromInterned((try mod.intern(.{
1634 .undef = Type.fromInterned(ty).elemType2(mod).toIntern(),1624 .undef = Type.fromInterned(ty).elemType2(mod).toIntern(),
1635 }))),1625 }))),
1636 .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValue(mod, index),1626 .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index),
1637 .ptr => |ptr| switch (ptr.addr) {1627 .ptr => |ptr| switch (ptr.addr) {
1638 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),1628 .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index),
1639 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValue(mod, index),1629 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index),
1640 .mut_decl => |mut_decl| Value.fromInterned((try mod.declPtr(mut_decl.decl).internValue(mod))).maybeElemValue(mod, index),1630 .comptime_alloc => |idx| if (sema) |s| s.getComptimeAlloc(idx).val.maybeElemValueFull(sema, mod, index) else null,
1641 .int, .eu_payload => null,1631 .int, .eu_payload => null,
1642 .opt_payload => |base| Value.fromInterned(base).maybeElemValue(mod, index),1632 .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index),
1643 .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValue(mod, index),1633 .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index),
1644 .elem => |elem| Value.fromInterned(elem.base).maybeElemValue(mod, index + @as(usize, @intCast(elem.index))),1634 .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))),
1645 .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| {1635 .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| {
1646 const base_decl = mod.declPtr(decl_index);1636 const base_decl = mod.declPtr(decl_index);
1647 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));1637 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);
1649 } else null,1639 } else null,
1650 },1640 },
1651 .opt => |opt| Value.fromInterned(opt.val).maybeElemValue(mod, index),1641 .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index),
1652 .aggregate => |aggregate| {1642 .aggregate => |aggregate| {
1653 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);1643 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
1654 if (index < len) return Value.fromInterned(switch (aggregate.storage) {1644 if (index < len) return Value.fromInterned(switch (aggregate.storage) {
...@@ -1690,29 +1680,28 @@ pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {...@@ -1690,29 +1680,28 @@ pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
1690// Asserts that the provided start/end are in-bounds.1680// Asserts that the provided start/end are in-bounds.
1691pub fn sliceArray(1681pub fn sliceArray(
1692 val: Value,1682 val: Value,
1693 mod: *Module,1683 sema: *Sema,
1694 arena: Allocator,
1695 start: usize,1684 start: usize,
1696 end: usize,1685 end: usize,
1697) error{OutOfMemory}!Value {1686) error{OutOfMemory}!Value {
1698 // TODO: write something like getCoercedInts to avoid needing to dupe1687 // TODO: write something like getCoercedInts to avoid needing to dupe
1688 const mod = sema.mod;
1699 return switch (val.ip_index) {1689 return switch (val.ip_index) {
1700 .none => switch (val.tag()) {1690 .none => switch (val.tag()) {
1701 .slice => val.castTag(.slice).?.data.ptr.sliceArray(mod, arena, start, end),1691 .slice => val.castTag(.slice).?.data.ptr.sliceArray(sema, start, end),
1702 .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),1692 .bytes => Tag.bytes.create(sema.arena, val.castTag(.bytes).?.data[start..end]),
1703 .repeated => val,1693 .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]),
1705 else => unreachable,1695 else => unreachable,
1706 },1696 },
1707 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {1697 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1708 .ptr => |ptr| switch (ptr.addr) {1698 .ptr => |ptr| switch (ptr.addr) {
1709 .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end),1699 .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end),
1710 .mut_decl => |mut_decl| Value.fromInterned((try mod.declPtr(mut_decl.decl).internValue(mod)))1700 .comptime_alloc => |idx| sema.getComptimeAlloc(idx).val.sliceArray(sema, start, end),
1711 .sliceArray(mod, arena, start, end),
1712 .comptime_field => |comptime_field| Value.fromInterned(comptime_field)1701 .comptime_field => |comptime_field| Value.fromInterned(comptime_field)
1713 .sliceArray(mod, arena, start, end),1702 .sliceArray(sema, start, end),
1714 .elem => |elem| Value.fromInterned(elem.base)1703 .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))),
1716 else => unreachable,1705 else => unreachable,
1717 },1706 },
1718 .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{1707 .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{
...@@ -1729,8 +1718,8 @@ pub fn sliceArray(...@@ -1729,8 +1718,8 @@ pub fn sliceArray(
1729 else => unreachable,1718 else => unreachable,
1730 }.toIntern(),1719 }.toIntern(),
1731 .storage = switch (aggregate.storage) {1720 .storage = switch (aggregate.storage) {
1732 .bytes => .{ .bytes = try arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },1721 .bytes => .{ .bytes = try sema.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]) },1722 .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
1734 .repeated_elem => |elem| .{ .repeated_elem = elem },1723 .repeated_elem => |elem| .{ .repeated_elem = elem },
1735 },1724 },
1736 } }))),1725 } }))),
...@@ -1838,26 +1827,6 @@ pub fn isUndefDeep(val: Value, mod: *Module) bool {...@@ -1838,26 +1827,6 @@ pub fn isUndefDeep(val: Value, mod: *Module) bool {
1838 return val.isUndef(mod);1827 return val.isUndef(mod);
1839}1828}
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
1861/// Asserts the value is not undefined and not unreachable.1830/// Asserts the value is not undefined and not unreachable.
1862/// C pointers with an integer value of 0 are also considered null.1831/// C pointers with an integer value of 0 are also considered null.
1863pub fn isNull(val: Value, mod: *Module) bool {1832pub 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...@@ -3067,14 +3067,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
3067 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3067 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
3068 },3068 },
3069 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),3069 .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 },
3074 .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}),3070 .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}),
3075 .int => |base| return func.lowerConstant(Value.fromInterned(base), Type.usize),3071 .int => |base| return func.lowerConstant(Value.fromInterned(base), Type.usize),
3076 .opt_payload => |base_ptr| return func.lowerParentPtr(Value.fromInterned(base_ptr), offset),3072 .opt_payload => |base_ptr| return func.lowerParentPtr(Value.fromInterned(base_ptr), offset),
3077 .comptime_field => unreachable,3073 .comptime_field, .comptime_alloc => unreachable,
3078 .elem => |elem| {3074 .elem => |elem| {
3079 const index = elem.index;3075 const index = elem.index;
3080 const elem_type = Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod);3076 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 {...@@ -3320,20 +3316,19 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3320 var ptr = ip.indexToKey(slice.ptr).ptr;3316 var ptr = ip.indexToKey(slice.ptr).ptr;
3321 const owner_decl = while (true) switch (ptr.addr) {3317 const owner_decl = while (true) switch (ptr.addr) {
3322 .decl => |decl| break decl,3318 .decl => |decl| break decl,
3323 .mut_decl => |mut_decl| break mut_decl.decl,
3324 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),3319 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),
3325 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,3320 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,
3326 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,3321 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
3327 .comptime_field => unreachable,3322 .comptime_field, .comptime_alloc => unreachable,
3328 };3323 };
3329 return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) };3324 return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) };
3330 },3325 },
3331 .ptr => |ptr| switch (ptr.addr) {3326 .ptr => |ptr| switch (ptr.addr) {
3332 .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),3327 .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),
3334 .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))),3328 .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))),
3335 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),3329 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3336 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),3330 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
3331 .comptime_field, .comptime_alloc => unreachable,
3337 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),3332 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
3338 },3333 },
3339 .opt => if (ty.optionalReprIsPayload(mod)) {3334 .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...@@ -818,7 +818,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
818}818}
819819
820const mnemonic_to_encodings_map = init: {820const mnemonic_to_encodings_map = init: {
821 @setEvalBranchQuota(4_000);821 @setEvalBranchQuota(5_000);
822 const mnemonic_count = @typeInfo(Mnemonic).Enum.fields.len;822 const mnemonic_count = @typeInfo(Mnemonic).Enum.fields.len;
823 var mnemonic_map: [mnemonic_count][]Data = .{&.{}} ** mnemonic_count;823 var mnemonic_map: [mnemonic_count][]Data = .{&.{}} ** mnemonic_count;
824 const encodings = @import("encodings.zig");824 const encodings = @import("encodings.zig");
...@@ -845,5 +845,13 @@ const mnemonic_to_encodings_map = init: {...@@ -845,5 +845,13 @@ const mnemonic_to_encodings_map = init: {
845 };845 };
846 i.* += 1;846 i.* += 1;
847 }847 }
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;
849};857};
src/codegen.zig+1-3
...@@ -680,7 +680,6 @@ fn lowerParentPtr(...@@ -680,7 +680,6 @@ fn lowerParentPtr(
680 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;680 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
681 return switch (ptr.addr) {681 return switch (ptr.addr) {
682 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),682 .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),
684 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),683 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
685 .int => |int| try generateSymbol(bin_file, src_loc, .{684 .int => |int| try generateSymbol(bin_file, src_loc, .{
686 .ty = Type.usize,685 .ty = Type.usize,
...@@ -756,7 +755,7 @@ fn lowerParentPtr(...@@ -756,7 +755,7 @@ fn lowerParentPtr(
756 }),755 }),
757 );756 );
758 },757 },
759 .comptime_field => unreachable,758 .comptime_field, .comptime_alloc => unreachable,
760 };759 };
761}760}
762761
...@@ -1089,7 +1088,6 @@ pub fn genTypedValue(...@@ -1089,7 +1088,6 @@ pub fn genTypedValue(
1089 if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) {1088 if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) {
1090 .ptr => |ptr| switch (ptr.addr) {1089 .ptr => |ptr| switch (ptr.addr) {
1091 .decl => |decl| return genDeclRef(lf, src_loc, typed_value, decl),1090 .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),
1093 else => {},1091 else => {},
1094 },1092 },
1095 else => {},1093 else => {},
src/codegen/c.zig+2-4
...@@ -698,7 +698,6 @@ pub const DeclGen = struct {...@@ -698,7 +698,6 @@ pub const DeclGen = struct {
698 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;698 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;
699 switch (ptr.addr) {699 switch (ptr.addr) {
700 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), d, location),700 .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),
702 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), anon_decl, location),701 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, Value.fromInterned(ptr_val), anon_decl, location),
703 .int => |int| {702 .int => |int| {
704 try writer.writeByte('(');703 try writer.writeByte('(');
...@@ -795,7 +794,7 @@ pub const DeclGen = struct {...@@ -795,7 +794,7 @@ pub const DeclGen = struct {
795 },794 },
796 }795 }
797 },796 },
798 .comptime_field => unreachable,797 .comptime_field, .comptime_alloc => unreachable,
799 }798 }
800 }799 }
801800
...@@ -1229,7 +1228,6 @@ pub const DeclGen = struct {...@@ -1229,7 +1228,6 @@ pub const DeclGen = struct {
1229 },1228 },
1230 .ptr => |ptr| switch (ptr.addr) {1229 .ptr => |ptr| switch (ptr.addr) {
1231 .decl => |d| try dg.renderDeclValue(writer, ty, val, d, location),1230 .decl => |d| try dg.renderDeclValue(writer, ty, val, d, location),
1232 .mut_decl => |md| try dg.renderDeclValue(writer, ty, val, md.decl, location),
1233 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ty, val, decl_val, location),1231 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ty, val, decl_val, location),
1234 .int => |int| {1232 .int => |int| {
1235 try writer.writeAll("((");1233 try writer.writeAll("((");
...@@ -1243,7 +1241,7 @@ pub const DeclGen = struct {...@@ -1243,7 +1241,7 @@ pub const DeclGen = struct {
1243 .elem,1241 .elem,
1244 .field,1242 .field,
1245 => try dg.renderParentPtr(writer, val.ip_index, location),1243 => try dg.renderParentPtr(writer, val.ip_index, location),
1246 .comptime_field => unreachable,1244 .comptime_field, .comptime_alloc => unreachable,
1247 },1245 },
1248 .opt => |opt| {1246 .opt => |opt| {
1249 const payload_ty = ty.optionalChild(mod);1247 const payload_ty = ty.optionalChild(mod);
src/codegen/llvm.zig+2-4
...@@ -3808,7 +3808,6 @@ pub const Object = struct {...@@ -3808,7 +3808,6 @@ pub const Object = struct {
3808 },3808 },
3809 .ptr => |ptr| return switch (ptr.addr) {3809 .ptr => |ptr| return switch (ptr.addr) {
3810 .decl => |decl| try o.lowerDeclRefValue(ty, decl),3810 .decl => |decl| try o.lowerDeclRefValue(ty, decl),
3811 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ty, mut_decl.decl),
3812 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ty, anon_decl),3811 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ty, anon_decl),
3813 .int => |int| try o.lowerIntAsPtr(int),3812 .int => |int| try o.lowerIntAsPtr(int),
3814 .eu_payload,3813 .eu_payload,
...@@ -3816,7 +3815,7 @@ pub const Object = struct {...@@ -3816,7 +3815,7 @@ pub const Object = struct {
3816 .elem,3815 .elem,
3817 .field,3816 .field,
3818 => try o.lowerParentPtr(val),3817 => try o.lowerParentPtr(val),
3819 .comptime_field => unreachable,3818 .comptime_field, .comptime_alloc => unreachable,
3820 },3819 },
3821 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{3820 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
3822 try o.lowerValue(slice.ptr),3821 try o.lowerValue(slice.ptr),
...@@ -4274,7 +4273,6 @@ pub const Object = struct {...@@ -4274,7 +4273,6 @@ pub const Object = struct {
4274 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;4273 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;
4275 return switch (ptr.addr) {4274 return switch (ptr.addr) {
4276 .decl => |decl| try o.lowerParentPtrDecl(decl),4275 .decl => |decl| try o.lowerParentPtrDecl(decl),
4277 .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl),
4278 .anon_decl => |ad| try o.lowerAnonDeclRef(Type.fromInterned(ad.orig_ty), ad),4276 .anon_decl => |ad| try o.lowerAnonDeclRef(Type.fromInterned(ad.orig_ty), ad),
4279 .int => |int| try o.lowerIntAsPtr(int),4277 .int => |int| try o.lowerIntAsPtr(int),
4280 .eu_payload => |eu_ptr| {4278 .eu_payload => |eu_ptr| {
...@@ -4311,7 +4309,7 @@ pub const Object = struct {...@@ -4311,7 +4309,7 @@ pub const Object = struct {
43114309
4312 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{ .@"0", .@"0" });4310 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{ .@"0", .@"0" });
4313 },4311 },
4314 .comptime_field => unreachable,4312 .comptime_field, .comptime_alloc => unreachable,
4315 .elem => |elem_ptr| {4313 .elem => |elem_ptr| {
4316 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(elem_ptr.base));4314 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(elem_ptr.base));
4317 const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod);4315 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 {...@@ -1105,7 +1105,6 @@ const DeclGen = struct {
1105 const mod = self.module;1105 const mod = self.module;
1106 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {1106 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
1107 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),1107 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
1108 .mut_decl => |decl_mut| return try self.constantDeclRef(ptr_ty, decl_mut.decl),
1109 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),1108 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),
1110 .int => |int| {1109 .int => |int| {
1111 const ptr_id = self.spv.allocId();1110 const ptr_id = self.spv.allocId();
...@@ -1121,7 +1120,7 @@ const DeclGen = struct {...@@ -1121,7 +1120,7 @@ const DeclGen = struct {
1121 },1120 },
1122 .eu_payload => unreachable, // TODO1121 .eu_payload => unreachable, // TODO
1123 .opt_payload => unreachable, // TODO1122 .opt_payload => unreachable, // TODO
1124 .comptime_field => unreachable,1123 .comptime_field, .comptime_alloc => unreachable,
1125 .elem => |elem_ptr| {1124 .elem => |elem_ptr| {
1126 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));1125 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
1127 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));1126 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 {...@@ -109,11 +109,14 @@ const Command = enum {
109109
110 fn fromString(s: []const u8) ?Command {110 fn fromString(s: []const u8) ?Command {
111 inline for (@typeInfo(Command).Enum.fields) |field| {111 inline for (@typeInfo(Command).Enum.fields) |field| {
112 comptime var buf: [field.name.len]u8 = undefined;112 const upper_name = n: {
113 inline for (field.name, 0..) |c, i| {113 comptime var buf: [field.name.len]u8 = undefined;
114 buf[i] = comptime std.ascii.toUpper(c);114 inline for (field.name, 0..) |c, i| {
115 }115 buf[i] = comptime std.ascii.toUpper(c);
116 if (std.mem.eql(u8, &buf, s)) return @field(Command, field.name);116 }
117 break :n buf;
118 };
119 if (std.mem.eql(u8, &upper_name, s)) return @field(Command, field.name);
117 }120 }
118 return null;121 return null;
119 }122 }
src/print_zir.zig+4
...@@ -2810,6 +2810,10 @@ const Writer = struct {...@@ -2810,6 +2810,10 @@ const Writer = struct {
2810 switch (capture.unwrap()) {2810 switch (capture.unwrap()) {
2811 .nested => |i| return stream.print("[{d}]", .{i}),2811 .nested => |i| return stream.print("[{d}]", .{i}),
2812 .instruction => |inst| return self.writeInstIndex(stream, inst),2812 .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 },
2813 .decl_val => |str| try stream.print("decl_val \"{}\"", .{2817 .decl_val => |str| try stream.print("decl_val \"{}\"", .{
2814 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),2818 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
2815 }),2819 }),
test/behavior/align.zig+2
...@@ -586,6 +586,8 @@ fn overaligned_fn() align(0x1000) i32 {...@@ -586,6 +586,8 @@ fn overaligned_fn() align(0x1000) i32 {
586}586}
587587
588test "comptime alloc alignment" {588test "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;
589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO591 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO592 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
591 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO593 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" {...@@ -461,7 +461,7 @@ test "write empty array to end" {
461 array[5..5].* = .{};461 array[5..5].* = .{};
462 array[5..5].* = [0]u8{};462 array[5..5].* = [0]u8{};
463 array[5..5].* = [_]u8{};463 array[5..5].* = [_]u8{};
464 try testing.expectEqualStrings("hello", &array);464 comptime std.debug.assert(std.mem.eql(u8, "hello", &array));
465}465}
466466
467fn doublePtrTest() !void {467fn doublePtrTest() !void {
test/behavior/eval.zig+1-1
...@@ -1211,7 +1211,7 @@ test "storing an array of type in a field" {...@@ -1211,7 +1211,7 @@ test "storing an array of type in a field" {
12111211
1212 const S = struct {1212 const S = struct {
1213 fn doTheTest() void {1213 fn doTheTest() void {
1214 comptime var foobar = Foobar.foo();1214 const foobar = Foobar.foo();
1215 foo(foobar.str[0..10]);1215 foo(foobar.str[0..10]);
1216 }1216 }
1217 const Foobar = struct {1217 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 {...@@ -23,10 +23,13 @@ comptime {
2323
24pub fn main() !void {}24pub 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
26// error29// error
27//30//
28// :20:5: error: found compile log statement31// :20:5: error: found compile log statement
29//32//
30// Compile Log Output:33// Compile Log Output:
31// @as([]i32, .{ 1, 2 })34// @as([]i32, .{ (reinterpreted data) })
32// @as([]i32, .{ 3, 4 })35// @as([]i32, .{ (reinterpreted data) })