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(...@@ -5315,8 +5315,9 @@ fn structDeclInner(
5315 const fields_slice = wip_members.fieldsSlice();5315 const fields_slice = wip_members.fieldsSlice();
5316 const bodies_slice = astgen.scratch.items[bodies_start..];5316 const bodies_slice = astgen.scratch.items[bodies_start..];
5317 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +5317 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);
5319 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));5319 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5320 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5320 if (backing_int_ref != .none) {5321 if (backing_int_ref != .none) {
5321 astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));5322 astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));
5322 if (backing_int_body_len == 0) {5323 if (backing_int_body_len == 0) {
...@@ -5595,8 +5596,9 @@ fn unionDeclInner(...@@ -5595,8 +5596,9 @@ fn unionDeclInner(
5595 wip_members.finishBits(bits_per_field);5596 wip_members.finishBits(bits_per_field);
5596 const decls_slice = wip_members.declsSlice();5597 const decls_slice = wip_members.declsSlice();
5597 const fields_slice = wip_members.fieldsSlice();5598 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);
5599 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));5600 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5601 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5600 astgen.extra.appendSliceAssumeCapacity(decls_slice);5602 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5601 astgen.appendBodyWithFixups(body);5603 astgen.appendBodyWithFixups(body);
5602 astgen.extra.appendSliceAssumeCapacity(fields_slice);5604 astgen.extra.appendSliceAssumeCapacity(fields_slice);
...@@ -5855,8 +5857,9 @@ fn containerDecl(...@@ -5855,8 +5857,9 @@ fn containerDecl(
5855 wip_members.finishBits(bits_per_field);5857 wip_members.finishBits(bits_per_field);
5856 const decls_slice = wip_members.declsSlice();5858 const decls_slice = wip_members.declsSlice();
5857 const fields_slice = wip_members.fieldsSlice();5859 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);
5859 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));5861 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5862 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5860 astgen.extra.appendSliceAssumeCapacity(decls_slice);5863 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5861 astgen.appendBodyWithFixups(body);5864 astgen.appendBodyWithFixups(body);
5862 astgen.extra.appendSliceAssumeCapacity(fields_slice);5865 astgen.extra.appendSliceAssumeCapacity(fields_slice);
...@@ -5910,8 +5913,9 @@ fn containerDecl(...@@ -5910,8 +5913,9 @@ fn containerDecl(
59105913
5911 wip_members.finishBits(0);5914 wip_members.finishBits(0);
5912 const decls_slice = wip_members.declsSlice();5915 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);
5914 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));5917 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5918 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5915 astgen.extra.appendSliceAssumeCapacity(decls_slice);5919 astgen.extra.appendSliceAssumeCapacity(decls_slice);
59165920
5917 block_scope.unstack();5921 block_scope.unstack();
...@@ -8548,6 +8552,7 @@ fn localVarRef(...@@ -8548,6 +8552,7 @@ fn localVarRef(
8548 num_namespaces_out,8552 num_namespaces_out,
8549 .{ .ref = local_val.inst },8553 .{ .ref = local_val.inst },
8550 .{ .token = local_val.token_src },8554 .{ .token = local_val.token_src },
8555 name_str_index,
8551 ) else local_val.inst;8556 ) else local_val.inst;
85528557
8553 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);8558 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
...@@ -8580,6 +8585,7 @@ fn localVarRef(...@@ -8580,6 +8585,7 @@ fn localVarRef(
8580 num_namespaces_out,8585 num_namespaces_out,
8581 .{ .ref = local_ptr.ptr },8586 .{ .ref = local_ptr.ptr },
8582 .{ .token = local_ptr.token_src },8587 .{ .token = local_ptr.token_src },
8588 name_str_index,
8583 ) else local_ptr.ptr;8589 ) else local_ptr.ptr;
8584 local_ptr.used_as_lvalue = true;8590 local_ptr.used_as_lvalue = true;
8585 return ptr_inst;8591 return ptr_inst;
...@@ -8591,6 +8597,7 @@ fn localVarRef(...@@ -8591,6 +8597,7 @@ fn localVarRef(
8591 num_namespaces_out,8597 num_namespaces_out,
8592 .{ .ref_load = local_ptr.ptr },8598 .{ .ref_load = local_ptr.ptr },
8593 .{ .token = local_ptr.token_src },8599 .{ .token = local_ptr.token_src },
8600 name_str_index,
8594 ) else try gz.addUnNode(.load, local_ptr.ptr, ident);8601 ) else try gz.addUnNode(.load, local_ptr.ptr, ident);
8595 return rvalueNoCoercePreRef(gz, ri, val_inst, ident);8602 return rvalueNoCoercePreRef(gz, ri, val_inst, ident);
8596 },8603 },
...@@ -8636,6 +8643,7 @@ fn localVarRef(...@@ -8636,6 +8643,7 @@ fn localVarRef(
8636 found_namespaces_out,8643 found_namespaces_out,
8637 .{ .decl_ref = name_str_index },8644 .{ .decl_ref = name_str_index },
8638 .{ .node = found_already.? },8645 .{ .node = found_already.? },
8646 name_str_index,
8639 ),8647 ),
8640 else => {8648 else => {
8641 const result = try tunnelThroughClosure(8649 const result = try tunnelThroughClosure(
...@@ -8644,6 +8652,7 @@ fn localVarRef(...@@ -8644,6 +8652,7 @@ fn localVarRef(
8644 found_namespaces_out,8652 found_namespaces_out,
8645 .{ .decl_val = name_str_index },8653 .{ .decl_val = name_str_index },
8646 .{ .node = found_already.? },8654 .{ .node = found_already.? },
8655 name_str_index,
8647 );8656 );
8648 return rvalueNoCoercePreRef(gz, ri, result, ident);8657 return rvalueNoCoercePreRef(gz, ri, result, ident);
8649 },8658 },
...@@ -8680,6 +8689,7 @@ fn tunnelThroughClosure(...@@ -8680,6 +8689,7 @@ fn tunnelThroughClosure(
8680 token: Ast.TokenIndex,8689 token: Ast.TokenIndex,
8681 node: Ast.Node.Index,8690 node: Ast.Node.Index,
8682 },8691 },
8692 name_str_index: Zir.NullTerminatedString,
8683) !Zir.Inst.Ref {8693) !Zir.Inst.Ref {
8684 switch (value) {8694 switch (value) {
8685 .ref => |v| if (v.toIndex() == null) return v, // trivial value; do not need tunnel8695 .ref => |v| if (v.toIndex() == null) return v, // trivial value; do not need tunnel
...@@ -8714,34 +8724,43 @@ fn tunnelThroughClosure(...@@ -8714,34 +8724,43 @@ fn tunnelThroughClosure(
87148724
8715 // Now that we know the scopes we're tunneling through, begin adding8725 // Now that we know the scopes we're tunneling through, begin adding
8716 // captures as required, starting with the outermost namespace.8726 // 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) {
8718 .ref => |v| .{ .instruction = v.toIndex().? },8728 .ref => |v| .{ .instruction = v.toIndex().? },
8719 .ref_load => |v| .{ .instruction_load = v.toIndex().? },8729 .ref_load => |v| .{ .instruction_load = v.toIndex().? },
8720 .decl_val => |str| .{ .decl_val = str },8730 .decl_val => |str| .{ .decl_val = str },
8721 .decl_ref => |str| .{ .decl_ref = str },8731 .decl_ref => |str| .{ .decl_ref = str },
8722 });8732 });
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| {8734 const root_gop = try root_ns.captures.getOrPut(gpa, root_capture);
8735 cur_capture_index = std.math.cast(8735 root_gop.value_ptr.* = name_str_index;
8736 u16,8736 var cur_capture_index = std.math.cast(u16, root_gop.index) orelse return astgen.failNodeNotes(
8737 (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index,8737 root_ns.node,
8738 ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{8738 "this compiler implementation only supports up to 65536 captures per namespace",
8739 .{},
8740 &.{
8739 switch (decl_src) {8741 switch (decl_src) {
8740 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),8742 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
8741 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),8743 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
8742 },8744 },
8743 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),8745 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 );
8745 }8764 }
87468765
8747 // Incorporate the capture index into the source hash, so that changes in8766 // Incorporate the capture index into the source hash, so that changes in
...@@ -11920,7 +11939,7 @@ const Scope = struct {...@@ -11920,7 +11939,7 @@ const Scope = struct {
11920 declaring_gz: ?*GenZir,11939 declaring_gz: ?*GenZir,
1192111940
11922 /// Set of captures used by this namespace.11941 /// 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
11925 fn deinit(self: *Namespace, gpa: Allocator) void {11944 fn deinit(self: *Namespace, gpa: Allocator) void {
11926 self.decls.deinit(gpa);11945 self.decls.deinit(gpa);
lib/std/zig/Zir.zig+27-23
...@@ -3284,24 +3284,25 @@ pub const Inst = struct {...@@ -3284,24 +3284,25 @@ pub const Inst = struct {
3284 /// 1. fields_len: u32, // if has_fields_len3284 /// 1. fields_len: u32, // if has_fields_len
3285 /// 2. decls_len: u32, // if has_decls_len3285 /// 2. decls_len: u32, // if has_decls_len
3286 /// 3. capture: Capture // for every captures_len3286 /// 3. capture: Capture // for every captures_len
3287 /// 4. backing_int_body_len: u32, // if has_backing_int3287 /// 4. capture_name: NullTerminatedString // for every captures_len
3288 /// 5. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 03288 /// 5. backing_int_body_len: u32, // if has_backing_int
3289 /// 6. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 03289 /// 6. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3290 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction3290 /// 7. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3291 /// 8. flags: u32 // for every 8 fields3291 /// 8. decl: Index, // for every decls_len; points to a `declaration` instruction
3292 /// 9. flags: u32 // for every 8 fields
3292 /// - sets of 4 bits:3293 /// - sets of 4 bits:
3293 /// 0b000X: whether corresponding field has an align expression3294 /// 0b000X: whether corresponding field has an align expression
3294 /// 0b00X0: whether corresponding field has a default expression3295 /// 0b00X0: whether corresponding field has a default expression
3295 /// 0b0X00: whether corresponding field is comptime3296 /// 0b0X00: whether corresponding field is comptime
3296 /// 0bX000: whether corresponding field has a type expression3297 /// 0bX000: whether corresponding field has a type expression
3297 /// 9. fields: { // for every fields_len3298 /// 10. fields: { // for every fields_len
3298 /// field_name: u32,3299 /// field_name: u32,
3299 /// field_type: Ref, // if corresponding bit is not set. none means anytype.3300 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
3300 /// field_type_body_len: u32, // if corresponding bit is set3301 /// field_type_body_len: u32, // if corresponding bit is set
3301 /// align_body_len: u32, // if corresponding bit is set3302 /// align_body_len: u32, // if corresponding bit is set
3302 /// init_body_len: u32, // if corresponding bit is set3303 /// init_body_len: u32, // if corresponding bit is set
3303 /// }3304 /// }
3304 /// 10. bodies: { // for every fields_len3305 /// 11. bodies: { // for every fields_len
3305 /// field_type_body_inst: Inst, // for each field_type_body_len3306 /// field_type_body_inst: Inst, // for each field_type_body_len
3306 /// align_body_inst: Inst, // for each align_body_len3307 /// align_body_inst: Inst, // for each align_body_len
3307 /// init_body_inst: Inst, // for each init_body_len3308 /// init_body_inst: Inst, // for each init_body_len
...@@ -3450,11 +3451,12 @@ pub const Inst = struct {...@@ -3450,11 +3451,12 @@ pub const Inst = struct {
3450 /// 3. fields_len: u32, // if has_fields_len3451 /// 3. fields_len: u32, // if has_fields_len
3451 /// 4. decls_len: u32, // if has_decls_len3452 /// 4. decls_len: u32, // if has_decls_len
3452 /// 5. capture: Capture // for every captures_len3453 /// 5. capture: Capture // for every captures_len
3453 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction3454 /// 6. capture_name: NullTerminatedString // for every captures_len
3454 /// 7. inst: Index // for every body_len3455 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3455 /// 8. has_bits: u32 // for every 32 fields3456 /// 8. inst: Index // for every body_len
3457 /// 9. has_bits: u32 // for every 32 fields
3456 /// - the bit is whether corresponding field has an value expression3458 /// - the bit is whether corresponding field has an value expression
3457 /// 9. fields: { // for every fields_len3459 /// 10. fields: { // for every fields_len
3458 /// field_name: u32,3460 /// field_name: u32,
3459 /// value: Ref, // if corresponding bit is set3461 /// value: Ref, // if corresponding bit is set
3460 /// }3462 /// }
...@@ -3488,15 +3490,16 @@ pub const Inst = struct {...@@ -3488,15 +3490,16 @@ pub const Inst = struct {
3488 /// 3. fields_len: u32, // if has_fields_len3490 /// 3. fields_len: u32, // if has_fields_len
3489 /// 4. decls_len: u32, // if has_decls_len3491 /// 4. decls_len: u32, // if has_decls_len
3490 /// 5. capture: Capture // for every captures_len3492 /// 5. capture: Capture // for every captures_len
3491 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction3493 /// 6. capture_name: NullTerminatedString // for every captures_len
3492 /// 7. inst: Index // for every body_len3494 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3493 /// 8. has_bits: u32 // for every 8 fields3495 /// 8. inst: Index // for every body_len
3496 /// 9. has_bits: u32 // for every 8 fields
3494 /// - sets of 4 bits:3497 /// - sets of 4 bits:
3495 /// 0b000X: whether corresponding field has a type expression3498 /// 0b000X: whether corresponding field has a type expression
3496 /// 0b00X0: whether corresponding field has a align expression3499 /// 0b00X0: whether corresponding field has a align expression
3497 /// 0b0X00: whether corresponding field has a tag value expression3500 /// 0b0X00: whether corresponding field has a tag value expression
3498 /// 0bX000: unused3501 /// 0bX000: unused
3499 /// 9. fields: { // for every fields_len3502 /// 10. fields: { // for every fields_len
3500 /// field_name: NullTerminatedString, // null terminated string index3503 /// field_name: NullTerminatedString, // null terminated string index
3501 /// field_type: Ref, // if corresponding bit is set3504 /// field_type: Ref, // if corresponding bit is set
3502 /// align: Ref, // if corresponding bit is set3505 /// align: Ref, // if corresponding bit is set
...@@ -3537,7 +3540,8 @@ pub const Inst = struct {...@@ -3537,7 +3540,8 @@ pub const Inst = struct {
3537 /// 0. captures_len: u32, // if has_captures_len3540 /// 0. captures_len: u32, // if has_captures_len
3538 /// 1. decls_len: u32, // if has_decls_len3541 /// 1. decls_len: u32, // if has_decls_len
3539 /// 2. capture: Capture, // for every captures_len3542 /// 2. capture: Capture, // for every captures_len
3540 /// 3. decl: Index, // for every decls_len; points to a `declaration` instruction3543 /// 3. capture_name: NullTerminatedString // for every captures_len
3544 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
3541 pub const OpaqueDecl = struct {3545 pub const OpaqueDecl = struct {
3542 src_line: u32,3546 src_line: u32,
3543 /// This node provides a new absolute baseline node for all instructions within this struct.3547 /// 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 {...@@ -3852,7 +3856,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3852 break :decls_len decls_len;3856 break :decls_len decls_len;
3853 } else 0;3857 } else 0;
38543858
3855 extra_index += captures_len;3859 extra_index += captures_len * 2;
38563860
3857 if (small.has_backing_int) {3861 if (small.has_backing_int) {
3858 const backing_int_body_len = zir.extra[extra_index];3862 const backing_int_body_len = zir.extra[extra_index];
...@@ -3887,7 +3891,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3887,7 +3891,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3887 break :decls_len decls_len;3891 break :decls_len decls_len;
3888 } else 0;3892 } else 0;
38893893
3890 extra_index += captures_len;3894 extra_index += captures_len * 2;
38913895
3892 return .{3896 return .{
3893 .extra_index = extra_index,3897 .extra_index = extra_index,
...@@ -3912,7 +3916,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3912,7 +3916,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3912 break :decls_len decls_len;3916 break :decls_len decls_len;
3913 } else 0;3917 } else 0;
39143918
3915 extra_index += captures_len;3919 extra_index += captures_len * 2;
39163920
3917 return .{3921 return .{
3918 .extra_index = extra_index,3922 .extra_index = extra_index,
...@@ -3934,7 +3938,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3934,7 +3938,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3934 break :captures_len captures_len;3938 break :captures_len captures_len;
3935 } else 0;3939 } else 0;
39363940
3937 extra_index += captures_len;3941 extra_index += captures_len * 2;
39383942
3939 return .{3943 return .{
3940 .extra_index = extra_index,3944 .extra_index = extra_index,
...@@ -4349,7 +4353,7 @@ fn findTrackableInner(...@@ -4349,7 +4353,7 @@ fn findTrackableInner(
4349 extra_index += 1;4353 extra_index += 1;
4350 break :blk decls_len;4354 break :blk decls_len;
4351 } else 0;4355 } else 0;
4352 extra_index += captures_len;4356 extra_index += captures_len * 2;
4353 if (small.has_backing_int) {4357 if (small.has_backing_int) {
4354 const backing_int_body_len = zir.extra[extra_index];4358 const backing_int_body_len = zir.extra[extra_index];
4355 extra_index += 1;4359 extra_index += 1;
...@@ -4441,7 +4445,7 @@ fn findTrackableInner(...@@ -4441,7 +4445,7 @@ fn findTrackableInner(
4441 extra_index += 1;4445 extra_index += 1;
4442 break :blk decls_len;4446 break :blk decls_len;
4443 } else 0;4447 } else 0;
4444 extra_index += captures_len;4448 extra_index += captures_len * 2;
4445 extra_index += decls_len;4449 extra_index += decls_len;
4446 const body = zir.bodySlice(extra_index, body_len);4450 const body = zir.bodySlice(extra_index, body_len);
4447 try zir.findTrackableBody(gpa, contents, defers, body);4451 try zir.findTrackableBody(gpa, contents, defers, body);
...@@ -4471,7 +4475,7 @@ fn findTrackableInner(...@@ -4471,7 +4475,7 @@ fn findTrackableInner(
4471 extra_index += 1;4475 extra_index += 1;
4472 break :blk decls_len;4476 break :blk decls_len;
4473 } else 0;4477 } else 0;
4474 extra_index += captures_len;4478 extra_index += captures_len * 2;
4475 extra_index += decls_len;4479 extra_index += decls_len;
4476 const body = zir.bodySlice(extra_index, body_len);4480 const body = zir.bodySlice(extra_index, body_len);
4477 try zir.findTrackableBody(gpa, contents, defers, body);4481 try zir.findTrackableBody(gpa, contents, defers, body);
src/Sema.zig+224-36
...@@ -134,6 +134,7 @@ const MaybeComptimeAlloc = struct {...@@ -134,6 +134,7 @@ const MaybeComptimeAlloc = struct {
134const ComptimeAlloc = struct {134const ComptimeAlloc = struct {
135 val: MutableValue,135 val: MutableValue,
136 is_const: bool,136 is_const: bool,
137 src: LazySrcLoc,
137 /// `.none` indicates that the alignment is the natural alignment of `val`.138 /// `.none` indicates that the alignment is the natural alignment of `val`.
138 alignment: Alignment,139 alignment: Alignment,
139 /// This is the `runtime_index` at the point of this allocation. If an store140 /// This is the `runtime_index` at the point of this allocation. If an store
...@@ -142,11 +143,13 @@ const ComptimeAlloc = struct {...@@ -142,11 +143,13 @@ const ComptimeAlloc = struct {
142 runtime_index: RuntimeIndex,143 runtime_index: RuntimeIndex,
143};144};
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 {
146 const idx = sema.comptime_allocs.items.len;148 const idx = sema.comptime_allocs.items.len;
147 try sema.comptime_allocs.append(sema.gpa, .{149 try sema.comptime_allocs.append(sema.gpa, .{
148 .val = .{ .interned = try sema.pt.intern(.{ .undef = ty.toIntern() }) },150 .val = .{ .interned = try sema.pt.intern(.{ .undef = ty.toIntern() }) },
149 .is_const = false,151 .is_const = false,
152 .src = src,
150 .alignment = alignment,153 .alignment = alignment,
151 .runtime_index = block.runtime_index,154 .runtime_index = block.runtime_index,
152 });155 });
...@@ -1308,7 +1311,7 @@ fn analyzeBodyInner(...@@ -1308,7 +1311,7 @@ fn analyzeBodyInner(
1308 .shl_exact => try sema.zirShl(block, inst, .shl_exact),1311 .shl_exact => try sema.zirShl(block, inst, .shl_exact),
1309 .shl_sat => try sema.zirShl(block, inst, .shl_sat),1312 .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),
1312 .ret_type => Air.internedToRef(sema.fn_ret_ty.toIntern()),1315 .ret_type => Air.internedToRef(sema.fn_ret_ty.toIntern()),
13131316
1314 // Instructions that we know to *always* be noreturn based solely on their tag.1317 // Instructions that we know to *always* be noreturn based solely on their tag.
...@@ -2301,7 +2304,9 @@ pub fn resolveFinalDeclValue(...@@ -2301,7 +2304,9 @@ pub fn resolveFinalDeclValue(
2301 };2304 };
23022305
2303 if (val.canMutateComptimeVarState(zcu)) {2306 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);
2305 }2310 }
23062311
2307 return val;2312 return val;
...@@ -2757,7 +2762,8 @@ fn zirTupleDecl(...@@ -2757,7 +2762,8 @@ fn zirTupleDecl(
2757 const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);2762 const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);
2758 const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });2763 const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });
2759 if (field_init_val.canMutateComptimeVarState(zcu)) {2764 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);
2761 }2767 }
2762 break :init field_init_val.toIntern();2768 break :init field_init_val.toIntern();
2763 }2769 }
...@@ -2813,8 +2819,10 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2813,8 +2819,10 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
28132819
2814 const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);2820 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| {
2817 const zir_capture: Zir.Inst.Capture = @bitCast(raw);2823 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);
2818 capture.* = switch (zir_capture.unwrap()) {2826 capture.* = switch (zir_capture.unwrap()) {
2819 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],2827 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
2820 .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {2828 .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {
...@@ -2828,8 +2836,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2828,8 +2836,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
2828 };2836 };
2829 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);2837 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
2830 if (loaded_val.canMutateComptimeVarState(zcu)) {2838 if (loaded_val.canMutateComptimeVarState(zcu)) {
2831 // TODO: source location of captured value2839 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2832 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});2840 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);
2833 }2841 }
2834 break :capture .{ .@"comptime" = loaded_val.toIntern() };2842 break :capture .{ .@"comptime" = loaded_val.toIntern() };
2835 }),2843 }),
...@@ -2837,8 +2845,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2837,8 +2845,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
2837 const air_ref = try sema.resolveInst(inst.toRef());2845 const air_ref = try sema.resolveInst(inst.toRef());
2838 if (try sema.resolveValueResolveLazy(air_ref)) |val| {2846 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
2839 if (val.canMutateComptimeVarState(zcu)) {2847 if (val.canMutateComptimeVarState(zcu)) {
2840 // TODO: source location of captured value2848 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2841 return sema.fail(block, type_src, "type capture contains reference to comptime var", .{});2849 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);
2842 }2850 }
2843 break :capture .{ .@"comptime" = val.toIntern() };2851 break :capture .{ .@"comptime" = val.toIntern() };
2844 }2852 }
...@@ -2908,7 +2916,7 @@ fn zirStructDecl(...@@ -2908,7 +2916,7 @@ fn zirStructDecl(
2908 } else 0;2916 } else 0;
29092917
2910 const captures = try sema.getCaptures(block, src, extra_index, captures_len);2918 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
2911 extra_index += captures_len;2919 extra_index += captures_len * 2;
29122920
2913 if (small.has_backing_int) {2921 if (small.has_backing_int) {
2914 const backing_int_body_len = sema.code.extra[extra_index];2922 const backing_int_body_len = sema.code.extra[extra_index];
...@@ -3132,7 +3140,7 @@ fn zirEnumDecl(...@@ -3132,7 +3140,7 @@ fn zirEnumDecl(
3132 } else 0;3140 } else 0;
31333141
3134 const captures = try sema.getCaptures(block, src, extra_index, captures_len);3142 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3135 extra_index += captures_len;3143 extra_index += captures_len * 2;
31363144
3137 const decls = sema.code.bodySlice(extra_index, decls_len);3145 const decls = sema.code.bodySlice(extra_index, decls_len);
3138 extra_index += decls_len;3146 extra_index += decls_len;
...@@ -3275,7 +3283,7 @@ fn zirUnionDecl(...@@ -3275,7 +3283,7 @@ fn zirUnionDecl(
3275 } else 0;3283 } else 0;
32763284
3277 const captures = try sema.getCaptures(block, src, extra_index, captures_len);3285 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3278 extra_index += captures_len;3286 extra_index += captures_len * 2;
32793287
3280 const union_init: InternPool.UnionTypeInit = .{3288 const union_init: InternPool.UnionTypeInit = .{
3281 .flags = .{3289 .flags = .{
...@@ -3393,7 +3401,7 @@ fn zirOpaqueDecl(...@@ -3393,7 +3401,7 @@ fn zirOpaqueDecl(
3393 } else 0;3401 } else 0;
33943402
3395 const captures = try sema.getCaptures(block, src, extra_index, captures_len);3403 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3396 extra_index += captures_len;3404 extra_index += captures_len * 2;
33973405
3398 const opaque_init: InternPool.OpaqueTypeInit = .{3406 const opaque_init: InternPool.OpaqueTypeInit = .{
3399 .key = .{ .declared = .{3407 .key = .{ .declared = .{
...@@ -3474,15 +3482,17 @@ fn zirErrorSetDecl(...@@ -3474,15 +3482,17 @@ fn zirErrorSetDecl(
3474 return Air.internedToRef((try pt.errorSetFromUnsortedNames(names.keys())).toIntern());3482 return Air.internedToRef((try pt.errorSetFromUnsortedNames(names.keys())).toIntern());
3475}3483}
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 {
3478 const tracy = trace(@src());3486 const tracy = trace(@src());
3479 defer tracy.end();3487 defer tracy.end();
34803488
3481 const pt = sema.pt;3489 const pt = sema.pt;
34823490
3491 const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node);
3492
3483 if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) {3493 if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) {
3484 try sema.fn_ret_ty.resolveFields(pt);3494 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);
3486 }3496 }
34873497
3488 const target = pt.zcu.getTarget();3498 const target = pt.zcu.getTarget();
...@@ -3658,6 +3668,7 @@ fn zirAllocExtended(...@@ -3658,6 +3668,7 @@ fn zirAllocExtended(
3658 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);3668 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
3659 const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node });3669 const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node });
3660 const align_src = block.src(.{ .node_offset_var_decl_align = extra.data.src_node });3670 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 });
3661 const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small);3672 const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small);
36623673
3663 var extra_index: usize = extra.end;3674 var extra_index: usize = extra.end;
...@@ -3676,7 +3687,7 @@ fn zirAllocExtended(...@@ -3676,7 +3687,7 @@ fn zirAllocExtended(
36763687
3677 if (block.isComptime() or small.is_comptime) {3688 if (block.isComptime() or small.is_comptime) {
3678 if (small.has_type) {3689 if (small.has_type) {
3679 return sema.analyzeComptimeAlloc(block, var_ty, alignment);3690 return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment);
3680 } else {3691 } else {
3681 try sema.air_instructions.append(gpa, .{3692 try sema.air_instructions.append(gpa, .{
3682 .tag = .inferred_alloc_comptime,3693 .tag = .inferred_alloc_comptime,
...@@ -3691,7 +3702,7 @@ fn zirAllocExtended(...@@ -3691,7 +3702,7 @@ fn zirAllocExtended(
3691 }3702 }
36923703
3693 if (small.has_type and try var_ty.comptimeOnlySema(pt)) {3704 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);
3695 }3706 }
36963707
3697 if (small.has_type) {3708 if (small.has_type) {
...@@ -3741,8 +3752,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -3741,8 +3752,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
37413752
3742 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;3753 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
3743 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });3754 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 });
3744 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3756 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);
3746}3758}
37473759
3748fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3760fn 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,...@@ -3860,7 +3872,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
3860 // The simple strategy failed: we must create a mutable comptime alloc and3872 // The simple strategy failed: we must create a mutable comptime alloc and
3861 // perform all of the runtime store operations at comptime.3873 // 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
3865 const alloc_ptr = try pt.intern(.{ .ptr = .{3877 const alloc_ptr = try pt.intern(.{ .ptr = .{
3866 .ty = alloc_ty.toIntern(),3878 .ty = alloc_ty.toIntern(),
...@@ -4073,7 +4085,7 @@ fn finishResolveComptimeKnownAllocPtr(...@@ -4073,7 +4085,7 @@ fn finishResolveComptimeKnownAllocPtr(
40734085
4074 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {4086 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {
4075 const alloc_index = existing_comptime_alloc orelse a: {4087 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));
4077 const alloc = sema.getComptimeAlloc(idx);4089 const alloc = sema.getComptimeAlloc(idx);
4078 alloc.val = .{ .interned = result_val };4090 alloc.val = .{ .interned = result_val };
4079 break :a idx;4091 break :a idx;
...@@ -4139,10 +4151,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -4139,10 +4151,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
41394151
4140 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;4152 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4141 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });4153 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
4143 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);4156 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
4144 if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) {4157 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);
4146 }4159 }
4147 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {4160 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
4148 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });4161 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...@@ -4168,9 +4181,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
41684181
4169 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;4182 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4170 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });4183 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 });
4171 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);4185 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
4172 if (block.isComptime()) {4186 if (block.isComptime()) {
4173 return sema.analyzeComptimeAlloc(block, var_ty, .none);4187 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
4174 }4188 }
4175 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {4189 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
4176 const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });4190 const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
...@@ -5726,7 +5740,7 @@ fn storeToInferredAllocComptime(...@@ -5726,7 +5740,7 @@ fn storeToInferredAllocComptime(
5726 .byte_offset = 0,5740 .byte_offset = 0,
5727 } });5741 } });
5728 } else {5742 } 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);
5730 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };5744 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };
5731 iac.ptr = try pt.intern(.{ .ptr = .{5745 iac.ptr = try pt.intern(.{ .ptr = .{
5732 .ty = alloc_ty.toIntern(),5746 .ty = alloc_ty.toIntern(),
...@@ -31206,14 +31220,7 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins...@@ -31206,14 +31220,7 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins
31206 }31220 }
31207 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;31221 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;
31208 const other_operand = other_data.rhs;31222 const other_operand = other_data.rhs;
31209 if (!sema.checkRuntimeValue(other_operand)) {31223 try sema.validateRuntimeValue(block, other_src, 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 }
31217 }31224 }
31218}31225}
3121931226
...@@ -35328,7 +35335,7 @@ fn backingIntType(...@@ -35328,7 +35335,7 @@ fn backingIntType(
35328 extra_index += @intFromBool(small.has_fields_len);35335 extra_index += @intFromBool(small.has_fields_len);
35329 extra_index += @intFromBool(small.has_decls_len);35336 extra_index += @intFromBool(small.has_decls_len);
3533035337
35331 extra_index += captures_len;35338 extra_index += captures_len * 2;
3533235339
35333 const backing_int_body_len = zir.extra[extra_index];35340 const backing_int_body_len = zir.extra[extra_index];
35334 extra_index += 1;35341 extra_index += 1;
...@@ -35904,7 +35911,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -35904,7 +35911,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
35904 break :decls_len decls_len;35911 break :decls_len decls_len;
35905 } else 0;35912 } else 0;
3590635913
35907 extra_index += captures_len;35914 extra_index += captures_len * 2;
3590835915
35909 // The backing integer cannot be handled until `resolveStructLayout()`.35916 // The backing integer cannot be handled until `resolveStructLayout()`.
35910 if (small.has_backing_int) {35917 if (small.has_backing_int) {
...@@ -36233,7 +36240,8 @@ fn structFieldInits(...@@ -36233,7 +36240,8 @@ fn structFieldInits(
36233 const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null);36240 const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null);
3623436241
36235 if (default_val.canMutateComptimeVarState(zcu)) {36242 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);
36237 }36245 }
36238 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();36246 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
36239 }36247 }
...@@ -36293,7 +36301,7 @@ fn unionFields(...@@ -36293,7 +36301,7 @@ fn unionFields(
36293 } else 0;36301 } else 0;
3629436302
36295 // Skip over captures and decls.36303 // Skip over captures and decls.
36296 extra_index += captures_len + decls_len;36304 extra_index += captures_len * 2 + decls_len;
3629736305
36298 const body = zir.bodySlice(extra_index, body_len);36306 const body = zir.bodySlice(extra_index, body_len);
36299 extra_index += body.len;36307 extra_index += body.len;
...@@ -37055,6 +37063,7 @@ fn isComptimeKnown(...@@ -37055,6 +37063,7 @@ fn isComptimeKnown(
37055fn analyzeComptimeAlloc(37063fn analyzeComptimeAlloc(
37056 sema: *Sema,37064 sema: *Sema,
37057 block: *Block,37065 block: *Block,
37066 src: LazySrcLoc,
37058 var_type: Type,37067 var_type: Type,
37059 alignment: Alignment,37068 alignment: Alignment,
37060) CompileError!Air.Inst.Ref {37069) CompileError!Air.Inst.Ref {
...@@ -37072,7 +37081,7 @@ fn analyzeComptimeAlloc(...@@ -37072,7 +37081,7 @@ fn analyzeComptimeAlloc(
37072 },37081 },
37073 });37082 });
3707437083
37075 const alloc = try sema.newComptimeAlloc(block, var_type, alignment);37084 const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);
3707637085
37077 return Air.internedToRef((try pt.intern(.{ .ptr = .{37086 return Air.internedToRef((try pt.intern(.{ .ptr = .{
37078 .ty = ptr_type.toIntern(),37087 .ty = ptr_type.toIntern(),
...@@ -37979,10 +37988,189 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai...@@ -37979,10 +37988,189 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai
37979 const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{});37988 const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{});
37980 errdefer msg.destroy(sema.gpa);37989 errdefer msg.destroy(sema.gpa);
37981 try sema.errNote(val_src, msg, "comptime var pointers are not available at runtime", .{});37990 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);
37982 break :msg msg;38004 break :msg msg;
37983 });38005 });
37984}38006}
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
37986/// Returns true if any value contained in `val` is undefined.38174/// Returns true if any value contained in `val` is undefined.
37987fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {38175fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
37988 const pt = sema.pt;38176 const pt = sema.pt;
src/Value.zig+51-15
...@@ -4064,6 +4064,7 @@ pub const PointerDeriveStep = union(enum) {...@@ -4064,6 +4064,7 @@ pub const PointerDeriveStep = union(enum) {
4064 nav_ptr: InternPool.Nav.Index,4064 nav_ptr: InternPool.Nav.Index,
4065 uav_ptr: InternPool.Key.Ptr.BaseAddr.Uav,4065 uav_ptr: InternPool.Key.Ptr.BaseAddr.Uav,
4066 comptime_alloc_ptr: struct {4066 comptime_alloc_ptr: struct {
4067 idx: InternPool.ComptimeAllocIndex,
4067 val: Value,4068 val: Value,
4068 ptr_ty: Type,4069 ptr_ty: Type,
4069 },4070 },
...@@ -4110,7 +4111,7 @@ pub const PointerDeriveStep = union(enum) {...@@ -4110,7 +4111,7 @@ pub const PointerDeriveStep = union(enum) {
4110};4111};
41114112
4112pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Allocator.Error!PointerDeriveStep {4113pub 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) {
4114 error.OutOfMemory => |e| return e,4115 error.OutOfMemory => |e| return e,
4115 error.AnalysisFail => unreachable,4116 error.AnalysisFail => unreachable,
4116 };4117 };
...@@ -4120,7 +4121,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al...@@ -4120,7 +4121,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al
4120/// only field and element pointers with no casts. This can be used by codegen backends4121/// only field and element pointers with no casts. This can be used by codegen backends
4121/// which prefer field/elem accesses when lowering constant pointer values.4122/// which prefer field/elem accesses when lowering constant pointer values.
4122/// It is also used by the Value printing logic for pointers.4123/// 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 {
4124 const zcu = pt.zcu;4125 const zcu = pt.zcu;
4125 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;4126 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
4126 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {4127 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
...@@ -4143,11 +4144,12 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4143,11 +4144,12 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4143 } };4144 } };
4144 },4145 },
4145 .comptime_alloc => |idx| base: {4146 .comptime_alloc => |idx| base: {
4146 if (!have_sema) unreachable;4147 const sema = opt_sema.?;
4147 const alloc = sema.getComptimeAlloc(idx);4148 const alloc = sema.getComptimeAlloc(idx);
4148 const val = try alloc.val.intern(pt, sema.arena);4149 const val = try alloc.val.intern(pt, sema.arena);
4149 const ty = val.typeOf(zcu);4150 const ty = val.typeOf(zcu);
4150 break :base .{ .comptime_alloc_ptr = .{4151 break :base .{ .comptime_alloc_ptr = .{
4152 .idx = idx,
4151 .val = val,4153 .val = val,
4152 .ptr_ty = try pt.ptrType(.{4154 .ptr_ty = try pt.ptrType(.{
4153 .child = ty.toIntern(),4155 .child = ty.toIntern(),
...@@ -4162,7 +4164,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4162,7 +4164,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4162 const base_ptr = Value.fromInterned(eu_ptr);4164 const base_ptr = Value.fromInterned(eu_ptr);
4163 const base_ptr_ty = base_ptr.typeOf(zcu);4165 const base_ptr_ty = base_ptr.typeOf(zcu);
4164 const parent_step = try arena.create(PointerDeriveStep);4166 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);
4166 break :base .{ .eu_payload_ptr = .{4168 break :base .{ .eu_payload_ptr = .{
4167 .parent = parent_step,4169 .parent = parent_step,
4168 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),4170 .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...@@ -4172,7 +4174,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4172 const base_ptr = Value.fromInterned(opt_ptr);4174 const base_ptr = Value.fromInterned(opt_ptr);
4173 const base_ptr_ty = base_ptr.typeOf(zcu);4175 const base_ptr_ty = base_ptr.typeOf(zcu);
4174 const parent_step = try arena.create(PointerDeriveStep);4176 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);
4176 break :base .{ .opt_payload_ptr = .{4178 break :base .{ .opt_payload_ptr = .{
4177 .parent = parent_step,4179 .parent = parent_step,
4178 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),4180 .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...@@ -4185,15 +4187,15 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4185 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {4187 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {
4186 .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(4188 .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
4187 @intCast(field.index),4189 @intCast(field.index),
4188 if (have_sema) .sema else .normal,4190 if (resolve_types) .sema else .normal,
4189 pt.zcu,4191 pt.zcu,
4190 if (have_sema) pt.tid else {},4192 if (resolve_types) pt.tid else {},
4191 ) },4193 ) },
4192 .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(4194 .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
4193 @intCast(field.index),4195 @intCast(field.index),
4194 if (have_sema) .sema else .normal,4196 if (resolve_types) .sema else .normal,
4195 pt.zcu,4197 pt.zcu,
4196 if (have_sema) pt.tid else {},4198 if (resolve_types) pt.tid else {},
4197 ) },4199 ) },
4198 .pointer => .{ switch (field.index) {4200 .pointer => .{ switch (field.index) {
4199 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),4201 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
...@@ -4217,7 +4219,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4217,7 +4219,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4217 },4219 },
4218 });4220 });
4219 const parent_step = try arena.create(PointerDeriveStep);4221 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);
4221 break :base .{ .field_ptr = .{4223 break :base .{ .field_ptr = .{
4222 .parent = parent_step,4224 .parent = parent_step,
4223 .field_idx = @intCast(field.index),4225 .field_idx = @intCast(field.index),
...@@ -4226,7 +4228,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4226,7 +4228,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4226 },4228 },
4227 .arr_elem => |arr_elem| base: {4229 .arr_elem => |arr_elem| base: {
4228 const parent_step = try arena.create(PointerDeriveStep);4230 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);
4230 const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);4232 const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);
4231 const result_ptr_ty = try pt.ptrType(.{4233 const result_ptr_ty = try pt.ptrType(.{
4232 .child = parent_ptr_info.child,4234 .child = parent_ptr_info.child,
...@@ -4248,7 +4250,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4248,7 +4250,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4248 return base_derive;4250 return base_derive;
4249 }4251 }
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);
4252 if (need_child.comptimeOnly(zcu)) {4255 if (need_child.comptimeOnly(zcu)) {
4253 // No refinement can happen - this pointer is presumably invalid.4256 // No refinement can happen - this pointer is presumably invalid.
4254 // Just offset it.4257 // Just offset it.
...@@ -4293,16 +4296,34 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4293,16 +4296,34 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4293 .frame,4296 .frame,
4294 .@"enum",4297 .@"enum",
4295 .vector,4298 .vector,
4296 .optional,
4297 .@"union",4299 .@"union",
4298 => break,4300 => 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
4300 .array => {4321 .array => {
4301 const elem_ty = cur_ty.childType(zcu);4322 const elem_ty = cur_ty.childType(zcu);
4302 const elem_size = elem_ty.abiSize(zcu);4323 const elem_size = elem_ty.abiSize(zcu);
4303 const start_idx = cur_offset / elem_size;4324 const start_idx = cur_offset / elem_size;
4304 const end_idx = (cur_offset + need_bytes + elem_size - 1) / elem_size;4325 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) {
4306 const parent = try arena.create(PointerDeriveStep);4327 const parent = try arena.create(PointerDeriveStep);
4307 parent.* = cur_derive;4328 parent.* = cur_derive;
4308 cur_derive = .{ .elem_ptr = .{4329 cur_derive = .{ .elem_ptr = .{
...@@ -4363,7 +4384,22 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -4363,7 +4384,22 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
4363 }4384 }
4364 };4385 };
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
4367 return cur_derive;4403 return cur_derive;
4368 }4404 }
43694405
src/Zcu/PerThread.zig+5-5
...@@ -3944,7 +3944,7 @@ fn recreateEnumType(...@@ -3944,7 +3944,7 @@ fn recreateEnumType(
39443944
3945 assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`3945 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;
3948 extra_index += decls_len;3948 extra_index += decls_len;
39493949
3950 const body = zir.bodySlice(extra_index, body_len);3950 const body = zir.bodySlice(extra_index, body_len);
...@@ -4071,7 +4071,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4071,7 +4071,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4071 extra_index += 1;4071 extra_index += 1;
4072 break :blk decls_len;4072 break :blk decls_len;
4073 } else 0;4073 } else 0;
4074 extra_index += captures_len;4074 extra_index += captures_len * 2;
4075 if (small.has_backing_int) {4075 if (small.has_backing_int) {
4076 const backing_int_body_len = zir.extra[extra_index];4076 const backing_int_body_len = zir.extra[extra_index];
4077 extra_index += 1; // backing_int_body_len4077 extra_index += 1; // backing_int_body_len
...@@ -4101,7 +4101,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4101,7 +4101,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4101 extra_index += 1;4101 extra_index += 1;
4102 break :blk decls_len;4102 break :blk decls_len;
4103 } else 0;4103 } else 0;
4104 extra_index += captures_len;4104 extra_index += captures_len * 2;
4105 break :decls zir.bodySlice(extra_index, decls_len);4105 break :decls zir.bodySlice(extra_index, decls_len);
4106 },4106 },
4107 .@"enum" => decls: {4107 .@"enum" => decls: {
...@@ -4122,7 +4122,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4122,7 +4122,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4122 extra_index += 1;4122 extra_index += 1;
4123 break :blk decls_len;4123 break :blk decls_len;
4124 } else 0;4124 } else 0;
4125 extra_index += captures_len;4125 extra_index += captures_len * 2;
4126 break :decls zir.bodySlice(extra_index, decls_len);4126 break :decls zir.bodySlice(extra_index, decls_len);
4127 },4127 },
4128 .@"opaque" => decls: {4128 .@"opaque" => decls: {
...@@ -4140,7 +4140,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4140,7 +4140,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4140 extra_index += 1;4140 extra_index += 1;
4141 break :blk decls_len;4141 break :blk decls_len;
4142 } else 0;4142 } else 0;
4143 extra_index += captures_len;4143 extra_index += captures_len * 2;
4144 break :decls zir.bodySlice(extra_index, decls_len);4144 break :decls zir.bodySlice(extra_index, decls_len);
4145 },4145 },
4146 };4146 };
src/print_value.zig+145-70
...@@ -29,7 +29,7 @@ pub fn formatSema(...@@ -29,7 +29,7 @@ pub fn formatSema(
29 _ = options;29 _ = options;
30 const sema = ctx.opt_sema.?;30 const sema = ctx.opt_sema.?;
31 comptime std.debug.assert(fmt.len == 0);31 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) {
33 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function33 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
34 error.ComptimeBreak, error.ComptimeReturn => unreachable,34 error.ComptimeBreak, error.ComptimeReturn => unreachable,
35 error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully35 error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully
...@@ -46,7 +46,7 @@ pub fn format(...@@ -46,7 +46,7 @@ pub fn format(
46 _ = options;46 _ = options;
47 std.debug.assert(ctx.opt_sema == null);47 std.debug.assert(ctx.opt_sema == null);
48 comptime std.debug.assert(fmt.len == 0);48 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) {
50 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function50 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
51 error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,51 error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,
52 else => |e| return e,52 else => |e| return e,
...@@ -58,9 +58,7 @@ pub fn print(...@@ -58,9 +58,7 @@ pub fn print(
58 writer: anytype,58 writer: anytype,
59 level: u8,59 level: u8,
60 pt: Zcu.PerThread,60 pt: Zcu.PerThread,
61 /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output.61 opt_sema: ?*Sema,
62 comptime have_sema: bool,
63 sema: if (have_sema) *Sema else void,
64) (@TypeOf(writer).Error || Zcu.CompileError)!void {62) (@TypeOf(writer).Error || Zcu.CompileError)!void {
65 const zcu = pt.zcu;63 const zcu = pt.zcu;
66 const ip = &zcu.intern_pool;64 const ip = &zcu.intern_pool;
...@@ -94,11 +92,11 @@ pub fn print(...@@ -94,11 +92,11 @@ pub fn print(
94 .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),92 .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
95 .int => |int| switch (int.storage) {93 .int => |int| switch (int.storage) {
96 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),94 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) {
98 const a = try Type.fromInterned(ty).abiAlignmentSema(pt);96 const a = try Type.fromInterned(ty).abiAlignmentSema(pt);
99 try writer.print("{}", .{a.toByteUnits() orelse 0});97 try writer.print("{}", .{a.toByteUnits() orelse 0});
100 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(pt)}),98 } 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) {
102 const s = try Type.fromInterned(ty).abiSizeSema(pt);100 const s = try Type.fromInterned(ty).abiSizeSema(pt);
103 try writer.print("{}", .{s});101 try writer.print("{}", .{s});
104 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}),102 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}),
...@@ -110,7 +108,7 @@ pub fn print(...@@ -110,7 +108,7 @@ pub fn print(
110 .err_name => |err_name| try writer.print("error.{}", .{108 .err_name => |err_name| try writer.print("error.{}", .{
111 err_name.fmt(ip),109 err_name.fmt(ip),
112 }),110 }),
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),
114 },112 },
115 .enum_literal => |enum_literal| try writer.print(".{}", .{113 .enum_literal => |enum_literal| try writer.print(".{}", .{
116 enum_literal.fmt(ip),114 enum_literal.fmt(ip),
...@@ -124,7 +122,7 @@ pub fn print(...@@ -124,7 +122,7 @@ pub fn print(
124 return writer.writeAll("@enumFromInt(...)");122 return writer.writeAll("@enumFromInt(...)");
125 }123 }
126 try writer.writeAll("@enumFromInt(");124 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);
128 try writer.writeAll(")");126 try writer.writeAll(")");
129 },127 },
130 .empty_enum_value => try writer.writeAll("(empty enum value)"),128 .empty_enum_value => try writer.writeAll("(empty enum value)"),
...@@ -141,12 +139,12 @@ pub fn print(...@@ -141,12 +139,12 @@ pub fn print(
141 // TODO: eventually we want to load the slice as an array with `sema`, but that's139 // TODO: eventually we want to load the slice as an array with `sema`, but that's
142 // currently not possible without e.g. triggering compile errors.140 // currently not possible without e.g. triggering compile errors.
143 }141 }
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);
145 try writer.writeAll("[0..");143 try writer.writeAll("[0..");
146 if (level == 0) {144 if (level == 0) {
147 try writer.writeAll("(...)");145 try writer.writeAll("(...)");
148 } else {146 } 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);
150 }148 }
151 try writer.writeAll("]");149 try writer.writeAll("]");
152 },150 },
...@@ -160,13 +158,13 @@ pub fn print(...@@ -160,13 +158,13 @@ pub fn print(
160 // TODO: eventually we want to load the pointer with `sema`, but that's158 // TODO: eventually we want to load the pointer with `sema`, but that's
161 // currently not possible without e.g. triggering compile errors.159 // currently not possible without e.g. triggering compile errors.
162 }160 }
163 try printPtr(val, writer, level, pt, have_sema, sema);161 try printPtr(val, .rvalue, writer, level, pt, opt_sema);
164 },162 },
165 .opt => |opt| switch (opt.val) {163 .opt => |opt| switch (opt.val) {
166 .none => try writer.writeAll("null"),164 .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),
168 },166 },
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),
170 .un => |un| {168 .un => |un| {
171 if (level == 0) {169 if (level == 0) {
172 try writer.writeAll(".{ ... }");170 try writer.writeAll(".{ ... }");
...@@ -175,13 +173,13 @@ pub fn print(...@@ -175,13 +173,13 @@ pub fn print(
175 if (un.tag == .none) {173 if (un.tag == .none) {
176 const backing_ty = try val.typeOf(zcu).unionBackingType(pt);174 const backing_ty = try val.typeOf(zcu).unionBackingType(pt);
177 try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(pt)});175 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);
179 try writer.writeAll("))");177 try writer.writeAll("))");
180 } else {178 } else {
181 try writer.writeAll(".{ ");179 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);
183 try writer.writeAll(" = ");181 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);
185 try writer.writeAll(" }");183 try writer.writeAll(" }");
186 }184 }
187 },185 },
...@@ -196,8 +194,7 @@ fn printAggregate(...@@ -196,8 +194,7 @@ fn printAggregate(
196 writer: anytype,194 writer: anytype,
197 level: u8,195 level: u8,
198 pt: Zcu.PerThread,196 pt: Zcu.PerThread,
199 comptime have_sema: bool,197 opt_sema: ?*Sema,
200 sema: if (have_sema) *Sema else void,
201) (@TypeOf(writer).Error || Zcu.CompileError)!void {198) (@TypeOf(writer).Error || Zcu.CompileError)!void {
202 if (level == 0) {199 if (level == 0) {
203 if (is_ref) try writer.writeByte('&');200 if (is_ref) try writer.writeByte('&');
...@@ -218,7 +215,7 @@ fn printAggregate(...@@ -218,7 +215,7 @@ fn printAggregate(
218 if (i != 0) try writer.writeAll(", ");215 if (i != 0) try writer.writeAll(", ");
219 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;216 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
220 try writer.print(".{i} = ", .{field_name.fmt(ip)});217 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);
222 }219 }
223 try writer.writeAll(" }");220 try writer.writeAll(" }");
224 return;221 return;
...@@ -268,7 +265,7 @@ fn printAggregate(...@@ -268,7 +265,7 @@ fn printAggregate(
268 const max_len = @min(len, max_aggregate_items);265 const max_len = @min(len, max_aggregate_items);
269 for (0..max_len) |i| {266 for (0..max_len) |i| {
270 if (i != 0) try writer.writeAll(", ");267 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);
272 }269 }
273 if (len > max_aggregate_items) {270 if (len > max_aggregate_items) {
274 try writer.writeAll(", ...");271 try writer.writeAll(", ...");
...@@ -278,11 +275,12 @@ fn printAggregate(...@@ -278,11 +275,12 @@ fn printAggregate(
278275
279fn printPtr(276fn printPtr(
280 ptr_val: Value,277 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,
281 writer: anytype,280 writer: anytype,
282 level: u8,281 level: u8,
283 pt: Zcu.PerThread,282 pt: Zcu.PerThread,
284 comptime have_sema: bool,283 opt_sema: ?*Sema,
285 sema: if (have_sema) *Sema else void,
286) (@TypeOf(writer).Error || Zcu.CompileError)!void {284) (@TypeOf(writer).Error || Zcu.CompileError)!void {
287 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {285 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
288 .undef => return writer.writeAll("undefined"),286 .undef => return writer.writeAll("undefined"),
...@@ -300,8 +298,7 @@ fn printPtr(...@@ -300,8 +298,7 @@ fn printPtr(
300 writer,298 writer,
301 level,299 level,
302 pt,300 pt,
303 have_sema,301 opt_sema,
304 sema,
305 ),302 ),
306 else => {},303 else => {},
307 }304 }
...@@ -309,57 +306,96 @@ fn printPtr(...@@ -309,57 +306,96 @@ fn printPtr(
309306
310 var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);307 var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);
311 defer arena.deinit();308 defer arena.deinit();
312 const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, have_sema, sema);309 const derivation = if (opt_sema) |sema|
313 try printPtrDerivation(derivation, writer, level, pt, have_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);
314}318}
315319
316/// Print `derivation` as an lvalue, i.e. such that writing `&` before this gives the pointer value.320const PrintPtrKind = enum { lvalue, rvalue };
317fn printPtrDerivation(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(
318 derivation: Value.PointerDeriveStep,325 derivation: Value.PointerDeriveStep,
319 writer: anytype,326 writer: anytype,
320 level: u8,
321 pt: Zcu.PerThread,327 pt: Zcu.PerThread,
322 comptime have_sema: bool,328 /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen.
323 sema: if (have_sema) *Sema else void,329 /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as
324) (@TypeOf(writer).Error || Zcu.CompileError)!void {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 {
325 const zcu = pt.zcu;345 const zcu = pt.zcu;
326 const ip = &zcu.intern_pool;346 const ip = &zcu.intern_pool;
327 switch (derivation) {347
328 .int => |int| try writer.print("@as({}, @ptrFromInt({x})).*", .{348 if (ptr_depth == 0) {
329 int.ptr_ty.fmt(pt),349 const root_step = root: switch (derivation) {
330 int.addr,350 inline .eu_payload_ptr,
331 }),351 .opt_payload_ptr,
332 .nav_ptr => |nav| {352 .field_ptr,
333 try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)});353 .elem_ptr,
334 },354 .offset_and_cast,
335 .uav_ptr => |uav| {355 => |step| continue :root step.parent.*,
336 const ty = Value.fromInterned(uav.val).typeOf(zcu);356 else => |step| break :root step,
337 try writer.print("@as({}, ", .{ty.fmt(pt)});357 };
338 try print(Value.fromInterned(uav.val), writer, level - 1, pt, have_sema, sema);358 try writer.writeAll("...");
339 try writer.writeByte(')');359 return root_step;
340 },360 }
341 .comptime_alloc_ptr => |info| {361
342 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)});362 const result_kind: PrintPtrKind = switch (derivation) {
343 try print(info.val, writer, level - 1, pt, have_sema, sema);363 .nav_ptr,
344 try writer.writeByte(')');364 .uav_ptr,
345 },365 .comptime_alloc_ptr,
346 .comptime_field_ptr => |val| {366 .comptime_field_ptr,
347 const ty = val.typeOf(zcu);367 .eu_payload_ptr,
348 try writer.print("@as({}, ", .{ty.fmt(pt)});368 .opt_payload_ptr,
349 try print(val, writer, level - 1, pt, have_sema, sema);369 .field_ptr,
350 try writer.writeByte(')');370 .elem_ptr,
351 },371 => .lvalue,
352 .eu_payload_ptr => |info| {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: {
353 try writer.writeByte('(');387 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);
355 try writer.writeAll(" catch unreachable)");389 try writer.writeAll(" catch unreachable)");
390 break :root root;
356 },391 },
357 .opt_payload_ptr => |info| {392 .opt_payload_ptr => |info| root: {
358 try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema);393 const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1);
359 try writer.writeAll(".?");394 try writer.writeAll(".?");
395 break :root root;
360 },396 },
361 .field_ptr => |field| {397 .field_ptr => |field| root: {
362 try printPtrDerivation(field.parent.*, writer, level, pt, have_sema, sema);398 const root = try printPtrDerivation(field.parent.*, writer, pt, null, root_strat, ptr_depth - 1);
363 const agg_ty = (try field.parent.ptrType(pt)).childType(zcu);399 const agg_ty = (try field.parent.ptrType(pt)).childType(zcu);
364 switch (agg_ty.zigTypeTag(zcu)) {400 switch (agg_ty.zigTypeTag(zcu)) {
365 .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {401 .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {
...@@ -379,19 +415,58 @@ fn printPtrDerivation(...@@ -379,19 +415,58 @@ fn printPtrDerivation(
379 },415 },
380 else => unreachable,416 else => unreachable,
381 }417 }
418 break :root root;
382 },419 },
383 .elem_ptr => |elem| {420 .elem_ptr => |elem| root: {
384 try printPtrDerivation(elem.parent.*, writer, level, pt, have_sema, sema);421 const root = try printPtrDerivation(elem.parent.*, writer, pt, null, root_strat, ptr_depth - 1);
385 try writer.print("[{d}]", .{elem.elem_idx});422 try writer.print("[{d}]", .{elem.elem_idx});
423 break :root root;
386 },424 },
387 .offset_and_cast => |oac| if (oac.byte_offset == 0) {425
426 .offset_and_cast => |oac| if (oac.byte_offset == 0) root: {
388 try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)});427 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);
390 try writer.writeAll("))");429 try writer.writeAll("))");
391 } else {430 break :root root;
431 } else root: {
392 try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)});432 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);
394 try writer.print(") + {d}))", .{oac.byte_offset});434 try writer.print(") + {d}))", .{oac.byte_offset});
435 break :root root;
395 },436 },
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(".*");
396 }469 }
470
471 return root_or_null orelse derivation;
397}472}
src/print_zir.zig+28-52
...@@ -1430,19 +1430,8 @@ const Writer = struct {...@@ -1430,19 +1430,8 @@ const Writer = struct {
14301430
1431 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1431 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
14321432
1433 if (captures_len == 0) {1433 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1434 try stream.writeAll("{}, ");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 }
14461435
1447 if (small.has_backing_int) {1436 if (small.has_backing_int) {
1448 const backing_int_body_len = self.code.extra[extra_index];1437 const backing_int_body_len = self.code.extra[extra_index];
...@@ -1645,19 +1634,8 @@ const Writer = struct {...@@ -1645,19 +1634,8 @@ const Writer = struct {
1645 });1634 });
1646 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1635 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
16471636
1648 if (captures_len == 0) {1637 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1649 try stream.writeAll("{}, ");1638 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 }
16611639
1662 if (decls_len == 0) {1640 if (decls_len == 0) {
1663 try stream.writeAll("{}");1641 try stream.writeAll("{}");
...@@ -1805,19 +1783,8 @@ const Writer = struct {...@@ -1805,19 +1783,8 @@ const Writer = struct {
1805 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1783 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1806 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);1784 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
18071785
1808 if (captures_len == 0) {1786 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1809 try stream.writeAll("{}, ");1787 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 }
18211788
1822 if (decls_len == 0) {1789 if (decls_len == 0) {
1823 try stream.writeAll("{}, ");1790 try stream.writeAll("{}, ");
...@@ -1910,19 +1877,8 @@ const Writer = struct {...@@ -1910,19 +1877,8 @@ const Writer = struct {
19101877
1911 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1878 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
19121879
1913 if (captures_len == 0) {1880 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1914 try stream.writeAll("{}, ");1881 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 }
19261882
1927 if (decls_len == 0) {1883 if (decls_len == 0) {
1928 try stream.writeAll("{}) ");1884 try stream.writeAll("{}) ");
...@@ -2720,6 +2676,26 @@ const Writer = struct {...@@ -2720,6 +2676,26 @@ const Writer = struct {
2720 return stream.print("%{d}", .{@intFromEnum(inst)});2676 return stream.print("%{d}", .{@intFromEnum(inst)});
2721 }2677 }
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
2723 fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void {2699 fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void {
2724 switch (capture.unwrap()) {2700 switch (capture.unwrap()) {
2725 .nested => |i| return stream.print("[{d}]", .{i}),2701 .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 {...@@ -3,10 +3,8 @@ export fn entry() void {
3}3}
44
5// error5// error
6// backend=stage2
7// target=native
8//6//
9// :2:5: error: found compile log statement7// :2:5: error: found compile log statement
10//8//
11// Compile Log Output:9// 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 {...@@ -67,19 +67,28 @@ export fn far() void {
67//67//
68// :5:19: error: runtime value contains reference to comptime var68// :5:19: error: runtime value contains reference to comptime var
69// :5:19: note: comptime var pointers are not available at runtime69// :5:19: note: comptime var pointers are not available at runtime
70// :4:27: note: 'runtime_value' points to comptime var declared here
70// :12:40: error: runtime value contains reference to comptime var71// :12:40: error: runtime value contains reference to comptime var
71// :12:40: note: comptime var pointers are not available at runtime72// :12:40: note: comptime var pointers are not available at runtime
73// :11:27: note: 'runtime_value' points to comptime var declared here
72// :19:50: error: runtime value contains reference to comptime var74// :19:50: error: runtime value contains reference to comptime var
73// :19:50: note: comptime var pointers are not available at runtime75// :19:50: note: comptime var pointers are not available at runtime
76// :18:27: note: 'runtime_value' points to comptime var declared here
74// :28:9: error: runtime value contains reference to comptime var77// :28:9: error: runtime value contains reference to comptime var
75// :28:9: note: comptime var pointers are not available at runtime78// :28:9: note: comptime var pointers are not available at runtime
79// :27:27: note: 'runtime_value' points to comptime var declared here
76// :36:9: error: runtime value contains reference to comptime var80// :36:9: error: runtime value contains reference to comptime var
77// :36:9: note: comptime var pointers are not available at runtime81// :36:9: note: comptime var pointers are not available at runtime
82// :35:27: note: 'runtime_value' points to comptime var declared here
78// :41:12: error: runtime value contains reference to comptime var83// :41:12: error: runtime value contains reference to comptime var
79// :41:12: note: comptime var pointers are not available at runtime84// :41:12: note: comptime var pointers are not available at runtime
85// :40:27: note: 'runtime_value' points to comptime var declared here
80// :46:39: error: runtime value contains reference to comptime var86// :46:39: error: runtime value contains reference to comptime var
81// :46:39: note: comptime var pointers are not available at runtime87// :46:39: note: comptime var pointers are not available at runtime
88// :45:27: note: 'runtime_value' points to comptime var declared here
82// :55:18: error: runtime value contains reference to comptime var89// :55:18: error: runtime value contains reference to comptime var
83// :55:18: note: comptime var pointers are not available at runtime90// :55:18: note: comptime var pointers are not available at runtime
91// :51:30: note: 'runtime_value' points to comptime var declared here
84// :63:18: error: runtime value contains reference to comptime var92// :63:18: error: runtime value contains reference to comptime var
85// :63:18: note: comptime var pointers are not available at runtime93// :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: {...@@ -47,10 +47,19 @@ export var h: *[1]u32 = h: {
47// error47// error
48//48//
49// :1:27: error: global variable contains reference to comptime var49// :1:27: error: global variable contains reference to comptime var
50// :2:18: note: 'a' points to comptime var declared here
50// :6:30: error: global variable contains reference to comptime var51// :6:30: error: global variable contains reference to comptime var
52// :7:18: note: 'b[0]' points to comptime var declared here
51// :11:30: error: global variable contains reference to comptime var53// :11:30: error: global variable contains reference to comptime var
54// :12:18: note: 'c' points to comptime var declared here
52// :16:33: error: global variable contains reference to comptime var55// :16:33: error: global variable contains reference to comptime var
56// :17:18: note: 'd' points to comptime var declared here
53// :22:24: error: global variable contains reference to comptime var57// :22:24: error: global variable contains reference to comptime var
58// :23:18: note: 'e.ptr' points to comptime var declared here
54// :28:33: error: global variable contains reference to comptime var59// :28:33: error: global variable contains reference to comptime var
60// :29:18: note: 'f' points to comptime var declared here
55// :34:40: error: global variable contains reference to comptime var61// :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
56// :42:28: error: global variable contains reference to comptime var64// :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 {}...@@ -31,5 +31,5 @@ pub fn main() !void {}
31// :20:5: error: found compile log statement31// :20:5: error: found compile log statement
32//32//
33// Compile Log Output:33// Compile Log Output:
34// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).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]))[0..2])35// @as([]i32, @as([*]i32, @ptrCast(&@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf))[0..2])