diff options
| author | Denis Merigoux <denis.merigoux@gmail.com> | 2018-09-20 15:47:22 +0200 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2018-11-16 14:33:10 +0200 |
| commit | 6a993fe353e1290d1e89345494ba389f6f1dae5e (patch) | |
| tree | c57d28d4569abb1c369b055e063d96096fe97eda /src/librustc_codegen_llvm/debuginfo | |
| parent | cbe31a4229c519d7af7b5d86f9295fd23adb8cd3 (diff) | |
| download | rust-6a993fe353e1290d1e89345494ba389f6f1dae5e.tar.gz rust-6a993fe353e1290d1e89345494ba389f6f1dae5e.zip | |
Generalized mir::codegen_mir (and all subsequent functions)
Diffstat (limited to 'src/librustc_codegen_llvm/debuginfo')
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/create_scope_map.rs | 16 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/gdb.rs | 5 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/metadata.rs | 120 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/mod.rs | 670 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/source_loc.rs | 10 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/type_names.rs | 1 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/utils.rs | 1 |
7 files changed, 435 insertions, 388 deletions
diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index 56352ae963f..0fd5f7fb8cd 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -13,7 +13,7 @@ use super::metadata::file_metadata; use super::utils::{DIB, span_start}; use llvm; -use llvm::debuginfo::DIScope; +use llvm::debuginfo::{DIScope, DISubprogram}; use common::CodegenCx; use rustc::mir::{Mir, SourceScope}; @@ -27,15 +27,15 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use syntax_pos::BytePos; #[derive(Clone, Copy, Debug)] -pub struct MirDebugScope<'ll> { - pub scope_metadata: Option<&'ll DIScope>, +pub struct MirDebugScope<D> { + pub scope_metadata: Option<D>, // 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 MirDebugScope<'ll> { +impl<D> MirDebugScope<D> { pub fn is_valid(&self) -> bool { self.scope_metadata.is_some() } @@ -46,8 +46,8 @@ impl MirDebugScope<'ll> { pub fn create_mir_scopes( cx: &CodegenCx<'ll, '_>, mir: &Mir, - debug_context: &FunctionDebugContext<'ll>, -) -> IndexVec<SourceScope, MirDebugScope<'ll>> { + debug_context: &FunctionDebugContext<&'ll DISubprogram>, +) -> IndexVec<SourceScope, MirDebugScope<&'ll DIScope>> { let null_scope = MirDebugScope { scope_metadata: None, file_start_pos: BytePos(0), @@ -82,9 +82,9 @@ pub fn create_mir_scopes( fn make_mir_scope(cx: &CodegenCx<'ll, '_>, mir: &Mir, has_variables: &BitSet<SourceScope>, - debug_context: &FunctionDebugContextData<'ll>, + debug_context: &FunctionDebugContextData<&'ll DISubprogram>, scope: SourceScope, - scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) { + scopes: &mut IndexVec<SourceScope, MirDebugScope<&'ll DIScope>>) { if scopes[scope].is_valid() { return; } diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index f0ff8cd188f..607920091bc 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -14,10 +14,9 @@ use llvm; use common::CodegenCx; use builder::Builder; -use declare; use rustc::session::config::DebugInfo; use value::Value; -use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods}; +use interfaces::*; use syntax::attr; @@ -58,7 +57,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64); - let section_var = declare::define_global(cx, section_var_name, + let section_var = cx.define_global(section_var_name, llvm_type).unwrap_or_else(||{ bug!("symbol `{}` is already defined", section_var_name) }); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 923b04c0ecc..8da138f10e9 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1968,6 +1968,68 @@ pub fn create_global_var_metadata( } } +/// Creates debug information for the given vtable, which is for the +/// given type. +/// +/// Adds the created metadata nodes directly to the crate's IR. +pub fn create_vtable_metadata( + cx: &CodegenCx<'ll, 'tcx>, + ty: ty::Ty<'tcx>, + vtable: &'ll Value, +) { + if cx.dbg_cx.is_none() { + return; + } + + let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP); + + unsafe { + // LLVMRustDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + let name = const_cstr!("vtable"); + + // Create a new one each time. We don't want metadata caching + // here, because each vtable will refer to a unique containing + // type. + let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + Size::ZERO.bits(), + cx.tcx.data_layout.pointer_align.abi_bits() as u32, + DIFlags::FlagArtificial, + None, + empty_array, + 0, + Some(type_metadata), + name.as_ptr() + ); + + llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr(), + // LLVM 3.9 + // doesn't accept + // null here, so + // pass the name + // as the linkage + // name. + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + vtable_type, + true, + vtable, + None, + 0); + } +} + // Creates an "extension" of an existing DIScope into another file. pub fn extend_scope_to_file( cx: &CodegenCx<'ll, '_>, @@ -1983,61 +2045,3 @@ pub fn extend_scope_to_file( file_metadata) } } - -impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { - /// Creates debug information for the given vtable, which is for the - /// given type. - /// - /// Adds the created metadata nodes directly to the crate's IR. - fn create_vtable_metadata( - &self, - ty: ty::Ty<'tcx>, - vtable: &'ll Value, - ) { - if self.dbg_cx.is_none() { - return; - } - - let type_metadata = type_metadata(&self, ty, syntax_pos::DUMMY_SP); - - unsafe { - // LLVMRustDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(&self), &[]); - - let name = const_cstr!("vtable"); - - // Create a new one each time. We don't want metadata caching - // here, because each vtable will refer to a unique containing - // type. - let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( - DIB(&self), - NO_SCOPE_METADATA, - name.as_ptr(), - unknown_file_metadata(&self), - UNKNOWN_LINE_NUMBER, - Size::ZERO.bits(), - self.tcx.data_layout.pointer_align.abi_bits() as u32, - DIFlags::FlagArtificial, - None, - empty_array, - 0, - Some(type_metadata), - name.as_ptr() - ); - - llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(&self), - NO_SCOPE_METADATA, - name.as_ptr(), - ptr::null(), - unknown_file_metadata(&self), - UNKNOWN_LINE_NUMBER, - vtable_type, - true, - vtable, - None, - 0); - } - } -} diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 9fcd57a1ec5..b802acb04bd 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -21,7 +21,8 @@ use self::metadata::{type_metadata, file_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; -use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags}; +use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags, + DILexicalBlock}; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, CrateNum}; use rustc::ty::subst::{Substs, UnpackedKind}; @@ -35,6 +36,7 @@ use rustc::mir; use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_data_structures::indexed_vec::IndexVec; use value::Value; use libc::c_uint; @@ -44,8 +46,8 @@ use std::ffi::CString; use syntax_pos::{self, Span, Pos}; use syntax::ast; use syntax::symbol::{Symbol, InternedString}; -use rustc::ty::layout::{self, LayoutOf}; -use interfaces::BuilderMethods; +use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; +use interfaces::*; pub mod gdb; mod utils; @@ -109,21 +111,21 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> { } } -pub enum FunctionDebugContext<'ll> { - RegularContext(FunctionDebugContextData<'ll>), +pub enum FunctionDebugContext<D> { + RegularContext(FunctionDebugContextData<D>), DebugInfoDisabled, FunctionWithoutDebugInfo, } -impl FunctionDebugContext<'ll> { - pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData<'ll> { +impl<D> FunctionDebugContext<D> { + pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData<D> { match *self { FunctionDebugContext::RegularContext(ref data) => data, FunctionDebugContext::DebugInfoDisabled => { - span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message()); + span_bug!(span, "{}", Self::debuginfo_disabled_message()); } FunctionDebugContext::FunctionWithoutDebugInfo => { - span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message()); + span_bug!(span, "{}", Self::should_be_ignored_message()); } } } @@ -138,18 +140,18 @@ impl FunctionDebugContext<'ll> { } } -pub struct FunctionDebugContextData<'ll> { - fn_metadata: &'ll DISubprogram, +pub struct FunctionDebugContextData<D> { + fn_metadata: D, source_locations_enabled: Cell<bool>, pub defining_crate: CrateNum, } -pub enum VariableAccess<'a, 'll> { +pub enum VariableAccess<'a, V> { // The llptr given is an alloca containing the variable's value - DirectVariable { alloca: &'ll Value }, + DirectVariable { alloca: V }, // The llptr given is an alloca containing the start of some pointer chain // leading to the variable's content. - IndirectVariable { alloca: &'ll Value, address_operations: &'a [i64] } + IndirectVariable { alloca: V, address_operations: &'a [i64] } } pub enum VariableKind { @@ -202,348 +204,388 @@ pub fn finalize(cx: &CodegenCx) { }; } -/// Creates the function-specific debug context. -/// -/// Returns the FunctionDebugContext for the function which holds state needed -/// for debug info creation. The function may also return another variant of the -/// FunctionDebugContext enum which indicates why no debuginfo should be created -/// for the function. -pub fn create_function_debug_context( - cx: &CodegenCx<'ll, 'tcx>, - instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, - llfn: &'ll Value, - mir: &mir::Mir, -) -> FunctionDebugContext<'ll> { - if cx.sess().opts.debuginfo == DebugInfo::None { - return FunctionDebugContext::DebugInfoDisabled; +impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { + fn declare_local( + &self, + dbg_context: &FunctionDebugContext<&'ll DISubprogram>, + variable_name: ast::Name, + variable_type: Ty<'tcx>, + scope_metadata: &'ll DIScope, + variable_access: VariableAccess<'_, &'ll Value>, + variable_kind: VariableKind, + span: Span, + ) { + assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); + let cx = self.cx(); + + let file = span_start(cx, span).file; + let file_metadata = file_metadata(cx, + &file.name, + dbg_context.get_ref(span).defining_crate); + + let loc = span_start(cx, span); + let type_metadata = type_metadata(cx, variable_type, span); + + let (argument_index, dwarf_tag) = match variable_kind { + ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), + LocalVariable => (0, DW_TAG_auto_variable) + }; + let align = cx.align_of(variable_type); + + let name = SmallCStr::new(&variable_name.as_str()); + match (variable_access, &[][..]) { + (DirectVariable { alloca }, address_operations) | + (IndirectVariable {alloca, address_operations}, _) => { + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::OptLevel::No, + DIFlags::FlagZero, + argument_index, + align.abi() as u32, + ) + }; + source_loc::set_debug_location(self, + InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); + unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder); + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( + DIB(cx), + alloca, + metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + debug_loc, + self.llbb()); + + llvm::LLVMSetInstDebugLocation(self.llbuilder, instr); + } + source_loc::set_debug_location(self, UnknownLocation); + } + } } - if let InstanceDef::Item(def_id) = instance.def { - if cx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { - return FunctionDebugContext::FunctionWithoutDebugInfo; - } + fn set_source_location( + &self, + debug_context: &FunctionDebugContext<&'ll DISubprogram>, + scope: Option<&'ll DIScope>, + span: Span, + ) { + set_source_location(debug_context, &self, scope, span) } +} - let span = mir.span; +impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { + /// Creates the function-specific debug context. + /// + /// Returns the FunctionDebugContext for the function which holds state needed + /// for debug info creation. The function may also return another variant of the + /// FunctionDebugContext enum which indicates why no debuginfo should be created + /// for the function. + fn create_function_debug_context( + &self, + instance: Instance<'tcx>, + sig: ty::FnSig<'tcx>, + llfn: &'ll Value, + mir: &mir::Mir, + ) -> FunctionDebugContext<&'ll DISubprogram> { + if self.sess().opts.debuginfo == DebugInfo::None { + return FunctionDebugContext::DebugInfoDisabled; + } - // This can be the case for functions inlined from another crate - if span.is_dummy() { - // FIXME(simulacrum): Probably can't happen; remove. - return FunctionDebugContext::FunctionWithoutDebugInfo; - } + if let InstanceDef::Item(def_id) = instance.def { + if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { + return FunctionDebugContext::FunctionWithoutDebugInfo; + } + } - let def_id = instance.def_id(); - let containing_scope = get_containing_scope(cx, instance); - let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate); + let span = mir.span; - let function_type_metadata = unsafe { - let fn_signature = get_function_signature(cx, sig); - llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) - }; + // This can be the case for functions inlined from another crate + if span.is_dummy() { + // FIXME(simulacrum): Probably can't happen; remove. + return FunctionDebugContext::FunctionWithoutDebugInfo; + } - // Find the enclosing function, in case this is a closure. - let def_key = cx.tcx.def_key(def_id); - let mut name = def_key.disambiguated_data.data.to_string(); + let def_id = instance.def_id(); + let containing_scope = get_containing_scope(self, instance); + let loc = span_start(self, span); + let file_metadata = file_metadata(self, &loc.file.name, def_id.krate); - let enclosing_fn_def_id = cx.tcx.closure_base_def_id(def_id); + let function_type_metadata = unsafe { + let fn_signature = get_function_signature(self, sig); + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature) + }; + + // Find the enclosing function, in case this is a closure. + let def_key = self.tcx().def_key(def_id); + let mut name = def_key.disambiguated_data.data.to_string(); + + let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id); - // Get_template_parameters() will append a `<...>` clause to the function - // name if necessary. - let generics = cx.tcx.generics_of(enclosing_fn_def_id); - let substs = instance.substs.truncate_to(cx.tcx, generics); - let template_parameters = get_template_parameters(cx, - &generics, - substs, - file_metadata, - &mut name); + // Get_template_parameters() will append a `<...>` clause to the function + // name if necessary. + let generics = self.tcx().generics_of(enclosing_fn_def_id); + let substs = instance.substs.truncate_to(self.tcx(), generics); + let template_parameters = get_template_parameters(self, + &generics, + substs, + file_metadata, + &mut name); - // Get the linkage_name, which is just the symbol name - let linkage_name = mangled_name_of_instance(cx, instance); + // Get the linkage_name, which is just the symbol name + let linkage_name = mangled_name_of_instance(self, instance); - let scope_line = span_start(cx, span).line; - let is_local_to_unit = is_node_local_to_unit(cx, def_id); + let scope_line = span_start(self, span).line; + let is_local_to_unit = is_node_local_to_unit(self, def_id); - let function_name = CString::new(name).unwrap(); - let linkage_name = SmallCStr::new(&linkage_name.as_str()); + let function_name = CString::new(name).unwrap(); + let linkage_name = SmallCStr::new(&linkage_name.as_str()); - let mut flags = DIFlags::FlagPrototyped; + let mut flags = DIFlags::FlagPrototyped; - let local_id = cx.tcx.hir.as_local_node_id(def_id); - if let Some((id, _, _)) = *cx.sess().entry_fn.borrow() { - if local_id == Some(id) { - flags |= DIFlags::FlagMainSubprogram; + let local_id = self.tcx().hir.as_local_node_id(def_id); + if let Some((id, _, _)) = *self.sess().entry_fn.borrow() { + if local_id == Some(id) { + flags |= DIFlags::FlagMainSubprogram; + } } - } - if cx.layout_of(sig.output()).abi.is_uninhabited() { - flags |= DIFlags::FlagNoReturn; - } + if self.layout_of(sig.output()).abi.is_uninhabited() { + flags |= DIFlags::FlagNoReturn; + } - let fn_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name.as_ptr(), - linkage_name.as_ptr(), - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - flags, - cx.sess().opts.optimize != config::OptLevel::No, - llfn, - template_parameters, - None) - }; + let fn_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFunction( + DIB(self), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + flags, + self.sess().opts.optimize != config::OptLevel::No, + llfn, + template_parameters, + None) + }; - // Initialize fn debug context (including scope map and namespace map) - let fn_debug_context = FunctionDebugContextData { - fn_metadata, - source_locations_enabled: Cell::new(false), - defining_crate: def_id.krate, - }; + // Initialize fn debug context (including scope map and namespace map) + let fn_debug_context = FunctionDebugContextData { + fn_metadata, + source_locations_enabled: Cell::new(false), + defining_crate: def_id.krate, + }; - return FunctionDebugContext::RegularContext(fn_debug_context); + return FunctionDebugContext::RegularContext(fn_debug_context); - fn get_function_signature( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - ) -> &'ll DIArray { - if cx.sess().opts.debuginfo == DebugInfo::Limited { - return create_DIArray(DIB(cx), &[]); - } + fn get_function_signature<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + ) -> &'ll DIArray { + if cx.sess().opts.debuginfo == DebugInfo::Limited { + return create_DIArray(DIB(cx), &[]); + } - let mut signature = Vec::with_capacity(sig.inputs().len() + 1); + let mut signature = Vec::with_capacity(sig.inputs().len() + 1); - // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output().sty { - ty::Tuple(ref tys) if tys.is_empty() => None, - _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)) - }); + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output().sty { + ty::Tuple(ref tys) if tys.is_empty() => None, + _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)) + }); - let inputs = if sig.abi == Abi::RustCall { - &sig.inputs()[..sig.inputs().len() - 1] - } else { - sig.inputs() - }; + let inputs = if sig.abi == Abi::RustCall { + &sig.inputs()[..sig.inputs().len() - 1] + } else { + sig.inputs() + }; - // Arguments types - if cx.sess().target.target.options.is_like_msvc { - // FIXME(#42800): - // There is a bug in MSDIA that leads to a crash when it encounters - // a fixed-size array of `u8` or something zero-sized in a - // function-type (see #40477). - // As a workaround, we replace those fixed-size arrays with a - // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would - // appear as `fn foo(a: u8, b: *const u8)` in debuginfo, - // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. - // This transformed type is wrong, but these function types are - // already inaccurate due to ABI adjustments (see #42800). - signature.extend(inputs.iter().map(|&t| { - let t = match t.sty { - ty::Array(ct, _) - if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { - cx.tcx.mk_imm_ptr(ct) - } - _ => t - }; - Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) - })); - } else { - signature.extend(inputs.iter().map(|t| { - Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) - })); - } + // Arguments types + if cx.sess().target.target.options.is_like_msvc { + // FIXME(#42800): + // There is a bug in MSDIA that leads to a crash when it encounters + // a fixed-size array of `u8` or something zero-sized in a + // function-type (see #40477). + // As a workaround, we replace those fixed-size arrays with a + // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would + // appear as `fn foo(a: u8, b: *const u8)` in debuginfo, + // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. + // This transformed type is wrong, but these function types are + // already inaccurate due to ABI adjustments (see #42800). + signature.extend(inputs.iter().map(|&t| { + let t = match t.sty { + ty::Array(ct, _) + if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { + cx.tcx.mk_imm_ptr(ct) + } + _ => t + }; + Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) + })); + } else { + signature.extend(inputs.iter().map(|t| { + Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) + })); + } - if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { - if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { - signature.extend( - args.iter().map(|argument_type| { - Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)) - }) - ); + if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { + if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { + signature.extend( + args.iter().map(|argument_type| { + Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)) + }) + ); + } } + + create_DIArray(DIB(cx), &signature[..]) } - create_DIArray(DIB(cx), &signature[..]) - } + fn get_template_parameters<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + generics: &ty::Generics, + substs: &Substs<'tcx>, + file_metadata: &'ll DIFile, + name_to_append_suffix_to: &mut String, + ) -> &'ll DIArray { + if substs.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } - fn get_template_parameters( - cx: &CodegenCx<'ll, 'tcx>, - generics: &ty::Generics, - substs: &Substs<'tcx>, - file_metadata: &'ll DIFile, - name_to_append_suffix_to: &mut String, - ) -> &'ll DIArray { - if substs.types().next().is_none() { - return create_DIArray(DIB(cx), &[]); - } + name_to_append_suffix_to.push('<'); + for (i, actual_type) in substs.types().enumerate() { + if i != 0 { + name_to_append_suffix_to.push_str(","); + } - name_to_append_suffix_to.push('<'); - for (i, actual_type) in substs.types().enumerate() { - if i != 0 { - name_to_append_suffix_to.push_str(","); + let actual_type = + cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); + // Add actual type name to <...> clause of function name + let actual_type_name = compute_debuginfo_type_name(cx, + actual_type, + true); + name_to_append_suffix_to.push_str(&actual_type_name[..]); } + name_to_append_suffix_to.push('>'); + + // Again, only create type information if full debuginfo is enabled + let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { + let names = get_parameter_names(cx, generics); + substs.iter().zip(names).filter_map(|(kind, name)| { + if let UnpackedKind::Type(ty) = kind.unpack() { + let actual_type = + cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); + let actual_type_metadata = + type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); + let name = SmallCStr::new(&name.as_str()); + Some(unsafe { + Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + DIB(cx), + None, + name.as_ptr(), + actual_type_metadata, + file_metadata, + 0, + 0, + )) + }) + } else { + None + } + }).collect() + } else { + vec![] + }; + + return create_DIArray(DIB(cx), &template_params[..]); + } - let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); - // Add actual type name to <...> clause of function name - let actual_type_name = compute_debuginfo_type_name(cx, - actual_type, - true); - name_to_append_suffix_to.push_str(&actual_type_name[..]); + fn get_parameter_names(cx: &CodegenCx, + generics: &ty::Generics) + -> Vec<InternedString> { + let mut names = generics.parent.map_or(vec![], |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.params.iter().map(|param| param.name)); + names } - name_to_append_suffix_to.push('>'); - - // Again, only create type information if full debuginfo is enabled - let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { - let names = get_parameter_names(cx, generics); - substs.iter().zip(names).filter_map(|(kind, name)| { - if let UnpackedKind::Type(ty) = kind.unpack() { - let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); - let actual_type_metadata = - type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = SmallCStr::new(&name.as_str()); - Some(unsafe { - Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( - DIB(cx), - None, - name.as_ptr(), - actual_type_metadata, - file_metadata, - 0, - 0, - )) - }) + + fn get_containing_scope<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + instance: Instance<'tcx>, + ) -> &'ll DIScope { + // First, let's see if this is a method within an inherent impl. Because + // if yes, we want to make the result subroutine DIE a child of the + // subroutine's self-type. + let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { + // If the method does *not* belong to a trait, proceed + if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { + let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + &cx.tcx.type_of(impl_def_id), + ); + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g. `<*mut T>::null`). + match impl_self_ty.sty { + ty::Adt(def, ..) if !def.is_box() => { + Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) + } + _ => None + } } else { + // For trait method impls we still use the "parallel namespace" + // strategy None } - }).collect() - } else { - vec![] - }; - - create_DIArray(DIB(cx), &template_params[..]) + }); + + self_type.unwrap_or_else(|| { + namespace::item_namespace(cx, DefId { + krate: instance.def_id().krate, + index: cx.tcx + .def_key(instance.def_id()) + .parent + .expect("get_containing_scope: missing parent?") + }) + }) + } } - fn get_parameter_names(cx: &CodegenCx, - generics: &ty::Generics) - -> Vec<InternedString> { - let mut names = generics.parent.map_or(vec![], |def_id| { - get_parameter_names(cx, cx.tcx.generics_of(def_id)) - }); - names.extend(generics.params.iter().map(|param| param.name)); - names + fn create_vtable_metadata( + &self, + ty: Ty<'tcx>, + vtable: Self::Value, + ) { + metadata::create_vtable_metadata(self, ty, vtable) } - fn get_containing_scope( - cx: &CodegenCx<'ll, 'tcx>, - instance: Instance<'tcx>, - ) -> &'ll DIScope { - // First, let's see if this is a method within an inherent impl. Because - // if yes, we want to make the result subroutine DIE a child of the - // subroutine's self-type. - let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { - // If the method does *not* belong to a trait, proceed - if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { - let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - &cx.tcx.type_of(impl_def_id), - ); - - // Only "class" methods are generally understood by LLVM, - // so avoid methods on other types (e.g. `<*mut T>::null`). - match impl_self_ty.sty { - ty::Adt(def, ..) if !def.is_box() => { - Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) - } - _ => None - } - } else { - // For trait method impls we still use the "parallel namespace" - // strategy - None - } - }); - - self_type.unwrap_or_else(|| { - namespace::item_namespace(cx, DefId { - krate: instance.def_id().krate, - index: cx.tcx - .def_key(instance.def_id()) - .parent - .expect("get_containing_scope: missing parent?") - }) - }) + fn create_mir_scopes( + &self, + mir: &mir::Mir, + debug_context: &FunctionDebugContext<&'ll DISubprogram>, + ) -> IndexVec<mir::SourceScope, MirDebugScope<&'ll DIScope>> { + create_scope_map::create_mir_scopes(self, mir, debug_context) } -} -pub fn declare_local( - bx: &Builder<'a, 'll, 'tcx>, - dbg_context: &FunctionDebugContext<'ll>, - variable_name: ast::Name, - variable_type: Ty<'tcx>, - scope_metadata: &'ll DIScope, - variable_access: VariableAccess<'_, 'll>, - variable_kind: VariableKind, - span: Span, -) { - assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); - let cx = bx.cx(); - - let file = span_start(cx, span).file; - let file_metadata = file_metadata(cx, - &file.name, - dbg_context.get_ref(span).defining_crate); - - let loc = span_start(cx, span); - let type_metadata = type_metadata(cx, variable_type, span); - - let (argument_index, dwarf_tag) = match variable_kind { - ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), - LocalVariable => (0, DW_TAG_auto_variable) - }; - let align = cx.align_of(variable_type); - - let name = SmallCStr::new(&variable_name.as_str()); - match (variable_access, &[][..]) { - (DirectVariable { alloca }, address_operations) | - (IndirectVariable {alloca, address_operations}, _) => { - let metadata = unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name.as_ptr(), - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::OptLevel::No, - DIFlags::FlagZero, - argument_index, - align.abi() as u32, - ) - }; - source_loc::set_debug_location(bx, - InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); - unsafe { - let debug_loc = llvm::LLVMGetCurrentDebugLocation(bx.llbuilder); - let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(cx), - alloca, - metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - debug_loc, - bx.llbb()); - - llvm::LLVMSetInstDebugLocation(bx.llbuilder, instr); - } - source_loc::set_debug_location(bx, UnknownLocation); - } + fn extend_scope_to_file( + &self, + scope_metadata: &'ll DIScope, + file: &syntax_pos::SourceFile, + defining_crate: CrateNum, + ) -> &'ll DILexicalBlock { + metadata::extend_scope_to_file(&self, scope_metadata, file, defining_crate) } } diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index 96d22ea1d15..514649290e2 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -17,7 +17,7 @@ use super::FunctionDebugContext; use llvm; use llvm::debuginfo::DIScope; use builder::Builder; -use interfaces::BuilderMethods; +use interfaces::*; use libc::c_uint; use syntax_pos::{Span, Pos}; @@ -25,8 +25,8 @@ use syntax_pos::{Span, Pos}; /// Sets the current debug location at the beginning of the span. /// /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). -pub fn set_source_location( - debug_context: &FunctionDebugContext<'ll>, +pub fn set_source_location<D>( + debug_context: &FunctionDebugContext<D>, bx: &Builder<'_, 'll, '_>, scope: Option<&'ll DIScope>, span: Span, @@ -41,7 +41,7 @@ pub fn set_source_location( }; let dbg_loc = if function_debug_context.source_locations_enabled.get() { - debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span)); + debug!("set_source_location: {}", bx.cx().sess().source_map().span_to_string(span)); let loc = span_start(bx.cx(), span); InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize()) } else { @@ -56,7 +56,7 @@ pub fn set_source_location( /// they are disabled when beginning to codegen a new function. This functions /// switches source location emitting on and must therefore be called before the /// first real statement/expression of the function is codegened. -pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext<'ll>) { +pub fn start_emitting_source_locations<D>(dbg_context: &FunctionDebugContext<D>) { if let FunctionDebugContext::RegularContext(ref data) = *dbg_context { data.source_locations_enabled.set(true); } diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index eb5ae81b218..5fbeb2124ac 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -14,6 +14,7 @@ use common::CodegenCx; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; +use interfaces::*; use rustc::hir; diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs index 19bc4ac39d3..2d1ec840882 100644 --- a/src/librustc_codegen_llvm/debuginfo/utils.rs +++ b/src/librustc_codegen_llvm/debuginfo/utils.rs @@ -19,6 +19,7 @@ use rustc::ty::DefIdTree; use llvm; use llvm::debuginfo::{DIScope, DIBuilder, DIDescriptor, DIArray}; use common::{CodegenCx}; +use interfaces::*; use syntax_pos::{self, Span}; |
