diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 7658b86a3a200..7a25fc46fd3fc 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -7,7 +7,6 @@ use gccjit::{CType, Context, FunctionType, GlobalKind}; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; -use rustc_codegen_ssa::traits::DebugInfoCodegenMethods; use rustc_hir::attrs::{AttributeKind, Linkage}; use rustc_hir::find_attr; use rustc_middle::dep_graph; diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 8907d8a42b38f..5e598e5825d1b 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -16,6 +16,66 @@ pub(super) const UNKNOWN_LINE_NUMBER: u32 = 0; pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0; impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn dbg_scope_fn( + &mut self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _maybe_definition_llfn: Option>, + ) -> Self::DIScope { + // FIXME(antoyo): implement. + } + + fn dbg_create_lexical_block( + &mut self, + _pos: BytePos, + _parent_scope: Self::DIScope, + ) -> Self::DIScope { + } + + fn dbg_location_clone_with_discriminator( + &mut self, + loc: Self::DILocation, + _discriminator: u32, + ) -> Option { + Some(loc) + } + + fn extend_scope_to_file( + &mut self, + _scope_metadata: Self::DIScope, + _file: &SourceFile, + ) -> Self::DIScope { + // FIXME(antoyo): implement. + } + + fn dbg_loc( + &mut self, + _scope: Self::DIScope, + _inlined_at: Option, + span: Span, + ) -> Self::DILocation { + let pos = span.lo(); + let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); + match file.name { + rustc_span::FileName::Real(ref name) => self.context.new_location( + name.path(rustc_span::RemapPathScopeComponents::DEBUGINFO).to_string_lossy(), + line as i32, + col as i32, + ), + _ => Location::null(), + } + } + + fn create_dbg_var( + &mut self, + _variable_name: Symbol, + _variable_type: Ty<'tcx>, + _scope_metadata: Self::DIScope, + _variable_kind: VariableKind, + _span: Span, + ) -> Self::DIVariable { + } + // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn dbg_var_addr( @@ -103,6 +163,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { DebugLoc { file, line, col } } } + + pub(crate) fn debuginfo_finalize(&self) { + self.context.set_debug_info(true) + } } impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { @@ -114,68 +178,4 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ) { // FIXME(antoyo) } - - fn dbg_create_lexical_block( - &self, - _pos: BytePos, - _parent_scope: Self::DIScope, - ) -> Self::DIScope { - } - - fn dbg_location_clone_with_discriminator( - &self, - loc: Self::DILocation, - _discriminator: u32, - ) -> Option { - Some(loc) - } - - fn extend_scope_to_file( - &self, - _scope_metadata: Self::DIScope, - _file: &SourceFile, - ) -> Self::DIScope { - // FIXME(antoyo): implement. - } - - fn debuginfo_finalize(&self) { - self.context.set_debug_info(true) - } - - fn create_dbg_var( - &self, - _variable_name: Symbol, - _variable_type: Ty<'tcx>, - _scope_metadata: Self::DIScope, - _variable_kind: VariableKind, - _span: Span, - ) -> Self::DIVariable { - } - - fn dbg_scope_fn( - &self, - _instance: Instance<'tcx>, - _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - _maybe_definition_llfn: Option>, - ) -> Self::DIScope { - // FIXME(antoyo): implement. - } - - fn dbg_loc( - &self, - _scope: Self::DIScope, - _inlined_at: Option, - span: Span, - ) -> Self::DILocation { - let pos = span.lo(); - let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); - match file.name { - rustc_span::FileName::Real(ref name) => self.context.new_location( - name.path(rustc_span::RemapPathScopeComponents::DEBUGINFO).to_string_lossy(), - line as i32, - col as i32, - ), - _ => Location::null(), - } - } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 9bace9d2acf61..b20df0a6bad02 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -99,9 +99,9 @@ pub(crate) unsafe fn codegen( ); if tcx.sess.opts.debuginfo != DebugInfo::None { - let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod); + let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod, tcx.sess); debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx); - dbg_cx.finalize(tcx.sess); + dbg_cx.finalize(); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 6198a98e5f7ae..e89a46dc27c1c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -647,7 +647,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { tcx.sess.instrument_coverage().then(coverageinfo::CguCoverageContext::new); let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None { - let dctx = debuginfo::CodegenUnitDebugContext::new(llmod); + let dctx = debuginfo::CodegenUnitDebugContext::new(llmod, tcx.sess); debuginfo::metadata::build_compile_unit_di_node( tcx, codegen_unit.name().as_str(), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d8d529fee6f8b..580b7a89484d4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -51,7 +51,6 @@ mod utils; /// A context object for maintaining all state needed by the debuginfo module. pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { - llmod: &'ll llvm::Module, builder: DIBuilderBox<'ll>, created_files: RefCell, &'ll DIFile>>, @@ -62,23 +61,8 @@ pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { } impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { - pub(crate) fn new(llmod: &'ll llvm::Module) -> Self { + pub(crate) fn new(llmod: &'ll llvm::Module, sess: &Session) -> Self { debug!("CodegenUnitDebugContext::new"); - let builder = DIBuilderBox::new(llmod); - // DIBuilder inherits context from the module, so we'd better use the same one - CodegenUnitDebugContext { - llmod, - builder, - created_files: Default::default(), - type_map: Default::default(), - adt_stack: Default::default(), - namespace_map: RefCell::new(Default::default()), - recursion_marker_type: OnceCell::new(), - } - } - - pub(crate) fn finalize(&self, sess: &Session) { - unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) }; match sess.target.debuginfo_kind { DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => { @@ -89,7 +73,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { // This can be overridden using --llvm-opts -dwarf-version,N. // Android has the same issue (#22398) llvm::add_module_flag_u32( - self.llmod, + llmod, // In the case where multiple CGUs with different dwarf version // values are being merged together, such as with cross-crate // LTO, then we want to use the highest version of dwarf @@ -102,7 +86,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { DebuginfoKind::Pdb => { // Indicate that we want CodeView debug information llvm::add_module_flag_u32( - self.llmod, + llmod, llvm::ModuleFlagMergeBehavior::Warning, "CodeView", 1, @@ -112,28 +96,26 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { // Prevent bitcode readers from deleting the debug info. llvm::add_module_flag_u32( - self.llmod, + llmod, llvm::ModuleFlagMergeBehavior::Warning, "Debug Info Version", unsafe { llvm::LLVMRustDebugMetadataVersion() }, ); - } -} -/// Creates any deferred debug metadata nodes -pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { - if let Some(dbg_cx) = &cx.dbg_cx { - debug!("finalize"); - - if gdb::needs_gdb_debug_scripts_section(cx) { - // Add a .debug_gdb_scripts section to this compile-unit. This will - // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, - // which activates the Rust pretty printers for binary this section is - // contained in. - gdb::get_or_insert_gdb_debug_scripts_section_global(cx); + let builder = DIBuilderBox::new(llmod); + // DIBuilder inherits context from the module, so we'd better use the same one + CodegenUnitDebugContext { + builder, + created_files: Default::default(), + type_map: Default::default(), + adt_stack: Default::default(), + namespace_map: RefCell::new(Default::default()), + recursion_marker_type: OnceCell::new(), } + } - dbg_cx.finalize(cx.sess()); + pub(crate) fn finalize(&self) { + unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) }; } } @@ -144,381 +126,109 @@ impl<'ll> Builder<'_, 'll, '_> { } impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { - // FIXME(eddyb) find a common convention for all of the debuginfo-related - // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn dbg_var_addr( + fn dbg_scope_fn( &mut self, - dbg_var: &'ll DIVariable, - dbg_loc: &'ll DILocation, - variable_alloca: Self::Value, - direct_offset: Size, - indirect_offsets: &[Size], - fragment: &Option>, - ) { - use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst}; + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + maybe_definition_llfn: Option<&'ll Value>, + ) -> &'ll DIScope { + let tcx = self.tcx; - // Convert the direct and indirect offsets and fragment byte range to address ops. - let mut addr_ops = SmallVec::<[u64; 8]>::new(); + let def_id = instance.def_id(); + let (containing_scope, is_method) = get_containing_scope(self, instance); + let span = tcx.def_span(def_id); + let loc = self.lookup_debug_loc(span.lo()); + let file_metadata = file_metadata(self, &loc.file); - if direct_offset.bytes() > 0 { - addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(direct_offset.bytes()); - } - for &offset in indirect_offsets { - addr_ops.push(DW_OP_deref); - if offset.bytes() > 0 { - addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(offset.bytes()); - } - } - if let Some(fragment) = fragment { - // `DW_OP_LLVM_fragment` takes as arguments the fragment's - // offset and size, both of them in bits. - addr_ops.push(DW_OP_LLVM_fragment); - addr_ops.push(fragment.start.bits()); - addr_ops.push((fragment.end - fragment.start).bits()); - } + let function_type_metadata = + create_subroutine_type(self, &get_function_signature(self, fn_abi)); - let di_builder = DIB(self.cx()); - let addr_expr = di_builder.create_expression(&addr_ops); - unsafe { - llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( - di_builder, - variable_alloca, - dbg_var, - addr_expr, - dbg_loc, - self.llbb(), - ) - }; - } + let mut name = String::with_capacity(64); + type_names::push_item_name(tcx, def_id, false, &mut name); - fn dbg_var_value( - &mut self, - dbg_var: &'ll DIVariable, - dbg_loc: &'ll DILocation, - value: Self::Value, - direct_offset: Size, - indirect_offsets: &[Size], - fragment: &Option>, - ) { - use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value}; + // Find the enclosing function, in case this is a closure. + let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id); - // Convert the direct and indirect offsets and fragment byte range to address ops. - let mut addr_ops = SmallVec::<[u64; 8]>::new(); + // We look up the generics of the enclosing function and truncate the args + // to their length in order to cut off extra stuff that might be in there for + // closures or coroutines. + let generics = tcx.generics_of(enclosing_fn_def_id); + let args = instance.args.truncate_to(tcx, generics); - if direct_offset.bytes() > 0 { - addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(direct_offset.bytes() as u64); - addr_ops.push(DW_OP_stack_value); - } - for &offset in indirect_offsets { - addr_ops.push(DW_OP_deref); - if offset.bytes() > 0 { - addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(offset.bytes() as u64); - } - } - if let Some(fragment) = fragment { - // `DW_OP_LLVM_fragment` takes as arguments the fragment's - // offset and size, both of them in bits. - addr_ops.push(DW_OP_LLVM_fragment); - addr_ops.push(fragment.start.bits() as u64); - addr_ops.push((fragment.end - fragment.start).bits() as u64); - } + type_names::push_generic_args( + tcx, + tcx.normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(args)), + &mut name, + ); - let di_builder = DIB(self.cx()); - let addr_expr = unsafe { - llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) - }; - unsafe { - llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd( - di_builder, - value, - dbg_var, - addr_expr, - dbg_loc, - self.llbb(), - ); - } - } + let template_parameters = get_template_parameters(self, generics, args); - fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { - unsafe { - llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc); - } - } + let linkage_name = &mangled_name_of_instance(self, instance).name; + // Omit the linkage_name if it is the same as subprogram name. + let linkage_name = if &name == linkage_name { "" } else { linkage_name }; - fn clear_dbg_loc(&mut self) { - unsafe { - llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null()); - } - } + // FIXME(eddyb) does this need to be separate from `loc.line` for some reason? + let scope_line = loc.line; - fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { - gdb::insert_reference_to_gdb_debug_scripts_section_global(self) - } + let mut flags = DIFlags::FlagPrototyped; - fn set_var_name(&mut self, value: &'ll Value, name: &str) { - // Avoid wasting time if LLVM value names aren't even enabled. - if self.sess().fewer_names() { - return; + if fn_abi.ret.layout.is_uninhabited() { + flags |= DIFlags::FlagNoReturn; } - // Only function parameters and instructions are local to a function, - // don't change the name of anything else (e.g. globals). - let param_or_inst = unsafe { - llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some() - }; - if !param_or_inst { - return; + let mut spflags = DISPFlags::SPFlagDefinition; + if is_node_local_to_unit(self, def_id) { + spflags |= DISPFlags::SPFlagLocalToUnit; } - - // Avoid replacing the name if it already exists. - // While we could combine the names somehow, it'd - // get noisy quick, and the usefulness is dubious. - if llvm::get_value_name(value).is_empty() { - llvm::set_value_name(value, name.as_bytes()); + if self.sess().opts.optimize != config::OptLevel::No { + spflags |= DISPFlags::SPFlagOptimized; + } + if let Some((id, _)) = tcx.entry_fn(()) { + if id == def_id { + spflags |= DISPFlags::SPFlagMainSubprogram; + } } - } - /// Annotate move/copy operations with debug info for profiling. - /// - /// This creates a temporary debug scope that makes the move/copy appear as an inlined call to - /// `compiler_move()` or `compiler_copy()`. The provided closure is executed - /// with this temporary debug location active. - /// - /// The `instance` parameter should be the monomorphized instance of the `compiler_move` or - /// `compiler_copy` function with the actual type and size. - fn with_move_annotation( - &mut self, - instance: ty::Instance<'tcx>, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - // Save the current debug location - let saved_loc = self.get_dbg_loc(); + // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because + // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition. + // When we use this `decl` below, the subprogram definition gets created at the CU level + // with a DW_AT_specification pointing back to the type's declaration. + let decl = is_method.then(|| unsafe { + llvm::LLVMRustDIBuilderCreateMethod( + DIB(self), + containing_scope, + name.as_c_char_ptr(), + name.len(), + linkage_name.as_c_char_ptr(), + linkage_name.len(), + file_metadata, + loc.line, + function_type_metadata, + flags, + spflags & !DISPFlags::SPFlagDefinition, + template_parameters, + ) + }); - // Create a DIScope for the compiler_move/compiler_copy function - // We use the function's FnAbi for debug info generation - let fn_abi = self - .cx() - .tcx - .fn_abi_of_instance( - self.cx().typing_env().as_query_input((instance, ty::List::empty())), + return unsafe { + llvm::LLVMRustDIBuilderCreateFunction( + DIB(self), + containing_scope, + name.as_c_char_ptr(), + name.len(), + linkage_name.as_c_char_ptr(), + linkage_name.len(), + file_metadata, + loc.line, + function_type_metadata, + scope_line, + flags, + spflags, + maybe_definition_llfn, + template_parameters, + decl, ) - .unwrap(); - - let di_scope = self.cx().dbg_scope_fn(instance, fn_abi, None); - - // Create an inlined debug location: - // - scope: the compiler_move/compiler_copy function - // - inlined_at: the current location (where the move/copy actually occurs) - // - span: use the function's definition span - let fn_span = self.cx().tcx.def_span(instance.def_id()); - let inlined_loc = self.cx().dbg_loc(di_scope, saved_loc, fn_span); - - // Set the temporary debug location - self.set_dbg_loc(inlined_loc); - - // Execute the closure (which will generate the memcpy) - let result = f(self); - - // Restore the original debug location - if let Some(loc) = saved_loc { - self.set_dbg_loc(loc); - } else { - self.clear_dbg_loc(); - } - - result - } -} - -/// 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. -struct DebugLoc { - /// Information about the original source file. - file: Arc, - /// The (1-based) line number. - line: u32, - /// The (1-based) column number. - col: u32, -} - -impl<'ll> 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. - 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.lines()[line]; - - // Use 1-based indexing. - let line = (line + 1) as u32; - let col = (file.relative_position(pos) - line_pos).to_u32() + 1; - - (file, line, col) - } - Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER), - }; - - // 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.is_like_msvc { - DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER } - } else { - DebugLoc { file, line, col } - } - } - - fn create_template_type_parameter( - &self, - name: &str, - actual_type_metadata: &'ll DIType, - ) -> &'ll DITemplateTypeParameter { - unsafe { - llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( - DIB(self), - None, - name.as_c_char_ptr(), - name.len(), - actual_type_metadata, - ) - } - } -} - -impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: &'ll DIScope) -> &'ll DIScope { - let loc = self.lookup_debug_loc(pos); - let file_metadata = file_metadata(self, &loc.file); - unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( - DIB(self), - parent_scope, - file_metadata, - loc.line, - loc.col, - ) - } - } - - fn dbg_location_clone_with_discriminator( - &self, - loc: &'ll DILocation, - discriminator: u32, - ) -> Option<&'ll DILocation> { - unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) } - } - - fn dbg_scope_fn( - &self, - instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - maybe_definition_llfn: Option<&'ll Value>, - ) -> &'ll DIScope { - let tcx = self.tcx; - - let def_id = instance.def_id(); - let (containing_scope, is_method) = get_containing_scope(self, instance); - let span = tcx.def_span(def_id); - let loc = self.lookup_debug_loc(span.lo()); - let file_metadata = file_metadata(self, &loc.file); - - let function_type_metadata = - create_subroutine_type(self, &get_function_signature(self, fn_abi)); - - let mut name = String::with_capacity(64); - type_names::push_item_name(tcx, def_id, false, &mut name); - - // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id); - - // We look up the generics of the enclosing function and truncate the args - // to their length in order to cut off extra stuff that might be in there for - // closures or coroutines. - let generics = tcx.generics_of(enclosing_fn_def_id); - let args = instance.args.truncate_to(tcx, generics); - - type_names::push_generic_args( - tcx, - tcx.normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(args)), - &mut name, - ); - - let template_parameters = get_template_parameters(self, generics, args); - - let linkage_name = &mangled_name_of_instance(self, instance).name; - // Omit the linkage_name if it is the same as subprogram name. - let linkage_name = if &name == linkage_name { "" } else { linkage_name }; - - // FIXME(eddyb) does this need to be separate from `loc.line` for some reason? - let scope_line = loc.line; - - let mut flags = DIFlags::FlagPrototyped; - - if fn_abi.ret.layout.is_uninhabited() { - flags |= DIFlags::FlagNoReturn; - } - - let mut spflags = DISPFlags::SPFlagDefinition; - if is_node_local_to_unit(self, def_id) { - spflags |= DISPFlags::SPFlagLocalToUnit; - } - if self.sess().opts.optimize != config::OptLevel::No { - spflags |= DISPFlags::SPFlagOptimized; - } - if let Some((id, _)) = tcx.entry_fn(()) { - if id == def_id { - spflags |= DISPFlags::SPFlagMainSubprogram; - } - } - - // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because - // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition. - // When we use this `decl` below, the subprogram definition gets created at the CU level - // with a DW_AT_specification pointing back to the type's declaration. - let decl = is_method.then(|| unsafe { - llvm::LLVMRustDIBuilderCreateMethod( - DIB(self), - containing_scope, - name.as_c_char_ptr(), - name.len(), - linkage_name.as_c_char_ptr(), - linkage_name.len(), - file_metadata, - loc.line, - function_type_metadata, - flags, - spflags & !DISPFlags::SPFlagDefinition, - template_parameters, - ) - }); - - return unsafe { - llvm::LLVMRustDIBuilderCreateFunction( - DIB(self), - containing_scope, - name.as_c_char_ptr(), - name.len(), - linkage_name.as_c_char_ptr(), - linkage_name.len(), - file_metadata, - loc.line, - function_type_metadata, - scope_line, - flags, - spflags, - maybe_definition_llfn, - template_parameters, - decl, - ) - }; + }; fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, @@ -658,8 +368,34 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } + fn dbg_create_lexical_block( + &mut self, + pos: BytePos, + parent_scope: &'ll DIScope, + ) -> &'ll DIScope { + let loc = self.lookup_debug_loc(pos); + let file_metadata = file_metadata(self, &loc.file); + unsafe { + llvm::LLVMDIBuilderCreateLexicalBlock( + DIB(self), + parent_scope, + file_metadata, + loc.line, + loc.col, + ) + } + } + + fn dbg_location_clone_with_discriminator( + &mut self, + loc: &'ll DILocation, + discriminator: u32, + ) -> Option<&'ll DILocation> { + unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) } + } + fn dbg_loc( - &self, + &mut self, scope: &'ll DIScope, inlined_at: Option<&'ll DILocation>, span: Span, @@ -679,31 +415,18 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) } } - fn create_vtable_debuginfo( - &self, - ty: Ty<'tcx>, - trait_ref: Option>, - vtable: Self::Value, - ) { - metadata::create_vtable_di_node(self, ty, trait_ref, vtable) - } - fn extend_scope_to_file( - &self, + &mut self, scope_metadata: &'ll DIScope, file: &rustc_span::SourceFile, ) -> &'ll DILexicalBlock { metadata::extend_scope_to_file(self, scope_metadata, file) } - fn debuginfo_finalize(&self) { - finalize(self) - } - // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn create_dbg_var( - &self, + &mut self, variable_name: Symbol, variable_type: Ty<'tcx>, scope_metadata: &'ll DIScope, @@ -750,4 +473,280 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { }, } } + + // FIXME(eddyb) find a common convention for all of the debuginfo-related + // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). + fn dbg_var_addr( + &mut self, + dbg_var: &'ll DIVariable, + dbg_loc: &'ll DILocation, + variable_alloca: Self::Value, + direct_offset: Size, + indirect_offsets: &[Size], + fragment: &Option>, + ) { + use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst}; + + // Convert the direct and indirect offsets and fragment byte range to address ops. + let mut addr_ops = SmallVec::<[u64; 8]>::new(); + + if direct_offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(direct_offset.bytes()); + } + for &offset in indirect_offsets { + addr_ops.push(DW_OP_deref); + if offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(offset.bytes()); + } + } + if let Some(fragment) = fragment { + // `DW_OP_LLVM_fragment` takes as arguments the fragment's + // offset and size, both of them in bits. + addr_ops.push(DW_OP_LLVM_fragment); + addr_ops.push(fragment.start.bits()); + addr_ops.push((fragment.end - fragment.start).bits()); + } + + let di_builder = DIB(self.cx()); + let addr_expr = di_builder.create_expression(&addr_ops); + unsafe { + llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( + di_builder, + variable_alloca, + dbg_var, + addr_expr, + dbg_loc, + self.llbb(), + ) + }; + } + + fn dbg_var_value( + &mut self, + dbg_var: &'ll DIVariable, + dbg_loc: &'ll DILocation, + value: Self::Value, + direct_offset: Size, + indirect_offsets: &[Size], + fragment: &Option>, + ) { + use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value}; + + // Convert the direct and indirect offsets and fragment byte range to address ops. + let mut addr_ops = SmallVec::<[u64; 8]>::new(); + + if direct_offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(direct_offset.bytes() as u64); + addr_ops.push(DW_OP_stack_value); + } + for &offset in indirect_offsets { + addr_ops.push(DW_OP_deref); + if offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(offset.bytes() as u64); + } + } + if let Some(fragment) = fragment { + // `DW_OP_LLVM_fragment` takes as arguments the fragment's + // offset and size, both of them in bits. + addr_ops.push(DW_OP_LLVM_fragment); + addr_ops.push(fragment.start.bits() as u64); + addr_ops.push((fragment.end - fragment.start).bits() as u64); + } + + let di_builder = DIB(self.cx()); + let addr_expr = unsafe { + llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) + }; + unsafe { + llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd( + di_builder, + value, + dbg_var, + addr_expr, + dbg_loc, + self.llbb(), + ); + } + } + + fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { + unsafe { + llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc); + } + } + + fn clear_dbg_loc(&mut self) { + unsafe { + llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null()); + } + } + + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { + gdb::insert_reference_to_gdb_debug_scripts_section_global(self) + } + + fn set_var_name(&mut self, value: &'ll Value, name: &str) { + // Avoid wasting time if LLVM value names aren't even enabled. + if self.sess().fewer_names() { + return; + } + + // Only function parameters and instructions are local to a function, + // don't change the name of anything else (e.g. globals). + let param_or_inst = unsafe { + llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some() + }; + if !param_or_inst { + return; + } + + // Avoid replacing the name if it already exists. + // While we could combine the names somehow, it'd + // get noisy quick, and the usefulness is dubious. + if llvm::get_value_name(value).is_empty() { + llvm::set_value_name(value, name.as_bytes()); + } + } + + /// Annotate move/copy operations with debug info for profiling. + /// + /// This creates a temporary debug scope that makes the move/copy appear as an inlined call to + /// `compiler_move()` or `compiler_copy()`. The provided closure is executed + /// with this temporary debug location active. + /// + /// The `instance` parameter should be the monomorphized instance of the `compiler_move` or + /// `compiler_copy` function with the actual type and size. + fn with_move_annotation( + &mut self, + instance: ty::Instance<'tcx>, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + // Save the current debug location + let saved_loc = self.get_dbg_loc(); + + // Create a DIScope for the compiler_move/compiler_copy function + // We use the function's FnAbi for debug info generation + let fn_abi = self + .cx() + .tcx + .fn_abi_of_instance( + self.cx().typing_env().as_query_input((instance, ty::List::empty())), + ) + .unwrap(); + + let di_scope = self.dbg_scope_fn(instance, fn_abi, None); + + // Create an inlined debug location: + // - scope: the compiler_move/compiler_copy function + // - inlined_at: the current location (where the move/copy actually occurs) + // - span: use the function's definition span + let fn_span = self.cx().tcx.def_span(instance.def_id()); + let inlined_loc = self.dbg_loc(di_scope, saved_loc, fn_span); + + // Set the temporary debug location + self.set_dbg_loc(inlined_loc); + + // Execute the closure (which will generate the memcpy) + let result = f(self); + + // Restore the original debug location + if let Some(loc) = saved_loc { + self.set_dbg_loc(loc); + } else { + self.clear_dbg_loc(); + } + + result + } +} + +/// 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. +struct DebugLoc { + /// Information about the original source file. + file: Arc, + /// The (1-based) line number. + line: u32, + /// The (1-based) column number. + col: u32, +} + +impl<'ll> 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. + 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.lines()[line]; + + // Use 1-based indexing. + let line = (line + 1) as u32; + let col = (file.relative_position(pos) - line_pos).to_u32() + 1; + + (file, line, col) + } + Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER), + }; + + // 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.is_like_msvc { + DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER } + } else { + DebugLoc { file, line, col } + } + } + + fn create_template_type_parameter( + &self, + name: &str, + actual_type_metadata: &'ll DIType, + ) -> &'ll DITemplateTypeParameter { + unsafe { + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + DIB(self), + None, + name.as_c_char_ptr(), + name.len(), + actual_type_metadata, + ) + } + } + + /// Creates any deferred debug metadata nodes + pub(crate) fn debuginfo_finalize(&self) { + if let Some(dbg_cx) = &self.dbg_cx { + debug!("finalize"); + + if gdb::needs_gdb_debug_scripts_section(self) { + // Add a .debug_gdb_scripts section to this compile-unit. This will + // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, + // which activates the Rust pretty printers for binary this section is + // contained in. + gdb::get_or_insert_gdb_debug_scripts_section_global(self); + } + + dbg_cx.finalize(); + } + } +} + +impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { + fn create_vtable_debuginfo( + &self, + ty: Ty<'tcx>, + trait_ref: Option>, + vtable: Self::Value, + ) { + metadata::create_vtable_di_node(self, ty, trait_ref, vtable) + } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 2a55cbedfb3b8..71315acc4e5db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -78,15 +78,18 @@ impl<'tcx, S: Copy, L: Copy> DebugScope { /// 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>( + pub fn adjust_dbg_scope_for_span< + 'a, + Bx: BuilderMethods<'a, 'tcx, DIScope = S, DILocation = L>, + >( &self, - cx: &Cx, + bx: &mut Bx, span: Span, ) -> S { 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(self.dbg_scope, &sm.lookup_char_pos(pos).file) + let sm = bx.sess().source_map(); + bx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file) } else { self.dbg_scope } @@ -217,23 +220,24 @@ fn calculate_debuginfo_offset< impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) { bx.set_span(source_info.span); - if let Some(dbg_loc) = self.dbg_loc(source_info) { + if let Some(dbg_loc) = self.dbg_loc(bx, source_info) { bx.set_dbg_loc(dbg_loc); } } - fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option { - let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?; - Some(self.cx.dbg_loc(dbg_scope, inlined_at, span)) + fn dbg_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) -> Option { + let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(bx, source_info)?; + Some(bx.dbg_loc(dbg_scope, inlined_at, span)) } fn adjusted_span_and_dbg_scope( &self, + bx: &mut Bx, source_info: mir::SourceInfo, ) -> Option<(Bx::DIScope, Option, Span)> { let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span); - Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) + Some((scope.adjust_dbg_scope_for_span(bx, span), scope.inlined_at, span)) } fn spill_operand_to_stack( @@ -279,7 +283,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Some(dbg_var) = var.dbg_var else { continue; }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { + let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else { continue; }; bx.dbg_var_value( @@ -334,14 +338,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let name = sym::empty; let decl = &self.mir.local_decls[local]; let dbg_var = if full_debug_info { - self.adjusted_span_and_dbg_scope(decl.source_info).map( + self.adjusted_span_and_dbg_scope(bx, decl.source_info).map( |(dbg_scope, _, span)| { // FIXME(eddyb) is this `+ 1` needed at all? let kind = VariableKind::ArgumentVariable(arg_index + 1); let arg_ty = self.monomorphize(decl.ty); - self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) + bx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) }, ) } else { @@ -483,7 +487,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, ) { let Some(dbg_var) = var.dbg_var else { return }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; + let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else { return }; let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = calculate_debuginfo_offset(bx, var.projection, base.layout); @@ -579,7 +583,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default(); for var in &self.mir.var_debug_info { let dbg_scope_and_span = if full_debug_info { - self.adjusted_span_and_dbg_scope(var.source_info) + self.adjusted_span_and_dbg_scope(bx, var.source_info) } else { None }; @@ -625,13 +629,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match params_seen.entry((dbg_scope, arg_index)) { Entry::Occupied(o) => o.get().clone(), Entry::Vacant(v) => v - .insert( - self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span), - ) + .insert(bx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)) .clone(), } } else { - self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) + bx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) } }); @@ -669,7 +671,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::VarDebugInfoContents::Const(c) => { if let Some(dbg_var) = dbg_var { - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; + let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else { continue }; let operand = self.eval_mir_constant_to_operand(bx, &c); constants.push(ConstDebugInfo { @@ -692,7 +694,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// /// Returns the FunctionDebugContext for the function which holds state needed /// for debug info creation, if it is enabled. - pub(super) fn fill_function_debug_context(&mut self) { + pub(super) fn fill_function_debug_context(&mut self, bx: &mut Bx) { if self.cx.sess().opts.debuginfo == DebugInfo::None { return; } @@ -722,7 +724,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Instantiate all scopes. let mut discriminators = FxHashMap::default(); for scope in self.mir.source_scopes.indices() { - let scope_data = self.make_mir_scope(&variables, &mut discriminators, scope); + let scope_data = self.make_mir_scope(bx, &variables, &mut discriminators, scope); let _s = self.debug_context.as_mut().unwrap().scopes.push(scope_data); debug_assert_eq!(_s, scope); } @@ -730,6 +732,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn make_mir_scope( &mut self, + bx: &mut Bx, variables: &Option>, discriminators: &mut FxHashMap, scope: mir::SourceScope, @@ -741,7 +744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { // The root is the function itself. let file = self.cx.sess().source_map().lookup_source_file(self.mir.span.lo()); - let dbg_scope = self.cx.dbg_scope_fn(self.instance, self.fn_abi, Some(self.llfn)); + let dbg_scope = bx.dbg_scope_fn(self.instance, self.fn_abi, Some(self.llfn)); return DebugScope { dbg_scope, inlined_at: None, @@ -770,16 +773,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .entry(callee) .or_insert_with(|| { let callee_fn_abi = self.cx.fn_abi_of_instance(callee, ty::List::empty()); - self.cx.dbg_scope_fn(callee, callee_fn_abi, None) + bx.dbg_scope_fn(callee, callee_fn_abi, None) }) } - None => self.cx.dbg_create_lexical_block(scope_data.span.lo(), parent_scope.dbg_scope), + None => bx.dbg_create_lexical_block(scope_data.span.lo(), parent_scope.dbg_scope), }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { let callsite_span = hygiene::walk_chain_collapsed(callsite_span, self.mir.span); - let callsite_scope = parent_scope.adjust_dbg_scope_for_span(self.cx, callsite_span); - let loc = self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span); + let callsite_scope = parent_scope.adjust_dbg_scope_for_span(bx, callsite_span); + let loc = bx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span); // NB: In order to produce proper debug info for variables (particularly // arguments) in multiply-inlined functions, LLVM expects to see a single @@ -805,9 +808,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // NB: We have to emit *something* here or we'll fail LLVM IR verification // in at least some circumstances (see issue #135322) so if the required // discriminant cannot be encoded fall back to the dummy location. - self.cx.dbg_location_clone_with_discriminator(loc, *o.get()).unwrap_or_else( - || self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP), - ) + bx.dbg_location_clone_with_discriminator(loc, *o.get()).unwrap_or_else(|| { + bx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP) + }) } Entry::Vacant(v) => { v.insert(0); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 68fed6c867fa5..2fa283a6c2eb4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -269,7 +269,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // monomorphization, and if there is an error during collection then codegen never starts -- so // we don't have to do it again. - fx.fill_function_debug_context(); + fx.fill_function_debug_context(&mut start_bx); let (per_local_var_debug_info, consts_debug_info) = fx.compute_per_local_var_debug_info(&mut start_bx).unzip(); diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index d3af9e52f1b91..5e407ad13d859 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -15,51 +15,54 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { trait_ref: Option>, vtable: Self::Value, ); +} - fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: Self::DIScope) -> Self::DIScope; - - fn dbg_location_clone_with_discriminator( - &self, - loc: Self::DILocation, - discriminator: u32, - ) -> Option; - +pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { // 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, + &mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, maybe_definition_llfn: Option, ) -> Self::DIScope; + fn dbg_create_lexical_block( + &mut self, + pos: BytePos, + parent_scope: Self::DIScope, + ) -> Self::DIScope; + + fn dbg_location_clone_with_discriminator( + &mut self, + loc: Self::DILocation, + discriminator: u32, + ) -> Option; + fn dbg_loc( - &self, + &mut self, scope: Self::DIScope, inlined_at: Option, span: Span, ) -> Self::DILocation; fn extend_scope_to_file( - &self, + &mut self, scope_metadata: Self::DIScope, file: &SourceFile, ) -> Self::DIScope; - fn debuginfo_finalize(&self); // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn create_dbg_var( - &self, + &mut self, variable_name: Symbol, variable_type: Ty<'tcx>, scope_metadata: Self::DIScope, variable_kind: VariableKind, span: Span, ) -> Self::DIVariable; -} -pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). fn dbg_var_addr(