authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-25 16:32:18-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-25 16:32:18-07:00
log405502286d28baee4dc3a6152282d1e6fe6c6472
tree679088dc9e31d849582989a572a8685d9d7f2492
parentabadad464090a897813e35539d669f707ea3a8b4
parentf8b8259e5caf30bd87151a0dcad7867768930e6b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19414 from mlugg/comptime-mutable-memory-yet-again

compiler: implement analysis-local comptime-mutable memory

29 files changed, 887 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/behavior/extern.zig+1
...@@ -5,6 +5,7 @@ const expect = std.testing.expect;...@@ -5,6 +5,7 @@ const expect = std.testing.expect;
5test "anyopaque extern symbol" {5test "anyopaque extern symbol" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
910
10 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });11 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });
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) })