Skip to content

Commit 5f38376

Browse files
committed
Auto merge of #68965 - eddyb:mir-inline-scope, r=<try>
rustc_mir: track inlined callees in SourceScopeData. This would be a prerequisite for generating the correct debuginfo in codegen, which would look similar to what LLVM inlining generates (we should be able to "fake it" as well). Also, `#[track_caller]` is now correct in the face of MIR inlining (cc @anp). However, the debuginfo side isn't implemented yet. I might take a stab at it soon, not sure. r? @rust-lang/wg-mir-opt
2 parents a19edd6 + c43d529 commit 5f38376

25 files changed

+315
-143
lines changed

src/librustc/mir/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub struct Body<'tcx> {
112112

113113
/// A list of source scopes; these are referenced by statements
114114
/// and used for debuginfo. Indexed by a `SourceScope`.
115-
pub source_scopes: IndexVec<SourceScope, SourceScopeData>,
115+
pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
116116

117117
/// The yield type of the function, if it is a generator.
118118
pub yield_ty: Option<Ty<'tcx>>,
@@ -179,7 +179,7 @@ pub struct Body<'tcx> {
179179
impl<'tcx> Body<'tcx> {
180180
pub fn new(
181181
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
182-
source_scopes: IndexVec<SourceScope, SourceScopeData>,
182+
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
183183
local_decls: LocalDecls<'tcx>,
184184
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
185185
arg_count: usize,
@@ -1916,11 +1916,16 @@ rustc_index::newtype_index! {
19161916
}
19171917
}
19181918

1919-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
1920-
pub struct SourceScopeData {
1919+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
1920+
pub struct SourceScopeData<'tcx> {
19211921
pub span: Span,
19221922
pub parent_scope: Option<SourceScope>,
19231923

1924+
/// Whether this scope is the root of a scope tree of another body,
1925+
/// inlined into this body by the MIR inliner.
1926+
/// `ty::Instance` is the callee, and the `Span` is the call site.
1927+
pub inlined: Option<(ty::Instance<'tcx>, Span)>,
1928+
19241929
/// Crate-local information for this source scope, that can't (and
19251930
/// needn't) be tracked across crates.
19261931
pub local_data: ClearCrossCrate<SourceScopeLocalData>,
@@ -2621,7 +2626,6 @@ CloneTypeFoldableAndLiftImpls! {
26212626
FakeReadCause,
26222627
RetagKind,
26232628
SourceScope,
2624-
SourceScopeData,
26252629
SourceScopeLocalData,
26262630
UserTypeAnnotationIndex,
26272631
}

src/librustc/mir/visit.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ macro_rules! make_mir_visitor {
9494
}
9595

9696
fn visit_source_scope_data(&mut self,
97-
scope_data: & $($mutability)? SourceScopeData) {
97+
scope_data: & $($mutability)? SourceScopeData<'tcx>) {
9898
self.super_source_scope_data(scope_data);
9999
}
100100

@@ -329,17 +329,45 @@ macro_rules! make_mir_visitor {
329329
}
330330
}
331331

332-
fn super_source_scope_data(&mut self, scope_data: & $($mutability)? SourceScopeData) {
332+
fn super_source_scope_data(
333+
&mut self,
334+
scope_data: & $($mutability)? SourceScopeData<'tcx>,
335+
) {
333336
let SourceScopeData {
334337
span,
335338
parent_scope,
339+
inlined,
336340
local_data: _,
337341
} = scope_data;
338342

339343
self.visit_span(span);
340344
if let Some(parent_scope) = parent_scope {
341345
self.visit_source_scope(parent_scope);
342346
}
347+
if let Some((callee, callsite_span)) = inlined {
348+
let location = START_BLOCK.start_location();
349+
350+
self.visit_span(callsite_span);
351+
352+
let ty::Instance { def: callee_def, substs: callee_substs } = callee;
353+
match callee_def {
354+
ty::InstanceDef::Item(_def_id) |
355+
ty::InstanceDef::Intrinsic(_def_id) |
356+
ty::InstanceDef::VtableShim(_def_id) |
357+
ty::InstanceDef::ReifyShim(_def_id) |
358+
ty::InstanceDef::Virtual(_def_id, _) |
359+
ty::InstanceDef::ClosureOnceShim { call_once: _def_id } |
360+
ty::InstanceDef::DropGlue(_def_id, None) => {}
361+
362+
ty::InstanceDef::FnPtrShim(_def_id, ty) |
363+
ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
364+
ty::InstanceDef::CloneShim(_def_id, ty) => {
365+
// FIXME(eddyb) use a better `TyContext` here.
366+
self.visit_ty(ty, TyContext::Location(location));
367+
}
368+
}
369+
self.visit_substs(callee_substs, location);
370+
}
343371
}
344372

345373
fn super_statement(&mut self,

src/librustc/ty/instance.rs

+67-20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
66
use rustc_hir::def::Namespace;
77
use rustc_hir::def_id::{CrateNum, DefId};
88
use rustc_macros::HashStable;
9+
use rustc_span::sym;
910
use rustc_target::spec::abi::Abi;
1011

1112
use std::fmt;
@@ -40,6 +41,11 @@ pub enum InstanceDef<'tcx> {
4041

4142
/// `<fn() as FnTrait>::call_*`
4243
/// `DefId` is `FnTrait::call_*`.
44+
///
45+
/// NB: the (`fn` pointer) type must be monomorphic for MIR shims to work.
46+
// FIXME(eddyb) support generating shims for a "shallow type",
47+
// e.g. `fn(_, _) -> _` instead of requiring a fully monomorphic
48+
// `fn(Foo, Bar) -> Baz` etc.
4349
FnPtrShim(DefId, Ty<'tcx>),
4450

4551
/// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
@@ -55,9 +61,19 @@ pub enum InstanceDef<'tcx> {
5561
},
5662

5763
/// `drop_in_place::<T>; None` for empty drop glue.
64+
///
65+
/// NB: the type must be monomorphic for MIR shims to work.
66+
// FIXME(eddyb) support generating shims for a "shallow type",
67+
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
68+
// `Foo<Bar>` or `[String]` etc.
5869
DropGlue(DefId, Option<Ty<'tcx>>),
5970

6071
///`<T as Clone>::clone` shim.
72+
///
73+
/// NB: the type must be monomorphic for MIR shims to work.
74+
// FIXME(eddyb) support generating shims for a "shallow type",
75+
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
76+
// `Foo<Bar>` or `[String]` etc.
6177
CloneShim(DefId, Ty<'tcx>),
6278
}
6379

@@ -282,21 +298,28 @@ impl<'tcx> Instance<'tcx> {
282298
debug!(" => intrinsic");
283299
ty::InstanceDef::Intrinsic(def_id)
284300
}
285-
_ => {
286-
if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
287-
let ty = substs.type_at(0);
288-
if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
289-
debug!(" => nontrivial drop glue");
290-
ty::InstanceDef::DropGlue(def_id, Some(ty))
291-
} else {
292-
debug!(" => trivial drop glue");
293-
ty::InstanceDef::DropGlue(def_id, None)
301+
ty::FnDef(def_id, substs)
302+
if Some(def_id) == tcx.lang_items().drop_in_place_fn() =>
303+
{
304+
let ty = substs.type_at(0);
305+
306+
if ty.needs_drop(tcx, param_env) {
307+
// `DropGlue` requires a monomorphic aka concrete type.
308+
if ty.needs_subst() {
309+
return None;
294310
}
311+
312+
debug!(" => nontrivial drop glue");
313+
ty::InstanceDef::DropGlue(def_id, Some(ty))
295314
} else {
296-
debug!(" => free item");
297-
ty::InstanceDef::Item(def_id)
315+
debug!(" => trivial drop glue");
316+
ty::InstanceDef::DropGlue(def_id, None)
298317
}
299318
}
319+
_ => {
320+
debug!(" => free item");
321+
ty::InstanceDef::Item(def_id)
322+
}
300323
};
301324
Some(Instance { def: def, substs: substs })
302325
};
@@ -457,20 +480,44 @@ fn resolve_associated_item<'tcx>(
457480
trait_closure_kind,
458481
))
459482
}
460-
traits::VtableFnPointer(ref data) => Some(Instance {
461-
def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
462-
substs: rcvr_substs,
463-
}),
483+
traits::VtableFnPointer(ref data) => {
484+
// `FnPtrShim` requires a monomorphic aka concrete type.
485+
if data.fn_ty.needs_subst() {
486+
return None;
487+
}
488+
489+
Some(Instance {
490+
def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
491+
substs: rcvr_substs,
492+
})
493+
}
464494
traits::VtableObject(ref data) => {
465495
let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
466496
Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
467497
}
468498
traits::VtableBuiltin(..) => {
469-
if tcx.lang_items().clone_trait().is_some() {
470-
Some(Instance {
471-
def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
472-
substs: rcvr_substs,
473-
})
499+
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
500+
// FIXME(eddyb) use lang items for methods instead of names.
501+
let name = tcx.item_name(def_id);
502+
if name == sym::clone {
503+
let self_ty = trait_ref.self_ty();
504+
505+
// `CloneShim` requires a monomorphic aka concrete type.
506+
if self_ty.needs_subst() {
507+
return None;
508+
}
509+
510+
Some(Instance {
511+
def: ty::InstanceDef::CloneShim(def_id, self_ty),
512+
substs: rcvr_substs,
513+
})
514+
} else {
515+
assert_eq!(name, sym::clone_from);
516+
517+
// Use the default `fn clone_from` from `trait Clone`.
518+
let substs = tcx.erase_regions(&rcvr_substs);
519+
Some(ty::Instance::new(def_id, substs))
520+
}
474521
} else {
475522
None
476523
}

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

0 commit comments

Comments
 (0)