]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | use std::convert::TryFrom; |
2 | ||
17df50a5 | 3 | use rustc_ast::Mutability; |
3dfed10e | 4 | use rustc_hir::lang_items::LangItem; |
f035d41b | 5 | use rustc_middle::mir::TerminatorKind; |
c295e0f8 | 6 | use rustc_middle::ty::layout::LayoutOf; |
dfeec247 | 7 | use rustc_span::{Span, Symbol}; |
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 | 16 | /// frame which is not `#[track_caller]`. |
923072b8 | 17 | pub(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 | |
487cf647 FG |
22 | // (`loc` is `Right` when we are unwinding and the frame does not require cleanup). |
23 | let loc = frame.loc.left().unwrap(); | |
29967ef6 XL |
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. | |
f2b60f7d | 30 | let block = &frame.body.basic_blocks[loc.block]; |
29967ef6 | 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 | 71 | |
923072b8 | 72 | span_bug!(self.cur_span(), "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. | |
923072b8 | 76 | pub(crate) fn alloc_caller_location( |
e74abb32 XL |
77 | &mut self, |
78 | filename: Symbol, | |
79 | line: u32, | |
80 | col: u32, | |
064997fb FG |
81 | ) -> MPlaceTy<'tcx, M::Provenance> { |
82 | let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; | |
3c0e092e | 83 | let file = if loc_details.file { |
a2a8927a | 84 | self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not) |
3c0e092e XL |
85 | } else { |
86 | // FIXME: This creates a new allocation each time. It might be preferable to | |
87 | // perform this allocation only once, and re-use the `MPlaceTy`. | |
88 | // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 | |
89 | self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not) | |
90 | }; | |
91 | let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; | |
92 | let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; | |
e74abb32 | 93 | |
60c5eb7d | 94 | // Allocate memory for `CallerLocation` struct. |
dfeec247 XL |
95 | let loc_ty = self |
96 | .tcx | |
04454e1e | 97 | .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) |
ba9703b0 | 98 | .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); |
60c5eb7d | 99 | let loc_layout = self.layout_of(loc_ty).unwrap(); |
136023e0 XL |
100 | // This can fail if rustc runs out of memory right here. Trying to emit an error would be |
101 | // pointless, since that would require allocating more memory than a Location. | |
102 | let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); | |
60c5eb7d XL |
103 | |
104 | // Initialize fields. | |
136023e0 | 105 | self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into()) |
60c5eb7d | 106 | .expect("writing to memory we just allocated cannot fail"); |
6a06907d | 107 | self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into()) |
60c5eb7d | 108 | .expect("writing to memory we just allocated cannot fail"); |
6a06907d | 109 | self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into()) |
60c5eb7d XL |
110 | .expect("writing to memory we just allocated cannot fail"); |
111 | ||
112 | location | |
113 | } | |
e74abb32 | 114 | |
923072b8 | 115 | pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { |
60c5eb7d XL |
116 | let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); |
117 | let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); | |
dfeec247 | 118 | ( |
17df50a5 | 119 | Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()), |
ba9703b0 XL |
120 | u32::try_from(caller.line).unwrap(), |
121 | u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(), | |
60c5eb7d | 122 | ) |
e74abb32 | 123 | } |
74b04a01 | 124 | |
064997fb | 125 | pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> { |
74b04a01 XL |
126 | let (file, line, column) = self.location_triple_for_span(span); |
127 | self.alloc_caller_location(file, line, column) | |
128 | } | |
e74abb32 | 129 | } |