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