]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_mir / src / interpret / intrinsics / caller_location.rs
CommitLineData
ba9703b0
XL
1use std::convert::TryFrom;
2
3dfed10e 3use rustc_hir::lang_items::LangItem;
f035d41b 4use rustc_middle::mir::TerminatorKind;
ba9703b0 5use rustc_middle::ty::subst::Subst;
dfeec247 6use rustc_span::{Span, Symbol};
60c5eb7d 7use rustc_target::abi::LayoutOf;
e74abb32 8
dfeec247
XL
9use crate::interpret::{
10 intrinsics::{InterpCx, Machine},
11 MPlaceTy, MemoryKind, Scalar,
12};
e74abb32 13
ba9703b0 14impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
dfeec247 15 /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
ba9703b0
XL
16 /// frame which is not `#[track_caller]`.
17 crate fn find_closest_untracked_caller_location(&self) -> Span {
29967ef6
XL
18 for frame in self.stack().iter().rev() {
19 debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);
20
21 // Assert that the frame we look at is actually executing code currently
22 // (`loc` is `Err` when we are unwinding and the frame does not require cleanup).
23 let loc = frame.loc.unwrap();
24
25 // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
26 // (such as `box`). Use the normal span by default.
27 let mut source_info = *frame.body.source_info(loc);
28
29 // If this is a `Call` terminator, use the `fn_span` instead.
30 let block = &frame.body.basic_blocks()[loc.block];
31 if loc.statement_index == block.statements.len() {
f035d41b 32 debug!(
29967ef6
XL
33 "find_closest_untracked_caller_location: got terminator {:?} ({:?})",
34 block.terminator(),
35 block.terminator().kind
f035d41b 36 );
29967ef6
XL
37 if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
38 source_info.span = fn_span;
39 }
40 }
41
42 // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
43 // If so, the starting `source_info.span` is in the innermost inlined
44 // function, and will be replaced with outer callsite spans as long
45 // as the inlined functions were `#[track_caller]`.
46 loop {
47 let scope_data = &frame.body.source_scopes[source_info.scope];
48
49 if let Some((callee, callsite_span)) = scope_data.inlined {
50 // Stop inside the most nested non-`#[track_caller]` function,
51 // before ever reaching its caller (which is irrelevant).
52 if !callee.def.requires_caller_location(*self.tcx) {
53 return source_info.span;
54 }
55 source_info.span = callsite_span;
56 }
57
58 // Skip past all of the parents with `inlined: None`.
59 match scope_data.inlined_parent_scope {
60 Some(parent) => source_info.scope = parent,
61 None => break,
62 }
63 }
64
65 // Stop inside the most nested non-`#[track_caller]` function,
66 // before ever reaching its caller (which is irrelevant).
67 if !frame.instance.def.requires_caller_location(*self.tcx) {
68 return source_info.span;
f035d41b
XL
69 }
70 }
29967ef6
XL
71
72 bug!("no non-`#[track_caller]` frame found")
60c5eb7d
XL
73 }
74
75 /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
76 crate fn alloc_caller_location(
e74abb32
XL
77 &mut self,
78 filename: Symbol,
79 line: u32,
80 col: u32,
60c5eb7d
XL
81 ) -> MPlaceTy<'tcx, M::PointerTag> {
82 let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation);
e74abb32
XL
83 let line = Scalar::from_u32(line);
84 let col = Scalar::from_u32(col);
85
60c5eb7d 86 // Allocate memory for `CallerLocation` struct.
dfeec247
XL
87 let loc_ty = self
88 .tcx
3dfed10e 89 .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
ba9703b0 90 .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
60c5eb7d
XL
91 let loc_layout = self.layout_of(loc_ty).unwrap();
92 let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
93
94 // Initialize fields.
95 self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into())
96 .expect("writing to memory we just allocated cannot fail");
97 self.write_scalar(line, self.mplace_field(location, 1).unwrap().into())
98 .expect("writing to memory we just allocated cannot fail");
99 self.write_scalar(col, self.mplace_field(location, 2).unwrap().into())
100 .expect("writing to memory we just allocated cannot fail");
101
102 location
103 }
e74abb32 104
74b04a01 105 crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
60c5eb7d
XL
106 let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
107 let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
dfeec247 108 (
60c5eb7d 109 Symbol::intern(&caller.file.name.to_string()),
ba9703b0
XL
110 u32::try_from(caller.line).unwrap(),
111 u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
60c5eb7d 112 )
e74abb32 113 }
74b04a01
XL
114
115 pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> {
116 let (file, line, column) = self.location_triple_for_span(span);
117 self.alloc_caller_location(file, line, column)
118 }
e74abb32 119}