]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | use std::convert::TryFrom; |
2 | ||
3dfed10e | 3 | use rustc_hir::lang_items::LangItem; |
f035d41b | 4 | use rustc_middle::mir::TerminatorKind; |
ba9703b0 | 5 | use rustc_middle::ty::subst::Subst; |
dfeec247 | 6 | use rustc_span::{Span, Symbol}; |
60c5eb7d | 7 | use rustc_target::abi::LayoutOf; |
e74abb32 | 8 | |
dfeec247 XL |
9 | use crate::interpret::{ |
10 | intrinsics::{InterpCx, Machine}, | |
11 | MPlaceTy, MemoryKind, Scalar, | |
12 | }; | |
e74abb32 | 13 | |
ba9703b0 | 14 | impl<'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 | } |