diff options
Diffstat (limited to 'src/librustc_codegen_ssa')
| -rw-r--r-- | src/librustc_codegen_ssa/mir/block.rs | 74 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/mir/debuginfo.rs | 172 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/mir/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/traits/backend.rs | 1 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/traits/debuginfo.rs | 28 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/traits/mod.rs | 1 |
6 files changed, 155 insertions, 123 deletions
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, >; } |
