authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-05 11:28:16+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-11 08:54:47+00:00
log04c9f50aec5c1d01ee2c230534454a0ddf551c38
tree60b898e67a3a570bf44c15531647c6f575ac5c09
parent6cfc9c0e02cb1ccf9edfbdc64fcca285fea022fb

compiler: improve "... contains reference to comptime var" errors

`Sema.explainWhyValueContainsReferenceToComptimeVar` (concise name!) adds notes to an error explaining how to get from a given `Value` to a pointer to some `comptime var` (or a comptime field). Previously, this error could be very opaque in any case where it wasn't obvious where the comptime var pointer came from; particularly for type captures. Now, the error notes explain this to the user.

12 files changed, 567 insertions(+), 228 deletions(-)

lib/std/zig/AstGen.zig+41-22
......@@ -5315,8 +5315,9 @@ fn structDeclInner(
53155315 const fields_slice = wip_members.fieldsSlice();
53165316 const bodies_slice = astgen.scratch.items[bodies_start..];
53175317 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +
5318 decls_slice.len + namespace.captures.count() + fields_slice.len + bodies_slice.len);
5318 decls_slice.len + namespace.captures.count() * 2 + fields_slice.len + bodies_slice.len);
53195319 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5320 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
53205321 if (backing_int_ref != .none) {
53215322 astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));
53225323 if (backing_int_body_len == 0) {
......@@ -5595,8 +5596,9 @@ fn unionDeclInner(
55955596 wip_members.finishBits(bits_per_field);
55965597 const decls_slice = wip_members.declsSlice();
55975598 const fields_slice = wip_members.fieldsSlice();
5598 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len + body_len + fields_slice.len);
5599 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
55995600 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5601 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
56005602 astgen.extra.appendSliceAssumeCapacity(decls_slice);
56015603 astgen.appendBodyWithFixups(body);
56025604 astgen.extra.appendSliceAssumeCapacity(fields_slice);
......@@ -5855,8 +5857,9 @@ fn containerDecl(
58555857 wip_members.finishBits(bits_per_field);
58565858 const decls_slice = wip_members.declsSlice();
58575859 const fields_slice = wip_members.fieldsSlice();
5858 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len + body_len + fields_slice.len);
5860 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
58595861 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5862 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
58605863 astgen.extra.appendSliceAssumeCapacity(decls_slice);
58615864 astgen.appendBodyWithFixups(body);
58625865 astgen.extra.appendSliceAssumeCapacity(fields_slice);
......@@ -5910,8 +5913,9 @@ fn containerDecl(
59105913
59115914 wip_members.finishBits(0);
59125915 const decls_slice = wip_members.declsSlice();
5913 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len);
5916 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len);
59145917 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5918 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
59155919 astgen.extra.appendSliceAssumeCapacity(decls_slice);
59165920
59175921 block_scope.unstack();
......@@ -8548,6 +8552,7 @@ fn localVarRef(
85488552 num_namespaces_out,
85498553 .{ .ref = local_val.inst },
85508554 .{ .token = local_val.token_src },
8555 name_str_index,
85518556 ) else local_val.inst;
85528557
85538558 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
......@@ -8580,6 +8585,7 @@ fn localVarRef(
85808585 num_namespaces_out,
85818586 .{ .ref = local_ptr.ptr },
85828587 .{ .token = local_ptr.token_src },
8588 name_str_index,
85838589 ) else local_ptr.ptr;
85848590 local_ptr.used_as_lvalue = true;
85858591 return ptr_inst;
......@@ -8591,6 +8597,7 @@ fn localVarRef(
85918597 num_namespaces_out,
85928598 .{ .ref_load = local_ptr.ptr },
85938599 .{ .token = local_ptr.token_src },
8600 name_str_index,
85948601 ) else try gz.addUnNode(.load, local_ptr.ptr, ident);
85958602 return rvalueNoCoercePreRef(gz, ri, val_inst, ident);
85968603 },
......@@ -8636,6 +8643,7 @@ fn localVarRef(
86368643 found_namespaces_out,
86378644 .{ .decl_ref = name_str_index },
86388645 .{ .node = found_already.? },
8646 name_str_index,
86398647 ),
86408648 else => {
86418649 const result = try tunnelThroughClosure(
......@@ -8644,6 +8652,7 @@ fn localVarRef(
86448652 found_namespaces_out,
86458653 .{ .decl_val = name_str_index },
86468654 .{ .node = found_already.? },
8655 name_str_index,
86478656 );
86488657 return rvalueNoCoercePreRef(gz, ri, result, ident);
86498658 },
......@@ -8680,6 +8689,7 @@ fn tunnelThroughClosure(
86808689 token: Ast.TokenIndex,
86818690 node: Ast.Node.Index,
86828691 },
8692 name_str_index: Zir.NullTerminatedString,
86838693) !Zir.Inst.Ref {
86848694 switch (value) {
86858695 .ref => |v| if (v.toIndex() == null) return v, // trivial value; do not need tunnel
......@@ -8714,34 +8724,43 @@ fn tunnelThroughClosure(
87148724
87158725 // Now that we know the scopes we're tunneling through, begin adding
87168726 // captures as required, starting with the outermost namespace.
8717 const root_capture = Zir.Inst.Capture.wrap(switch (value) {
8727 const root_capture: Zir.Inst.Capture = .wrap(switch (value) {
87188728 .ref => |v| .{ .instruction = v.toIndex().? },
87198729 .ref_load => |v| .{ .instruction_load = v.toIndex().? },
87208730 .decl_val => |str| .{ .decl_val = str },
87218731 .decl_ref => |str| .{ .decl_ref = str },
87228732 });
8723 var cur_capture_index = std.math.cast(
8724 u16,
8725 (try root_ns.captures.getOrPut(gpa, root_capture)).index,
8726 ) orelse return astgen.failNodeNotes(root_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{
8727 switch (decl_src) {
8728 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
8729 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
8730 },
8731 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),
8732 });
87338733
8734 for (intermediate_tunnels) |tunnel_ns| {
8735 cur_capture_index = std.math.cast(
8736 u16,
8737 (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index,
8738 ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{
8734 const root_gop = try root_ns.captures.getOrPut(gpa, root_capture);
8735 root_gop.value_ptr.* = name_str_index;
8736 var cur_capture_index = std.math.cast(u16, root_gop.index) orelse return astgen.failNodeNotes(
8737 root_ns.node,
8738 "this compiler implementation only supports up to 65536 captures per namespace",
8739 .{},
8740 &.{
87398741 switch (decl_src) {
87408742 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
87418743 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
87428744 },
87438745 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),
8744 });
8746 },
8747 );
8748
8749 for (intermediate_tunnels) |tunnel_ns| {
8750 const tunnel_gop = try tunnel_ns.captures.getOrPut(gpa, .wrap(.{ .nested = cur_capture_index }));
8751 tunnel_gop.value_ptr.* = name_str_index;
8752 cur_capture_index = std.math.cast(u16, tunnel_gop.index) orelse return astgen.failNodeNotes(
8753 tunnel_ns.node,
8754 "this compiler implementation only supports up to 65536 captures per namespace",
8755 .{},
8756 &.{
8757 switch (decl_src) {
8758 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
8759 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
8760 },
8761 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),
8762 },
8763 );
87458764 }
87468765
87478766 // Incorporate the capture index into the source hash, so that changes in
......@@ -11920,7 +11939,7 @@ const Scope = struct {
1192011939 declaring_gz: ?*GenZir,
1192111940
1192211941 /// Set of captures used by this namespace.
11923 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Capture, void) = .empty,
11942 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Capture, Zir.NullTerminatedString) = .empty,
1192411943
1192511944 fn deinit(self: *Namespace, gpa: Allocator) void {
1192611945 self.decls.deinit(gpa);
lib/std/zig/Zir.zig+27-23
......@@ -3284,24 +3284,25 @@ pub const Inst = struct {
32843284 /// 1. fields_len: u32, // if has_fields_len
32853285 /// 2. decls_len: u32, // if has_decls_len
32863286 /// 3. capture: Capture // for every captures_len
3287 /// 4. backing_int_body_len: u32, // if has_backing_int
3288 /// 5. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3289 /// 6. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3290 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3291 /// 8. flags: u32 // for every 8 fields
3287 /// 4. capture_name: NullTerminatedString // for every captures_len
3288 /// 5. backing_int_body_len: u32, // if has_backing_int
3289 /// 6. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3290 /// 7. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3291 /// 8. decl: Index, // for every decls_len; points to a `declaration` instruction
3292 /// 9. flags: u32 // for every 8 fields
32923293 /// - sets of 4 bits:
32933294 /// 0b000X: whether corresponding field has an align expression
32943295 /// 0b00X0: whether corresponding field has a default expression
32953296 /// 0b0X00: whether corresponding field is comptime
32963297 /// 0bX000: whether corresponding field has a type expression
3297 /// 9. fields: { // for every fields_len
3298 /// 10. fields: { // for every fields_len
32983299 /// field_name: u32,
32993300 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
33003301 /// field_type_body_len: u32, // if corresponding bit is set
33013302 /// align_body_len: u32, // if corresponding bit is set
33023303 /// init_body_len: u32, // if corresponding bit is set
33033304 /// }
3304 /// 10. bodies: { // for every fields_len
3305 /// 11. bodies: { // for every fields_len
33053306 /// field_type_body_inst: Inst, // for each field_type_body_len
33063307 /// align_body_inst: Inst, // for each align_body_len
33073308 /// init_body_inst: Inst, // for each init_body_len
......@@ -3450,11 +3451,12 @@ pub const Inst = struct {
34503451 /// 3. fields_len: u32, // if has_fields_len
34513452 /// 4. decls_len: u32, // if has_decls_len
34523453 /// 5. capture: Capture // for every captures_len
3453 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3454 /// 7. inst: Index // for every body_len
3455 /// 8. has_bits: u32 // for every 32 fields
3454 /// 6. capture_name: NullTerminatedString // for every captures_len
3455 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3456 /// 8. inst: Index // for every body_len
3457 /// 9. has_bits: u32 // for every 32 fields
34563458 /// - the bit is whether corresponding field has an value expression
3457 /// 9. fields: { // for every fields_len
3459 /// 10. fields: { // for every fields_len
34583460 /// field_name: u32,
34593461 /// value: Ref, // if corresponding bit is set
34603462 /// }
......@@ -3488,15 +3490,16 @@ pub const Inst = struct {
34883490 /// 3. fields_len: u32, // if has_fields_len
34893491 /// 4. decls_len: u32, // if has_decls_len
34903492 /// 5. capture: Capture // for every captures_len
3491 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3492 /// 7. inst: Index // for every body_len
3493 /// 8. has_bits: u32 // for every 8 fields
3493 /// 6. capture_name: NullTerminatedString // for every captures_len
3494 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3495 /// 8. inst: Index // for every body_len
3496 /// 9. has_bits: u32 // for every 8 fields
34943497 /// - sets of 4 bits:
34953498 /// 0b000X: whether corresponding field has a type expression
34963499 /// 0b00X0: whether corresponding field has a align expression
34973500 /// 0b0X00: whether corresponding field has a tag value expression
34983501 /// 0bX000: unused
3499 /// 9. fields: { // for every fields_len
3502 /// 10. fields: { // for every fields_len
35003503 /// field_name: NullTerminatedString, // null terminated string index
35013504 /// field_type: Ref, // if corresponding bit is set
35023505 /// align: Ref, // if corresponding bit is set
......@@ -3537,7 +3540,8 @@ pub const Inst = struct {
35373540 /// 0. captures_len: u32, // if has_captures_len
35383541 /// 1. decls_len: u32, // if has_decls_len
35393542 /// 2. capture: Capture, // for every captures_len
3540 /// 3. decl: Index, // for every decls_len; points to a `declaration` instruction
3543 /// 3. capture_name: NullTerminatedString // for every captures_len
3544 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
35413545 pub const OpaqueDecl = struct {
35423546 src_line: u32,
35433547 /// This node provides a new absolute baseline node for all instructions within this struct.
......@@ -3852,7 +3856,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
38523856 break :decls_len decls_len;
38533857 } else 0;
38543858
3855 extra_index += captures_len;
3859 extra_index += captures_len * 2;
38563860
38573861 if (small.has_backing_int) {
38583862 const backing_int_body_len = zir.extra[extra_index];
......@@ -3887,7 +3891,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
38873891 break :decls_len decls_len;
38883892 } else 0;
38893893
3890 extra_index += captures_len;
3894 extra_index += captures_len * 2;
38913895
38923896 return .{
38933897 .extra_index = extra_index,
......@@ -3912,7 +3916,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
39123916 break :decls_len decls_len;
39133917 } else 0;
39143918
3915 extra_index += captures_len;
3919 extra_index += captures_len * 2;
39163920
39173921 return .{
39183922 .extra_index = extra_index,
......@@ -3934,7 +3938,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
39343938 break :captures_len captures_len;
39353939 } else 0;
39363940
3937 extra_index += captures_len;
3941 extra_index += captures_len * 2;
39383942
39393943 return .{
39403944 .extra_index = extra_index,
......@@ -4349,7 +4353,7 @@ fn findTrackableInner(
43494353 extra_index += 1;
43504354 break :blk decls_len;
43514355 } else 0;
4352 extra_index += captures_len;
4356 extra_index += captures_len * 2;
43534357 if (small.has_backing_int) {
43544358 const backing_int_body_len = zir.extra[extra_index];
43554359 extra_index += 1;
......@@ -4441,7 +4445,7 @@ fn findTrackableInner(
44414445 extra_index += 1;
44424446 break :blk decls_len;
44434447 } else 0;
4444 extra_index += captures_len;
4448 extra_index += captures_len * 2;
44454449 extra_index += decls_len;
44464450 const body = zir.bodySlice(extra_index, body_len);
44474451 try zir.findTrackableBody(gpa, contents, defers, body);
......@@ -4471,7 +4475,7 @@ fn findTrackableInner(
44714475 extra_index += 1;
44724476 break :blk decls_len;
44734477 } else 0;
4474 extra_index += captures_len;
4478 extra_index += captures_len * 2;
44754479 extra_index += decls_len;
44764480 const body = zir.bodySlice(extra_index, body_len);
44774481 try zir.findTrackableBody(gpa, contents, defers, body);
src/Sema.zig+224-36
......@@ -134,6 +134,7 @@ const MaybeComptimeAlloc = struct {
134134const ComptimeAlloc = struct {
135135 val: MutableValue,
136136 is_const: bool,
137 src: LazySrcLoc,
137138 /// `.none` indicates that the alignment is the natural alignment of `val`.
138139 alignment: Alignment,
139140 /// This is the `runtime_index` at the point of this allocation. If an store
......@@ -142,11 +143,13 @@ const ComptimeAlloc = struct {
142143 runtime_index: RuntimeIndex,
143144};
144145
145fn newComptimeAlloc(sema: *Sema, block: *Block, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
146/// `src` may be `null` if `is_const` will be set.
147fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
146148 const idx = sema.comptime_allocs.items.len;
147149 try sema.comptime_allocs.append(sema.gpa, .{
148150 .val = .{ .interned = try sema.pt.intern(.{ .undef = ty.toIntern() }) },
149151 .is_const = false,
152 .src = src,
150153 .alignment = alignment,
151154 .runtime_index = block.runtime_index,
152155 });
......@@ -1308,7 +1311,7 @@ fn analyzeBodyInner(
13081311 .shl_exact => try sema.zirShl(block, inst, .shl_exact),
13091312 .shl_sat => try sema.zirShl(block, inst, .shl_sat),
13101313
1311 .ret_ptr => try sema.zirRetPtr(block),
1314 .ret_ptr => try sema.zirRetPtr(block, inst),
13121315 .ret_type => Air.internedToRef(sema.fn_ret_ty.toIntern()),
13131316
13141317 // Instructions that we know to *always* be noreturn based solely on their tag.
......@@ -2301,7 +2304,9 @@ pub fn resolveFinalDeclValue(
23012304 };
23022305
23032306 if (val.canMutateComptimeVarState(zcu)) {
2304 return sema.fail(block, src, "global variable contains reference to comptime var", .{});
2307 const ip = &zcu.intern_pool;
2308 const nav = ip.getNav(sema.owner.unwrap().nav_val);
2309 return sema.failWithContainsReferenceToComptimeVar(block, src, nav.name, "global variable", val);
23052310 }
23062311
23072312 return val;
......@@ -2757,7 +2762,8 @@ fn zirTupleDecl(
27572762 const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);
27582763 const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });
27592764 if (field_init_val.canMutateComptimeVarState(zcu)) {
2760 return sema.fail(block, init_src, "field default value contains reference to comptime-mutable memory", .{});
2765 const field_name = try zcu.intern_pool.getOrPutStringFmt(gpa, pt.tid, "{}", .{field_index}, .no_embedded_nulls);
2766 return sema.failWithContainsReferenceToComptimeVar(block, init_src, field_name, "field default value", field_init_val);
27612767 }
27622768 break :init field_init_val.toIntern();
27632769 }
......@@ -2813,8 +2819,10 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
28132819
28142820 const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
28152821
2816 for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| {
2822 for (sema.code.extra[extra_index..][0..captures_len], sema.code.extra[extra_index + captures_len ..][0..captures_len], captures) |raw, raw_name, *capture| {
28172823 const zir_capture: Zir.Inst.Capture = @bitCast(raw);
2824 const zir_name: Zir.NullTerminatedString = @enumFromInt(raw_name);
2825 const zir_name_slice = sema.code.nullTerminatedString(zir_name);
28182826 capture.* = switch (zir_capture.unwrap()) {
28192827 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
28202828 .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {
......@@ -2828,8 +2836,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
28282836 };
28292837 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
28302838 if (loaded_val.canMutateComptimeVarState(zcu)) {
2831 // TODO: source location of captured value
2832 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});
2839 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2840 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);
28332841 }
28342842 break :capture .{ .@"comptime" = loaded_val.toIntern() };
28352843 }),
......@@ -2837,8 +2845,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
28372845 const air_ref = try sema.resolveInst(inst.toRef());
28382846 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
28392847 if (val.canMutateComptimeVarState(zcu)) {
2840 // TODO: source location of captured value
2841 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});
2848 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2849 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);
28422850 }
28432851 break :capture .{ .@"comptime" = val.toIntern() };
28442852 }
......@@ -2908,7 +2916,7 @@ fn zirStructDecl(
29082916 } else 0;
29092917
29102918 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
2911 extra_index += captures_len;
2919 extra_index += captures_len * 2;
29122920
29132921 if (small.has_backing_int) {
29142922 const backing_int_body_len = sema.code.extra[extra_index];
......@@ -3132,7 +3140,7 @@ fn zirEnumDecl(
31323140 } else 0;
31333141
31343142 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3135 extra_index += captures_len;
3143 extra_index += captures_len * 2;
31363144
31373145 const decls = sema.code.bodySlice(extra_index, decls_len);
31383146 extra_index += decls_len;
......@@ -3275,7 +3283,7 @@ fn zirUnionDecl(
32753283 } else 0;
32763284
32773285 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3278 extra_index += captures_len;
3286 extra_index += captures_len * 2;
32793287
32803288 const union_init: InternPool.UnionTypeInit = .{
32813289 .flags = .{
......@@ -3393,7 +3401,7 @@ fn zirOpaqueDecl(
33933401 } else 0;
33943402
33953403 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3396 extra_index += captures_len;
3404 extra_index += captures_len * 2;
33973405
33983406 const opaque_init: InternPool.OpaqueTypeInit = .{
33993407 .key = .{ .declared = .{
......@@ -3474,15 +3482,17 @@ fn zirErrorSetDecl(
34743482 return Air.internedToRef((try pt.errorSetFromUnsortedNames(names.keys())).toIntern());
34753483}
34763484
3477fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
3485fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
34783486 const tracy = trace(@src());
34793487 defer tracy.end();
34803488
34813489 const pt = sema.pt;
34823490
3491 const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node);
3492
34833493 if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) {
34843494 try sema.fn_ret_ty.resolveFields(pt);
3485 return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none);
3495 return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none);
34863496 }
34873497
34883498 const target = pt.zcu.getTarget();
......@@ -3658,6 +3668,7 @@ fn zirAllocExtended(
36583668 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
36593669 const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node });
36603670 const align_src = block.src(.{ .node_offset_var_decl_align = extra.data.src_node });
3671 const init_src = block.src(.{ .node_offset_var_decl_init = extra.data.src_node });
36613672 const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small);
36623673
36633674 var extra_index: usize = extra.end;
......@@ -3676,7 +3687,7 @@ fn zirAllocExtended(
36763687
36773688 if (block.isComptime() or small.is_comptime) {
36783689 if (small.has_type) {
3679 return sema.analyzeComptimeAlloc(block, var_ty, alignment);
3690 return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment);
36803691 } else {
36813692 try sema.air_instructions.append(gpa, .{
36823693 .tag = .inferred_alloc_comptime,
......@@ -3691,7 +3702,7 @@ fn zirAllocExtended(
36913702 }
36923703
36933704 if (small.has_type and try var_ty.comptimeOnlySema(pt)) {
3694 return sema.analyzeComptimeAlloc(block, var_ty, alignment);
3705 return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment);
36953706 }
36963707
36973708 if (small.has_type) {
......@@ -3741,8 +3752,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
37413752
37423753 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
37433754 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
3755 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
37443756 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3745 return sema.analyzeComptimeAlloc(block, var_ty, .none);
3757 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
37463758}
37473759
37483760fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -3860,7 +3872,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38603872 // The simple strategy failed: we must create a mutable comptime alloc and
38613873 // perform all of the runtime store operations at comptime.
38623874
3863 const ct_alloc = try sema.newComptimeAlloc(block, elem_ty, ptr_info.flags.alignment);
3875 const ct_alloc = try sema.newComptimeAlloc(block, .unneeded, elem_ty, ptr_info.flags.alignment);
38643876
38653877 const alloc_ptr = try pt.intern(.{ .ptr = .{
38663878 .ty = alloc_ty.toIntern(),
......@@ -4073,7 +4085,7 @@ fn finishResolveComptimeKnownAllocPtr(
40734085
40744086 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {
40754087 const alloc_index = existing_comptime_alloc orelse a: {
4076 const idx = try sema.newComptimeAlloc(block, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu));
4088 const idx = try sema.newComptimeAlloc(block, .unneeded, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu));
40774089 const alloc = sema.getComptimeAlloc(idx);
40784090 alloc.val = .{ .interned = result_val };
40794091 break :a idx;
......@@ -4139,10 +4151,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
41394151
41404152 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
41414153 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4154 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
41424155
41434156 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
41444157 if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) {
4145 return sema.analyzeComptimeAlloc(block, var_ty, .none);
4158 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
41464159 }
41474160 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
41484161 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
......@@ -4168,9 +4181,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
41684181
41694182 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
41704183 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4184 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
41714185 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
41724186 if (block.isComptime()) {
4173 return sema.analyzeComptimeAlloc(block, var_ty, .none);
4187 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
41744188 }
41754189 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
41764190 const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
......@@ -5726,7 +5740,7 @@ fn storeToInferredAllocComptime(
57265740 .byte_offset = 0,
57275741 } });
57285742 } else {
5729 const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment);
5743 const alloc_index = try sema.newComptimeAlloc(block, src, operand_ty, iac.alignment);
57305744 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };
57315745 iac.ptr = try pt.intern(.{ .ptr = .{
57325746 .ty = alloc_ty.toIntern(),
......@@ -31206,14 +31220,7 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins
3120631220 }
3120731221 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;
3120831222 const other_operand = other_data.rhs;
31209 if (!sema.checkRuntimeValue(other_operand)) {
31210 return sema.failWithOwnedErrorMsg(block, msg: {
31211 const msg = try sema.errMsg(other_src, "runtime value contains reference to comptime var", .{});
31212 errdefer msg.destroy(sema.gpa);
31213 try sema.errNote(other_src, msg, "comptime var pointers are not available at runtime", .{});
31214 break :msg msg;
31215 });
31216 }
31223 try sema.validateRuntimeValue(block, other_src, other_operand);
3121731224 }
3121831225}
3121931226
......@@ -35328,7 +35335,7 @@ fn backingIntType(
3532835335 extra_index += @intFromBool(small.has_fields_len);
3532935336 extra_index += @intFromBool(small.has_decls_len);
3533035337
35331 extra_index += captures_len;
35338 extra_index += captures_len * 2;
3533235339
3533335340 const backing_int_body_len = zir.extra[extra_index];
3533435341 extra_index += 1;
......@@ -35904,7 +35911,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3590435911 break :decls_len decls_len;
3590535912 } else 0;
3590635913
35907 extra_index += captures_len;
35914 extra_index += captures_len * 2;
3590835915
3590935916 // The backing integer cannot be handled until `resolveStructLayout()`.
3591035917 if (small.has_backing_int) {
......@@ -36233,7 +36240,8 @@ fn structFieldInits(
3623336240 const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null);
3623436241
3623536242 if (default_val.canMutateComptimeVarState(zcu)) {
36236 return sema.fail(&block_scope, init_src, "field default value contains reference to comptime-mutable memory", .{});
36243 const field_name = struct_type.fieldName(ip, field_i).unwrap().?;
36244 return sema.failWithContainsReferenceToComptimeVar(&block_scope, init_src, field_name, "field default value", default_val);
3623736245 }
3623836246 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
3623936247 }
......@@ -36293,7 +36301,7 @@ fn unionFields(
3629336301 } else 0;
3629436302
3629536303 // Skip over captures and decls.
36296 extra_index += captures_len + decls_len;
36304 extra_index += captures_len * 2 + decls_len;
3629736305
3629836306 const body = zir.bodySlice(extra_index, body_len);
3629936307 extra_index += body.len;
......@@ -37055,6 +37063,7 @@ fn isComptimeKnown(
3705537063fn analyzeComptimeAlloc(
3705637064 sema: *Sema,
3705737065 block: *Block,
37066 src: LazySrcLoc,
3705837067 var_type: Type,
3705937068 alignment: Alignment,
3706037069) CompileError!Air.Inst.Ref {
......@@ -37072,7 +37081,7 @@ fn analyzeComptimeAlloc(
3707237081 },
3707337082 });
3707437083
37075 const alloc = try sema.newComptimeAlloc(block, var_type, alignment);
37084 const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);
3707637085
3707737086 return Air.internedToRef((try pt.intern(.{ .ptr = .{
3707837087 .ty = ptr_type.toIntern(),
......@@ -37979,10 +37988,189 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai
3797937988 const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{});
3798037989 errdefer msg.destroy(sema.gpa);
3798137990 try sema.errNote(val_src, msg, "comptime var pointers are not available at runtime", .{});
37991 const pt = sema.pt;
37992 const zcu = pt.zcu;
37993 const val_str = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, "runtime_value", .no_embedded_nulls);
37994 try sema.explainWhyValueContainsReferenceToComptimeVar(msg, val_src, val_str, .fromInterned(val.toInterned().?));
37995 break :msg msg;
37996 });
37997}
37998
37999fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError {
38000 return sema.failWithOwnedErrorMsg(block, msg: {
38001 const msg = try sema.errMsg(src, "{s} contains reference to comptime var", .{kind_of_value});
38002 errdefer msg.destroy(sema.gpa);
38003 if (val) |v| try sema.explainWhyValueContainsReferenceToComptimeVar(msg, src, value_name, v);
3798238004 break :msg msg;
3798338005 });
3798438006}
3798538007
38008fn explainWhyValueContainsReferenceToComptimeVar(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, val: Value) Allocator.Error!void {
38009 // Our goal is something like this:
38010 // note: '(value.? catch unreachable)[0]' points to 'v0.?.foo'
38011 // note: '(v0.?.bar catch unreachable)' points to 'v1'
38012 // note: 'v1.?' points to a comptime var
38013
38014 var intermediate_value_count: u32 = 0;
38015 var cur_val: Value = val;
38016 while (true) {
38017 switch (try sema.notePathToComptimeAllocPtr(msg, src, cur_val, intermediate_value_count, value_name)) {
38018 .done => return,
38019 .new_val => |new_val| {
38020 intermediate_value_count += 1;
38021 cur_val = new_val;
38022 },
38023 }
38024 }
38025}
38026
38027fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, val: Value, intermediate_value_count: u32, start_value_name: InternPool.NullTerminatedString) Allocator.Error!union(enum) {
38028 done,
38029 new_val: Value,
38030} {
38031 const arena = sema.arena;
38032 const pt = sema.pt;
38033 const zcu = pt.zcu;
38034 const ip = &zcu.intern_pool;
38035
38036 var first_path: std.ArrayListUnmanaged(u8) = .empty;
38037 if (intermediate_value_count == 0) {
38038 try first_path.writer(arena).print("{i}", .{start_value_name.fmt(ip)});
38039 } else {
38040 try first_path.writer(arena).print("v{}", .{intermediate_value_count - 1});
38041 }
38042
38043 const comptime_ptr = try sema.notePathToComptimeAllocPtrInner(val, &first_path);
38044
38045 switch (ip.indexToKey(comptime_ptr.toIntern()).ptr.base_addr) {
38046 .comptime_field => {
38047 try sema.errNote(src, msg, "'{s}' points to comptime field", .{first_path.items});
38048 return .done;
38049 },
38050 .comptime_alloc => |idx| {
38051 const cta = sema.getComptimeAlloc(idx);
38052 if (!cta.is_const) {
38053 try sema.errNote(cta.src, msg, "'{s}' points to comptime var declared here", .{first_path.items});
38054 return .done;
38055 }
38056 },
38057 else => {}, // there will be another stage
38058 }
38059
38060 const derivation = comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema) catch |err| switch (err) {
38061 error.OutOfMemory => |e| return e,
38062 error.AnalysisFail => unreachable,
38063 };
38064
38065 var second_path: std.ArrayListUnmanaged(u8) = .empty;
38066 const inter_name = try std.fmt.allocPrint(arena, "v{d}", .{intermediate_value_count});
38067 const deriv_start = @import("print_value.zig").printPtrDerivation(
38068 derivation,
38069 second_path.writer(arena),
38070 pt,
38071 .lvalue,
38072 .{ .str = inter_name },
38073 20,
38074 ) catch |err| switch (err) {
38075 error.OutOfMemory => |e| return e,
38076 error.AnalysisFail => unreachable,
38077 error.GenericPoison => unreachable,
38078 error.ComptimeReturn => unreachable,
38079 error.ComptimeBreak => unreachable,
38080 };
38081
38082 switch (deriv_start) {
38083 .int, .nav_ptr => unreachable,
38084 .uav_ptr => |uav| {
38085 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
38086 return .{ .new_val = .fromInterned(uav.val) };
38087 },
38088 .comptime_alloc_ptr => |cta_info| {
38089 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
38090 const cta = sema.getComptimeAlloc(cta_info.idx);
38091 if (cta.is_const) {
38092 return .{ .new_val = cta_info.val };
38093 } else {
38094 try sema.errNote(cta.src, msg, "'{s}' is a comptime var declared here", .{inter_name});
38095 return .done;
38096 }
38097 },
38098 .comptime_field_ptr => {
38099 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
38100 try sema.errNote(src, msg, "'{s}' is a comptime field", .{inter_name});
38101 return .done;
38102 },
38103 .eu_payload_ptr,
38104 .opt_payload_ptr,
38105 .field_ptr,
38106 .elem_ptr,
38107 .offset_and_cast,
38108 => unreachable,
38109 }
38110}
38111
38112fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayListUnmanaged(u8)) Allocator.Error!Value {
38113 const pt = sema.pt;
38114 const zcu = pt.zcu;
38115 const ip = &zcu.intern_pool;
38116 const arena = sema.arena;
38117 assert(val.canMutateComptimeVarState(zcu));
38118 switch (ip.indexToKey(val.toIntern())) {
38119 .ptr => return val,
38120 .error_union => |eu| {
38121 try path.insert(arena, 0, '(');
38122 try path.appendSlice(arena, " catch unreachable)");
38123 return sema.notePathToComptimeAllocPtrInner(.fromInterned(eu.val.payload), path);
38124 },
38125 .slice => |slice| {
38126 try path.appendSlice(arena, ".ptr");
38127 return sema.notePathToComptimeAllocPtrInner(.fromInterned(slice.ptr), path);
38128 },
38129 .opt => |opt| {
38130 try path.appendSlice(arena, ".?");
38131 return sema.notePathToComptimeAllocPtrInner(.fromInterned(opt.val), path);
38132 },
38133 .un => |un| {
38134 assert(un.tag != .none);
38135 const union_ty: Type = .fromInterned(un.ty);
38136 const backing_enum = union_ty.unionTagTypeHypothetical(zcu);
38137 const field_idx = backing_enum.enumTagFieldIndex(.fromInterned(un.tag), zcu).?;
38138 const field_name = backing_enum.enumFieldName(field_idx, zcu);
38139 try path.writer(arena).print(".{i}", .{field_name.fmt(ip)});
38140 return sema.notePathToComptimeAllocPtrInner(.fromInterned(un.val), path);
38141 },
38142 .aggregate => |agg| {
38143 const elem: InternPool.Index, const elem_idx: usize = switch (agg.storage) {
38144 .bytes => unreachable,
38145 .repeated_elem => |elem| .{ elem, 0 },
38146 .elems => |elems| for (elems, 0..) |elem, elem_idx| {
38147 if (Value.fromInterned(elem).canMutateComptimeVarState(zcu)) {
38148 break .{ elem, elem_idx };
38149 }
38150 } else unreachable,
38151 };
38152 const agg_ty: Type = .fromInterned(agg.ty);
38153 switch (agg_ty.zigTypeTag(zcu)) {
38154 .array, .vector => try path.writer(arena).print("[{d}]", .{elem_idx}),
38155 .pointer => switch (elem_idx) {
38156 Value.slice_ptr_index => try path.appendSlice(arena, ".ptr"),
38157 Value.slice_len_index => try path.appendSlice(arena, ".len"),
38158 else => unreachable,
38159 },
38160 .@"struct" => if (agg_ty.isTuple(zcu)) {
38161 try path.writer(arena).print("[{d}]", .{elem_idx});
38162 } else {
38163 const name = agg_ty.structFieldName(elem_idx, zcu).unwrap().?;
38164 try path.writer(arena).print(".{i}", .{name.fmt(ip)});
38165 },
38166 else => unreachable,
38167 }
38168 return sema.notePathToComptimeAllocPtrInner(.fromInterned(elem), path);
38169 },
38170 else => unreachable,
38171 }
38172}
38173
3798638174/// Returns true if any value contained in `val` is undefined.
3798738175fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
3798838176 const pt = sema.pt;
src/Value.zig+51-15
......@@ -4064,6 +4064,7 @@ pub const PointerDeriveStep = union(enum) {
40644064 nav_ptr: InternPool.Nav.Index,
40654065 uav_ptr: InternPool.Key.Ptr.BaseAddr.Uav,
40664066 comptime_alloc_ptr: struct {
4067 idx: InternPool.ComptimeAllocIndex,
40674068 val: Value,
40684069 ptr_ty: Type,
40694070 },
......@@ -4110,7 +4111,7 @@ pub const PointerDeriveStep = union(enum) {
41104111};
41114112
41124113pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Allocator.Error!PointerDeriveStep {
4113 return ptr_val.pointerDerivationAdvanced(arena, pt, false, {}) catch |err| switch (err) {
4114 return ptr_val.pointerDerivationAdvanced(arena, pt, false, null) catch |err| switch (err) {
41144115 error.OutOfMemory => |e| return e,
41154116 error.AnalysisFail => unreachable,
41164117 };
......@@ -4120,7 +4121,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al
41204121/// only field and element pointers with no casts. This can be used by codegen backends
41214122/// which prefer field/elem accesses when lowering constant pointer values.
41224123/// It is also used by the Value printing logic for pointers.
4123pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime have_sema: bool, sema: if (have_sema) *Sema else void) !PointerDeriveStep {
4124pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep {
41244125 const zcu = pt.zcu;
41254126 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
41264127 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
......@@ -4143,11 +4144,12 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
41434144 } };
41444145 },
41454146 .comptime_alloc => |idx| base: {
4146 if (!have_sema) unreachable;
4147 const sema = opt_sema.?;
41474148 const alloc = sema.getComptimeAlloc(idx);
41484149 const val = try alloc.val.intern(pt, sema.arena);
41494150 const ty = val.typeOf(zcu);
41504151 break :base .{ .comptime_alloc_ptr = .{
4152 .idx = idx,
41514153 .val = val,
41524154 .ptr_ty = try pt.ptrType(.{
41534155 .child = ty.toIntern(),
......@@ -4162,7 +4164,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
41624164 const base_ptr = Value.fromInterned(eu_ptr);
41634165 const base_ptr_ty = base_ptr.typeOf(zcu);
41644166 const parent_step = try arena.create(PointerDeriveStep);
4165 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, pt, have_sema, sema);
4167 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, pt, resolve_types, opt_sema);
41664168 break :base .{ .eu_payload_ptr = .{
41674169 .parent = parent_step,
41684170 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),
......@@ -4172,7 +4174,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
41724174 const base_ptr = Value.fromInterned(opt_ptr);
41734175 const base_ptr_ty = base_ptr.typeOf(zcu);
41744176 const parent_step = try arena.create(PointerDeriveStep);
4175 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, pt, have_sema, sema);
4177 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, pt, resolve_types, opt_sema);
41764178 break :base .{ .opt_payload_ptr = .{
41774179 .parent = parent_step,
41784180 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),
......@@ -4185,15 +4187,15 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
41854187 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {
41864188 .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
41874189 @intCast(field.index),
4188 if (have_sema) .sema else .normal,
4190 if (resolve_types) .sema else .normal,
41894191 pt.zcu,
4190 if (have_sema) pt.tid else {},
4192 if (resolve_types) pt.tid else {},
41914193 ) },
41924194 .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
41934195 @intCast(field.index),
4194 if (have_sema) .sema else .normal,
4196 if (resolve_types) .sema else .normal,
41954197 pt.zcu,
4196 if (have_sema) pt.tid else {},
4198 if (resolve_types) pt.tid else {},
41974199 ) },
41984200 .pointer => .{ switch (field.index) {
41994201 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
......@@ -4217,7 +4219,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
42174219 },
42184220 });
42194221 const parent_step = try arena.create(PointerDeriveStep);
4220 parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, pt, have_sema, sema);
4222 parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, pt, resolve_types, opt_sema);
42214223 break :base .{ .field_ptr = .{
42224224 .parent = parent_step,
42234225 .field_idx = @intCast(field.index),
......@@ -4226,7 +4228,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
42264228 },
42274229 .arr_elem => |arr_elem| base: {
42284230 const parent_step = try arena.create(PointerDeriveStep);
4229 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, pt, have_sema, sema);
4231 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, pt, resolve_types, opt_sema);
42304232 const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);
42314233 const result_ptr_ty = try pt.ptrType(.{
42324234 .child = parent_ptr_info.child,
......@@ -4248,7 +4250,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
42484250 return base_derive;
42494251 }
42504252
4251 const need_child = Type.fromInterned(ptr.ty).childType(zcu);
4253 const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu);
4254 const need_child: Type = .fromInterned(ptr_ty_info.child);
42524255 if (need_child.comptimeOnly(zcu)) {
42534256 // No refinement can happen - this pointer is presumably invalid.
42544257 // Just offset it.
......@@ -4293,16 +4296,34 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
42934296 .frame,
42944297 .@"enum",
42954298 .vector,
4296 .optional,
42974299 .@"union",
42984300 => break,
42994301
4302 .optional => {
4303 ptr_opt: {
4304 if (!cur_ty.isPtrLikeOptional(zcu)) break :ptr_opt;
4305 if (need_child.zigTypeTag(zcu) != .pointer) break :ptr_opt;
4306 switch (need_child.ptrSize(zcu)) {
4307 .One, .Many => {},
4308 .Slice, .C => break :ptr_opt,
4309 }
4310 const parent = try arena.create(PointerDeriveStep);
4311 parent.* = cur_derive;
4312 cur_derive = .{ .opt_payload_ptr = .{
4313 .parent = parent,
4314 .result_ptr_ty = try pt.adjustPtrTypeChild(try parent.ptrType(pt), cur_ty.optionalChild(zcu)),
4315 } };
4316 continue;
4317 }
4318 break;
4319 },
4320
43004321 .array => {
43014322 const elem_ty = cur_ty.childType(zcu);
43024323 const elem_size = elem_ty.abiSize(zcu);
43034324 const start_idx = cur_offset / elem_size;
43044325 const end_idx = (cur_offset + need_bytes + elem_size - 1) / elem_size;
4305 if (end_idx == start_idx + 1) {
4326 if (end_idx == start_idx + 1 and ptr_ty_info.flags.size == .One) {
43064327 const parent = try arena.create(PointerDeriveStep);
43074328 parent.* = cur_derive;
43084329 cur_derive = .{ .elem_ptr = .{
......@@ -4363,7 +4384,22 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
43634384 }
43644385 };
43654386
4366 if (cur_offset == 0 and (try cur_derive.ptrType(pt)).toIntern() == ptr.ty) {
4387 if (cur_offset == 0) compatible: {
4388 const src_ptr_ty_info = (try cur_derive.ptrType(pt)).ptrInfo(zcu);
4389 // We allow silently doing some "coercible" pointer things.
4390 // In particular, we only give up if cv qualifiers are *removed*.
4391 if (src_ptr_ty_info.flags.is_const and !ptr_ty_info.flags.is_const) break :compatible;
4392 if (src_ptr_ty_info.flags.is_volatile and !ptr_ty_info.flags.is_volatile) break :compatible;
4393 if (src_ptr_ty_info.flags.is_allowzero and !ptr_ty_info.flags.is_allowzero) break :compatible;
4394 // Everything else has to match exactly.
4395 if (src_ptr_ty_info.child != ptr_ty_info.child) break :compatible;
4396 if (src_ptr_ty_info.sentinel != ptr_ty_info.sentinel) break :compatible;
4397 if (src_ptr_ty_info.packed_offset != ptr_ty_info.packed_offset) break :compatible;
4398 if (src_ptr_ty_info.flags.size != ptr_ty_info.flags.size) break :compatible;
4399 if (src_ptr_ty_info.flags.alignment != ptr_ty_info.flags.alignment) break :compatible;
4400 if (src_ptr_ty_info.flags.address_space != ptr_ty_info.flags.address_space) break :compatible;
4401 if (src_ptr_ty_info.flags.vector_index != ptr_ty_info.flags.vector_index) break :compatible;
4402
43674403 return cur_derive;
43684404 }
43694405
src/Zcu/PerThread.zig+5-5
......@@ -3944,7 +3944,7 @@ fn recreateEnumType(
39443944
39453945 assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
39463946
3947 extra_index += captures_len;
3947 extra_index += captures_len * 2;
39483948 extra_index += decls_len;
39493949
39503950 const body = zir.bodySlice(extra_index, body_len);
......@@ -4071,7 +4071,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
40714071 extra_index += 1;
40724072 break :blk decls_len;
40734073 } else 0;
4074 extra_index += captures_len;
4074 extra_index += captures_len * 2;
40754075 if (small.has_backing_int) {
40764076 const backing_int_body_len = zir.extra[extra_index];
40774077 extra_index += 1; // backing_int_body_len
......@@ -4101,7 +4101,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
41014101 extra_index += 1;
41024102 break :blk decls_len;
41034103 } else 0;
4104 extra_index += captures_len;
4104 extra_index += captures_len * 2;
41054105 break :decls zir.bodySlice(extra_index, decls_len);
41064106 },
41074107 .@"enum" => decls: {
......@@ -4122,7 +4122,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
41224122 extra_index += 1;
41234123 break :blk decls_len;
41244124 } else 0;
4125 extra_index += captures_len;
4125 extra_index += captures_len * 2;
41264126 break :decls zir.bodySlice(extra_index, decls_len);
41274127 },
41284128 .@"opaque" => decls: {
......@@ -4140,7 +4140,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
41404140 extra_index += 1;
41414141 break :blk decls_len;
41424142 } else 0;
4143 extra_index += captures_len;
4143 extra_index += captures_len * 2;
41444144 break :decls zir.bodySlice(extra_index, decls_len);
41454145 },
41464146 };
src/print_value.zig+145-70
......@@ -29,7 +29,7 @@ pub fn formatSema(
2929 _ = options;
3030 const sema = ctx.opt_sema.?;
3131 comptime std.debug.assert(fmt.len == 0);
32 return print(ctx.val, writer, ctx.depth, ctx.pt, true, sema) catch |err| switch (err) {
32 return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) {
3333 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
3434 error.ComptimeBreak, error.ComptimeReturn => unreachable,
3535 error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully
......@@ -46,7 +46,7 @@ pub fn format(
4646 _ = options;
4747 std.debug.assert(ctx.opt_sema == null);
4848 comptime std.debug.assert(fmt.len == 0);
49 return print(ctx.val, writer, ctx.depth, ctx.pt, false, {}) catch |err| switch (err) {
49 return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) {
5050 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
5151 error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,
5252 else => |e| return e,
......@@ -58,9 +58,7 @@ pub fn print(
5858 writer: anytype,
5959 level: u8,
6060 pt: Zcu.PerThread,
61 /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output.
62 comptime have_sema: bool,
63 sema: if (have_sema) *Sema else void,
61 opt_sema: ?*Sema,
6462) (@TypeOf(writer).Error || Zcu.CompileError)!void {
6563 const zcu = pt.zcu;
6664 const ip = &zcu.intern_pool;
......@@ -94,11 +92,11 @@ pub fn print(
9492 .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
9593 .int => |int| switch (int.storage) {
9694 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
97 .lazy_align => |ty| if (have_sema) {
95 .lazy_align => |ty| if (opt_sema != null) {
9896 const a = try Type.fromInterned(ty).abiAlignmentSema(pt);
9997 try writer.print("{}", .{a.toByteUnits() orelse 0});
10098 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(pt)}),
101 .lazy_size => |ty| if (have_sema) {
99 .lazy_size => |ty| if (opt_sema != null) {
102100 const s = try Type.fromInterned(ty).abiSizeSema(pt);
103101 try writer.print("{}", .{s});
104102 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}),
......@@ -110,7 +108,7 @@ pub fn print(
110108 .err_name => |err_name| try writer.print("error.{}", .{
111109 err_name.fmt(ip),
112110 }),
113 .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, have_sema, sema),
111 .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema),
114112 },
115113 .enum_literal => |enum_literal| try writer.print(".{}", .{
116114 enum_literal.fmt(ip),
......@@ -124,7 +122,7 @@ pub fn print(
124122 return writer.writeAll("@enumFromInt(...)");
125123 }
126124 try writer.writeAll("@enumFromInt(");
127 try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, have_sema, sema);
125 try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema);
128126 try writer.writeAll(")");
129127 },
130128 .empty_enum_value => try writer.writeAll("(empty enum value)"),
......@@ -141,12 +139,12 @@ pub fn print(
141139 // TODO: eventually we want to load the slice as an array with `sema`, but that's
142140 // currently not possible without e.g. triggering compile errors.
143141 }
144 try printPtr(Value.fromInterned(slice.ptr), writer, level, pt, have_sema, sema);
142 try printPtr(Value.fromInterned(slice.ptr), null, writer, level, pt, opt_sema);
145143 try writer.writeAll("[0..");
146144 if (level == 0) {
147145 try writer.writeAll("(...)");
148146 } else {
149 try print(Value.fromInterned(slice.len), writer, level - 1, pt, have_sema, sema);
147 try print(Value.fromInterned(slice.len), writer, level - 1, pt, opt_sema);
150148 }
151149 try writer.writeAll("]");
152150 },
......@@ -160,13 +158,13 @@ pub fn print(
160158 // TODO: eventually we want to load the pointer with `sema`, but that's
161159 // currently not possible without e.g. triggering compile errors.
162160 }
163 try printPtr(val, writer, level, pt, have_sema, sema);
161 try printPtr(val, .rvalue, writer, level, pt, opt_sema);
164162 },
165163 .opt => |opt| switch (opt.val) {
166164 .none => try writer.writeAll("null"),
167 else => |payload| try print(Value.fromInterned(payload), writer, level, pt, have_sema, sema),
165 else => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema),
168166 },
169 .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, pt, have_sema, sema),
167 .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, pt, opt_sema),
170168 .un => |un| {
171169 if (level == 0) {
172170 try writer.writeAll(".{ ... }");
......@@ -175,13 +173,13 @@ pub fn print(
175173 if (un.tag == .none) {
176174 const backing_ty = try val.typeOf(zcu).unionBackingType(pt);
177175 try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(pt)});
178 try print(Value.fromInterned(un.val), writer, level - 1, pt, have_sema, sema);
176 try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema);
179177 try writer.writeAll("))");
180178 } else {
181179 try writer.writeAll(".{ ");
182 try print(Value.fromInterned(un.tag), writer, level - 1, pt, have_sema, sema);
180 try print(Value.fromInterned(un.tag), writer, level - 1, pt, opt_sema);
183181 try writer.writeAll(" = ");
184 try print(Value.fromInterned(un.val), writer, level - 1, pt, have_sema, sema);
182 try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema);
185183 try writer.writeAll(" }");
186184 }
187185 },
......@@ -196,8 +194,7 @@ fn printAggregate(
196194 writer: anytype,
197195 level: u8,
198196 pt: Zcu.PerThread,
199 comptime have_sema: bool,
200 sema: if (have_sema) *Sema else void,
197 opt_sema: ?*Sema,
201198) (@TypeOf(writer).Error || Zcu.CompileError)!void {
202199 if (level == 0) {
203200 if (is_ref) try writer.writeByte('&');
......@@ -218,7 +215,7 @@ fn printAggregate(
218215 if (i != 0) try writer.writeAll(", ");
219216 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
220217 try writer.print(".{i} = ", .{field_name.fmt(ip)});
221 try print(try val.fieldValue(pt, i), writer, level - 1, pt, have_sema, sema);
218 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
222219 }
223220 try writer.writeAll(" }");
224221 return;
......@@ -268,7 +265,7 @@ fn printAggregate(
268265 const max_len = @min(len, max_aggregate_items);
269266 for (0..max_len) |i| {
270267 if (i != 0) try writer.writeAll(", ");
271 try print(try val.fieldValue(pt, i), writer, level - 1, pt, have_sema, sema);
268 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
272269 }
273270 if (len > max_aggregate_items) {
274271 try writer.writeAll(", ...");
......@@ -278,11 +275,12 @@ fn printAggregate(
278275
279276fn printPtr(
280277 ptr_val: Value,
278 /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen.
279 want_kind: ?PrintPtrKind,
281280 writer: anytype,
282281 level: u8,
283282 pt: Zcu.PerThread,
284 comptime have_sema: bool,
285 sema: if (have_sema) *Sema else void,
283 opt_sema: ?*Sema,
286284) (@TypeOf(writer).Error || Zcu.CompileError)!void {
287285 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
288286 .undef => return writer.writeAll("undefined"),
......@@ -300,8 +298,7 @@ fn printPtr(
300298 writer,
301299 level,
302300 pt,
303 have_sema,
304 sema,
301 opt_sema,
305302 ),
306303 else => {},
307304 }
......@@ -309,57 +306,96 @@ fn printPtr(
309306
310307 var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);
311308 defer arena.deinit();
312 const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, have_sema, sema);
313 try printPtrDerivation(derivation, writer, level, pt, have_sema, sema);
309 const derivation = if (opt_sema) |sema|
310 try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, true, sema)
311 else
312 try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, false, null);
313
314 _ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{
315 .level = level,
316 .opt_sema = opt_sema,
317 } }, 20);
314318}
315319
316/// Print `derivation` as an lvalue, i.e. such that writing `&` before this gives the pointer value.
317fn printPtrDerivation(
320const PrintPtrKind = enum { lvalue, rvalue };
321
322/// Print the pointer defined by `derivation` as an lvalue or an rvalue.
323/// Returns the root derivation, which may be ignored.
324pub fn printPtrDerivation(
318325 derivation: Value.PointerDeriveStep,
319326 writer: anytype,
320 level: u8,
321327 pt: Zcu.PerThread,
322 comptime have_sema: bool,
323 sema: if (have_sema) *Sema else void,
324) (@TypeOf(writer).Error || Zcu.CompileError)!void {
328 /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen.
329 /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as
330 /// an atom -- e.g. `&foo.*` is distinct from `(&foo).*`.
331 want_kind: ?PrintPtrKind,
332 /// How to print the "root" of the derivation. `.print_val` will recursively print other values if needed,
333 /// e.g. for UAV refs. `.str` will just write the root as the given string.
334 root_strat: union(enum) {
335 str: []const u8,
336 print_val: struct {
337 level: u8,
338 opt_sema: ?*Sema,
339 },
340 },
341 /// The maximum recursion depth. We can never recurse infinitely here, but the depth can be arbitrary,
342 /// so at this depth we just write "..." to prevent stack overflow.
343 ptr_depth: u8,
344) !Value.PointerDeriveStep {
325345 const zcu = pt.zcu;
326346 const ip = &zcu.intern_pool;
327 switch (derivation) {
328 .int => |int| try writer.print("@as({}, @ptrFromInt({x})).*", .{
329 int.ptr_ty.fmt(pt),
330 int.addr,
331 }),
332 .nav_ptr => |nav| {
333 try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)});
334 },
335 .uav_ptr => |uav| {
336 const ty = Value.fromInterned(uav.val).typeOf(zcu);
337 try writer.print("@as({}, ", .{ty.fmt(pt)});
338 try print(Value.fromInterned(uav.val), writer, level - 1, pt, have_sema, sema);
339 try writer.writeByte(')');
340 },
341 .comptime_alloc_ptr => |info| {
342 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)});
343 try print(info.val, writer, level - 1, pt, have_sema, sema);
344 try writer.writeByte(')');
345 },
346 .comptime_field_ptr => |val| {
347 const ty = val.typeOf(zcu);
348 try writer.print("@as({}, ", .{ty.fmt(pt)});
349 try print(val, writer, level - 1, pt, have_sema, sema);
350 try writer.writeByte(')');
351 },
352 .eu_payload_ptr => |info| {
347
348 if (ptr_depth == 0) {
349 const root_step = root: switch (derivation) {
350 inline .eu_payload_ptr,
351 .opt_payload_ptr,
352 .field_ptr,
353 .elem_ptr,
354 .offset_and_cast,
355 => |step| continue :root step.parent.*,
356 else => |step| break :root step,
357 };
358 try writer.writeAll("...");
359 return root_step;
360 }
361
362 const result_kind: PrintPtrKind = switch (derivation) {
363 .nav_ptr,
364 .uav_ptr,
365 .comptime_alloc_ptr,
366 .comptime_field_ptr,
367 .eu_payload_ptr,
368 .opt_payload_ptr,
369 .field_ptr,
370 .elem_ptr,
371 => .lvalue,
372
373 .offset_and_cast,
374 .int,
375 => .rvalue,
376 };
377
378 const need_kind = want_kind orelse result_kind;
379
380 if (need_kind == .rvalue and result_kind == .lvalue) {
381 try writer.writeByte('&');
382 }
383
384 // null if `derivation` is the root.
385 const root_or_null: ?Value.PointerDeriveStep = switch (derivation) {
386 .eu_payload_ptr => |info| root: {
353387 try writer.writeByte('(');
354 try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema);
388 const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1);
355389 try writer.writeAll(" catch unreachable)");
390 break :root root;
356391 },
357 .opt_payload_ptr => |info| {
358 try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema);
392 .opt_payload_ptr => |info| root: {
393 const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1);
359394 try writer.writeAll(".?");
395 break :root root;
360396 },
361 .field_ptr => |field| {
362 try printPtrDerivation(field.parent.*, writer, level, pt, have_sema, sema);
397 .field_ptr => |field| root: {
398 const root = try printPtrDerivation(field.parent.*, writer, pt, null, root_strat, ptr_depth - 1);
363399 const agg_ty = (try field.parent.ptrType(pt)).childType(zcu);
364400 switch (agg_ty.zigTypeTag(zcu)) {
365401 .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {
......@@ -379,19 +415,58 @@ fn printPtrDerivation(
379415 },
380416 else => unreachable,
381417 }
418 break :root root;
382419 },
383 .elem_ptr => |elem| {
384 try printPtrDerivation(elem.parent.*, writer, level, pt, have_sema, sema);
420 .elem_ptr => |elem| root: {
421 const root = try printPtrDerivation(elem.parent.*, writer, pt, null, root_strat, ptr_depth - 1);
385422 try writer.print("[{d}]", .{elem.elem_idx});
423 break :root root;
386424 },
387 .offset_and_cast => |oac| if (oac.byte_offset == 0) {
425
426 .offset_and_cast => |oac| if (oac.byte_offset == 0) root: {
388427 try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)});
389 try printPtrDerivation(oac.parent.*, writer, level, pt, have_sema, sema);
428 const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1);
390429 try writer.writeAll("))");
391 } else {
430 break :root root;
431 } else root: {
392432 try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)});
393 try printPtrDerivation(oac.parent.*, writer, level, pt, have_sema, sema);
433 const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1);
394434 try writer.print(") + {d}))", .{oac.byte_offset});
435 break :root root;
395436 },
437
438 .int, .nav_ptr, .uav_ptr, .comptime_alloc_ptr, .comptime_field_ptr => null,
439 };
440
441 if (root_or_null == null) switch (root_strat) {
442 .str => |x| try writer.writeAll(x),
443 .print_val => |x| switch (derivation) {
444 .int => |int| try writer.print("@as({}, @ptrFromInt(0x{x}))", .{ int.ptr_ty.fmt(pt), int.addr }),
445 .nav_ptr => |nav| try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)}),
446 .uav_ptr => |uav| {
447 const ty = Value.fromInterned(uav.val).typeOf(zcu);
448 try writer.print("@as({}, ", .{ty.fmt(pt)});
449 try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema);
450 try writer.writeByte(')');
451 },
452 .comptime_alloc_ptr => |info| {
453 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)});
454 try print(info.val, writer, x.level - 1, pt, x.opt_sema);
455 try writer.writeByte(')');
456 },
457 .comptime_field_ptr => |val| {
458 const ty = val.typeOf(zcu);
459 try writer.print("@as({}, ", .{ty.fmt(pt)});
460 try print(val, writer, x.level - 1, pt, x.opt_sema);
461 try writer.writeByte(')');
462 },
463 else => unreachable,
464 },
465 };
466
467 if (need_kind == .lvalue and result_kind == .rvalue) {
468 try writer.writeAll(".*");
396469 }
470
471 return root_or_null orelse derivation;
397472}
src/print_zir.zig+28-52
......@@ -1430,19 +1430,8 @@ const Writer = struct {
14301430
14311431 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
14321432
1433 if (captures_len == 0) {
1434 try stream.writeAll("{}, ");
1435 } else {
1436 try stream.writeAll("{ ");
1437 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1438 extra_index += 1;
1439 for (1..captures_len) |_| {
1440 try stream.writeAll(", ");
1441 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1442 extra_index += 1;
1443 }
1444 try stream.writeAll(" }, ");
1445 }
1433 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1434 try stream.writeAll(", ");
14461435
14471436 if (small.has_backing_int) {
14481437 const backing_int_body_len = self.code.extra[extra_index];
......@@ -1645,19 +1634,8 @@ const Writer = struct {
16451634 });
16461635 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
16471636
1648 if (captures_len == 0) {
1649 try stream.writeAll("{}, ");
1650 } else {
1651 try stream.writeAll("{ ");
1652 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1653 extra_index += 1;
1654 for (1..captures_len) |_| {
1655 try stream.writeAll(", ");
1656 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1657 extra_index += 1;
1658 }
1659 try stream.writeAll(" }, ");
1660 }
1637 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1638 try stream.writeAll(", ");
16611639
16621640 if (decls_len == 0) {
16631641 try stream.writeAll("{}");
......@@ -1805,19 +1783,8 @@ const Writer = struct {
18051783 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
18061784 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
18071785
1808 if (captures_len == 0) {
1809 try stream.writeAll("{}, ");
1810 } else {
1811 try stream.writeAll("{ ");
1812 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1813 extra_index += 1;
1814 for (1..captures_len) |_| {
1815 try stream.writeAll(", ");
1816 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1817 extra_index += 1;
1818 }
1819 try stream.writeAll(" }, ");
1820 }
1786 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1787 try stream.writeAll(", ");
18211788
18221789 if (decls_len == 0) {
18231790 try stream.writeAll("{}, ");
......@@ -1910,19 +1877,8 @@ const Writer = struct {
19101877
19111878 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
19121879
1913 if (captures_len == 0) {
1914 try stream.writeAll("{}, ");
1915 } else {
1916 try stream.writeAll("{ ");
1917 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1918 extra_index += 1;
1919 for (1..captures_len) |_| {
1920 try stream.writeAll(", ");
1921 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1922 extra_index += 1;
1923 }
1924 try stream.writeAll(" }, ");
1925 }
1880 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1881 try stream.writeAll(", ");
19261882
19271883 if (decls_len == 0) {
19281884 try stream.writeAll("{}) ");
......@@ -2720,6 +2676,26 @@ const Writer = struct {
27202676 return stream.print("%{d}", .{@intFromEnum(inst)});
27212677 }
27222678
2679 fn writeCaptures(self: *Writer, stream: anytype, extra_index: usize, captures_len: u32) !usize {
2680 if (captures_len == 0) {
2681 try stream.writeAll("{}");
2682 return extra_index;
2683 }
2684
2685 const captures: []const Zir.Inst.Capture = @ptrCast(self.code.extra[extra_index..][0..captures_len]);
2686 const capture_names: []const Zir.NullTerminatedString = @ptrCast(self.code.extra[extra_index + captures_len ..][0..captures_len]);
2687 for (captures, capture_names) |capture, name| {
2688 try stream.writeAll("{ ");
2689 if (name != .empty) {
2690 const name_slice = self.code.nullTerminatedString(name);
2691 try stream.print("{s} = ", .{name_slice});
2692 }
2693 try self.writeCapture(stream, capture);
2694 }
2695
2696 return extra_index + 2 * captures_len;
2697 }
2698
27232699 fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void {
27242700 switch (capture.unwrap()) {
27252701 .nested => |i| return stream.print("[{d}]", .{i}),
test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig+1-3
......@@ -3,10 +3,8 @@ export fn entry() void {
33}
44
55// error
6// backend=stage2
7// target=native
86//
97// :2:5: error: found compile log statement
108//
119// Compile Log Output:
12// @as(*const anyopaque, @as(*const anyopaque, @ptrCast(tmp.entry)))
10// @as(*const anyopaque, @as(*const anyopaque, @ptrCast(&tmp.entry)))
test/cases/compile_errors/comptime_var_referenced_at_runtime.zig+9
......@@ -67,19 +67,28 @@ export fn far() void {
6767//
6868// :5:19: error: runtime value contains reference to comptime var
6969// :5:19: note: comptime var pointers are not available at runtime
70// :4:27: note: 'runtime_value' points to comptime var declared here
7071// :12:40: error: runtime value contains reference to comptime var
7172// :12:40: note: comptime var pointers are not available at runtime
73// :11:27: note: 'runtime_value' points to comptime var declared here
7274// :19:50: error: runtime value contains reference to comptime var
7375// :19:50: note: comptime var pointers are not available at runtime
76// :18:27: note: 'runtime_value' points to comptime var declared here
7477// :28:9: error: runtime value contains reference to comptime var
7578// :28:9: note: comptime var pointers are not available at runtime
79// :27:27: note: 'runtime_value' points to comptime var declared here
7680// :36:9: error: runtime value contains reference to comptime var
7781// :36:9: note: comptime var pointers are not available at runtime
82// :35:27: note: 'runtime_value' points to comptime var declared here
7883// :41:12: error: runtime value contains reference to comptime var
7984// :41:12: note: comptime var pointers are not available at runtime
85// :40:27: note: 'runtime_value' points to comptime var declared here
8086// :46:39: error: runtime value contains reference to comptime var
8187// :46:39: note: comptime var pointers are not available at runtime
88// :45:27: note: 'runtime_value' points to comptime var declared here
8289// :55:18: error: runtime value contains reference to comptime var
8390// :55:18: note: comptime var pointers are not available at runtime
91// :51:30: note: 'runtime_value' points to comptime var declared here
8492// :63:18: error: runtime value contains reference to comptime var
8593// :63:18: note: comptime var pointers are not available at runtime
94// :59:27: note: 'runtime_value' points to comptime var declared here
test/cases/compile_errors/comptime_var_referenced_by_decl.zig+9
......@@ -47,10 +47,19 @@ export var h: *[1]u32 = h: {
4747// error
4848//
4949// :1:27: error: global variable contains reference to comptime var
50// :2:18: note: 'a' points to comptime var declared here
5051// :6:30: error: global variable contains reference to comptime var
52// :7:18: note: 'b[0]' points to comptime var declared here
5153// :11:30: error: global variable contains reference to comptime var
54// :12:18: note: 'c' points to comptime var declared here
5255// :16:33: error: global variable contains reference to comptime var
56// :17:18: note: 'd' points to comptime var declared here
5357// :22:24: error: global variable contains reference to comptime var
58// :23:18: note: 'e.ptr' points to comptime var declared here
5459// :28:33: error: global variable contains reference to comptime var
60// :29:18: note: 'f' points to comptime var declared here
5561// :34:40: error: global variable contains reference to comptime var
62// :34:40: note: 'g' points to 'v0[0]', where
63// :36:24: note: 'v0[1]' points to comptime var declared here
5664// :42:28: error: global variable contains reference to comptime var
65// :43:22: note: 'h' points to comptime var declared here
test/cases/compile_errors/comptime_var_referenced_by_type.zig created+25
......@@ -0,0 +1,25 @@
1const Wrapper = struct { ptr: *ComptimeThing };
2
3const ComptimeThing = struct {
4 x: comptime_int,
5 fn NewType(comptime ct: *ComptimeThing) type {
6 const wrapper: Wrapper = .{ .ptr = ct };
7 return struct {
8 pub fn foo() void {
9 _ = wrapper.ct;
10 }
11 };
12 }
13};
14
15comptime {
16 var ct: ComptimeThing = .{ .x = 123 };
17 const Inner = ct.NewType();
18 Inner.foo();
19}
20
21// error
22//
23// :7:16: error: captured value contains reference to comptime var
24// :16:30: note: 'wrapper.ptr' points to comptime var declared here
25// :17:29: note: called from here
test/cases/comptime_aggregate_print.zig+2-2
......@@ -31,5 +31,5 @@ pub fn main() !void {}
3131// :20:5: error: found compile log statement
3232//
3333// Compile Log Output:
34// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).buf[0]))[0..2])
35// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf[0]))[0..2])
34// @as([]i32, @as([*]i32, @ptrCast(&@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).buf))[0..2])
35// @as([]i32, @as([*]i32, @ptrCast(&@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf))[0..2])