summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-19 11:41:41 +0000
committerbors <bors@rust-lang.org>2020-03-19 11:41:41 +0000
commitcf35136850a7698c0da0a76785c1552ed88e1cfd (patch)
treec694b90a17f58fd2680ff3f51859d80b86933728
parent6724d584b8e3b5fa5e06466d1e900cdd60953707 (diff)
parent40dea87fbdf2ce943bfe245f0a13d7821831a88b (diff)
downloadrust-try.tar.gz
Auto merge of #68965 - eddyb:mir-inline-scope, r=<try>try
rustc_mir: track inlined callees in SourceScopeData. We now record which MIR scopes are the roots of *other* (inlined) functions's scope trees, which allows us to generate the correct debuginfo in codegen, similar to what LLVM inlining generates. This PR makes the `ui` test `backtrace-debuginfo` pass, if the MIR inliner is turned on by default. Also, `#[track_caller]` is now correct in the face of MIR inlining (cc @anp). r? @rust-lang/wg-mir-opt
-rw-r--r--src/librustc/mir/mod.rs21
-rw-r--r--src/librustc/mir/visit.rs36
-rw-r--r--src/librustc_codegen_llvm/builder.rs1
-rw-r--r--src/librustc_codegen_llvm/common.rs2
-rw-r--r--src/librustc_codegen_llvm/debuginfo/create_scope_map.rs82
-rw-r--r--src/librustc_codegen_llvm/debuginfo/doc.rs2
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs21
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs168
-rw-r--r--src/librustc_codegen_llvm/debuginfo/source_loc.rs61
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs14
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs74
-rw-r--r--src/librustc_codegen_ssa/mir/debuginfo.rs172
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs2
-rw-r--r--src/librustc_codegen_ssa/traits/backend.rs1
-rw-r--r--src/librustc_codegen_ssa/traits/debuginfo.rs28
-rw-r--r--src/librustc_codegen_ssa/traits/mod.rs1
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs29
-rw-r--r--src/librustc_mir/shim.rs8
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir/transform/inline.rs104
-rw-r--r--src/librustc_mir/util/pretty.rs19
-rw-r--r--src/librustc_mir_build/build/mod.rs2
-rw-r--r--src/librustc_mir_build/build/scope.rs2
-rw-r--r--src/rustllvm/RustWrapper.cpp13
-rw-r--r--src/test/mir-opt/inline/inline-closure-borrows-arg.rs2
-rw-r--r--src/test/mir-opt/inline/inline-closure-captures.rs2
-rw-r--r--src/test/mir-opt/inline/inline-closure.rs2
-rw-r--r--src/test/mir-opt/inline/inline-into-box-place.rs2
-rw-r--r--src/test/mir-opt/inline/inline-specialization.rs2
-rw-r--r--src/test/mir-opt/simplify_try.rs24
-rw-r--r--src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs6
-rw-r--r--src/test/ui/rfc-2091-track-caller/const-caller-location.rs10
-rw-r--r--src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs6
-rw-r--r--src/test/ui/rfc-2091-track-caller/pass.rs3
-rw-r--r--src/test/ui/rfc-2091-track-caller/std-panic-locations.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs10
-rw-r--r--src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs2
38 files changed, 557 insertions, 383 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9018cd2656f..8a685d62f44 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
//! MIR datatypes and passes. See the [rustc dev guide] for more info.
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
@@ -111,7 +113,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<SourceScope, SourceScopeData>,
+ pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
/// The yield type of the function, if it is a generator.
pub yield_ty: Option<Ty<'tcx>>,
@@ -178,7 +180,7 @@ pub struct Body<'tcx> {
impl<'tcx> Body<'tcx> {
pub fn new(
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
- source_scopes: IndexVec<SourceScope, SourceScopeData>,
+ source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
local_decls: LocalDecls<'tcx>,
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
arg_count: usize,
@@ -1969,11 +1971,21 @@ 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<SourceScope>,
+ /// 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)>,
+
+ /// Nearest (transitive) parent scope (if any) which is inlined.
+ /// This is an optimization over walking up `parent_scope`
+ /// until a scope with `inlined: Some(...)` is found.
+ pub inlined_parent_scope: Option<SourceScope>,
+
/// Crate-local information for this source scope, that can't (and
/// needn't) be tracked across crates.
pub local_data: ClearCrossCrate<SourceScopeLocalData>,
@@ -2683,7 +2695,6 @@ CloneTypeFoldableAndLiftImpls! {
FakeReadCause,
RetagKind,
SourceScope,
- SourceScopeData,
SourceScopeLocalData,
UserTypeAnnotationIndex,
}
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 2aca6f684f4..03368770e65 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,15 @@ 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,
+ inlined_parent_scope,
local_data: _,
} = scope_data;
@@ -340,6 +345,33 @@ 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);
+ }
+ if let Some(inlined_parent_scope) = inlined_parent_scope {
+ self.visit_source_scope(inlined_parent_scope);
+ }
}
fn super_statement(&mut self,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index b37d63fce65..b2fca31e0f7 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -57,6 +57,7 @@ impl BackendTypes for Builder<'_, 'll, 'tcx> {
type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope;
+ type DILocation = <CodegenCx<'ll, 'tcx> as BackendTypes>::DILocation;
type DIVariable = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIVariable;
}
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 609ddfc1d3a..faa68f92fe7 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -84,6 +84,7 @@ impl Funclet<'ll> {
impl BackendTypes for CodegenCx<'ll, 'tcx> {
type Value = &'ll Value;
+ // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.
type Function = &'ll Value;
type BasicBlock = &'ll BasicBlock;
@@ -91,6 +92,7 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
type Funclet = Funclet<'ll>;
type DIScope = &'ll llvm::debuginfo::DIScope;
+ type DILocation = &'ll llvm::debuginfo::DILocation;
type DIVariable = &'ll llvm::debuginfo::DIVariable;
}
diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
index 09422f4ec37..e36311b82c3 100644
--- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
+++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
@@ -1,21 +1,27 @@
use super::metadata::{file_metadata, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
use super::utils::DIB;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
+use rustc_codegen_ssa::traits::*;
+use crate::abi::FnAbi;
use crate::common::CodegenCx;
use crate::llvm;
-use crate::llvm::debuginfo::{DIScope, DISubprogram};
+use crate::llvm::debuginfo::{DILocation, DIScope};
use rustc::mir::{Body, SourceScope};
+use rustc::ty::layout::FnAbiExt;
+use rustc::ty::{self, Instance};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
+// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
pub fn compute_mir_scopes(
- cx: &CodegenCx<'ll, '_>,
- mir: &Body<'_>,
- fn_metadata: &'ll DISubprogram,
- debug_context: &mut FunctionDebugContext<&'ll DIScope>,
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+ mir: &Body<'tcx>,
+ fn_dbg_scope: &'ll DIScope,
+ debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
) {
// Find all the scopes with variables defined in them.
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
@@ -28,58 +34,82 @@ pub fn compute_mir_scopes(
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
- make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
+ make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope);
}
}
fn make_mir_scope(
- cx: &CodegenCx<'ll, '_>,
- mir: &Body<'_>,
- fn_metadata: &'ll DISubprogram,
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+ mir: &Body<'tcx>,
+ fn_dbg_scope: &'ll DIScope,
has_variables: &BitSet<SourceScope>,
- debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
+ debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
scope: SourceScope,
) {
- if debug_context.scopes[scope].is_valid() {
+ if debug_context.scopes[scope].dbg_scope.is_some() {
return;
}
let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
- make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
+ make_mir_scope(cx, instance, mir, fn_dbg_scope, has_variables, debug_context, parent);
debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = cx.lookup_debug_loc(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
- scope_metadata: Some(fn_metadata),
+ dbg_scope: Some(fn_dbg_scope),
+ inlined_at: None,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
return;
};
- if !has_variables.contains(scope) {
- // Do not create a DIScope if there are no variables
- // defined in this MIR Scope, to avoid debuginfo bloat.
+ if !has_variables.contains(scope) && scope_data.inlined.is_none() {
+ // Do not create a DIScope if there are no variables defined in this
+ // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
debug_context.scopes[scope] = parent_scope;
return;
}
let loc = cx.lookup_debug_loc(scope_data.span.lo());
- let file_metadata = file_metadata(cx, &loc.file.name, debug_context.defining_crate);
+ let file_metadata = file_metadata(cx, &loc.file);
- let scope_metadata = unsafe {
- Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
- DIB(cx),
- parent_scope.scope_metadata.unwrap(),
- file_metadata,
- loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
- loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
- ))
+ let dbg_scope = match scope_data.inlined {
+ Some((callee, _)) => {
+ // FIXME(eddyb) this would be `self.monomorphize(&callee)`
+ // if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
+ let callee = cx.tcx.subst_and_normalize_erasing_regions(
+ instance.substs,
+ ty::ParamEnv::reveal_all(),
+ &callee,
+ );
+ let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
+ cx.dbg_scope_fn(callee, &callee_fn_abi, None)
+ }
+ None => unsafe {
+ llvm::LLVMRustDIBuilderCreateLexicalBlock(
+ DIB(cx),
+ parent_scope.dbg_scope.unwrap(),
+ file_metadata,
+ loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
+ )
+ },
};
+
+ let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
+ // FIXME(eddyb) this doesn't account for the macro-related
+ // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
+ let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
+ cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
+ });
+
debug_context.scopes[scope] = DebugScope {
- scope_metadata,
+ dbg_scope: Some(dbg_scope),
+ inlined_at: inlined_at.or(parent_scope.inlined_at),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs
index b3a8fa29887..10dd5906529 100644
--- a/src/librustc_codegen_llvm/debuginfo/doc.rs
+++ b/src/librustc_codegen_llvm/debuginfo/doc.rs
@@ -28,7 +28,7 @@
//! utilizing a cache. The way to get a shared metadata node when needed is
//! thus to just call the corresponding function in this module:
//!
-//! let file_metadata = file_metadata(crate_context, path);
+//! let file_metadata = file_metadata(cx, file);
//!
//! The function will take care of probing the cache for an existing node for
//! that exact file path.
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 6a7ed4e1dc3..1c6520cb844 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -39,11 +39,11 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_fs_util::path_to_c_string;
use rustc_hir::def::CtorKind;
-use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol};
-use rustc_span::{self, FileName, Span};
+use rustc_span::{self, Span};
use rustc_target::abi::HasDataLayout;
use libc::{c_longlong, c_uint};
@@ -751,15 +751,11 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
metadata
}
-pub fn file_metadata(
- cx: &CodegenCx<'ll, '_>,
- file_name: &FileName,
- defining_crate: CrateNum,
-) -> &'ll DIFile {
- debug!("file_metadata: file_name: {}, defining_crate: {}", file_name, defining_crate);
+pub fn file_metadata(cx: &CodegenCx<'ll, '_>, file: &rustc_span::SourceFile) -> &'ll DIFile {
+ debug!("file_metadata({:?})", file);
- let file_name = Some(file_name.to_string());
- let directory = if defining_crate == LOCAL_CRATE {
+ let file_name = Some(file.name.to_string());
+ let directory = if file.is_real_file() && !file.is_imported() {
Some(cx.sess().working_dir.0.to_string_lossy().to_string())
} else {
// If the path comes from an upstream crate we assume it has been made
@@ -2310,7 +2306,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
let (file_metadata, line_number) = if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
- (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line)
+ (file_metadata(cx, &loc.file), loc.line)
} else {
(unknown_file_metadata(cx), None)
};
@@ -2412,8 +2408,7 @@ pub fn extend_scope_to_file(
cx: &CodegenCx<'ll, '_>,
scope_metadata: &'ll DIScope,
file: &rustc_span::SourceFile,
- defining_crate: CrateNum,
) -> &'ll DILexicalBlock {
- let file_metadata = file_metadata(cx, &file.name, defining_crate);
+ let file_metadata = file_metadata(cx, file);
unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
}
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 85decff35b9..a10da4a801f 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -3,17 +3,19 @@ mod doc;
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
-use self::metadata::{file_metadata, type_metadata, TypeMap, UNKNOWN_LINE_NUMBER};
+use self::metadata::{file_metadata, type_metadata, TypeMap};
+use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
use self::namespace::mangled_name_of_instance;
use self::type_names::compute_debuginfo_type_name;
use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
use crate::llvm;
use crate::llvm::debuginfo::{
- DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DISPFlags, DIScope, DIType, DIVariable,
+ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
+ DIVariable,
};
use rustc::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdMap, LOCAL_CRATE};
use crate::abi::FnAbi;
use crate::builder::Builder;
@@ -24,6 +26,7 @@ use rustc::ty::{self, Instance, ParamEnv, Ty};
use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync::Lrc;
use rustc_index::vec::IndexVec;
use rustc_session::config::{self, DebugInfo};
@@ -35,14 +38,13 @@ use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, Size};
use rustc_ast::ast;
use rustc_codegen_ssa::traits::*;
use rustc_span::symbol::Symbol;
-use rustc_span::{self, BytePos, Span};
+use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span};
use smallvec::SmallVec;
mod create_scope_map;
pub mod gdb;
pub mod metadata;
mod namespace;
-mod source_loc;
mod utils;
pub use self::create_scope_map::compute_mir_scopes;
@@ -144,14 +146,11 @@ impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
fn dbg_var_addr(
&mut self,
dbg_var: &'ll DIVariable,
- scope_metadata: &'ll DIScope,
+ dbg_loc: &'ll DILocation,
variable_alloca: Self::Value,
direct_offset: Size,
indirect_offsets: &[Size],
- span: Span,
) {
- let cx = self.cx();
-
// Convert the direct and indirect offsets to address ops.
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
// the values should match the ones in the DWARF standard anyway.
@@ -171,14 +170,10 @@ impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
}
}
- // FIXME(eddyb) maybe this information could be extracted from `dbg_var`,
- // to avoid having to pass it down in both places?
- // NB: `var` doesn't seem to know about the column, so that's a limitation.
- let dbg_loc = cx.create_debug_loc(scope_metadata, span);
unsafe {
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
- DIB(cx),
+ DIB(self.cx()),
variable_alloca,
dbg_var,
addr_ops.as_ptr(),
@@ -189,15 +184,13 @@ impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
}
}
- fn set_source_location(&mut self, scope: &'ll DIScope, span: Span) {
- debug!("set_source_location: {}", self.sess().source_map().span_to_string(span));
-
- let dbg_loc = self.cx().create_debug_loc(scope, span);
-
+ fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
unsafe {
- llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc);
+ let dbg_loc_as_llval = llvm::LLVMRustMetadataAsValue(self.cx().llcx, dbg_loc);
+ llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc_as_llval);
}
}
+
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
}
@@ -226,30 +219,95 @@ impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
}
}
+/// A source code location used to generate debug information.
+// FIXME(eddyb) rename this to better indicate it's a duplicate of
+// `rustc_span::Loc` rather than `DILocation`, perhaps by making
+// `lookup_char_pos` return the right information instead.
+pub struct DebugLoc {
+ /// Information about the original source file.
+ pub file: Lrc<SourceFile>,
+ /// The (1-based) line number.
+ pub line: Option<u32>,
+ /// The (1-based) column number.
+ pub col: Option<u32>,
+}
+
+impl CodegenCx<'ll, '_> {
+ /// Looks up debug source information about a `BytePos`.
+ // FIXME(eddyb) rename this to better indicate it's a duplicate of
+ // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
+ // `lookup_char_pos` return the right information instead.
+ pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
+ let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
+ Ok(SourceFileAndLine { sf: file, line }) => {
+ let line_pos = file.line_begin_pos(pos);
+
+ // Use 1-based indexing.
+ let line = (line + 1) as u32;
+ let col = (pos - line_pos).to_u32() + 1;
+
+ (file, Some(line), Some(col))
+ }
+ Err(file) => (file, None, None),
+ };
+
+ // For MSVC, omit the column number.
+ // Otherwise, emit it. This mimics clang behaviour.
+ // See discussion in https://github.com/rust-lang/rust/issues/42921
+ if self.sess().target.target.options.is_like_msvc {
+ DebugLoc { file, line, col: None }
+ } else {
+ DebugLoc { file, line, col }
+ }
+ }
+}
+
impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: &'ll Value,
- mir: &mir::Body<'_>,
- ) -> Option<FunctionDebugContext<&'ll DIScope>> {
+ mir: &mir::Body<'tcx>,
+ ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
if self.sess().opts.debuginfo == DebugInfo::None {
return None;
}
- let span = mir.span;
+ // Initialize fn debug context (including scopes).
+ // FIXME(eddyb) figure out a way to not need `Option` for `dbg_scope`.
+ let empty_scope = DebugScope {
+ dbg_scope: None,
+ inlined_at: None,
+ file_start_pos: BytePos(0),
+ file_end_pos: BytePos(0),
+ };
+ let mut fn_debug_context =
+ FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
- // This can be the case for functions inlined from another crate
- if span.is_dummy() {
- // FIXME(simulacrum): Probably can't happen; remove.
- return None;
- }
+ // Fill in all the scopes, with the information from the MIR body.
+ compute_mir_scopes(
+ self,
+ instance,
+ mir,
+ self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
+ &mut fn_debug_context,
+ );
+
+ Some(fn_debug_context)
+ }
+ fn dbg_scope_fn(
+ &self,
+ instance: Instance<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ maybe_definition_llfn: Option<&'ll Value>,
+ ) -> &'ll DIScope {
let def_id = instance.def_id();
let containing_scope = get_containing_scope(self, instance);
+ let span = self.tcx.def_span(def_id);
let loc = self.lookup_debug_loc(span.lo());
- let file_metadata = file_metadata(self, &loc.file.name, def_id.krate);
+ let file_metadata = file_metadata(self, &loc.file);
let function_type_metadata = unsafe {
let fn_signature = get_function_signature(self, fn_abi);
@@ -295,8 +353,8 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
- let fn_metadata = unsafe {
- llvm::LLVMRustDIBuilderCreateFunction(
+ unsafe {
+ return llvm::LLVMRustDIBuilderCreateFunction(
DIB(self),
containing_scope,
name.as_ptr().cast(),
@@ -309,28 +367,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
scope_line.unwrap_or(UNKNOWN_LINE_NUMBER),
flags,
spflags,
- llfn,
+ maybe_definition_llfn,
template_parameters,
None,
- )
- };
-
- // Initialize fn debug context (including scopes).
- // FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
- let null_scope = DebugScope {
- scope_metadata: None,
- file_start_pos: BytePos(0),
- file_end_pos: BytePos(0),
- };
- let mut fn_debug_context = FunctionDebugContext {
- scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
- defining_crate: def_id.krate,
- };
-
- // Fill in all the scopes, with the information from the MIR body.
- compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);
-
- return Some(fn_debug_context);
+ );
+ }
fn get_function_signature<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
@@ -502,6 +543,25 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
+ fn dbg_loc(
+ &self,
+ scope: &'ll DIScope,
+ inlined_at: Option<&'ll DILocation>,
+ span: Span,
+ ) -> &'ll DILocation {
+ let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateDebugLocation(
+ utils::debug_context(self).llcontext,
+ line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
+ scope,
+ inlined_at,
+ )
+ }
+ }
+
fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) {
metadata::create_vtable_metadata(self, ty, vtable)
}
@@ -510,9 +570,8 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
&self,
scope_metadata: &'ll DIScope,
file: &rustc_span::SourceFile,
- defining_crate: CrateNum,
) -> &'ll DILexicalBlock {
- metadata::extend_scope_to_file(&self, scope_metadata, file, defining_crate)
+ metadata::extend_scope_to_file(&self, scope_metadata, file)
}
fn debuginfo_finalize(&self) {
@@ -523,7 +582,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
fn create_dbg_var(
&self,
- dbg_context: &FunctionDebugContext<&'ll DIScope>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: &'ll DIScope,
@@ -531,7 +589,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
span: Span,
) -> &'ll DIVariable {
let loc = self.lookup_debug_loc(span.lo());
- let file_metadata = file_metadata(self, &loc.file.name, dbg_context.defining_crate);
+ let file_metadata = file_metadata(self, &loc.file);
let type_metadata = type_metadata(self, variable_type, span);
diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
deleted file mode 100644
index 66ae9d72c3e..00000000000
--- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use super::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
-use super::utils::debug_context;
-
-use crate::common::CodegenCx;
-use crate::llvm::debuginfo::DIScope;
-use crate::llvm::{self, Value};
-use rustc_codegen_ssa::traits::*;
-
-use rustc_data_structures::sync::Lrc;
-use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span};
-
-/// A source code location used to generate debug information.
-pub struct DebugLoc {
- /// Information about the original source file.
- pub file: Lrc<SourceFile>,
- /// The (1-based) line number.
- pub line: Option<u32>,
- /// The (1-based) column number.
- pub col: Option<u32>,
-}
-
-impl CodegenCx<'ll, '_> {
- /// Looks up debug source information about a `BytePos`.
- pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
- let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
- Ok(SourceFileAndLine { sf: file, line }) => {
- let line_pos = file.line_begin_pos(pos);
-
- // Use 1-based indexing.
- let line = (line + 1) as u32;
- let col = (pos - line_pos).to_u32() + 1;
-
- (file, Some(line), Some(col))
- }
- Err(file) => (file, None, None),
- };
-
- // For MSVC, omit the column number.
- // Otherwise, emit it. This mimics clang behaviour.
- // See discussion in https://github.com/rust-lang/rust/issues/42921
- if self.sess().target.target.options.is_like_msvc {
- DebugLoc { file, line, col: None }
- } else {
- DebugLoc { file, line, col }
- }
- }
-
- pub fn create_debug_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll Value {
- let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
-
- unsafe {
- llvm::LLVMRustDIBuilderCreateDebugLocation(
- debug_context(self).llcontext,
- line.unwrap_or(UNKNOWN_LINE_NUMBER),
- col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
- scope,
- None,
- )
- }
- }
-}
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index c17c06718f5..9a1a132f0d7 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -3,8 +3,9 @@
use super::debuginfo::{
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
- DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DINameSpace, DISPFlags, DIScope,
- DISubprogram, DISubrange, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind,
+ DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace,
+ DISPFlags, DIScope, DISubprogram, DISubrange, DITemplateTypeParameter, DIType, DIVariable,
+ DebugEmissionKind,
};
use libc::{c_char, c_int, c_uint, size_t};
@@ -624,6 +625,7 @@ pub mod debuginfo {
pub struct DIBuilder<'a>(InvariantOpaque<'a>);
pub type DIDescriptor = Metadata;
+ pub type DILocation = Metadata;
pub type DIScope = DIDescriptor;
pub type DIFile = DIScope;
pub type DILexicalBlock = DIScope;
@@ -1653,7 +1655,7 @@ extern "C" {
ScopeLine: c_uint,
Flags: DIFlags,
SPFlags: DISPFlags,
- Fn: &'a Value,
+ MaybeFn: Option<&'a Value>,
TParam: &'a DIArray,
Decl: Option<&'a DIDescriptor>,
) -> &'a DISubprogram;
@@ -1795,7 +1797,7 @@ extern "C" {
VarInfo: &'a DIVariable,
AddrOps: *const i64,
AddrOpsCount: c_uint,
- DL: &'a Value,
+ DL: &'a DILocation,
InsertAtEnd: &'a BasicBlock,
) -> &'a Value;
@@ -1886,8 +1888,8 @@ extern "C" {
Line: c_uint,
Column: c_uint,
Scope: &'a DIScope,
- InlinedAt: Option<&'a Metadata>,
- ) -> &'a Value;
+ InlinedAt: Option<&'a DILocation>,
+ ) -> &'a DILocation;
pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 8433f793020..32299a5b490 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -15,7 +15,7 @@ use rustc::mir::AssertKind;
use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf};
use rustc::ty::{self, Instance, Ty, TypeFoldable};
use rustc_index::vec::Idx;
-use rustc_span::{source_map::Span, symbol::Symbol};
+use rustc_span::{Span, Symbol};
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::spec::abi::Abi;
@@ -403,7 +403,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(&mut bx, terminator.source_info);
// Get the location information.
- let location = self.get_caller_location(&mut bx, span).immediate();
+ let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
// Put together the arguments to the panic entry point.
let (lang_item, args) = match msg {
@@ -440,7 +440,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &mut Bx,
intrinsic: Option<&str>,
instance: Option<Instance<'tcx>>,
- span: Span,
+ source_info: mir::SourceInfo,
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>,
) -> bool {
@@ -481,12 +481,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
};
let msg = bx.const_str(Symbol::intern(&msg_str));
- let location = self.get_caller_location(bx, span).immediate();
+ let location = self.get_caller_location(bx, source_info).immediate();
// Obtain the panic entry point.
// FIXME: dedup this with `codegen_assert_terminator` above.
- let def_id =
- common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
+ let def_id = common::langcall(
+ bx.tcx(),
+ Some(source_info.span),
+ "",
+ lang_items::PanicFnLangItem,
+ );
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_abi = FnAbi::of_instance(bx, instance, &[]);
let llfn = bx.get_fn_addr(instance);
@@ -526,7 +530,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>,
) {
- let span = terminator.source_info.span;
+ let source_info = terminator.source_info;
+ let span = source_info.span;
+
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
let callee = self.codegen_operand(&mut bx, func);
@@ -607,7 +613,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&mut bx,
intrinsic,
instance,
- span,
+ source_info,
destination,
cleanup,
) {
@@ -628,7 +634,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if intrinsic == Some("caller_location") {
if let Some((_, target)) = destination.as_ref() {
- let location = self.get_caller_location(&mut bx, span);
+ let location = self.get_caller_location(&mut bx, source_info);
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
location.val.store(&mut bx, tmp);
@@ -680,13 +686,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
- bx.codegen_intrinsic_call(
- *instance.as_ref().unwrap(),
- &fn_abi,
- &args,
- dest,
- terminator.source_info.span,
- );
+ bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_abi, &args, dest, span);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
@@ -792,7 +792,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args.len() + 1,
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
);
- let location = self.get_caller_location(&mut bx, span);
+ let location = self.get_caller_location(&mut bx, source_info);
let last_arg = fn_abi.args.last().unwrap();
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
}
@@ -1035,17 +1035,47 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
- fn get_caller_location(&mut self, bx: &mut Bx, span: Span) -> OperandRef<'tcx, Bx::Value> {
- self.caller_location.unwrap_or_else(|| {
+ fn get_caller_location(
+ &mut self,
+ bx: &mut Bx,
+ source_info: mir::SourceInfo,
+ ) -> OperandRef<'tcx, Bx::Value> {
+ let tcx = bx.tcx();
+
+ let mut span_to_caller_location = |span: Span| {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
- let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
- let const_loc = bx.tcx().const_caller_location((
+ let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
+ let const_loc = tcx.const_caller_location((
Symbol::intern(&caller.file.name.to_string()),
caller.line as u32,
caller.col_display as u32 + 1,
));
OperandRef::from_const(bx, const_loc, bx.tcx().caller_location_ty())
- })
+ };
+
+ // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
+ let mut caller_span = source_info.span;
+ let mut scope = source_info.scope;
+ loop {
+ let scope_data = &self.mir.source_scopes[scope];
+
+ if let Some((callee, callsite_span)) = scope_data.inlined {
+ // Stop before ("inside") the callsite of a non-`#[track_caller]` function.
+ if !callee.def.requires_caller_location(tcx) {
+ return span_to_caller_location(caller_span);
+ }
+ caller_span = callsite_span;
+ }
+
+ // Skip past all of the parents with `inlined: None`.
+ match scope_data.inlined_parent_scope {
+ Some(parent) => scope = parent,
+ None => break,
+ }
+ }
+
+ // No inlined `SourceScope`s, or all of them were `#[track_caller]`.
+ self.caller_location.unwrap_or_else(|| span_to_caller_location(caller_span))
}
fn get_personality_slot(&mut self, bx: &mut Bx) -> PlaceRef<'tcx, Bx::Value> {
diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs
index cbe5f511152..45bbfa4f099 100644
--- a/src/librustc_codegen_ssa/mir/debuginfo.rs
+++ b/src/librustc_codegen_ssa/mir/debuginfo.rs
@@ -2,7 +2,6 @@ use crate::traits::*;
use rustc::mir;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Size};
-use rustc_hir::def_id::CrateNum;
use rustc_index::vec::IndexVec;
use rustc_session::config::DebugInfo;
@@ -13,9 +12,8 @@ use super::operand::OperandValue;
use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};
-pub struct FunctionDebugContext<D> {
- pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
- pub defining_crate: CrateNum,
+pub struct FunctionDebugContext<S, L> {
+ pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
}
#[derive(Copy, Clone)]
@@ -38,76 +36,74 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
}
#[derive(Clone, Copy, Debug)]
-pub struct DebugScope<D> {
- pub scope_metadata: Option<D>,
+pub struct DebugScope<S, L> {
+ // FIXME(eddyb) this should never be `None`, after initialization.
+ pub dbg_scope: Option<S>,
+
+ /// Call site location, if this scope was inlined from another function.
+ pub inlined_at: Option<L>,
+
// Start and end offsets of the file to which this DIScope belongs.
// These are used to quickly determine whether some span refers to the same file.
pub file_start_pos: BytePos,
pub file_end_pos: BytePos,
}
-impl<D> DebugScope<D> {
- pub fn is_valid(&self) -> bool {
- self.scope_metadata.is_some()
+impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
+ /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
+ /// it may so happen that the current span belongs to a different file than the DIScope
+ /// corresponding to span's containing source scope. If so, we need to create a DIScope
+ /// "extension" into that file.
+ pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
+ &self,
+ cx: &Cx,
+ span: Span,
+ ) -> S {
+ // FIXME(eddyb) this should never be `None`.
+ let dbg_scope = self.dbg_scope.unwrap();
+
+ let pos = span.lo();
+ if pos < self.file_start_pos || pos >= self.file_end_pos {
+ let sm = cx.sess().source_map();
+ cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file)
+ } else {
+ dbg_scope
+ }
}
}
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
- let (scope, span) = self.debug_loc(source_info);
- if let Some(scope) = scope {
- bx.set_source_location(scope, span);
+ if let Some(dbg_loc) = self.dbg_loc(source_info) {
+ bx.set_dbg_loc(dbg_loc);
}
}
- pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
+ fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> {
+ let span = self.adjust_span_for_debugging(source_info.span);
+ let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
+ let dbg_scope = scope.adjust_dbg_scope_for_span(self.cx, span);
+ Some(self.cx.dbg_loc(dbg_scope, scope.inlined_at, span))
+ }
+
+ /// In order to have a good line stepping behavior in debugger, we overwrite debug
+ /// locations of macro expansions with that of the outermost expansion site
+ /// (unless the crate is being compiled with `-Z debug-macros`).
+ fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
// Bail out if debug info emission is not enabled.
- match self.debug_context {
- None => return (None, source_info.span),
- Some(_) => {}
+ if self.debug_context.is_none() {
+ return span;
}
- // In order to have a good line stepping behavior in debugger, we overwrite debug
- // locations of macro expansions with that of the outermost expansion site
- // (unless the crate is being compiled with `-Z debug-macros`).
- if !source_info.span.from_expansion() || self.cx.sess().opts.debugging_opts.debug_macros {
- let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
- (scope, source_info.span)
- } else {
+ if span.from_expansion() && !self.cx.sess().opts.debugging_opts.debug_macros {
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
- let span = rustc_span::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
- let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
// Use span of the outermost expansion site, while keeping the original lexical scope.
- (scope, span)
+ span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
}
- }
- // DILocations inherit source file name from the parent DIScope. Due to macro expansions
- // it may so happen that the current span belongs to a different file than the DIScope
- // corresponding to span's containing source scope. If so, we need to create a DIScope
- // "extension" into that file.
- fn scope_metadata_for_loc(
- &self,
- scope_id: mir::SourceScope,
- pos: BytePos,
- ) -> Option<Bx::DIScope> {
- let debug_context = self.debug_context.as_ref()?;
- let scope_metadata = debug_context.scopes[scope_id].scope_metadata;
- if pos < debug_context.scopes[scope_id].file_start_pos
- || pos >= debug_context.scopes[scope_id].file_end_pos
- {
- let sm = self.cx.sess().source_map();
- let defining_crate = debug_context.defining_crate;
- Some(self.cx.extend_scope_to_file(
- scope_metadata.unwrap(),
- &sm.lookup_char_pos(pos).file,
- defining_crate,
- ))
- } else {
- scope_metadata
- }
+ span
}
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
@@ -147,24 +143,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
let name = kw::Invalid;
let decl = &self.mir.local_decls[local];
- let (scope, span) = if full_debug_info {
- self.debug_loc(decl.source_info)
+ let dbg_var = if full_debug_info {
+ self.debug_context.as_ref().map(|debug_context| {
+ // FIXME(eddyb) is this `+ 1` needed at all?
+ let kind = VariableKind::ArgumentVariable(arg_index + 1);
+
+ let arg_ty = self.monomorphize(&decl.ty);
+
+ let span = self.adjust_span_for_debugging(decl.source_info.span);
+ let scope = &debug_context.scopes[decl.source_info.scope];
+ let dbg_scope = scope.adjust_dbg_scope_for_span(self.cx, span);
+
+ self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
+ })
} else {
- (None, decl.source_info.span)
+ None
};
- let dbg_var = scope.map(|scope| {
- // FIXME(eddyb) is this `+ 1` needed at all?
- let kind = VariableKind::ArgumentVariable(arg_index + 1);
-
- self.cx.create_dbg_var(
- self.debug_context.as_ref().unwrap(),
- name,
- self.monomorphize(&decl.ty),
- scope,
- kind,
- span,
- )
- });
Some(PerLocalVarDebugInfo {
name,
@@ -238,6 +232,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let vars = vars.iter().copied().chain(fallback_var);
for var in vars {
+ let dbg_var = match var.dbg_var {
+ Some(dbg_var) => dbg_var,
+ None => continue,
+ };
+ let dbg_loc = match self.dbg_loc(var.source_info) {
+ Some(dbg_loc) => dbg_loc,
+ None => continue,
+ };
+
let mut layout = base.layout;
let mut direct_offset = Size::ZERO;
// FIXME(eddyb) use smallvec here.
@@ -274,19 +277,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
- let (scope, span) = self.debug_loc(var.source_info);
- if let Some(scope) = scope {
- if let Some(dbg_var) = var.dbg_var {
- bx.dbg_var_addr(
- dbg_var,
- scope,
- base.llval,
- direct_offset,
- &indirect_offsets,
- span,
- );
- }
- }
+ bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
}
}
@@ -310,12 +301,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
for var in &self.mir.var_debug_info {
- let (scope, span) = if full_debug_info {
- self.debug_loc(var.source_info)
+ let dbg_scope_and_span = if full_debug_info {
+ self.debug_context.as_ref().map(|debug_context| {
+ let span = self.adjust_span_for_debugging(var.source_info.span);
+ let scope = &debug_context.scopes[var.source_info.scope];
+ (scope.adjust_dbg_scope_for_span(self.cx, span), span)
+ })
} else {
- (None, var.source_info.span)
+ None
};
- let dbg_var = scope.map(|scope| {
+ let dbg_var = dbg_scope_and_span.map(|(dbg_scope, span)| {
let place = var.place;
let var_ty = self.monomorphized_place_ty(place.as_ref());
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
@@ -331,14 +326,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
VariableKind::LocalVariable
};
- self.cx.create_dbg_var(
- self.debug_context.as_ref().unwrap(),
- var.name,
- var_ty,
- scope,
- var_kind,
- span,
- )
+ self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
});
per_local[var.place.local].push(PerLocalVarDebugInfo {
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 64ead19b358..72ceb3c597a 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -23,7 +23,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
mir: mir::ReadOnlyBodyAndCache<'tcx, 'tcx>,
- debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
+ debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
llfn: Bx::Function,
diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs
index 7acae300a2f..bb479a27c86 100644
--- a/src/librustc_codegen_ssa/traits/backend.rs
+++ b/src/librustc_codegen_ssa/traits/backend.rs
@@ -24,6 +24,7 @@ pub trait BackendTypes {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `Dbg`, `Debug`, `DebugInfo`, `DI` etc.).
type DIScope: Copy;
+ type DILocation: Copy;
type DIVariable: Copy;
}
diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs
index 14c5a1b8ee9..7408d78bbe7 100644
--- a/src/librustc_codegen_ssa/traits/debuginfo.rs
+++ b/src/librustc_codegen_ssa/traits/debuginfo.rs
@@ -4,7 +4,6 @@ use rustc::mir;
use rustc::ty::layout::Size;
use rustc::ty::{Instance, Ty};
use rustc_ast::ast::Name;
-use rustc_hir::def_id::CrateNum;
use rustc_span::{SourceFile, Span};
use rustc_target::abi::call::FnAbi;
@@ -20,14 +19,29 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: Self::Function,
- mir: &mir::Body<'_>,
- ) -> Option<FunctionDebugContext<Self::DIScope>>;
+ mir: &mir::Body<'tcx>,
+ ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
+
+ // FIXME(eddyb) find a common convention for all of the debuginfo-related
+ // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+ fn dbg_scope_fn(
+ &self,
+ instance: Instance<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ maybe_definition_llfn: Option<Self::Function>,
+ ) -> Self::DIScope;
+
+ fn dbg_loc(
+ &self,
+ scope: Self::DIScope,
+ inlined_at: Option<Self::DILocation>,
+ span: Span,
+ ) -> Self::DILocation;
fn extend_scope_to_file(
&self,
scope_metadata: Self::DIScope,
file: &SourceFile,
- defining_crate: CrateNum,
) -> Self::DIScope;
fn debuginfo_finalize(&self);
@@ -35,7 +49,6 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
fn create_dbg_var(
&self,
- dbg_context: &FunctionDebugContext<Self::DIScope>,
variable_name: Name,
variable_type: Ty<'tcx>,
scope_metadata: Self::DIScope,
@@ -50,14 +63,13 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
fn dbg_var_addr(
&mut self,
dbg_var: Self::DIVariable,
- scope_metadata: Self::DIScope,
+ dbg_loc: Self::DILocation,
variable_alloca: Self::Value,
direct_offset: Size,
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
indirect_offsets: &[Size],
- span: Span,
);
- fn set_source_location(&mut self, scope: Self::DIScope, span: Span);
+ fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
fn set_var_name(&mut self, value: Self::Value, name: &str);
}
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index d03ff8d4d37..d5b423d22a5 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -93,6 +93,7 @@ pub trait HasCodegen<'tcx>:
Type = Self::Type,
Funclet = Self::Funclet,
DIScope = Self::DIScope,
+ DILocation = Self::DILocation,
DIVariable = Self::DIVariable,
>;
}
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index 566601f0cae..aecefb097f6 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -14,11 +14,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// `None` is returned and the callsite of the function invocation itself should be used.
crate fn find_closest_untracked_caller_location(&self) -> Option<Span> {
let mut caller_span = None;
- for next_caller in self.stack.iter().rev() {
- if !next_caller.instance.def.requires_caller_location(*self.tcx) {
+ for frame in self.stack.iter().rev() {
+ if let Some(source_info) = frame.current_source_info() {
+ // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
+ let mut scope = source_info.scope;
+ loop {
+ let scope_data = &frame.body.source_scopes[scope];
+
+ if let Some((callee, callsite_span)) = scope_data.inlined {
+ // Stop before ("inside") the callsite of a non-`#[track_caller]` function.
+ if !callee.def.requires_caller_location(*self.tcx) {
+ return caller_span;
+ }
+ caller_span = Some(callsite_span);
+ }
+
+ // Skip past all of the parents with `inlined: None`.
+ match scope_data.inlined_parent_scope {
+ Some(parent) => scope = parent,
+ None => break,
+ }
+ }
+ }
+
+ // Stop before ("inside") the callsite of a non-`#[track_caller]` function.
+ if !frame.instance.def.requires_caller_location(*self.tcx) {
return caller_span;
}
- caller_span = Some(next_caller.span);
+ caller_span = Some(frame.span);
}
caller_span
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index c1d969a4b51..0663369e1e3 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -253,7 +253,13 @@ 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,
+ inlined_parent_scope: 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 ca23c44f646..375a620acc9 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -284,7 +284,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<SourceScope, SourceScopeData>,
+ source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
ret: Option<OpTy<'tcx, ()>>,
// 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 769f3fdcc01..d8124077366 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -3,10 +3,9 @@
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc::mir::visit::*;
use rustc::mir::*;
-use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_attr as attr;
-use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::config::Sanitizer;
@@ -29,10 +28,9 @@ pub struct Inline;
#[derive(Copy, Clone, Debug)]
struct CallSite<'tcx> {
- callee: DefId,
- substs: SubstsRef<'tcx>,
+ callee: Instance<'tcx>,
bb: BasicBlock,
- location: SourceInfo,
+ source_info: SourceInfo,
}
impl<'tcx> MirPass<'tcx> for Inline {
@@ -94,35 +92,43 @@ impl Inliner<'tcx> {
local_change = false;
while let Some(callsite) = callsites.pop_front() {
debug!("checking whether to inline callsite {:?}", callsite);
- if !self.tcx.is_mir_available(callsite.callee) {
- debug!("checking whether to inline callsite {:?} - MIR unavailable", callsite);
- continue;
+
+ if let InstanceDef::Item(callee_def_id) = callsite.callee.def {
+ if !self.tcx.is_mir_available(callee_def_id) {
+ debug!(
+ "checking whether to inline callsite {:?} - MIR unavailable",
+ callsite,
+ );
+ continue;
+ }
}
let self_node_id = self.tcx.hir().as_local_node_id(self.source.def_id()).unwrap();
- let callee_node_id = self.tcx.hir().as_local_node_id(callsite.callee);
+ 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.
if !self.tcx.dep_graph.is_fully_enabled()
&& self_node_id.as_u32() < callee_node_id.as_u32()
{
- self.tcx.optimized_mir(callsite.callee)
+ self.tcx.instance_mir(callsite.callee.def)
} else {
continue;
}
} else {
// This cannot result in a cycle since the callee MIR is from another crate
// and is already optimized.
- self.tcx.optimized_mir(callsite.callee)
+ self.tcx.instance_mir(callsite.callee.def)
};
+ let callee_body: &Body<'tcx> = &*callee_body;
+
let callee_body = if self.consider_optimizing(callsite, callee_body) {
self.tcx.subst_and_normalize_erasing_regions(
- &callsite.substs,
+ &callsite.callee.substs,
param_env,
callee_body,
)
@@ -183,18 +189,13 @@ impl Inliner<'tcx> {
let terminator = bb_data.terminator();
if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind {
- let instance = Instance::resolve(self.tcx, param_env, callee_def_id, substs)?;
+ let callee = Instance::resolve(self.tcx, param_env, callee_def_id, substs)?;
- if let InstanceDef::Virtual(..) = instance.def {
+ if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def {
return None;
}
- return Some(CallSite {
- callee: instance.def_id(),
- substs: instance.substs,
- bb,
- location: terminator.source_info,
- });
+ return Some(CallSite { callee, bb, source_info: terminator.source_info });
}
}
@@ -219,12 +220,7 @@ impl Inliner<'tcx> {
return false;
}
- let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee);
-
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) {
- debug!("`#[track_caller]` present - not inlining");
- return false;
- }
+ let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
// since instrumentation might be enabled and performed on the caller.
@@ -264,8 +260,8 @@ impl Inliner<'tcx> {
// Only inline local functions if they would be eligible for cross-crate
// inlining. This is to ensure that the final crate doesn't have MIR that
// reference unexported symbols
- if callsite.callee.is_local() {
- if callsite.substs.non_erasable_generics().count() == 0 && !hinted {
+ if callsite.callee.def_id().is_local() {
+ if callsite.callee.substs.non_erasable_generics().count() == 0 && !hinted {
debug!(" callee is an exported function - not inlining");
return false;
}
@@ -321,7 +317,7 @@ impl Inliner<'tcx> {
work_list.push(target);
// If the location doesn't actually need dropping, treat it like
// a regular goto.
- let ty = location.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
+ let ty = location.ty(callee_body, tcx).subst(tcx, callsite.callee.substs).ty;
if ty.needs_drop(tcx, param_env) {
cost += CALL_PENALTY;
if let Some(unwind) = unwind {
@@ -371,7 +367,7 @@ impl Inliner<'tcx> {
for v in callee_body.vars_and_temps_iter() {
let v = &callee_body.local_decls[v];
- let ty = v.ty.subst(tcx, callsite.substs);
+ let ty = v.ty.subst(tcx, callsite.callee.substs);
// Cost of the var is the size in machine-words, if we know
// it.
if let Some(size) = type_size_of(tcx, param_env, ty) {
@@ -399,7 +395,7 @@ impl Inliner<'tcx> {
&self,
callsite: CallSite<'tcx>,
caller_body: &mut BodyAndCache<'tcx>,
- mut callee_body: BodyAndCache<'tcx>,
+ mut callee_body: Body<'tcx>,
) -> bool {
let terminator = caller_body[callsite.bb].terminator.take().unwrap();
match terminator.kind {
@@ -407,22 +403,23 @@ impl Inliner<'tcx> {
TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
debug!("inlined {:?} into {:?}", callsite.callee, self.source);
+ // FIXME(eddyb) replace with a "first inlined local/scope" index,
+ // as they are contiguous.
let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len());
let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len());
for mut scope in callee_body.source_scopes.iter().cloned() {
if scope.parent_scope.is_none() {
- scope.parent_scope = Some(callsite.location.scope);
- // FIXME(eddyb) is this really needed?
- // (also note that it's always overwritten below)
- scope.span = callee_body.span;
+ scope.parent_scope = Some(callsite.source_info.scope);
+
+ // Mark the outermost callee scope as an inlined one.
+ assert_eq!(scope.inlined, None);
+ scope.inlined = Some((callsite.callee, callsite.source_info.span));
+ } else if scope.inlined_parent_scope.is_none() {
+ // Make it easy to find the scope with `inlined` set above.
+ scope.inlined_parent_scope = Some(scope_map[OUTERMOST_SOURCE_SCOPE]);
}
- // 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.location.span;
-
let idx = caller_body.source_scopes.push(scope);
scope_map.push(idx);
}
@@ -431,7 +428,6 @@ impl Inliner<'tcx> {
let mut local = callee_body.local_decls[loc].clone();
local.source_info.scope = scope_map[local.source_info.scope];
- local.source_info.span = callsite.location.span;
let idx = caller_body.local_decls.push(local);
local_map.push(idx);
@@ -463,13 +459,13 @@ impl Inliner<'tcx> {
let ty = dest.ty(&**caller_body, self.tcx);
- let temp = LocalDecl::new_temp(ty, callsite.location.span);
+ let temp = LocalDecl::new_temp(ty, callsite.source_info.span);
let tmp = caller_body.local_decls.push(temp);
let tmp = Place::from(tmp);
let stmt = Statement {
- source_info: callsite.location,
+ source_info: callsite.source_info,
kind: StatementKind::Assign(box (tmp, dest)),
};
caller_body[callsite.bb].statements.push(stmt);
@@ -501,13 +497,20 @@ impl Inliner<'tcx> {
caller_body.var_debug_info.push(var_debug_info);
}
+ // HACK(eddyb) work around the `basic_blocks` field of `mir::Body`
+ // being private, due to `BodyAndCache` implementing `DerefMut`
+ // to `mir::Body` (which would allow bypassing `basic_blocks_mut`).
+ // The only way to make `basic_blocks` public again would be to
+ // remove that `DerefMut` impl and add more `*_mut` accessors.
+ let mut callee_body = BodyAndCache::new(callee_body);
+
for (bb, mut block) in callee_body.basic_blocks_mut().drain_enumerated(..) {
integrator.visit_basic_block_data(bb, &mut block);
caller_body.basic_blocks_mut().push(block);
}
let terminator = Terminator {
- source_info: callsite.location,
+ source_info: callsite.source_info,
kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) },
};
@@ -554,7 +557,9 @@ impl Inliner<'tcx> {
// tmp2 = tuple_tmp.2
//
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
- if tcx.is_closure(callsite.callee) {
+ // FIXME(eddyb) make this check for `"rust-call"` ABI combined with
+ // `callee_body.spread_arg == None`, instead of special-casing closures.
+ if tcx.is_closure(callsite.callee.def_id()) {
let mut args = args.into_iter();
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
@@ -614,11 +619,11 @@ impl Inliner<'tcx> {
let ty = arg.ty(&**caller_body, self.tcx);
- let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
+ let arg_tmp = LocalDecl::new_temp(ty, callsite.source_info.span);
let arg_tmp = caller_body.local_decls.push(arg_tmp);
let stmt = Statement {
- source_info: callsite.location,
+ source_info: callsite.source_info,
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
};
caller_body[callsite.bb].statements.push(stmt);
@@ -642,9 +647,12 @@ fn type_size_of<'tcx>(
* stuff.
*/
struct Integrator<'a, 'tcx> {
+ // FIXME(eddyb) replace this with a `RangeFrom<BasicBlock>`.
block_idx: usize,
args: &'a [Local],
+ // FIXME(eddyb) replace this with a `RangeFrom<Local>`.
local_map: IndexVec<Local, Local>,
+ // FIXME(eddyb) replace this with a `RangeFrom<SourceScope>`.
scope_map: IndexVec<SourceScope, SourceScope>,
destination: Place<'tcx>,
return_block: BasicBlock,
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index f8dfddef2bb..f0407e3e847 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 821c4d68c7e..f50782c8fb4 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -299,7 +299,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<SourceScope, SourceScopeData>,
+ source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
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 a63ac06ec3f..affb7c3a800 100644
--- a/src/librustc_mir_build/build/scope.rs
+++ b/src/librustc_mir_build/build/scope.rs
@@ -684,6 +684,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.source_scopes.push(SourceScopeData {
span,
parent_scope: Some(parent),
+ inlined: None,
+ inlined_parent_scope: None,
local_data: ClearCrossCrate::Set(scope_local_data),
})
}
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 25cfee3373d..534eea91895 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -705,7 +705,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
const char *LinkageName, size_t LinkageNameLen,
LLVMMetadataRef File, unsigned LineNo,
LLVMMetadataRef Ty, unsigned ScopeLine, LLVMRustDIFlags Flags,
- LLVMRustDISPFlags SPFlags, LLVMValueRef Fn, LLVMMetadataRef TParam,
+ LLVMRustDISPFlags SPFlags, LLVMValueRef MaybeFn, LLVMMetadataRef TParam,
LLVMMetadataRef Decl) {
DITemplateParameterArray TParams =
DITemplateParameterArray(unwrap<MDTuple>(TParam));
@@ -739,7 +739,8 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
ScopeLine, llvmFlags, IsOptimized, TParams,
unwrapDIPtr<DISubprogram>(Decl));
#endif
- unwrap<Function>(Fn)->setSubprogram(Sub);
+ if (MaybeFn)
+ unwrap<Function>(MaybeFn)->setSubprogram(Sub);
return wrap(Sub);
}
@@ -913,12 +914,12 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
- int64_t *AddrOps, unsigned AddrOpsCount, LLVMValueRef DL,
+ int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
LLVMBasicBlockRef InsertAtEnd) {
return wrap(Builder->insertDeclare(
unwrap(V), unwrap<DILocalVariable>(VarInfo),
Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
- DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
+ DebugLoc(cast<MDNode>(DL)),
unwrap(InsertAtEnd)));
}
@@ -981,7 +982,7 @@ LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder,
DINodeArray(unwrap<MDTuple>(Params)));
}
-extern "C" LLVMValueRef
+extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line,
unsigned Column, LLVMMetadataRef Scope,
LLVMMetadataRef InlinedAt) {
@@ -990,7 +991,7 @@ LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line,
DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(Scope),
unwrapDIPtr<MDNode>(InlinedAt));
- return wrap(MetadataAsValue::get(Context, debug_loc.getAsMDNode()));
+ return wrap(debug_loc.getAsMDNode());
}
extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
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 768f4953228..f80508f6203 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: Copy>(_t: T, q: &i32) -> i32 {
// let mut _9: &i32;
// scope 1 {
// debug x => _3;
-// scope 2 {
+// scope 2 (inlined foo::<T>::{{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 e000a418d90..be5ece25bef 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: Copy>(t: T, q: i32) -> (i32, T) {
// let mut _11: i32;
// scope 1 {
// debug x => _3;
-// scope 2 {
+// scope 2 (inlined foo::<T>::{{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 bd36e77818e..e1d7ea90348 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: Copy>(_t: T, q: i32) -> i32 {
// let mut _9: i32;
// scope 1 {
// debug x => _3;
-// scope 2 {
+// scope 2 (inlined foo::<T>::{{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 f368bdef6f8..5961cab49c7 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::<u32>::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 9591019bb4f..a2f6b01a613 100644
--- a/src/test/mir-opt/inline/inline-specialization.rs
+++ b/src/test/mir-opt/inline/inline-specialization.rs
@@ -36,7 +36,7 @@ impl<T> Foo for Vec<T> {
// scope 1 {
// debug x => _1;
// }
-// scope 2 {
+// scope 2 (inlined <std::vec::Vec<()> 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 abac66d95c5..90fbc4f1f65 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 <i32 as std::convert::From<i32>>::from) {
// debug t => _6;
// }
-// scope 8 {
+// scope 8 (inlined <std::result::Result<u32, i32> 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 <std::result::Result<u32, i32> 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 <i32 as std::convert::From<i32>>::from) {
// debug t => _6;
// }
-// scope 8 {
+// scope 8 (inlined <std::result::Result<u32, i32> 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 <std::result::Result<u32, i32> 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 <i32 as std::convert::From<i32>>::from) {
// debug t => _6;
// }
-// scope 8 {
+// scope 8 (inlined <std::result::Result<u32, i32> 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 <std::result::Result<u32, i32> 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 <i32 as std::convert::From<i32>>::from) {
// debug t => _3;
// }
-// scope 8 {
+// scope 8 (inlined <std::result::Result<u32, i32> as std::ops::Try>::from_error) {
// debug v => _3;
// }
// }
@@ -205,7 +205,7 @@ fn main() {
// scope 5 {
// }
// }
-// scope 6 {
+// scope 6 (inlined <std::result::Result<u32, i32> as std::ops::Try>::into_result) {
// debug self => _1;
// }
// bb0: {
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
index 090e912c1d0..b8b62ab4d84 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(track_caller)]
@@ -15,13 +17,13 @@ macro_rules! caller_location_from_macro {
fn main() {
let loc = codegen_caller_loc();
assert_eq!(loc.file(), file!());
- assert_eq!(loc.line(), 16);
+ assert_eq!(loc.line(), 18);
assert_eq!(loc.column(), 15);
// `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
- assert_eq!(loc2.line(), 23);
+ assert_eq!(loc2.line(), 25);
assert_eq!(loc2.column(), 16);
}
diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
index 0614c52c660..a667e40ad69 100644
--- a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
+++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(const_fn, track_caller)]
@@ -24,18 +26,18 @@ const fn contained() -> &'static Location<'static> {
fn main() {
assert_eq!(LOCATION.file(), file!());
- assert_eq!(LOCATION.line(), 7);
+ assert_eq!(LOCATION.line(), 9);
assert_eq!(LOCATION.column(), 29);
assert_eq!(TRACKED.file(), file!());
- assert_eq!(TRACKED.line(), 9);
+ assert_eq!(TRACKED.line(), 11);
assert_eq!(TRACKED.column(), 28);
assert_eq!(NESTED.file(), file!());
- assert_eq!(NESTED.line(), 17);
+ assert_eq!(NESTED.line(), 19);
assert_eq!(NESTED.column(), 5);
assert_eq!(CONTAINED.file(), file!());
- assert_eq!(CONTAINED.line(), 22);
+ assert_eq!(CONTAINED.line(), 24);
assert_eq!(CONTAINED.column(), 5);
}
diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
index 76e62b89ab8..007b549812e 100644
--- a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
+++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(track_caller)]
@@ -9,13 +11,13 @@ macro_rules! caller_location_from_macro {
fn main() {
let loc = core::panic::Location::caller();
assert_eq!(loc.file(), file!());
- assert_eq!(loc.line(), 10);
+ assert_eq!(loc.line(), 12);
assert_eq!(loc.column(), 15);
// `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
- assert_eq!(loc2.line(), 17);
+ assert_eq!(loc2.line(), 19);
assert_eq!(loc2.column(), 16);
}
diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs
index eef83b3d68f..7f84b1be9c5 100644
--- a/src/test/ui/rfc-2091-track-caller/pass.rs
+++ b/src/test/ui/rfc-2091-track-caller/pass.rs
@@ -1,4 +1,7 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
+
#![feature(track_caller)]
#[track_caller]
diff --git a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
index be13076b8af..b482fdf0f71 100644
--- a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
+++ b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
@@ -1,5 +1,7 @@
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(option_expect_none, option_unwrap_none)]
diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
index 76a380ed3e3..02c98ac3c46 100644
--- a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
+++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(track_caller)]
@@ -20,21 +22,21 @@ fn nested_tracked() -> &'static Location<'static> {
fn main() {
let location = Location::caller();
assert_eq!(location.file(), file!());
- assert_eq!(location.line(), 21);
+ assert_eq!(location.line(), 23);
assert_eq!(location.column(), 20);
let tracked = tracked();
assert_eq!(tracked.file(), file!());
- assert_eq!(tracked.line(), 26);
+ assert_eq!(tracked.line(), 28);
assert_eq!(tracked.column(), 19);
let nested = nested_intrinsic();
assert_eq!(nested.file(), file!());
- assert_eq!(nested.line(), 13);
+ assert_eq!(nested.line(), 15);
assert_eq!(nested.column(), 5);
let contained = nested_tracked();
assert_eq!(contained.file(), file!());
- assert_eq!(contained.line(), 17);
+ assert_eq!(contained.line(), 19);
assert_eq!(contained.column(), 5);
}
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
index 0407eafbfd4..0bab351ec73 100644
--- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(track_caller)]
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
index a4baaa26ced..14b1111a0dd 100644
--- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
@@ -1,4 +1,6 @@
// run-pass
+// revisions: default mir-opt
+//[mir-opt] compile-flags: -Zmir-opt-level=3
#![feature(track_caller)]