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