Rollup merge of #147608 - Zalathar:debuginfo, r=nnethercote

cg_llvm: Use `LLVMDIBuilderCreateGlobalVariableExpression`

- Part of rust-lang/rust#134001
- Follow-up to rust-lang/rust#146763

---

This PR dismantles the somewhat complicated `LLVMRustDIBuilderCreateStaticVariable` function, and replaces it with equivalent calls to `LLVMDIBuilderCreateGlobalVariableExpression` and `LLVMGlobalSetMetadata`.

A key difference is that the new code does not replicate the attempted downcast of `InitVal`. As far as I can tell, those downcasts were actually dead, because `llvm::ConstantInt` and `llvm::ConstantFP` are not subclasses of `llvm::GlobalVariable`. I tried replacing those code paths with fatal errors, and was unable to induce failure in any of the relevant test suites I ran.

I have also confirmed that if the calls to `create_static_variable` are commented out, debuginfo tests will fail, demonstrating some amount of relevant test coverage.

The new `DIBuilder` methods have been added via an extension trait, not as inherent methods, to avoid impeding rust-lang/rust#142897.
This commit is contained in:
Guillaume Gomez
2025-10-13 11:25:23 +02:00
committed by GitHub
6 changed files with 150 additions and 93 deletions

View File

@@ -0,0 +1,69 @@
use libc::c_uint;
use rustc_abi::Align;
use crate::llvm::debuginfo::DIBuilder;
use crate::llvm::{self, ToLlvmBool};
/// Extension trait for defining safe wrappers and helper methods on
/// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate.
pub(crate) trait DIBuilderExt<'ll> {
fn as_di_builder(&self) -> &DIBuilder<'ll>;
fn create_expression(&self, addr_ops: &[u64]) -> &'ll llvm::Metadata {
let this = self.as_di_builder();
unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) }
}
fn create_static_variable(
&self,
scope: Option<&'ll llvm::Metadata>,
name: &str,
linkage_name: &str,
file: &'ll llvm::Metadata,
line_number: c_uint,
ty: &'ll llvm::Metadata,
is_local_to_unit: bool,
val: &'ll llvm::Value,
decl: Option<&'ll llvm::Metadata>,
align: Option<Align>,
) -> &'ll llvm::Metadata {
let this = self.as_di_builder();
let align_in_bits = align.map_or(0, |align| align.bits() as u32);
// `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we
// gave it a null `Expr` pointer, so give it an empty expression
// instead, which is what the C++ `createGlobalVariableExpression`
// method would do if given a null `DIExpression` pointer.
let expr = self.create_expression(&[]);
let global_var_expr = unsafe {
llvm::LLVMDIBuilderCreateGlobalVariableExpression(
this,
scope,
name.as_ptr(),
name.len(),
linkage_name.as_ptr(),
linkage_name.len(),
file,
line_number,
ty,
is_local_to_unit.to_llvm_bool(),
expr,
decl,
align_in_bits,
)
};
unsafe { llvm::LLVMGlobalSetMetadata(val, llvm::MD_dbg, global_var_expr) };
global_var_expr
}
}
impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> {
fn as_di_builder(&self) -> &DIBuilder<'ll> {
self
}
// All other methods have default bodies that rely on `as_di_builder`.
}

View File

@@ -34,9 +34,9 @@ use super::namespace::mangled_name_of_instance;
use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::dwarf_const;
use crate::debuginfo::metadata::type_map::build_type_with_children;
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
use crate::debuginfo::{DIBuilderExt, dwarf_const};
use crate::llvm::debuginfo::{
DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock,
DIScope, DIType, DebugEmissionKind, DebugNameTableKind,
@@ -1410,23 +1410,18 @@ pub(crate) fn build_global_var_di_node<'ll>(
let global_align = cx.align_of(variable_type);
unsafe {
llvm::LLVMRustDIBuilderCreateStaticVariable(
DIB(cx),
Some(var_scope),
var_name.as_c_char_ptr(),
var_name.len(),
linkage_name.as_c_char_ptr(),
linkage_name.len(),
file_metadata,
line_number,
type_di_node,
is_local_to_unit,
global,
None,
global_align.bits() as u32,
);
}
DIB(cx).create_static_variable(
Some(var_scope),
var_name,
linkage_name,
file_metadata,
line_number,
type_di_node,
is_local_to_unit,
global, // (value)
None, // (decl)
Some(global_align),
);
}
/// Generates LLVM debuginfo for a vtable.
@@ -1643,25 +1638,19 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
let vtable_name =
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
let linkage_name = "";
unsafe {
llvm::LLVMRustDIBuilderCreateStaticVariable(
DIB(cx),
NO_SCOPE_METADATA,
vtable_name.as_c_char_ptr(),
vtable_name.len(),
linkage_name.as_c_char_ptr(),
linkage_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
vtable_type_di_node,
true,
vtable,
None,
0,
);
}
DIB(cx).create_static_variable(
NO_SCOPE_METADATA,
&vtable_name,
"", // (linkage_name)
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
vtable_type_di_node,
true, // (is_local_to_unit)
vtable, // (value)
None, // (decl)
None::<Align>,
);
}
/// Creates an "extension" of an existing `DIScope` into another file.

