diff options
| author | bors <bors@rust-lang.org> | 2020-03-19 11:41:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-03-19 11:41:41 +0000 |
| commit | cf35136850a7698c0da0a76785c1552ed88e1cfd (patch) | |
| tree | c694b90a17f58fd2680ff3f51859d80b86933728 | |
| parent | 6724d584b8e3b5fa5e06466d1e900cdd60953707 (diff) | |
| parent | 40dea87fbdf2ce943bfe245f0a13d7821831a88b (diff) | |
| download | rust-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
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)] |
