From 275cb0547f40c680bff2f78926a7d411a77bb872 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 8 Feb 2020 21:31:09 +0200 Subject: [PATCH] rustc_mir: track inlined callees in SourceScopeData. --- src/librustc/mir/mod.rs | 14 +++++--- src/librustc/mir/visit.rs | 32 +++++++++++++++++-- src/librustc_mir/shim.rs | 7 +++- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_mir/transform/inline.rs | 14 +++----- src/librustc_mir/util/pretty.rs | 19 +++++++++-- src/librustc_mir_build/build/mod.rs | 2 +- src/librustc_mir_build/build/scope.rs | 1 + .../inline/inline-closure-borrows-arg.rs | 2 +- .../mir-opt/inline/inline-closure-captures.rs | 2 +- src/test/mir-opt/inline/inline-closure.rs | 2 +- .../mir-opt/inline/inline-into-box-place.rs | 2 +- .../mir-opt/inline/inline-specialization.rs | 2 +- src/test/mir-opt/simplify_try.rs | 24 +++++++------- 14 files changed, 87 insertions(+), 38 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f6c7174649fe8..5cff0e4ba0653 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -112,7 +112,7 @@ pub struct Body<'tcx> { /// A list of source scopes; these are referenced by statements /// and used for debuginfo. Indexed by a `SourceScope`. - pub source_scopes: IndexVec, + pub source_scopes: IndexVec>, /// The yield type of the function, if it is a generator. pub yield_ty: Option>, @@ -179,7 +179,7 @@ pub struct Body<'tcx> { impl<'tcx> Body<'tcx> { pub fn new( basic_blocks: IndexVec>, - source_scopes: IndexVec, + source_scopes: IndexVec>, local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, @@ -1916,11 +1916,16 @@ rustc_index::newtype_index! { } } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct SourceScopeData { +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct SourceScopeData<'tcx> { pub span: Span, pub parent_scope: Option, + /// Whether this scope is the root of a scope tree of another body, + /// inlined into this body by the MIR inliner. + /// `ty::Instance` is the callee, and the `Span` is the call site. + pub inlined: Option<(ty::Instance<'tcx>, Span)>, + /// Crate-local information for this source scope, that can't (and /// needn't) be tracked across crates. pub local_data: ClearCrossCrate, @@ -2621,7 +2626,6 @@ CloneTypeFoldableAndLiftImpls! { FakeReadCause, RetagKind, SourceScope, - SourceScopeData, SourceScopeLocalData, UserTypeAnnotationIndex, } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 2f094516a35d9..231978fab6a5f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -94,7 +94,7 @@ macro_rules! make_mir_visitor { } fn visit_source_scope_data(&mut self, - scope_data: & $($mutability)? SourceScopeData) { + scope_data: & $($mutability)? SourceScopeData<'tcx>) { self.super_source_scope_data(scope_data); } @@ -329,10 +329,14 @@ macro_rules! make_mir_visitor { } } - fn super_source_scope_data(&mut self, scope_data: & $($mutability)? SourceScopeData) { + fn super_source_scope_data( + &mut self, + scope_data: & $($mutability)? SourceScopeData<'tcx>, + ) { let SourceScopeData { span, parent_scope, + inlined, local_data: _, } = scope_data; @@ -340,6 +344,30 @@ macro_rules! make_mir_visitor { if let Some(parent_scope) = parent_scope { self.visit_source_scope(parent_scope); } + if let Some((callee, callsite_span)) = inlined { + let location = START_BLOCK.start_location(); + + self.visit_span(callsite_span); + + let ty::Instance { def: callee_def, substs: callee_substs } = callee; + match callee_def { + ty::InstanceDef::Item(_def_id) | + ty::InstanceDef::Intrinsic(_def_id) | + ty::InstanceDef::VtableShim(_def_id) | + ty::InstanceDef::ReifyShim(_def_id) | + ty::InstanceDef::Virtual(_def_id, _) | + ty::InstanceDef::ClosureOnceShim { call_once: _def_id } | + ty::InstanceDef::DropGlue(_def_id, None) => {} + + ty::InstanceDef::FnPtrShim(_def_id, ty) | + ty::InstanceDef::DropGlue(_def_id, Some(ty)) | + ty::InstanceDef::CloneShim(_def_id, ty) => { + // FIXME(eddyb) use a better `TyContext` here. + self.visit_ty(ty, TyContext::Location(location)); + } + } + self.visit_substs(callee_substs, location); + } } fn super_statement(&mut self, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 94a5f2b3bf86d..f78dcca856da7 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -243,7 +243,12 @@ fn new_body<'tcx>( Body::new( basic_blocks, IndexVec::from_elem_n( - SourceScopeData { span, parent_scope: None, local_data: ClearCrossCrate::Clear }, + SourceScopeData { + span, + parent_scope: None, + inlined: None, + local_data: ClearCrossCrate::Clear, + }, 1, ), local_decls, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index d645f6cf183b4..69ca6cf08362b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -297,7 +297,7 @@ struct ConstPropagator<'mir, 'tcx> { param_env: ParamEnv<'tcx>, // FIXME(eddyb) avoid cloning these two fields more than once, // by accessing them through `ecx` instead. - source_scopes: IndexVec, + source_scopes: IndexVec>, local_decls: IndexVec>, ret: Option>, // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index a3512178e8101..1a057500dae13 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -109,7 +109,7 @@ impl Inliner<'tcx> { let callee_node_id = self.tcx.hir().as_local_node_id(callsite.callee.def_id()); let callee_body = if let Some(callee_node_id) = callee_node_id { - // Avoid a cycle here by only using `optimized_mir` only if we have + // Avoid a cycle here by only using `instance_mir` only if we have // a lower node id than the callee. This ensures that the callee will // not inline us. This trick only works without incremental compilation. // So don't do it if that is enabled. @@ -416,15 +416,11 @@ impl Inliner<'tcx> { for mut scope in callee_body.source_scopes.iter().cloned() { if scope.parent_scope.is_none() { scope.parent_scope = Some(callsite.source_info.scope); - // FIXME(eddyb) is this really needed? - // (also note that it's always overwritten below) - scope.span = callee_body.span; - } - // FIXME(eddyb) this doesn't seem right at all. - // The inlined source scopes should probably be annotated as - // such, but also contain all of the original information. - scope.span = callsite.source_info.span; + // Mark the outermost callee scope as an inlined one. + assert_eq!(scope.inlined, None); + scope.inlined = Some((callsite.callee, callsite.source_info.span)); + } let idx = caller_body.source_scopes.push(scope); scope_map.push(idx); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index e0919e7e8f879..8b6d9ecdcbed0 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -495,8 +495,23 @@ fn write_scope_tree( }; for &child in children { - assert_eq!(body.source_scopes[child].parent_scope, Some(parent)); - writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; + let child_data = &body.source_scopes[child]; + assert_eq!(child_data.parent_scope, Some(parent)); + + if let Some((callee, callsite_span)) = child_data.inlined { + let indented_header = + format!("{0:1$}scope {2} (inlined {3}) {{", "", indent, child.index(), callee); + writeln!( + w, + "{0:1$} // at {2}", + indented_header, + ALIGN, + tcx.sess.source_map().span_to_string(callsite_span), + )?; + } else { + writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; + } + write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?; writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; } diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 32b1f2b6e1368..e6ffe286a6118 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -298,7 +298,7 @@ struct Builder<'a, 'tcx> { /// The vector of all scopes that we have created thus far; /// we track this for debuginfo later. - source_scopes: IndexVec, + source_scopes: IndexVec>, source_scope: SourceScope, /// The guard-context: each time we build the guard expression for diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs index a63ac06ec3fe9..0fe935077f9eb 100644 --- a/src/librustc_mir_build/build/scope.rs +++ b/src/librustc_mir_build/build/scope.rs @@ -684,6 +684,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.source_scopes.push(SourceScopeData { span, parent_scope: Some(parent), + inlined: None, local_data: ClearCrossCrate::Set(scope_local_data), }) } diff --git a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs index 768f495322809..f80508f6203a9 100644 --- a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs @@ -30,7 +30,7 @@ fn foo(_t: T, q: &i32) -> i32 { // let mut _9: &i32; // scope 1 { // debug x => _3; -// scope 2 { +// scope 2 (inlined foo::::{{closure}}#0) { // debug r => _8; // debug _s => _9; // } diff --git a/src/test/mir-opt/inline/inline-closure-captures.rs b/src/test/mir-opt/inline/inline-closure-captures.rs index e000a418d90c7..be5ece25bef12 100644 --- a/src/test/mir-opt/inline/inline-closure-captures.rs +++ b/src/test/mir-opt/inline/inline-closure-captures.rs @@ -26,7 +26,7 @@ fn foo(t: T, q: i32) -> (i32, T) { // let mut _11: i32; // scope 1 { // debug x => _3; -// scope 2 { +// scope 2 (inlined foo::::{{closure}}#0) { // debug _q => _11; // debug q => (*((*_6).0: &i32)); // debug t => (*((*_6).1: &T)); diff --git a/src/test/mir-opt/inline/inline-closure.rs b/src/test/mir-opt/inline/inline-closure.rs index bd36e77818edc..e1d7ea9034836 100644 --- a/src/test/mir-opt/inline/inline-closure.rs +++ b/src/test/mir-opt/inline/inline-closure.rs @@ -26,7 +26,7 @@ fn foo(_t: T, q: i32) -> i32 { // let mut _9: i32; // scope 1 { // debug x => _3; -// scope 2 { +// scope 2 (inlined foo::::{{closure}}#0) { // debug _t => _8; // debug _q => _9; // } diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs index f368bdef6f8e2..5961cab49c7b0 100644 --- a/src/test/mir-opt/inline/inline-into-box-place.rs +++ b/src/test/mir-opt/inline/inline-into-box-place.rs @@ -48,7 +48,7 @@ fn main() { // scope 1 { // debug _x => _1; // } -// scope 2 { +// scope 2 (inlined std::vec::Vec::::new) { // } // bb0: { // StorageLive(_1); diff --git a/src/test/mir-opt/inline/inline-specialization.rs b/src/test/mir-opt/inline/inline-specialization.rs index 9591019bb4f70..a2f6b01a6136f 100644 --- a/src/test/mir-opt/inline/inline-specialization.rs +++ b/src/test/mir-opt/inline/inline-specialization.rs @@ -36,7 +36,7 @@ impl Foo for Vec { // scope 1 { // debug x => _1; // } -// scope 2 { +// scope 2 (inlined as Foo>::bar) { // } // bb0: { // StorageLive(_1); diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index abac66d95c548..90fbc4f1f6599 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -28,10 +28,10 @@ fn main() { // scope 2 { // debug err => _6; // scope 3 { -// scope 7 { +// scope 7 (inlined >::from) { // debug t => _6; // } -// scope 8 { +// scope 8 (inlined as std::ops::Try>::from_error) { // debug v => _6; // let mut _12: i32; // } @@ -42,7 +42,7 @@ fn main() { // scope 5 { // } // } -// scope 6 { +// scope 6 (inlined as std::ops::Try>::into_result) { // debug self => _1; // } // bb0: { @@ -87,10 +87,10 @@ fn main() { // scope 2 { // debug err => _6; // scope 3 { -// scope 7 { +// scope 7 (inlined >::from) { // debug t => _6; // } -// scope 8 { +// scope 8 (inlined as std::ops::Try>::from_error) { // debug v => _6; // let mut _12: i32; // } @@ -101,7 +101,7 @@ fn main() { // scope 5 { // } // } -// scope 6 { +// scope 6 (inlined as std::ops::Try>::into_result) { // debug self => _1; // } // bb0: { @@ -146,10 +146,10 @@ fn main() { // scope 2 { // debug err => _6; // scope 3 { -// scope 7 { +// scope 7 (inlined >::from) { // debug t => _6; // } -// scope 8 { +// scope 8 (inlined as std::ops::Try>::from_error) { // debug v => _6; // let mut _12: i32; // } @@ -160,7 +160,7 @@ fn main() { // scope 5 { // } // } -// scope 6 { +// scope 6 (inlined as std::ops::Try>::into_result) { // debug self => _1; // } // bb0: { @@ -192,10 +192,10 @@ fn main() { // scope 2 { // debug err => _3; // scope 3 { -// scope 7 { +// scope 7 (inlined >::from) { // debug t => _3; // } -// scope 8 { +// scope 8 (inlined as std::ops::Try>::from_error) { // debug v => _3; // } // } @@ -205,7 +205,7 @@ fn main() { // scope 5 { // } // } -// scope 6 { +// scope 6 (inlined as std::ops::Try>::into_result) { // debug self => _1; // } // bb0: {