View File

@@ -28,6 +28,9 @@ use rustc_target::spec::DebuginfoKind;
use smallvec::SmallVec;
use tracing::debug;
use self::create_scope_map::compute_mir_scopes;
pub(crate) use self::di_builder::DIBuilderExt;
pub(crate) use self::metadata::build_global_var_di_node;
use self::metadata::{
UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node,
};
@@ -42,15 +45,13 @@ use crate::llvm::debuginfo::{
use crate::llvm::{self, Value};
mod create_scope_map;
mod di_builder;
mod dwarf_const;
mod gdb;
pub(crate) mod metadata;
mod namespace;
mod utils;
use self::create_scope_map::compute_mir_scopes;
pub(crate) use self::metadata::build_global_var_di_node;
/// A context object for maintaining all state needed by the debuginfo module.
pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
llmod: &'ll llvm::Module,
@@ -182,9 +183,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
}
let di_builder = DIB(self.cx());
let addr_expr = unsafe {
llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
};
let addr_expr = di_builder.create_expression(&addr_ops);
unsafe {
llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
di_builder,

View File

@@ -22,9 +22,9 @@ use libc::{c_char, c_int, c_uchar, c_uint, c_ulonglong, c_void, size_t};
use super::RustString;
use super::debuginfo::{
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, DILocation,
DISPFlags, DIScope, DISubprogram, DITemplateTypeParameter, DIType, DebugEmissionKind,
DebugNameTableKind,
};
use crate::llvm::MetadataKindId;
use crate::{TryFromU32, llvm};
@@ -781,7 +781,6 @@ pub(crate) mod debuginfo {
pub(crate) type DIDerivedType = DIType;
pub(crate) type DICompositeType = DIDerivedType;
pub(crate) type DIVariable = DIDescriptor;
pub(crate) type DIGlobalVariableExpression = DIDescriptor;
pub(crate) type DIArray = DIDescriptor;
pub(crate) type DIEnumerator = DIDescriptor;
pub(crate) type DITemplateTypeParameter = DIDescriptor;
@@ -1877,6 +1876,22 @@ unsafe extern "C" {
Length: size_t,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateGlobalVariableExpression<'ll>(
Builder: &DIBuilder<'ll>,
Scope: Option<&'ll Metadata>,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
Linkage: *const c_uchar, // See "PTR_LEN_STR".
LinkLen: size_t,
File: &'ll Metadata,
LineNo: c_uint,
Ty: &'ll Metadata,
LocalToUnit: llvm::Bool,
Expr: &'ll Metadata,
Decl: Option<&'ll Metadata>,
AlignInBits: u32,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>(
Builder: &DIBuilder<'ll>,
Storage: &'ll Value,
@@ -2213,22 +2228,6 @@ unsafe extern "C" {
Ty: &'a DIType,
) -> &'a DIType;
pub(crate) fn LLVMRustDIBuilderCreateStaticVariable<'a>(
Builder: &DIBuilder<'a>,
Context: Option<&'a DIScope>,
Name: *const c_char,
NameLen: size_t,
LinkageName: *const c_char,
LinkageNameLen: size_t,
File: &'a DIFile,
LineNo: c_uint,
Ty: &'a DIType,
isLocalToUnit: bool,
Val: &'a Value,
Decl: Option<&'a DIDescriptor>,
AlignInBits: u32,
) -> &'a DIGlobalVariableExpression;
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,