Skip to content

Commit 650412f

Browse files
committed
rustc_mir: support MIR-inlining #[track_caller] functions.
1 parent 5c3ec91 commit 650412f

File tree

3 files changed

+68
-26
lines changed

3 files changed

+68
-26
lines changed

src/librustc_codegen_ssa/mir/block.rs

+43-18
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::mir::interpret::PanicInfo;
1515
use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf};
1616
use rustc::ty::{self, Instance, Ty, TypeFoldable};
1717
use rustc_index::vec::Idx;
18-
use rustc_span::{source_map::Span, symbol::Symbol};
18+
use rustc_span::{Span, Symbol};
1919
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
2020
use rustc_target::spec::abi::Abi;
2121

@@ -408,7 +408,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
408408
self.set_debug_loc(&mut bx, terminator.source_info);
409409

410410
// Get the location information.
411-
let location = self.get_caller_location(&mut bx, span).immediate();
411+
let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
412412

413413
// Put together the arguments to the panic entry point.
414414
let (lang_item, args) = match msg {
@@ -444,7 +444,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
444444
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
445445
cleanup: Option<mir::BasicBlock>,
446446
) {
447-
let span = terminator.source_info.span;
447+
let source_info = terminator.source_info;
448+
let span = source_info.span;
449+
448450
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
449451
let callee = self.codegen_operand(&mut bx, func);
450452

@@ -530,7 +532,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
530532
if layout.abi.is_uninhabited() {
531533
let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
532534
let msg = bx.const_str(Symbol::intern(&msg_str));
533-
let location = self.get_caller_location(&mut bx, span).immediate();
535+
let location = self.get_caller_location(&mut bx, source_info).immediate();
534536

535537
// Obtain the panic entry point.
536538
let def_id =
@@ -575,7 +577,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
575577

576578
if intrinsic == Some("caller_location") {
577579
if let Some((_, target)) = destination.as_ref() {
578-
let location = self.get_caller_location(&mut bx, span);
580+
let location = self.get_caller_location(&mut bx, source_info);
579581

580582
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
581583
location.val.store(&mut bx, tmp);
@@ -627,13 +629,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
627629
})
628630
.collect();
629631

630-
bx.codegen_intrinsic_call(
631-
*instance.as_ref().unwrap(),
632-
&fn_abi,
633-
&args,
634-
dest,
635-
terminator.source_info.span,
636-
);
632+
bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_abi, &args, dest, span);
637633

638634
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
639635
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
@@ -739,7 +735,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
739735
args.len() + 1,
740736
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
741737
);
742-
let location = self.get_caller_location(&mut bx, span);
738+
let location = self.get_caller_location(&mut bx, source_info);
743739
let last_arg = fn_abi.args.last().unwrap();
744740
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
745741
}
@@ -982,17 +978,46 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
982978
}
983979
}
984980

985-
fn get_caller_location(&mut self, bx: &mut Bx, span: Span) -> OperandRef<'tcx, Bx::Value> {
986-
self.caller_location.unwrap_or_else(|| {
981+
fn get_caller_location(
982+
&mut self,
983+
bx: &mut Bx,
984+
source_info: mir::SourceInfo,
985+
) -> OperandRef<'tcx, Bx::Value> {
986+
let tcx = bx.tcx();
987+
988+
let mut span_to_caller_location = |span: Span| {
987989
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
988-
let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
989-
let const_loc = bx.tcx().const_caller_location((
990+
let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
991+
let const_loc = tcx.const_caller_location((
990992
Symbol::intern(&caller.file.name.to_string()),
991993
caller.line as u32,
992994
caller.col_display as u32 + 1,
993995
));
994996
OperandRef::from_const(bx, const_loc)
995-
})
997+
};
998+
999+
// Walk up the `SourceScope`s, in case some of them are from MIR inlining.
1000+
let mut caller_span = source_info.span;
1001+
let mut scope = source_info.scope;
1002+
loop {
1003+
let scope_data = &self.mir.source_scopes[scope];
1004+
1005+
if let Some((callee, callsite_span)) = scope_data.inlined {
1006+
// Stop before ("inside") the callsite of a non-`#[track_caller]` function.
1007+
if !callee.def.requires_caller_location(tcx) {
1008+
return span_to_caller_location(caller_span);
1009+
}
1010+
caller_span = callsite_span;
1011+
}
1012+
1013+
match scope_data.parent_scope {
1014+
Some(parent) => scope = parent,
1015+
None => break,
1016+
}
1017+
}
1018+
1019+
// No inlined `SourceScope`s, or all of them were `#[track_caller]`.
1020+
self.caller_location.unwrap_or_else(|| span_to_caller_location(caller_span))
9961021
}
9971022

9981023
fn get_personality_slot(&mut self, bx: &mut Bx) -> PlaceRef<'tcx, Bx::Value> {

src/librustc_mir/interpret/intrinsics/caller_location.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1414
/// `None` is returned and the callsite of the function invocation itself should be used.
1515
crate fn find_closest_untracked_caller_location(&self) -> Option<Span> {
1616
let mut caller_span = None;
17-
for next_caller in self.stack.iter().rev() {
18-
if !next_caller.instance.def.requires_caller_location(*self.tcx) {
17+
for frame in self.stack.iter().rev() {
18+
if let Some(source_info) = frame.current_source_info() {
19+
// Walk up the `SourceScope`s, in case some of them are from MIR inlining.
20+
let mut scope = source_info.scope;
21+
loop {
22+
let scope_data = &frame.body.source_scopes[scope];
23+
24+
if let Some((callee, callsite_span)) = scope_data.inlined {
25+
// Stop before ("inside") the callsite of a non-`#[track_caller]` function.
26+
if !callee.def.requires_caller_location(*self.tcx) {
27+
return caller_span;
28+
}
29+
caller_span = Some(callsite_span);
30+
}
31+
32+
match scope_data.parent_scope {
33+
Some(parent) => scope = parent,
34+
None => break,
35+
}
36+
}
37+
}
38+
39+
// Stop before ("inside") the callsite of a non-`#[track_caller]` function.
40+
if !frame.instance.def.requires_caller_location(*self.tcx) {
1941
return caller_span;
2042
}
21-
caller_span = Some(next_caller.span);
43+
caller_span = Some(frame.span);
2244
}
2345

2446
caller_span

src/librustc_mir/transform/inline.rs

-5
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ impl Inliner<'tcx> {
224224

225225
let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
226226

227-
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) {
228-
debug!("`#[track_caller]` present - not inlining");
229-
return false;
230-
}
231-
232227
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
233228
// since instrumentation might be enabled and performed on the caller.
234229
match self.tcx.sess.opts.debugging_opts.sanitizer {

0 commit comments

Comments
 (0)