From 67c85cc75656b26c8377ce1579ea731fc1522e1f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:27:00 +0200 Subject: [PATCH 1/5] Remove debuginfo_finalize from DebugInfoCodegenMethods It isn't called from cg_ssa. --- compiler/rustc_codegen_gcc/src/base.rs | 1 - compiler/rustc_codegen_gcc/src/debuginfo.rs | 8 ++-- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 38 +++++++++---------- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 1 - 4 files changed, 21 insertions(+), 27 deletions(-) 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..7993ababfac95 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -103,6 +103,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> { @@ -138,10 +142,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): implement. } - fn debuginfo_finalize(&self) { - self.context.set_debug_info(true) - } - fn create_dbg_var( &self, _variable_name: Symbol, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d8d529fee6f8b..e6dda274efe3e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -120,23 +120,6 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { } } -/// 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); - } - - dbg_cx.finalize(cx.sess()); - } -} - impl<'ll> Builder<'_, 'll, '_> { pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> { unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) } @@ -391,6 +374,23 @@ impl<'ll> CodegenCx<'ll, '_> { ) } } + + /// 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(self.sess()); + } + } } impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -696,10 +696,6 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { 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( diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index d3af9e52f1b91..d6502df86d331 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -45,7 +45,6 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { 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.). From 324705718e9fb62fc6e8ea8a7cf010de412ae86b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:39:43 +0200 Subject: [PATCH 2/5] Move a bunch of debuginfo functions from codegen to builder methods These functions are scoped to a single codegened function --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 52 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 800 +++++++++--------- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 19 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 26 +- 5 files changed, 449 insertions(+), 450 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 7993ababfac95..25ae0f8ffc202 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -16,6 +16,32 @@ 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( + &self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _maybe_definition_llfn: Option>, + ) -> Self::DIScope { + // FIXME(antoyo): implement. + } + + fn dbg_create_lexical_block( + &self, + _pos: BytePos, + _parent_scope: Self::DIScope, + ) -> Self::DIScope { + } + + fn create_dbg_var( + &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( @@ -119,13 +145,6 @@ 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, @@ -142,25 +161,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): implement. } - 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, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index e6dda274efe3e..4b56595e544cd 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -127,6 +127,313 @@ impl<'ll> Builder<'_, 'll, '_> { } impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { + 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>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + ) -> Vec> { + if cx.sess().opts.debuginfo != DebugInfo::Full { + return vec![]; + } + + let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(if fn_abi.ret.is_ignore() { + None + } else { + Some(type_di_node(cx, fn_abi.ret.layout.ty)) + }); + + // Arguments types + if cx.sess().target.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(fn_abi.args.iter().map(|arg| { + let t = arg.layout.ty; + let t = match t.kind() { + ty::Array(ct, _) + if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() => + { + Ty::new_imm_ptr(cx.tcx, *ct) + } + _ => t, + }; + Some(type_di_node(cx, t)) + })); + } else { + signature + .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); + } + + signature + } + + fn get_template_parameters<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + generics: &ty::Generics, + args: GenericArgsRef<'tcx>, + ) -> &'ll DIArray { + if args.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } + + // 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); + iter::zip(args, names) + .filter_map(|(kind, name)| { + kind.as_type().map(|ty| { + let actual_type = cx.tcx.normalize_erasing_regions( + cx.typing_env(), + Unnormalized::new_wip(ty), + ); + let actual_type_metadata = type_di_node(cx, actual_type); + Some(cx.create_template_type_parameter( + name.as_str(), + actual_type_metadata, + )) + }) + }) + .collect() + } else { + vec![] + }; + + create_DIArray(DIB(cx), &template_params) + } + + fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { + let mut names = generics.parent.map_or_else(Vec::new, |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.own_params.iter().map(|param| param.name)); + names + } + + /// Returns a scope, plus `true` if that's a type scope for "class" methods, + /// otherwise `false` for plain namespace scopes. + fn get_containing_scope<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + instance: Instance<'tcx>, + ) -> (&'ll DIScope, bool) { + // 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. + // For trait method impls we still use the "parallel namespace" + // strategy + if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) { + let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions( + instance.args, + cx.typing_env(), + cx.tcx.type_of(imp_def_id), + ); + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g., `<*mut T>::null`). + if let ty::Adt(def, ..) = impl_self_ty.kind() + && !def.is_box() + { + // Again, only create type information if full debuginfo is enabled + if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() { + return (type_di_node(cx, impl_self_ty), true); + } else { + return (namespace::item_namespace(cx, def.did()), false); + } + } + } + + let scope = 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?"), + }, + ); + (scope, false) + } + } + + 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, + ) + } + } + + // 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, + variable_name: Symbol, + variable_type: Ty<'tcx>, + scope_metadata: &'ll DIScope, + variable_kind: VariableKind, + span: Span, + ) -> &'ll DIVariable { + let loc = self.lookup_debug_loc(span.lo()); + let file_metadata = file_metadata(self, &loc.file); + + let type_metadata = spanned_type_di_node(self, variable_type, span); + + let align = self.align_of(variable_type); + + let name = variable_name.as_str(); + + match variable_kind { + ArgumentVariable(arg_index) => unsafe { + llvm::LLVMDIBuilderCreateParameterVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + arg_index as c_uint, + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + ) + }, + LocalVariable => unsafe { + llvm::LLVMDIBuilderCreateAutoVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + align.bits() as u32, + ) + }, + } + } + // 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( @@ -291,372 +598,116 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) .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, - ) - } - } - - /// 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(self.sess()); - } - } -} - -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>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - ) -> Vec> { - if cx.sess().opts.debuginfo != DebugInfo::Full { - return vec![]; - } + let di_scope = self.dbg_scope_fn(instance, fn_abi, None); - let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); + // 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); - // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(if fn_abi.ret.is_ignore() { - None - } else { - Some(type_di_node(cx, fn_abi.ret.layout.ty)) - }); + // Set the temporary debug location + self.set_dbg_loc(inlined_loc); - // Arguments types - if cx.sess().target.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(fn_abi.args.iter().map(|arg| { - let t = arg.layout.ty; - let t = match t.kind() { - ty::Array(ct, _) - if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() => - { - Ty::new_imm_ptr(cx.tcx, *ct) - } - _ => t, - }; - Some(type_di_node(cx, t)) - })); - } else { - signature - .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); - } + // Execute the closure (which will generate the memcpy) + let result = f(self); - signature + // Restore the original debug location + if let Some(loc) = saved_loc { + self.set_dbg_loc(loc); + } else { + self.clear_dbg_loc(); } - fn get_template_parameters<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - generics: &ty::Generics, - args: GenericArgsRef<'tcx>, - ) -> &'ll DIArray { - if args.types().next().is_none() { - return create_DIArray(DIB(cx), &[]); - } + result + } +} - // 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); - iter::zip(args, names) - .filter_map(|(kind, name)| { - kind.as_type().map(|ty| { - let actual_type = cx.tcx.normalize_erasing_regions( - cx.typing_env(), - Unnormalized::new_wip(ty), - ); - let actual_type_metadata = type_di_node(cx, actual_type); - Some(cx.create_template_type_parameter( - name.as_str(), - actual_type_metadata, - )) - }) - }) - .collect() - } else { - vec![] - }; +/// 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, +} - create_DIArray(DIB(cx), &template_params) +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 get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { - let mut names = generics.parent.map_or_else(Vec::new, |def_id| { - get_parameter_names(cx, cx.tcx.generics_of(def_id)) - }); - names.extend(generics.own_params.iter().map(|param| param.name)); - names + 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, + ) } + } - /// Returns a scope, plus `true` if that's a type scope for "class" methods, - /// otherwise `false` for plain namespace scopes. - fn get_containing_scope<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - instance: Instance<'tcx>, - ) -> (&'ll DIScope, bool) { - // 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. - // For trait method impls we still use the "parallel namespace" - // strategy - if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) { - let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions( - instance.args, - cx.typing_env(), - cx.tcx.type_of(imp_def_id), - ); + /// Creates any deferred debug metadata nodes + pub(crate) fn debuginfo_finalize(&self) { + if let Some(dbg_cx) = &self.dbg_cx { + debug!("finalize"); - // Only "class" methods are generally understood by LLVM, - // so avoid methods on other types (e.g., `<*mut T>::null`). - if let ty::Adt(def, ..) = impl_self_ty.kind() - && !def.is_box() - { - // Again, only create type information if full debuginfo is enabled - if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() { - return (type_di_node(cx, impl_self_ty), true); - } else { - return (namespace::item_namespace(cx, def.did()), false); - } - } + 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); } - let scope = 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?"), - }, - ); - (scope, false) + dbg_cx.finalize(self.sess()); } } +} + +impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { + fn dbg_location_clone_with_discriminator( + &self, + loc: &'ll DILocation, + discriminator: u32, + ) -> Option<&'ll DILocation> { + unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) } + } fn dbg_loc( &self, @@ -695,55 +746,4 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) -> &'ll DILexicalBlock { metadata::extend_scope_to_file(self, scope_metadata, file) } - - // 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, - variable_name: Symbol, - variable_type: Ty<'tcx>, - scope_metadata: &'ll DIScope, - variable_kind: VariableKind, - span: Span, - ) -> &'ll DIVariable { - let loc = self.lookup_debug_loc(span.lo()); - let file_metadata = file_metadata(self, &loc.file); - - let type_metadata = spanned_type_di_node(self, variable_type, span); - - let align = self.align_of(variable_type); - - let name = variable_name.as_str(); - - match variable_kind { - ArgumentVariable(arg_index) => unsafe { - llvm::LLVMDIBuilderCreateParameterVariable( - DIB(self), - scope_metadata, - name.as_ptr(), - name.len(), - arg_index as c_uint, - file_metadata, - loc.line, - type_metadata, - llvm::Bool::TRUE, // (preserve descriptor during optimizations) - DIFlags::FlagZero, - ) - }, - LocalVariable => unsafe { - llvm::LLVMDIBuilderCreateAutoVariable( - DIB(self), - scope_metadata, - name.as_ptr(), - name.len(), - file_metadata, - loc.line, - type_metadata, - llvm::Bool::TRUE, // (preserve descriptor during optimizations) - DIFlags::FlagZero, - align.bits() as u32, - ) - }, - } - } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 2a55cbedfb3b8..e622575f9a0db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -341,7 +341,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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 { @@ -625,13 +625,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) } }); @@ -692,7 +690,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 +720,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 +728,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 +740,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,10 +769,10 @@ 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)| { 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 d6502df86d331..9e94953ad1f94 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -16,23 +16,12 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { 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; - // 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::DIScope; - fn dbg_loc( &self, scope: Self::DIScope, @@ -45,6 +34,19 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { scope_metadata: Self::DIScope, file: &SourceFile, ) -> Self::DIScope; +} + +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, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + maybe_definition_llfn: Option, + ) -> Self::DIScope; + + fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: Self::DIScope) -> Self::DIScope; // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). @@ -56,9 +58,7 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { 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( From aa81c219de0656368e44fe538c830e27e7569e78 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:50:50 +0200 Subject: [PATCH 3/5] Move a couple more debuginfo functions from codegen to builder methods These functions are scoped to a single codegened function --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 68 ++++++++--------- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 76 +++++++++---------- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 42 +++++----- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 26 +++---- 4 files changed, 108 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 25ae0f8ffc202..efdbc00f95aaf 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -32,6 +32,40 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { ) -> 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 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(), + } + } + fn create_dbg_var( &self, _variable_name: Symbol, @@ -144,38 +178,4 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ) { // FIXME(antoyo) } - - 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 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/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 4b56595e544cd..f2981bc4ed1f5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -383,6 +383,43 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } + fn dbg_location_clone_with_discriminator( + &self, + loc: &'ll DILocation, + discriminator: u32, + ) -> Option<&'ll DILocation> { + unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) } + } + + fn dbg_loc( + &self, + scope: &'ll DIScope, + inlined_at: Option<&'ll DILocation>, + span: Span, + ) -> &'ll DILocation { + // When emitting debugging information, DWARF (i.e. everything but MSVC) + // treats line 0 as a magic value meaning that the code could not be + // attributed to any line in the source. That's also exactly what dummy + // spans are. Make that equivalence here, rather than passing dummy spans + // to lookup_debug_loc, which will return line 1 for them. + let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc { + (0, 0) + } else { + let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); + (line, col) + }; + + unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) } + } + + fn extend_scope_to_file( + &self, + scope_metadata: &'ll DIScope, + file: &rustc_span::SourceFile, + ) -> &'ll DILexicalBlock { + metadata::extend_scope_to_file(self, scope_metadata, file) + } + // 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( @@ -605,7 +642,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // - 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); + let inlined_loc = self.dbg_loc(di_scope, saved_loc, fn_span); // Set the temporary debug location self.set_dbg_loc(inlined_loc); @@ -701,35 +738,6 @@ impl<'ll> CodegenCx<'ll, '_> { } impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn dbg_location_clone_with_discriminator( - &self, - loc: &'ll DILocation, - discriminator: u32, - ) -> Option<&'ll DILocation> { - unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) } - } - - fn dbg_loc( - &self, - scope: &'ll DIScope, - inlined_at: Option<&'ll DILocation>, - span: Span, - ) -> &'ll DILocation { - // When emitting debugging information, DWARF (i.e. everything but MSVC) - // treats line 0 as a magic value meaning that the code could not be - // attributed to any line in the source. That's also exactly what dummy - // spans are. Make that equivalence here, rather than passing dummy spans - // to lookup_debug_loc, which will return line 1 for them. - let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc { - (0, 0) - } else { - let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); - (line, col) - }; - - unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) } - } - fn create_vtable_debuginfo( &self, ty: Ty<'tcx>, @@ -738,12 +746,4 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) { metadata::create_vtable_di_node(self, ty, trait_ref, vtable) } - - fn extend_scope_to_file( - &self, - scope_metadata: &'ll DIScope, - file: &rustc_span::SourceFile, - ) -> &'ll DILexicalBlock { - metadata::extend_scope_to_file(self, scope_metadata, file) - } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index e622575f9a0db..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,7 +338,7 @@ 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); @@ -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 }; @@ -667,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 { @@ -777,8 +781,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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 @@ -804,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/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 9e94953ad1f94..1d9fae3df8d50 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -15,6 +15,19 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { trait_ref: Option>, vtable: Self::Value, ); +} + +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, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + maybe_definition_llfn: Option, + ) -> Self::DIScope; + + fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: Self::DIScope) -> Self::DIScope; fn dbg_location_clone_with_discriminator( &self, @@ -34,19 +47,6 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { scope_metadata: Self::DIScope, file: &SourceFile, ) -> Self::DIScope; -} - -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, - instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - maybe_definition_llfn: Option, - ) -> Self::DIScope; - - fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: Self::DIScope) -> Self::DIScope; // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). From 0943c50eacaf745ca52bbd4f18eedcf01bb73168 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:10:59 +0200 Subject: [PATCH 4/5] Pass &mut self to all debuginfo builder methods --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 12 ++++++------ compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 16 ++++++++++------ .../rustc_codegen_ssa/src/traits/debuginfo.rs | 16 ++++++++++------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index efdbc00f95aaf..5e598e5825d1b 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -17,7 +17,7 @@ pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0; impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn dbg_scope_fn( - &self, + &mut self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>, @@ -26,14 +26,14 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } fn dbg_create_lexical_block( - &self, + &mut self, _pos: BytePos, _parent_scope: Self::DIScope, ) -> Self::DIScope { } fn dbg_location_clone_with_discriminator( - &self, + &mut self, loc: Self::DILocation, _discriminator: u32, ) -> Option { @@ -41,7 +41,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } fn extend_scope_to_file( - &self, + &mut self, _scope_metadata: Self::DIScope, _file: &SourceFile, ) -> Self::DIScope { @@ -49,7 +49,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } fn dbg_loc( - &self, + &mut self, _scope: Self::DIScope, _inlined_at: Option, span: Span, @@ -67,7 +67,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } fn create_dbg_var( - &self, + &mut self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index f2981bc4ed1f5..821bce339c07e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -128,7 +128,7 @@ impl<'ll> Builder<'_, 'll, '_> { impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn dbg_scope_fn( - &self, + &mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, maybe_definition_llfn: Option<&'ll Value>, @@ -369,7 +369,11 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: &'ll DIScope) -> &'ll DIScope { + 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 { @@ -384,7 +388,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn dbg_location_clone_with_discriminator( - &self, + &mut self, loc: &'ll DILocation, discriminator: u32, ) -> Option<&'ll DILocation> { @@ -392,7 +396,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn dbg_loc( - &self, + &mut self, scope: &'ll DIScope, inlined_at: Option<&'ll DILocation>, span: Span, @@ -413,7 +417,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn extend_scope_to_file( - &self, + &mut self, scope_metadata: &'ll DIScope, file: &rustc_span::SourceFile, ) -> &'ll DILexicalBlock { @@ -423,7 +427,7 @@ 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 create_dbg_var( - &self, + &mut self, variable_name: Symbol, variable_type: Ty<'tcx>, scope_metadata: &'ll DIScope, diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 1d9fae3df8d50..5e407ad13d859 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -21,29 +21,33 @@ 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(&self, pos: BytePos, parent_scope: Self::DIScope) -> Self::DIScope; + fn dbg_create_lexical_block( + &mut self, + pos: BytePos, + parent_scope: Self::DIScope, + ) -> Self::DIScope; fn dbg_location_clone_with_discriminator( - &self, + &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; @@ -51,7 +55,7 @@ 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 create_dbg_var( - &self, + &mut self, variable_name: Symbol, variable_type: Ty<'tcx>, scope_metadata: Self::DIScope, From 7d346e2c80a32ac18d326cc74caecd491077834d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:31:22 +0200 Subject: [PATCH 5/5] Avoid storing module in CodegenUnitDebugContext --- compiler/rustc_codegen_llvm/src/allocator.rs | 4 +- compiler/rustc_codegen_llvm/src/context.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 41 +++++++++---------- 3 files changed, 23 insertions(+), 24 deletions(-) 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 821bce339c07e..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,11 +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() }, ); + + 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(), + } + } + + pub(crate) fn finalize(&self) { + unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) }; } } @@ -736,7 +735,7 @@ impl<'ll> CodegenCx<'ll, '_> { gdb::get_or_insert_gdb_debug_scripts_section_global(self); } - dbg_cx.finalize(self.sess()); + dbg_cx.finalize(); } } }