| author | |
| committer | |
| log | 04c9f50aec5c1d01ee2c230534454a0ddf551c38 |
| tree | 60b898e67a3a570bf44c15531647c6f575ac5c09 |
| parent | 6cfc9c0e02cb1ccf9edfbdc64fcca285fea022fb |
`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 | 5315 | const fields_slice = wip_members.fieldsSlice(); |
| 5316 | 5316 | const bodies_slice = astgen.scratch.items[bodies_start..]; |
| 5317 | 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 | 5319 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys())); |
| 5320 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values())); | |
| 5320 | 5321 | if (backing_int_ref != .none) { |
| 5321 | 5322 | astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len)); |
| 5322 | 5323 | if (backing_int_body_len == 0) { |
| ... | ... | @@ -5595,8 +5596,9 @@ fn unionDeclInner( |
| 5595 | 5596 | wip_members.finishBits(bits_per_field); |
| 5596 | 5597 | const decls_slice = wip_members.declsSlice(); |
| 5597 | 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 | 5600 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys())); |
| 5601 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values())); | |
| 5600 | 5602 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 5601 | 5603 | astgen.appendBodyWithFixups(body); |
| 5602 | 5604 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| ... | ... | @@ -5855,8 +5857,9 @@ fn containerDecl( |
| 5855 | 5857 | wip_members.finishBits(bits_per_field); |
| 5856 | 5858 | const decls_slice = wip_members.declsSlice(); |
| 5857 | 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 | 5861 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys())); |
| 5862 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values())); | |
| 5860 | 5863 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 5861 | 5864 | astgen.appendBodyWithFixups(body); |
| 5862 | 5865 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| ... | ... | @@ -5910,8 +5913,9 @@ fn containerDecl( |
| 5910 | 5913 | |
| 5911 | 5914 | wip_members.finishBits(0); |
| 5912 | 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 | 5917 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys())); |
| 5918 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values())); | |
| 5915 | 5919 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 5916 | 5920 | |
| 5917 | 5921 | block_scope.unstack(); |
| ... | ... | @@ -8548,6 +8552,7 @@ fn localVarRef( |
| 8548 | 8552 | num_namespaces_out, |
| 8549 | 8553 | .{ .ref = local_val.inst }, |
| 8550 | 8554 | .{ .token = local_val.token_src }, |
| 8555 | name_str_index, | |
| 8551 | 8556 | ) else local_val.inst; |
| 8552 | 8557 | |
| 8553 | 8558 | return rvalueNoCoercePreRef(gz, ri, value_inst, ident); |
| ... | ... | @@ -8580,6 +8585,7 @@ fn localVarRef( |
| 8580 | 8585 | num_namespaces_out, |
| 8581 | 8586 | .{ .ref = local_ptr.ptr }, |
| 8582 | 8587 | .{ .token = local_ptr.token_src }, |
| 8588 | name_str_index, | |
| 8583 | 8589 | ) else local_ptr.ptr; |
| 8584 | 8590 | local_ptr.used_as_lvalue = true; |
| 8585 | 8591 | return ptr_inst; |
| ... | ... | @@ -8591,6 +8597,7 @@ fn localVarRef( |
| 8591 | 8597 | num_namespaces_out, |
| 8592 | 8598 | .{ .ref_load = local_ptr.ptr }, |
| 8593 | 8599 | .{ .token = local_ptr.token_src }, |
| 8600 | name_str_index, | |
| 8594 | 8601 | ) else try gz.addUnNode(.load, local_ptr.ptr, ident); |
| 8595 | 8602 | return rvalueNoCoercePreRef(gz, ri, val_inst, ident); |
| 8596 | 8603 | }, |
| ... | ... | @@ -8636,6 +8643,7 @@ fn localVarRef( |
| 8636 | 8643 | found_namespaces_out, |
| 8637 | 8644 | .{ .decl_ref = name_str_index }, |
| 8638 | 8645 | .{ .node = found_already.? }, |
| 8646 | name_str_index, | |
| 8639 | 8647 | ), |
| 8640 | 8648 | else => { |
| 8641 | 8649 | const result = try tunnelThroughClosure( |
| ... | ... | @@ -8644,6 +8652,7 @@ fn localVarRef( |
| 8644 | 8652 | found_namespaces_out, |
| 8645 | 8653 | .{ .decl_val = name_str_index }, |
| 8646 | 8654 | .{ .node = found_already.? }, |
| 8655 | name_str_index, | |
| 8647 | 8656 | ); |
| 8648 | 8657 | return rvalueNoCoercePreRef(gz, ri, result, ident); |
| 8649 | 8658 | }, |
| ... | ... | @@ -8680,6 +8689,7 @@ fn tunnelThroughClosure( |
| 8680 | 8689 | token: Ast.TokenIndex, |
| 8681 | 8690 | node: Ast.Node.Index, |
| 8682 | 8691 | }, |
| 8692 | name_str_index: Zir.NullTerminatedString, | |
| 8683 | 8693 | ) !Zir.Inst.Ref { |
| 8684 | 8694 | switch (value) { |
| 8685 | 8695 | .ref => |v| if (v.toIndex() == null) return v, // trivial value; do not need tunnel |
| ... | ... | @@ -8714,34 +8724,43 @@ fn tunnelThroughClosure( |
| 8714 | 8724 | |
| 8715 | 8725 | // Now that we know the scopes we're tunneling through, begin adding |
| 8716 | 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 | 8728 | .ref => |v| .{ .instruction = v.toIndex().? }, |
| 8719 | 8729 | .ref_load => |v| .{ .instruction_load = v.toIndex().? }, |
| 8720 | 8730 | .decl_val => |str| .{ .decl_val = str }, |
| 8721 | 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 | }); | |
| 8733 | 8733 | |
| 8734 | for (intermediate_tunnels) |tunnel_ns| { | |
| 8735 | cur_capture_index = std.math.cast( | |
| 8736 | u16, | |
| 8737 | (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index, | |
| 8738 | ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{ | |
| 8734 | const root_gop = try root_ns.captures.getOrPut(gpa, root_capture); | |
| 8735 | root_gop.value_ptr.* = name_str_index; | |
| 8736 | var cur_capture_index = std.math.cast(u16, root_gop.index) orelse return astgen.failNodeNotes( | |
| 8737 | root_ns.node, | |
| 8738 | "this compiler implementation only supports up to 65536 captures per namespace", | |
| 8739 | .{}, | |
| 8740 | &.{ | |
| 8739 | 8741 | switch (decl_src) { |
| 8740 | 8742 | .token => |t| try astgen.errNoteTok(t, "captured value here", .{}), |
| 8741 | 8743 | .node => |n| try astgen.errNoteNode(n, "captured value here", .{}), |
| 8742 | 8744 | }, |
| 8743 | 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 | } |
| 8746 | 8765 | |
| 8747 | 8766 | // Incorporate the capture index into the source hash, so that changes in |
| ... | ... | @@ -11920,7 +11939,7 @@ const Scope = struct { |
| 11920 | 11939 | declaring_gz: ?*GenZir, |
| 11921 | 11940 | |
| 11922 | 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, | |
| 11924 | 11943 | |
| 11925 | 11944 | fn deinit(self: *Namespace, gpa: Allocator) void { |
| 11926 | 11945 | self.decls.deinit(gpa); |
lib/std/zig/Zir.zig+27-23| ... | ... | @@ -3284,24 +3284,25 @@ pub const Inst = struct { |
| 3284 | 3284 | /// 1. fields_len: u32, // if has_fields_len |
| 3285 | 3285 | /// 2. decls_len: u32, // if has_decls_len |
| 3286 | 3286 | /// 3. capture: Capture // for every captures_len |
| 3287 | /// 4. backing_int_body_len: u32, // if has_backing_int | |
| 3288 | /// 5. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0 | |
| 3289 | /// 6. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0 | |
| 3290 | /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3291 | /// 8. flags: u32 // for every 8 fields | |
| 3287 | /// 4. capture_name: NullTerminatedString // for every captures_len | |
| 3288 | /// 5. backing_int_body_len: u32, // if has_backing_int | |
| 3289 | /// 6. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0 | |
| 3290 | /// 7. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0 | |
| 3291 | /// 8. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3292 | /// 9. flags: u32 // for every 8 fields | |
| 3292 | 3293 | /// - sets of 4 bits: |
| 3293 | 3294 | /// 0b000X: whether corresponding field has an align expression |
| 3294 | 3295 | /// 0b00X0: whether corresponding field has a default expression |
| 3295 | 3296 | /// 0b0X00: whether corresponding field is comptime |
| 3296 | 3297 | /// 0bX000: whether corresponding field has a type expression |
| 3297 | /// 9. fields: { // for every fields_len | |
| 3298 | /// 10. fields: { // for every fields_len | |
| 3298 | 3299 | /// field_name: u32, |
| 3299 | 3300 | /// field_type: Ref, // if corresponding bit is not set. none means anytype. |
| 3300 | 3301 | /// field_type_body_len: u32, // if corresponding bit is set |
| 3301 | 3302 | /// align_body_len: u32, // if corresponding bit is set |
| 3302 | 3303 | /// init_body_len: u32, // if corresponding bit is set |
| 3303 | 3304 | /// } |
| 3304 | /// 10. bodies: { // for every fields_len | |
| 3305 | /// 11. bodies: { // for every fields_len | |
| 3305 | 3306 | /// field_type_body_inst: Inst, // for each field_type_body_len |
| 3306 | 3307 | /// align_body_inst: Inst, // for each align_body_len |
| 3307 | 3308 | /// init_body_inst: Inst, // for each init_body_len |
| ... | ... | @@ -3450,11 +3451,12 @@ pub const Inst = struct { |
| 3450 | 3451 | /// 3. fields_len: u32, // if has_fields_len |
| 3451 | 3452 | /// 4. decls_len: u32, // if has_decls_len |
| 3452 | 3453 | /// 5. capture: Capture // for every captures_len |
| 3453 | /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3454 | /// 7. inst: Index // for every body_len | |
| 3455 | /// 8. has_bits: u32 // for every 32 fields | |
| 3454 | /// 6. capture_name: NullTerminatedString // for every captures_len | |
| 3455 | /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3456 | /// 8. inst: Index // for every body_len | |
| 3457 | /// 9. has_bits: u32 // for every 32 fields | |
| 3456 | 3458 | /// - the bit is whether corresponding field has an value expression |
| 3457 | /// 9. fields: { // for every fields_len | |
| 3459 | /// 10. fields: { // for every fields_len | |
| 3458 | 3460 | /// field_name: u32, |
| 3459 | 3461 | /// value: Ref, // if corresponding bit is set |
| 3460 | 3462 | /// } |
| ... | ... | @@ -3488,15 +3490,16 @@ pub const Inst = struct { |
| 3488 | 3490 | /// 3. fields_len: u32, // if has_fields_len |
| 3489 | 3491 | /// 4. decls_len: u32, // if has_decls_len |
| 3490 | 3492 | /// 5. capture: Capture // for every captures_len |
| 3491 | /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3492 | /// 7. inst: Index // for every body_len | |
| 3493 | /// 8. has_bits: u32 // for every 8 fields | |
| 3493 | /// 6. capture_name: NullTerminatedString // for every captures_len | |
| 3494 | /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3495 | /// 8. inst: Index // for every body_len | |
| 3496 | /// 9. has_bits: u32 // for every 8 fields | |
| 3494 | 3497 | /// - sets of 4 bits: |
| 3495 | 3498 | /// 0b000X: whether corresponding field has a type expression |
| 3496 | 3499 | /// 0b00X0: whether corresponding field has a align expression |
| 3497 | 3500 | /// 0b0X00: whether corresponding field has a tag value expression |
| 3498 | 3501 | /// 0bX000: unused |
| 3499 | /// 9. fields: { // for every fields_len | |
| 3502 | /// 10. fields: { // for every fields_len | |
| 3500 | 3503 | /// field_name: NullTerminatedString, // null terminated string index |
| 3501 | 3504 | /// field_type: Ref, // if corresponding bit is set |
| 3502 | 3505 | /// align: Ref, // if corresponding bit is set |
| ... | ... | @@ -3537,7 +3540,8 @@ pub const Inst = struct { |
| 3537 | 3540 | /// 0. captures_len: u32, // if has_captures_len |
| 3538 | 3541 | /// 1. decls_len: u32, // if has_decls_len |
| 3539 | 3542 | /// 2. capture: Capture, // for every captures_len |
| 3540 | /// 3. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3543 | /// 3. capture_name: NullTerminatedString // for every captures_len | |
| 3544 | /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction | |
| 3541 | 3545 | pub const OpaqueDecl = struct { |
| 3542 | 3546 | src_line: u32, |
| 3543 | 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 | 3856 | break :decls_len decls_len; |
| 3853 | 3857 | } else 0; |
| 3854 | 3858 | |
| 3855 | extra_index += captures_len; | |
| 3859 | extra_index += captures_len * 2; | |
| 3856 | 3860 | |
| 3857 | 3861 | if (small.has_backing_int) { |
| 3858 | 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 | 3891 | break :decls_len decls_len; |
| 3888 | 3892 | } else 0; |
| 3889 | 3893 | |
| 3890 | extra_index += captures_len; | |
| 3894 | extra_index += captures_len * 2; | |
| 3891 | 3895 | |
| 3892 | 3896 | return .{ |
| 3893 | 3897 | .extra_index = extra_index, |
| ... | ... | @@ -3912,7 +3916,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3912 | 3916 | break :decls_len decls_len; |
| 3913 | 3917 | } else 0; |
| 3914 | 3918 | |
| 3915 | extra_index += captures_len; | |
| 3919 | extra_index += captures_len * 2; | |
| 3916 | 3920 | |
| 3917 | 3921 | return .{ |
| 3918 | 3922 | .extra_index = extra_index, |
| ... | ... | @@ -3934,7 +3938,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3934 | 3938 | break :captures_len captures_len; |
| 3935 | 3939 | } else 0; |
| 3936 | 3940 | |
| 3937 | extra_index += captures_len; | |
| 3941 | extra_index += captures_len * 2; | |
| 3938 | 3942 | |
| 3939 | 3943 | return .{ |
| 3940 | 3944 | .extra_index = extra_index, |
| ... | ... | @@ -4349,7 +4353,7 @@ fn findTrackableInner( |
| 4349 | 4353 | extra_index += 1; |
| 4350 | 4354 | break :blk decls_len; |
| 4351 | 4355 | } else 0; |
| 4352 | extra_index += captures_len; | |
| 4356 | extra_index += captures_len * 2; | |
| 4353 | 4357 | if (small.has_backing_int) { |
| 4354 | 4358 | const backing_int_body_len = zir.extra[extra_index]; |
| 4355 | 4359 | extra_index += 1; |
| ... | ... | @@ -4441,7 +4445,7 @@ fn findTrackableInner( |
| 4441 | 4445 | extra_index += 1; |
| 4442 | 4446 | break :blk decls_len; |
| 4443 | 4447 | } else 0; |
| 4444 | extra_index += captures_len; | |
| 4448 | extra_index += captures_len * 2; | |
| 4445 | 4449 | extra_index += decls_len; |
| 4446 | 4450 | const body = zir.bodySlice(extra_index, body_len); |
| 4447 | 4451 | try zir.findTrackableBody(gpa, contents, defers, body); |
| ... | ... | @@ -4471,7 +4475,7 @@ fn findTrackableInner( |
| 4471 | 4475 | extra_index += 1; |
| 4472 | 4476 | break :blk decls_len; |
| 4473 | 4477 | } else 0; |
| 4474 | extra_index += captures_len; | |
| 4478 | extra_index += captures_len * 2; | |
| 4475 | 4479 | extra_index += decls_len; |
| 4476 | 4480 | const body = zir.bodySlice(extra_index, body_len); |
| 4477 | 4481 | try zir.findTrackableBody(gpa, contents, defers, body); |
src/Sema.zig+224-36| ... | ... | @@ -134,6 +134,7 @@ const MaybeComptimeAlloc = struct { |
| 134 | 134 | const ComptimeAlloc = struct { |
| 135 | 135 | val: MutableValue, |
| 136 | 136 | is_const: bool, |
| 137 | src: LazySrcLoc, | |
| 137 | 138 | /// `.none` indicates that the alignment is the natural alignment of `val`. |
| 138 | 139 | alignment: Alignment, |
| 139 | 140 | /// This is the `runtime_index` at the point of this allocation. If an store |
| ... | ... | @@ -142,11 +143,13 @@ const ComptimeAlloc = struct { |
| 142 | 143 | runtime_index: RuntimeIndex, |
| 143 | 144 | }; |
| 144 | 145 | |
| 145 | fn newComptimeAlloc(sema: *Sema, block: *Block, ty: Type, alignment: Alignment) !ComptimeAllocIndex { | |
| 146 | /// `src` may be `null` if `is_const` will be set. | |
| 147 | fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex { | |
| 146 | 148 | const idx = sema.comptime_allocs.items.len; |
| 147 | 149 | try sema.comptime_allocs.append(sema.gpa, .{ |
| 148 | 150 | .val = .{ .interned = try sema.pt.intern(.{ .undef = ty.toIntern() }) }, |
| 149 | 151 | .is_const = false, |
| 152 | .src = src, | |
| 150 | 153 | .alignment = alignment, |
| 151 | 154 | .runtime_index = block.runtime_index, |
| 152 | 155 | }); |
| ... | ... | @@ -1308,7 +1311,7 @@ fn analyzeBodyInner( |
| 1308 | 1311 | .shl_exact => try sema.zirShl(block, inst, .shl_exact), |
| 1309 | 1312 | .shl_sat => try sema.zirShl(block, inst, .shl_sat), |
| 1310 | 1313 | |
| 1311 | .ret_ptr => try sema.zirRetPtr(block), | |
| 1314 | .ret_ptr => try sema.zirRetPtr(block, inst), | |
| 1312 | 1315 | .ret_type => Air.internedToRef(sema.fn_ret_ty.toIntern()), |
| 1313 | 1316 | |
| 1314 | 1317 | // Instructions that we know to *always* be noreturn based solely on their tag. |
| ... | ... | @@ -2301,7 +2304,9 @@ pub fn resolveFinalDeclValue( |
| 2301 | 2304 | }; |
| 2302 | 2305 | |
| 2303 | 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 | } |
| 2306 | 2311 | |
| 2307 | 2312 | return val; |
| ... | ... | @@ -2757,7 +2762,8 @@ fn zirTupleDecl( |
| 2757 | 2762 | const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src); |
| 2758 | 2763 | const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value }); |
| 2759 | 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 | 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 | 2819 | |
| 2814 | 2820 | const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len); |
| 2815 | 2821 | |
| 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 | 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 | 2826 | capture.* = switch (zir_capture.unwrap()) { |
| 2819 | 2827 | .nested => |parent_idx| parent_captures.get(ip)[parent_idx], |
| 2820 | 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 | 2836 | }; |
| 2829 | 2837 | const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val); |
| 2830 | 2838 | if (loaded_val.canMutateComptimeVarState(zcu)) { |
| 2831 | // TODO: source location of captured value | |
| 2832 | return sema.fail(block, type_src, "type capture contains reference to comptime var", .{}); | |
| 2839 | const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls); | |
| 2840 | return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val); | |
| 2833 | 2841 | } |
| 2834 | 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 | 2845 | const air_ref = try sema.resolveInst(inst.toRef()); |
| 2838 | 2846 | if (try sema.resolveValueResolveLazy(air_ref)) |val| { |
| 2839 | 2847 | if (val.canMutateComptimeVarState(zcu)) { |
| 2840 | // TODO: source location of captured value | |
| 2841 | return sema.fail(block, type_src, "type capture contains reference to comptime var", .{}); | |
| 2848 | const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls); | |
| 2849 | return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val); | |
| 2842 | 2850 | } |
| 2843 | 2851 | break :capture .{ .@"comptime" = val.toIntern() }; |
| 2844 | 2852 | } |
| ... | ... | @@ -2908,7 +2916,7 @@ fn zirStructDecl( |
| 2908 | 2916 | } else 0; |
| 2909 | 2917 | |
| 2910 | 2918 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 2911 | extra_index += captures_len; | |
| 2919 | extra_index += captures_len * 2; | |
| 2912 | 2920 | |
| 2913 | 2921 | if (small.has_backing_int) { |
| 2914 | 2922 | const backing_int_body_len = sema.code.extra[extra_index]; |
| ... | ... | @@ -3132,7 +3140,7 @@ fn zirEnumDecl( |
| 3132 | 3140 | } else 0; |
| 3133 | 3141 | |
| 3134 | 3142 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 3135 | extra_index += captures_len; | |
| 3143 | extra_index += captures_len * 2; | |
| 3136 | 3144 | |
| 3137 | 3145 | const decls = sema.code.bodySlice(extra_index, decls_len); |
| 3138 | 3146 | extra_index += decls_len; |
| ... | ... | @@ -3275,7 +3283,7 @@ fn zirUnionDecl( |
| 3275 | 3283 | } else 0; |
| 3276 | 3284 | |
| 3277 | 3285 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 3278 | extra_index += captures_len; | |
| 3286 | extra_index += captures_len * 2; | |
| 3279 | 3287 | |
| 3280 | 3288 | const union_init: InternPool.UnionTypeInit = .{ |
| 3281 | 3289 | .flags = .{ |
| ... | ... | @@ -3393,7 +3401,7 @@ fn zirOpaqueDecl( |
| 3393 | 3401 | } else 0; |
| 3394 | 3402 | |
| 3395 | 3403 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); |
| 3396 | extra_index += captures_len; | |
| 3404 | extra_index += captures_len * 2; | |
| 3397 | 3405 | |
| 3398 | 3406 | const opaque_init: InternPool.OpaqueTypeInit = .{ |
| 3399 | 3407 | .key = .{ .declared = .{ |
| ... | ... | @@ -3474,15 +3482,17 @@ fn zirErrorSetDecl( |
| 3474 | 3482 | return Air.internedToRef((try pt.errorSetFromUnsortedNames(names.keys())).toIntern()); |
| 3475 | 3483 | } |
| 3476 | 3484 | |
| 3477 | fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | |
| 3485 | fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 3478 | 3486 | const tracy = trace(@src()); |
| 3479 | 3487 | defer tracy.end(); |
| 3480 | 3488 | |
| 3481 | 3489 | const pt = sema.pt; |
| 3482 | 3490 | |
| 3491 | const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node); | |
| 3492 | ||
| 3483 | 3493 | if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) { |
| 3484 | 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 | } |
| 3487 | 3497 | |
| 3488 | 3498 | const target = pt.zcu.getTarget(); |
| ... | ... | @@ -3658,6 +3668,7 @@ fn zirAllocExtended( |
| 3658 | 3668 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3659 | 3669 | const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node }); |
| 3660 | 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 | 3672 | const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small); |
| 3662 | 3673 | |
| 3663 | 3674 | var extra_index: usize = extra.end; |
| ... | ... | @@ -3676,7 +3687,7 @@ fn zirAllocExtended( |
| 3676 | 3687 | |
| 3677 | 3688 | if (block.isComptime() or small.is_comptime) { |
| 3678 | 3689 | if (small.has_type) { |
| 3679 | return sema.analyzeComptimeAlloc(block, var_ty, alignment); | |
| 3690 | return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment); | |
| 3680 | 3691 | } else { |
| 3681 | 3692 | try sema.air_instructions.append(gpa, .{ |
| 3682 | 3693 | .tag = .inferred_alloc_comptime, |
| ... | ... | @@ -3691,7 +3702,7 @@ fn zirAllocExtended( |
| 3691 | 3702 | } |
| 3692 | 3703 | |
| 3693 | 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 | } |
| 3696 | 3707 | |
| 3697 | 3708 | if (small.has_type) { |
| ... | ... | @@ -3741,8 +3752,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 3741 | 3752 | |
| 3742 | 3753 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 3743 | 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 | 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 | } |
| 3747 | 3759 | |
| 3748 | 3760 | fn 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 | 3872 | // The simple strategy failed: we must create a mutable comptime alloc and |
| 3861 | 3873 | // perform all of the runtime store operations at comptime. |
| 3862 | 3874 | |
| 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); | |
| 3864 | 3876 | |
| 3865 | 3877 | const alloc_ptr = try pt.intern(.{ .ptr = .{ |
| 3866 | 3878 | .ty = alloc_ty.toIntern(), |
| ... | ... | @@ -4073,7 +4085,7 @@ fn finishResolveComptimeKnownAllocPtr( |
| 4073 | 4085 | |
| 4074 | 4086 | if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) { |
| 4075 | 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 | 4089 | const alloc = sema.getComptimeAlloc(idx); |
| 4078 | 4090 | alloc.val = .{ .interned = result_val }; |
| 4079 | 4091 | break :a idx; |
| ... | ... | @@ -4139,10 +4151,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 4139 | 4151 | |
| 4140 | 4152 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4141 | 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 }); | |
| 4142 | 4155 | |
| 4143 | 4156 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 4144 | 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 | 4160 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { |
| 4148 | 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 | 4181 | |
| 4169 | 4182 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4170 | 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 | 4185 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 4172 | 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 | 4189 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { |
| 4176 | 4190 | const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); |
| ... | ... | @@ -5726,7 +5740,7 @@ fn storeToInferredAllocComptime( |
| 5726 | 5740 | .byte_offset = 0, |
| 5727 | 5741 | } }); |
| 5728 | 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 | 5744 | sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() }; |
| 5731 | 5745 | iac.ptr = try pt.intern(.{ .ptr = .{ |
| 5732 | 5746 | .ty = alloc_ty.toIntern(), |
| ... | ... | @@ -31206,14 +31220,7 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins |
| 31206 | 31220 | } |
| 31207 | 31221 | const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op; |
| 31208 | 31222 | const other_operand = other_data.rhs; |
| 31209 | if (!sema.checkRuntimeValue(other_operand)) { | |
| 31210 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 31211 | const msg = try sema.errMsg(other_src, "runtime value contains reference to comptime var", .{}); | |
| 31212 | errdefer msg.destroy(sema.gpa); | |
| 31213 | try sema.errNote(other_src, msg, "comptime var pointers are not available at runtime", .{}); | |
| 31214 | break :msg msg; | |
| 31215 | }); | |
| 31216 | } | |
| 31223 | try sema.validateRuntimeValue(block, other_src, other_operand); | |
| 31217 | 31224 | } |
| 31218 | 31225 | } |
| 31219 | 31226 | |
| ... | ... | @@ -35328,7 +35335,7 @@ fn backingIntType( |
| 35328 | 35335 | extra_index += @intFromBool(small.has_fields_len); |
| 35329 | 35336 | extra_index += @intFromBool(small.has_decls_len); |
| 35330 | 35337 | |
| 35331 | extra_index += captures_len; | |
| 35338 | extra_index += captures_len * 2; | |
| 35332 | 35339 | |
| 35333 | 35340 | const backing_int_body_len = zir.extra[extra_index]; |
| 35334 | 35341 | extra_index += 1; |
| ... | ... | @@ -35904,7 +35911,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct { |
| 35904 | 35911 | break :decls_len decls_len; |
| 35905 | 35912 | } else 0; |
| 35906 | 35913 | |
| 35907 | extra_index += captures_len; | |
| 35914 | extra_index += captures_len * 2; | |
| 35908 | 35915 | |
| 35909 | 35916 | // The backing integer cannot be handled until `resolveStructLayout()`. |
| 35910 | 35917 | if (small.has_backing_int) { |
| ... | ... | @@ -36233,7 +36240,8 @@ fn structFieldInits( |
| 36233 | 36240 | const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null); |
| 36234 | 36241 | |
| 36235 | 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 | 36246 | struct_type.field_inits.get(ip)[field_i] = default_val.toIntern(); |
| 36239 | 36247 | } |
| ... | ... | @@ -36293,7 +36301,7 @@ fn unionFields( |
| 36293 | 36301 | } else 0; |
| 36294 | 36302 | |
| 36295 | 36303 | // Skip over captures and decls. |
| 36296 | extra_index += captures_len + decls_len; | |
| 36304 | extra_index += captures_len * 2 + decls_len; | |
| 36297 | 36305 | |
| 36298 | 36306 | const body = zir.bodySlice(extra_index, body_len); |
| 36299 | 36307 | extra_index += body.len; |
| ... | ... | @@ -37055,6 +37063,7 @@ fn isComptimeKnown( |
| 37055 | 37063 | fn analyzeComptimeAlloc( |
| 37056 | 37064 | sema: *Sema, |
| 37057 | 37065 | block: *Block, |
| 37066 | src: LazySrcLoc, | |
| 37058 | 37067 | var_type: Type, |
| 37059 | 37068 | alignment: Alignment, |
| 37060 | 37069 | ) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -37072,7 +37081,7 @@ fn analyzeComptimeAlloc( |
| 37072 | 37081 | }, |
| 37073 | 37082 | }); |
| 37074 | 37083 | |
| 37075 | const alloc = try sema.newComptimeAlloc(block, var_type, alignment); | |
| 37084 | const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment); | |
| 37076 | 37085 | |
| 37077 | 37086 | return Air.internedToRef((try pt.intern(.{ .ptr = .{ |
| 37078 | 37087 | .ty = ptr_type.toIntern(), |
| ... | ... | @@ -37979,10 +37988,189 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai |
| 37979 | 37988 | const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{}); |
| 37980 | 37989 | errdefer msg.destroy(sema.gpa); |
| 37981 | 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 | ||
| 37999 | fn 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 | 38004 | break :msg msg; |
| 37983 | 38005 | }); |
| 37984 | 38006 | } |
| 37985 | 38007 | |
| 38008 | fn 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 | ||
| 38027 | fn 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 | ||
| 38112 | fn 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 | 38174 | /// Returns true if any value contained in `val` is undefined. |
| 37987 | 38175 | fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool { |
| 37988 | 38176 | const pt = sema.pt; |
src/Value.zig+51-15| ... | ... | @@ -4064,6 +4064,7 @@ pub const PointerDeriveStep = union(enum) { |
| 4064 | 4064 | nav_ptr: InternPool.Nav.Index, |
| 4065 | 4065 | uav_ptr: InternPool.Key.Ptr.BaseAddr.Uav, |
| 4066 | 4066 | comptime_alloc_ptr: struct { |
| 4067 | idx: InternPool.ComptimeAllocIndex, | |
| 4067 | 4068 | val: Value, |
| 4068 | 4069 | ptr_ty: Type, |
| 4069 | 4070 | }, |
| ... | ... | @@ -4110,7 +4111,7 @@ pub const PointerDeriveStep = union(enum) { |
| 4110 | 4111 | }; |
| 4111 | 4112 | |
| 4112 | 4113 | pub 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 | 4115 | error.OutOfMemory => |e| return e, |
| 4115 | 4116 | error.AnalysisFail => unreachable, |
| 4116 | 4117 | }; |
| ... | ... | @@ -4120,7 +4121,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al |
| 4120 | 4121 | /// only field and element pointers with no casts. This can be used by codegen backends |
| 4121 | 4122 | /// which prefer field/elem accesses when lowering constant pointer values. |
| 4122 | 4123 | /// It is also used by the Value printing logic for pointers. |
| 4123 | pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime have_sema: bool, sema: if (have_sema) *Sema else void) !PointerDeriveStep { | |
| 4124 | pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep { | |
| 4124 | 4125 | const zcu = pt.zcu; |
| 4125 | 4126 | const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 4126 | 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 | 4144 | } }; |
| 4144 | 4145 | }, |
| 4145 | 4146 | .comptime_alloc => |idx| base: { |
| 4146 | if (!have_sema) unreachable; | |
| 4147 | const sema = opt_sema.?; | |
| 4147 | 4148 | const alloc = sema.getComptimeAlloc(idx); |
| 4148 | 4149 | const val = try alloc.val.intern(pt, sema.arena); |
| 4149 | 4150 | const ty = val.typeOf(zcu); |
| 4150 | 4151 | break :base .{ .comptime_alloc_ptr = .{ |
| 4152 | .idx = idx, | |
| 4151 | 4153 | .val = val, |
| 4152 | 4154 | .ptr_ty = try pt.ptrType(.{ |
| 4153 | 4155 | .child = ty.toIntern(), |
| ... | ... | @@ -4162,7 +4164,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 4162 | 4164 | const base_ptr = Value.fromInterned(eu_ptr); |
| 4163 | 4165 | const base_ptr_ty = base_ptr.typeOf(zcu); |
| 4164 | 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 | 4168 | break :base .{ .eu_payload_ptr = .{ |
| 4167 | 4169 | .parent = parent_step, |
| 4168 | 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 | 4174 | const base_ptr = Value.fromInterned(opt_ptr); |
| 4173 | 4175 | const base_ptr_ty = base_ptr.typeOf(zcu); |
| 4174 | 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 | 4178 | break :base .{ .opt_payload_ptr = .{ |
| 4177 | 4179 | .parent = parent_step, |
| 4178 | 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 | 4187 | const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) { |
| 4186 | 4188 | .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner( |
| 4187 | 4189 | @intCast(field.index), |
| 4188 | if (have_sema) .sema else .normal, | |
| 4190 | if (resolve_types) .sema else .normal, | |
| 4189 | 4191 | pt.zcu, |
| 4190 | if (have_sema) pt.tid else {}, | |
| 4192 | if (resolve_types) pt.tid else {}, | |
| 4191 | 4193 | ) }, |
| 4192 | 4194 | .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner( |
| 4193 | 4195 | @intCast(field.index), |
| 4194 | if (have_sema) .sema else .normal, | |
| 4196 | if (resolve_types) .sema else .normal, | |
| 4195 | 4197 | pt.zcu, |
| 4196 | if (have_sema) pt.tid else {}, | |
| 4198 | if (resolve_types) pt.tid else {}, | |
| 4197 | 4199 | ) }, |
| 4198 | 4200 | .pointer => .{ switch (field.index) { |
| 4199 | 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 | 4219 | }, |
| 4218 | 4220 | }); |
| 4219 | 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 | 4223 | break :base .{ .field_ptr = .{ |
| 4222 | 4224 | .parent = parent_step, |
| 4223 | 4225 | .field_idx = @intCast(field.index), |
| ... | ... | @@ -4226,7 +4228,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 4226 | 4228 | }, |
| 4227 | 4229 | .arr_elem => |arr_elem| base: { |
| 4228 | 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 | 4232 | const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu); |
| 4231 | 4233 | const result_ptr_ty = try pt.ptrType(.{ |
| 4232 | 4234 | .child = parent_ptr_info.child, |
| ... | ... | @@ -4248,7 +4250,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 4248 | 4250 | return base_derive; |
| 4249 | 4251 | } |
| 4250 | 4252 | |
| 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 | 4255 | if (need_child.comptimeOnly(zcu)) { |
| 4253 | 4256 | // No refinement can happen - this pointer is presumably invalid. |
| 4254 | 4257 | // Just offset it. |
| ... | ... | @@ -4293,16 +4296,34 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 4293 | 4296 | .frame, |
| 4294 | 4297 | .@"enum", |
| 4295 | 4298 | .vector, |
| 4296 | .optional, | |
| 4297 | 4299 | .@"union", |
| 4298 | 4300 | => break, |
| 4299 | 4301 | |
| 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 | 4321 | .array => { |
| 4301 | 4322 | const elem_ty = cur_ty.childType(zcu); |
| 4302 | 4323 | const elem_size = elem_ty.abiSize(zcu); |
| 4303 | 4324 | const start_idx = cur_offset / elem_size; |
| 4304 | 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 | 4327 | const parent = try arena.create(PointerDeriveStep); |
| 4307 | 4328 | parent.* = cur_derive; |
| 4308 | 4329 | cur_derive = .{ .elem_ptr = .{ |
| ... | ... | @@ -4363,7 +4384,22 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 4363 | 4384 | } |
| 4364 | 4385 | }; |
| 4365 | 4386 | |
| 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 | 4403 | return cur_derive; |
| 4368 | 4404 | } |
| 4369 | 4405 |
src/Zcu/PerThread.zig+5-5| ... | ... | @@ -3944,7 +3944,7 @@ fn recreateEnumType( |
| 3944 | 3944 | |
| 3945 | 3945 | assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew` |
| 3946 | 3946 | |
| 3947 | extra_index += captures_len; | |
| 3947 | extra_index += captures_len * 2; | |
| 3948 | 3948 | extra_index += decls_len; |
| 3949 | 3949 | |
| 3950 | 3950 | const body = zir.bodySlice(extra_index, body_len); |
| ... | ... | @@ -4071,7 +4071,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4071 | 4071 | extra_index += 1; |
| 4072 | 4072 | break :blk decls_len; |
| 4073 | 4073 | } else 0; |
| 4074 | extra_index += captures_len; | |
| 4074 | extra_index += captures_len * 2; | |
| 4075 | 4075 | if (small.has_backing_int) { |
| 4076 | 4076 | const backing_int_body_len = zir.extra[extra_index]; |
| 4077 | 4077 | extra_index += 1; // backing_int_body_len |
| ... | ... | @@ -4101,7 +4101,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4101 | 4101 | extra_index += 1; |
| 4102 | 4102 | break :blk decls_len; |
| 4103 | 4103 | } else 0; |
| 4104 | extra_index += captures_len; | |
| 4104 | extra_index += captures_len * 2; | |
| 4105 | 4105 | break :decls zir.bodySlice(extra_index, decls_len); |
| 4106 | 4106 | }, |
| 4107 | 4107 | .@"enum" => decls: { |
| ... | ... | @@ -4122,7 +4122,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4122 | 4122 | extra_index += 1; |
| 4123 | 4123 | break :blk decls_len; |
| 4124 | 4124 | } else 0; |
| 4125 | extra_index += captures_len; | |
| 4125 | extra_index += captures_len * 2; | |
| 4126 | 4126 | break :decls zir.bodySlice(extra_index, decls_len); |
| 4127 | 4127 | }, |
| 4128 | 4128 | .@"opaque" => decls: { |
| ... | ... | @@ -4140,7 +4140,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4140 | 4140 | extra_index += 1; |
| 4141 | 4141 | break :blk decls_len; |
| 4142 | 4142 | } else 0; |
| 4143 | extra_index += captures_len; | |
| 4143 | extra_index += captures_len * 2; | |
| 4144 | 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 | 29 | _ = options; |
| 30 | 30 | const sema = ctx.opt_sema.?; |
| 31 | 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 | 33 | error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function |
| 34 | 34 | error.ComptimeBreak, error.ComptimeReturn => unreachable, |
| 35 | 35 | error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully |
| ... | ... | @@ -46,7 +46,7 @@ pub fn format( |
| 46 | 46 | _ = options; |
| 47 | 47 | std.debug.assert(ctx.opt_sema == null); |
| 48 | 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 | 50 | error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function |
| 51 | 51 | error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable, |
| 52 | 52 | else => |e| return e, |
| ... | ... | @@ -58,9 +58,7 @@ pub fn print( |
| 58 | 58 | writer: anytype, |
| 59 | 59 | level: u8, |
| 60 | 60 | pt: Zcu.PerThread, |
| 61 | /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output. | |
| 62 | comptime have_sema: bool, | |
| 63 | sema: if (have_sema) *Sema else void, | |
| 61 | opt_sema: ?*Sema, | |
| 64 | 62 | ) (@TypeOf(writer).Error || Zcu.CompileError)!void { |
| 65 | 63 | const zcu = pt.zcu; |
| 66 | 64 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -94,11 +92,11 @@ pub fn print( |
| 94 | 92 | .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}), |
| 95 | 93 | .int => |int| switch (int.storage) { |
| 96 | 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 | 96 | const a = try Type.fromInterned(ty).abiAlignmentSema(pt); |
| 99 | 97 | try writer.print("{}", .{a.toByteUnits() orelse 0}); |
| 100 | 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 | 100 | const s = try Type.fromInterned(ty).abiSizeSema(pt); |
| 103 | 101 | try writer.print("{}", .{s}); |
| 104 | 102 | } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}), |
| ... | ... | @@ -110,7 +108,7 @@ pub fn print( |
| 110 | 108 | .err_name => |err_name| try writer.print("error.{}", .{ |
| 111 | 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 | 113 | .enum_literal => |enum_literal| try writer.print(".{}", .{ |
| 116 | 114 | enum_literal.fmt(ip), |
| ... | ... | @@ -124,7 +122,7 @@ pub fn print( |
| 124 | 122 | return writer.writeAll("@enumFromInt(...)"); |
| 125 | 123 | } |
| 126 | 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 | 126 | try writer.writeAll(")"); |
| 129 | 127 | }, |
| 130 | 128 | .empty_enum_value => try writer.writeAll("(empty enum value)"), |
| ... | ... | @@ -141,12 +139,12 @@ pub fn print( |
| 141 | 139 | // TODO: eventually we want to load the slice as an array with `sema`, but that's |
| 142 | 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 | 143 | try writer.writeAll("[0.."); |
| 146 | 144 | if (level == 0) { |
| 147 | 145 | try writer.writeAll("(...)"); |
| 148 | 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 | 149 | try writer.writeAll("]"); |
| 152 | 150 | }, |
| ... | ... | @@ -160,13 +158,13 @@ pub fn print( |
| 160 | 158 | // TODO: eventually we want to load the pointer with `sema`, but that's |
| 161 | 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 | 163 | .opt => |opt| switch (opt.val) { |
| 166 | 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 | 168 | .un => |un| { |
| 171 | 169 | if (level == 0) { |
| 172 | 170 | try writer.writeAll(".{ ... }"); |
| ... | ... | @@ -175,13 +173,13 @@ pub fn print( |
| 175 | 173 | if (un.tag == .none) { |
| 176 | 174 | const backing_ty = try val.typeOf(zcu).unionBackingType(pt); |
| 177 | 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 | 177 | try writer.writeAll("))"); |
| 180 | 178 | } else { |
| 181 | 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 | 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 | 183 | try writer.writeAll(" }"); |
| 186 | 184 | } |
| 187 | 185 | }, |
| ... | ... | @@ -196,8 +194,7 @@ fn printAggregate( |
| 196 | 194 | writer: anytype, |
| 197 | 195 | level: u8, |
| 198 | 196 | pt: Zcu.PerThread, |
| 199 | comptime have_sema: bool, | |
| 200 | sema: if (have_sema) *Sema else void, | |
| 197 | opt_sema: ?*Sema, | |
| 201 | 198 | ) (@TypeOf(writer).Error || Zcu.CompileError)!void { |
| 202 | 199 | if (level == 0) { |
| 203 | 200 | if (is_ref) try writer.writeByte('&'); |
| ... | ... | @@ -218,7 +215,7 @@ fn printAggregate( |
| 218 | 215 | if (i != 0) try writer.writeAll(", "); |
| 219 | 216 | const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; |
| 220 | 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 | 220 | try writer.writeAll(" }"); |
| 224 | 221 | return; |
| ... | ... | @@ -268,7 +265,7 @@ fn printAggregate( |
| 268 | 265 | const max_len = @min(len, max_aggregate_items); |
| 269 | 266 | for (0..max_len) |i| { |
| 270 | 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 | 270 | if (len > max_aggregate_items) { |
| 274 | 271 | try writer.writeAll(", ..."); |
| ... | ... | @@ -278,11 +275,12 @@ fn printAggregate( |
| 278 | 275 | |
| 279 | 276 | fn printPtr( |
| 280 | 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 | 280 | writer: anytype, |
| 282 | 281 | level: u8, |
| 283 | 282 | pt: Zcu.PerThread, |
| 284 | comptime have_sema: bool, | |
| 285 | sema: if (have_sema) *Sema else void, | |
| 283 | opt_sema: ?*Sema, | |
| 286 | 284 | ) (@TypeOf(writer).Error || Zcu.CompileError)!void { |
| 287 | 285 | const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 288 | 286 | .undef => return writer.writeAll("undefined"), |
| ... | ... | @@ -300,8 +298,7 @@ fn printPtr( |
| 300 | 298 | writer, |
| 301 | 299 | level, |
| 302 | 300 | pt, |
| 303 | have_sema, | |
| 304 | sema, | |
| 301 | opt_sema, | |
| 305 | 302 | ), |
| 306 | 303 | else => {}, |
| 307 | 304 | } |
| ... | ... | @@ -309,57 +306,96 @@ fn printPtr( |
| 309 | 306 | |
| 310 | 307 | var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa); |
| 311 | 308 | defer arena.deinit(); |
| 312 | const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, have_sema, sema); | |
| 313 | try printPtrDerivation(derivation, writer, level, pt, have_sema, sema); | |
| 309 | const derivation = if (opt_sema) |sema| | |
| 310 | try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, true, sema) | |
| 311 | else | |
| 312 | try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, false, null); | |
| 313 | ||
| 314 | _ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{ | |
| 315 | .level = level, | |
| 316 | .opt_sema = opt_sema, | |
| 317 | } }, 20); | |
| 314 | 318 | } |
| 315 | 319 | |
| 316 | /// Print `derivation` as an lvalue, i.e. such that writing `&` before this gives the pointer value. | |
| 317 | fn printPtrDerivation( | |
| 320 | const PrintPtrKind = enum { lvalue, rvalue }; | |
| 321 | ||
| 322 | /// Print the pointer defined by `derivation` as an lvalue or an rvalue. | |
| 323 | /// Returns the root derivation, which may be ignored. | |
| 324 | pub fn printPtrDerivation( | |
| 318 | 325 | derivation: Value.PointerDeriveStep, |
| 319 | 326 | writer: anytype, |
| 320 | level: u8, | |
| 321 | 327 | pt: Zcu.PerThread, |
| 322 | comptime have_sema: bool, | |
| 323 | sema: if (have_sema) *Sema else void, | |
| 324 | ) (@TypeOf(writer).Error || Zcu.CompileError)!void { | |
| 328 | /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen. | |
| 329 | /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as | |
| 330 | /// an atom -- e.g. `&foo.*` is distinct from `(&foo).*`. | |
| 331 | want_kind: ?PrintPtrKind, | |
| 332 | /// How to print the "root" of the derivation. `.print_val` will recursively print other values if needed, | |
| 333 | /// e.g. for UAV refs. `.str` will just write the root as the given string. | |
| 334 | root_strat: union(enum) { | |
| 335 | str: []const u8, | |
| 336 | print_val: struct { | |
| 337 | level: u8, | |
| 338 | opt_sema: ?*Sema, | |
| 339 | }, | |
| 340 | }, | |
| 341 | /// The maximum recursion depth. We can never recurse infinitely here, but the depth can be arbitrary, | |
| 342 | /// so at this depth we just write "..." to prevent stack overflow. | |
| 343 | ptr_depth: u8, | |
| 344 | ) !Value.PointerDeriveStep { | |
| 325 | 345 | const zcu = pt.zcu; |
| 326 | 346 | const ip = &zcu.intern_pool; |
| 327 | switch (derivation) { | |
| 328 | .int => |int| try writer.print("@as({}, @ptrFromInt({x})).*", .{ | |
| 329 | int.ptr_ty.fmt(pt), | |
| 330 | int.addr, | |
| 331 | }), | |
| 332 | .nav_ptr => |nav| { | |
| 333 | try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)}); | |
| 334 | }, | |
| 335 | .uav_ptr => |uav| { | |
| 336 | const ty = Value.fromInterned(uav.val).typeOf(zcu); | |
| 337 | try writer.print("@as({}, ", .{ty.fmt(pt)}); | |
| 338 | try print(Value.fromInterned(uav.val), writer, level - 1, pt, have_sema, sema); | |
| 339 | try writer.writeByte(')'); | |
| 340 | }, | |
| 341 | .comptime_alloc_ptr => |info| { | |
| 342 | try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)}); | |
| 343 | try print(info.val, writer, level - 1, pt, have_sema, sema); | |
| 344 | try writer.writeByte(')'); | |
| 345 | }, | |
| 346 | .comptime_field_ptr => |val| { | |
| 347 | const ty = val.typeOf(zcu); | |
| 348 | try writer.print("@as({}, ", .{ty.fmt(pt)}); | |
| 349 | try print(val, writer, level - 1, pt, have_sema, sema); | |
| 350 | try writer.writeByte(')'); | |
| 351 | }, | |
| 352 | .eu_payload_ptr => |info| { | |
| 347 | ||
| 348 | if (ptr_depth == 0) { | |
| 349 | const root_step = root: switch (derivation) { | |
| 350 | inline .eu_payload_ptr, | |
| 351 | .opt_payload_ptr, | |
| 352 | .field_ptr, | |
| 353 | .elem_ptr, | |
| 354 | .offset_and_cast, | |
| 355 | => |step| continue :root step.parent.*, | |
| 356 | else => |step| break :root step, | |
| 357 | }; | |
| 358 | try writer.writeAll("..."); | |
| 359 | return root_step; | |
| 360 | } | |
| 361 | ||
| 362 | const result_kind: PrintPtrKind = switch (derivation) { | |
| 363 | .nav_ptr, | |
| 364 | .uav_ptr, | |
| 365 | .comptime_alloc_ptr, | |
| 366 | .comptime_field_ptr, | |
| 367 | .eu_payload_ptr, | |
| 368 | .opt_payload_ptr, | |
| 369 | .field_ptr, | |
| 370 | .elem_ptr, | |
| 371 | => .lvalue, | |
| 372 | ||
| 373 | .offset_and_cast, | |
| 374 | .int, | |
| 375 | => .rvalue, | |
| 376 | }; | |
| 377 | ||
| 378 | const need_kind = want_kind orelse result_kind; | |
| 379 | ||
| 380 | if (need_kind == .rvalue and result_kind == .lvalue) { | |
| 381 | try writer.writeByte('&'); | |
| 382 | } | |
| 383 | ||
| 384 | // null if `derivation` is the root. | |
| 385 | const root_or_null: ?Value.PointerDeriveStep = switch (derivation) { | |
| 386 | .eu_payload_ptr => |info| root: { | |
| 353 | 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 | 389 | try writer.writeAll(" catch unreachable)"); |
| 390 | break :root root; | |
| 356 | 391 | }, |
| 357 | .opt_payload_ptr => |info| { | |
| 358 | try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema); | |
| 392 | .opt_payload_ptr => |info| root: { | |
| 393 | const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1); | |
| 359 | 394 | try writer.writeAll(".?"); |
| 395 | break :root root; | |
| 360 | 396 | }, |
| 361 | .field_ptr => |field| { | |
| 362 | try printPtrDerivation(field.parent.*, writer, level, pt, have_sema, sema); | |
| 397 | .field_ptr => |field| root: { | |
| 398 | const root = try printPtrDerivation(field.parent.*, writer, pt, null, root_strat, ptr_depth - 1); | |
| 363 | 399 | const agg_ty = (try field.parent.ptrType(pt)).childType(zcu); |
| 364 | 400 | switch (agg_ty.zigTypeTag(zcu)) { |
| 365 | 401 | .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| { |
| ... | ... | @@ -379,19 +415,58 @@ fn printPtrDerivation( |
| 379 | 415 | }, |
| 380 | 416 | else => unreachable, |
| 381 | 417 | } |
| 418 | break :root root; | |
| 382 | 419 | }, |
| 383 | .elem_ptr => |elem| { | |
| 384 | try printPtrDerivation(elem.parent.*, writer, level, pt, have_sema, sema); | |
| 420 | .elem_ptr => |elem| root: { | |
| 421 | const root = try printPtrDerivation(elem.parent.*, writer, pt, null, root_strat, ptr_depth - 1); | |
| 385 | 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 | 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 | 429 | try writer.writeAll("))"); |
| 391 | } else { | |
| 430 | break :root root; | |
| 431 | } else root: { | |
| 392 | 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 | 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 | 1430 | |
| 1431 | 1431 | try stream.print("{s}, ", .{@tagName(small.name_strategy)}); |
| 1432 | 1432 | |
| 1433 | if (captures_len == 0) { | |
| 1434 | try stream.writeAll("{}, "); | |
| 1435 | } else { | |
| 1436 | try stream.writeAll("{ "); | |
| 1437 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1438 | extra_index += 1; | |
| 1439 | for (1..captures_len) |_| { | |
| 1440 | try stream.writeAll(", "); | |
| 1441 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1442 | extra_index += 1; | |
| 1443 | } | |
| 1444 | try stream.writeAll(" }, "); | |
| 1445 | } | |
| 1433 | extra_index = try self.writeCaptures(stream, extra_index, captures_len); | |
| 1434 | try stream.writeAll(", "); | |
| 1446 | 1435 | |
| 1447 | 1436 | if (small.has_backing_int) { |
| 1448 | 1437 | const backing_int_body_len = self.code.extra[extra_index]; |
| ... | ... | @@ -1645,19 +1634,8 @@ const Writer = struct { |
| 1645 | 1634 | }); |
| 1646 | 1635 | try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag); |
| 1647 | 1636 | |
| 1648 | if (captures_len == 0) { | |
| 1649 | try stream.writeAll("{}, "); | |
| 1650 | } else { | |
| 1651 | try stream.writeAll("{ "); | |
| 1652 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1653 | extra_index += 1; | |
| 1654 | for (1..captures_len) |_| { | |
| 1655 | try stream.writeAll(", "); | |
| 1656 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1657 | extra_index += 1; | |
| 1658 | } | |
| 1659 | try stream.writeAll(" }, "); | |
| 1660 | } | |
| 1637 | extra_index = try self.writeCaptures(stream, extra_index, captures_len); | |
| 1638 | try stream.writeAll(", "); | |
| 1661 | 1639 | |
| 1662 | 1640 | if (decls_len == 0) { |
| 1663 | 1641 | try stream.writeAll("{}"); |
| ... | ... | @@ -1805,19 +1783,8 @@ const Writer = struct { |
| 1805 | 1783 | try stream.print("{s}, ", .{@tagName(small.name_strategy)}); |
| 1806 | 1784 | try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive); |
| 1807 | 1785 | |
| 1808 | if (captures_len == 0) { | |
| 1809 | try stream.writeAll("{}, "); | |
| 1810 | } else { | |
| 1811 | try stream.writeAll("{ "); | |
| 1812 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1813 | extra_index += 1; | |
| 1814 | for (1..captures_len) |_| { | |
| 1815 | try stream.writeAll(", "); | |
| 1816 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1817 | extra_index += 1; | |
| 1818 | } | |
| 1819 | try stream.writeAll(" }, "); | |
| 1820 | } | |
| 1786 | extra_index = try self.writeCaptures(stream, extra_index, captures_len); | |
| 1787 | try stream.writeAll(", "); | |
| 1821 | 1788 | |
| 1822 | 1789 | if (decls_len == 0) { |
| 1823 | 1790 | try stream.writeAll("{}, "); |
| ... | ... | @@ -1910,19 +1877,8 @@ const Writer = struct { |
| 1910 | 1877 | |
| 1911 | 1878 | try stream.print("{s}, ", .{@tagName(small.name_strategy)}); |
| 1912 | 1879 | |
| 1913 | if (captures_len == 0) { | |
| 1914 | try stream.writeAll("{}, "); | |
| 1915 | } else { | |
| 1916 | try stream.writeAll("{ "); | |
| 1917 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1918 | extra_index += 1; | |
| 1919 | for (1..captures_len) |_| { | |
| 1920 | try stream.writeAll(", "); | |
| 1921 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); | |
| 1922 | extra_index += 1; | |
| 1923 | } | |
| 1924 | try stream.writeAll(" }, "); | |
| 1925 | } | |
| 1880 | extra_index = try self.writeCaptures(stream, extra_index, captures_len); | |
| 1881 | try stream.writeAll(", "); | |
| 1926 | 1882 | |
| 1927 | 1883 | if (decls_len == 0) { |
| 1928 | 1884 | try stream.writeAll("{}) "); |
| ... | ... | @@ -2720,6 +2676,26 @@ const Writer = struct { |
| 2720 | 2676 | return stream.print("%{d}", .{@intFromEnum(inst)}); |
| 2721 | 2677 | } |
| 2722 | 2678 | |
| 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 | 2699 | fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void { |
| 2724 | 2700 | switch (capture.unwrap()) { |
| 2725 | 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 | 3 | } |
| 4 | 4 | |
| 5 | 5 | // error |
| 6 | // backend=stage2 | |
| 7 | // target=native | |
| 8 | 6 | // |
| 9 | 7 | // :2:5: error: found compile log statement |
| 10 | 8 | // |
| 11 | 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 | 67 | // |
| 68 | 68 | // :5:19: error: runtime value contains reference to comptime var |
| 69 | 69 | // :5:19: note: comptime var pointers are not available at runtime |
| 70 | // :4:27: note: 'runtime_value' points to comptime var declared here | |
| 70 | 71 | // :12:40: error: runtime value contains reference to comptime var |
| 71 | 72 | // :12:40: note: comptime var pointers are not available at runtime |
| 73 | // :11:27: note: 'runtime_value' points to comptime var declared here | |
| 72 | 74 | // :19:50: error: runtime value contains reference to comptime var |
| 73 | 75 | // :19:50: note: comptime var pointers are not available at runtime |
| 76 | // :18:27: note: 'runtime_value' points to comptime var declared here | |
| 74 | 77 | // :28:9: error: runtime value contains reference to comptime var |
| 75 | 78 | // :28:9: note: comptime var pointers are not available at runtime |
| 79 | // :27:27: note: 'runtime_value' points to comptime var declared here | |
| 76 | 80 | // :36:9: error: runtime value contains reference to comptime var |
| 77 | 81 | // :36:9: note: comptime var pointers are not available at runtime |
| 82 | // :35:27: note: 'runtime_value' points to comptime var declared here | |
| 78 | 83 | // :41:12: error: runtime value contains reference to comptime var |
| 79 | 84 | // :41:12: note: comptime var pointers are not available at runtime |
| 85 | // :40:27: note: 'runtime_value' points to comptime var declared here | |
| 80 | 86 | // :46:39: error: runtime value contains reference to comptime var |
| 81 | 87 | // :46:39: note: comptime var pointers are not available at runtime |
| 88 | // :45:27: note: 'runtime_value' points to comptime var declared here | |
| 82 | 89 | // :55:18: error: runtime value contains reference to comptime var |
| 83 | 90 | // :55:18: note: comptime var pointers are not available at runtime |
| 91 | // :51:30: note: 'runtime_value' points to comptime var declared here | |
| 84 | 92 | // :63:18: error: runtime value contains reference to comptime var |
| 85 | 93 | // :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 | 47 | // error |
| 48 | 48 | // |
| 49 | 49 | // :1:27: error: global variable contains reference to comptime var |
| 50 | // :2:18: note: 'a' points to comptime var declared here | |
| 50 | 51 | // :6:30: error: global variable contains reference to comptime var |
| 52 | // :7:18: note: 'b[0]' points to comptime var declared here | |
| 51 | 53 | // :11:30: error: global variable contains reference to comptime var |
| 54 | // :12:18: note: 'c' points to comptime var declared here | |
| 52 | 55 | // :16:33: error: global variable contains reference to comptime var |
| 56 | // :17:18: note: 'd' points to comptime var declared here | |
| 53 | 57 | // :22:24: error: global variable contains reference to comptime var |
| 58 | // :23:18: note: 'e.ptr' points to comptime var declared here | |
| 54 | 59 | // :28:33: error: global variable contains reference to comptime var |
| 60 | // :29:18: note: 'f' points to comptime var declared here | |
| 55 | 61 | // :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 | 64 | // :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 @@ |
| 1 | const Wrapper = struct { ptr: *ComptimeThing }; | |
| 2 | ||
| 3 | const 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 | ||
| 15 | comptime { | |
| 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 | 31 | // :20:5: error: found compile log statement |
| 32 | 32 | // |
| 33 | 33 | // Compile Log Output: |
| 34 | // @as([]i32, @as([*]i32, @ptrCast(@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).buf[0]))[0..2]) | |
| 35 | // @as([]i32, @as([*]i32, @ptrCast(@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf[0]))[0..2]) | |
| 34 | // @as([]i32, @as([*]i32, @ptrCast(&@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).buf))[0..2]) | |
| 35 | // @as([]i32, @as([*]i32, @ptrCast(&@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf))[0..2]) |