]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_const_eval / src / interpret / intrinsics / caller_location.rs
CommitLineData
17df50a5 1use rustc_ast::Mutability;
3dfed10e 2use rustc_hir::lang_items::LangItem;
f035d41b 3use rustc_middle::mir::TerminatorKind;
c295e0f8 4use rustc_middle::ty::layout::LayoutOf;
dfeec247 5use rustc_span::{Span, Symbol};
e74abb32 6
dfeec247
XL
7use crate::interpret::{
8 intrinsics::{InterpCx, Machine},
9 MPlaceTy, MemoryKind, Scalar,
10};
e74abb32 11
ba9703b0 12impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
dfeec247 13 /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
ba9703b0 14 /// frame which is not `#[track_caller]`.
923072b8 15 pub(crate) fn find_closest_untracked_caller_location(&self) -> Span {
29967ef6
XL
16 for frame in self.stack().iter().rev() {
17 debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);
18
19 // Assert that the frame we look at is actually executing code currently
487cf647
FG
20 // (`loc` is `Right` when we are unwinding and the frame does not require cleanup).
21 let loc = frame.loc.left().unwrap();
29967ef6
XL
22
23 // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
24 // (such as `box`). Use the normal span by default.
25 let mut source_info = *frame.body.source_info(loc);
26
27 // If this is a `Call` terminator, use the `fn_span` instead.
f2b60f7d 28 let block = &frame.body.basic_blocks[loc.block];
29967ef6 29 if loc.statement_index == block.statements.len() {
f035d41b 30 debug!(
29967ef6
XL
31 "find_closest_untracked_caller_location: got terminator {:?} ({:?})",
32 block.terminator(),
33 block.terminator().kind
f035d41b 34 );
29967ef6
XL
35 if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
36 source_info.span = fn_span;
37 }
38 }
39
40 // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
41 // If so, the starting `source_info.span` is in the innermost inlined
42 // function, and will be replaced with outer callsite spans as long
43 // as the inlined functions were `#[track_caller]`.
44 loop {
45 let scope_data = &frame.body.source_scopes[source_info.scope];
46
47 if let Some((callee, callsite_span)) = scope_data.inlined {
48 // Stop inside the most nested non-`#[track_caller]` function,
49 // before ever reaching its caller (which is irrelevant).
50 if !callee.def.requires_caller_location(*self.tcx) {
51 return source_info.span;
52 }
53 source_info.span = callsite_span;
54 }
55
56 // Skip past all of the parents with `inlined: None`.
57 match scope_data.inlined_parent_scope {
58 Some(parent) => source_info.scope = parent,
59 None => break,
60 }
61 }
62
63 // Stop inside the most nested non-`#[track_caller]` function,
64 // before ever reaching its caller (which is irrelevant).
65 if !frame.instance.def.requires_caller_location(*self.tcx) {
66 return source_info.span;
f035d41b
XL
67 }
68 }
29967ef6 69
923072b8 70 span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
60c5eb7d
XL
71 }
72
73 /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
923072b8 74 pub(crate) fn alloc_caller_location(
e74abb32
XL
75 &mut self,
76 filename: Symbol,
77 line: u32,
78 col: u32,
064997fb 79 ) -> MPlaceTy<'tcx, M::Provenance> {
353b0b11 80 let loc_details = self.tcx.sess.opts.unstable_opts.location_detail;
9ffffee4
FG
81 // This can fail if rustc runs out of memory right here. Trying to emit an error would be
82 // pointless, since that would require allocating more memory than these short strings.
3c0e092e 83 let file = if loc_details.file {
a2a8927a 84 self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
9ffffee4 85 .unwrap()
3c0e092e
XL
86 } else {
87 // FIXME: This creates a new allocation each time. It might be preferable to
88 // perform this allocation only once, and re-use the `MPlaceTy`.
89 // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
9ffffee4 90 self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
3c0e092e
XL
91 };
92 let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
93 let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
e74abb32 94
60c5eb7d 95 // Allocate memory for `CallerLocation` struct.
dfeec247
XL
96 let loc_ty = self
97 .tcx
9ffffee4
FG
98 .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
99 .subst(*self.tcx, self.tcx.mk_substs(&[self.tcx.lifetimes.re_erased.into()]));
60c5eb7d 100 let loc_layout = self.layout_of(loc_ty).unwrap();
136023e0 101 let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
60c5eb7d
XL
102
103 // Initialize fields.
136023e0 104 self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into())
60c5eb7d 105 .expect("writing to memory we just allocated cannot fail");
6a06907d 106 self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
60c5eb7d 107 .expect("writing to memory we just allocated cannot fail");
6a06907d 108 self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
60c5eb7d
XL
109 .expect("writing to memory we just allocated cannot fail");
110
111 location
112 }
e74abb32 113
49aad941 114 pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
60c5eb7d
XL
115 let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
116 let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
dfeec247 117 (
17df50a5 118 Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()),
ba9703b0
XL
119 u32::try_from(caller.line).unwrap(),
120 u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
60c5eb7d 121 )
e74abb32 122 }
74b04a01 123
064997fb 124 pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> {
74b04a01
XL
125 let (file, line, column) = self.location_triple_for_span(span);
126 self.alloc_caller_location(file, line, column)
127 }
e74abb32 128}