Skip to content

Commit 2545459

Browse files
committed
Auto merge of rust-lang#85269 - dpaoliello:dpaoliello/DebugSymbols, r=michaelwoerister
Improve debug symbol names to avoid ambiguity and work better with MSVC's debugger There are several cases where names of types and functions in the debug info are either ambiguous, or not helpful, such as including ambiguous placeholders (e.g., `{{impl}}`, `{{closure}}` or `dyn _'`) or dropping qualifications (e.g., for dynamic types). Instead, each debug symbol name should be unique and useful: * Include disambiguators for anonymous `DefPathDataName` (closures and generators), and unify their formatting when used as a path-qualifier vs item being qualified. * Qualify the principal trait for dynamic types. * If there is no principal trait for a dynamic type, emit all other traits instead. * Respect the `qualified` argument when emitting ref and pointer types. * For implementations, emit the disambiguator. * Print const generics when emitting generic parameters or arguments. Additionally, when targeting MSVC, its debugger treats many command arguments as C++ expressions, even when the argument is defined to be a symbol name. As such names in the debug info need to be more C++-like to be parsed correctly: * Avoid characters with special meaning (`#`, `[`, `"`, `+`). * Never start a name with `<` or `{` as this is treated as an operator. * `>>` is always treated as a right-shift, even when parsing generic arguments (so add a space to avoid this). * Emit function declarations using C/C++ style syntax (e.g., leading return type). * Emit arrays as a synthetic `array$<type, size>` type. * Include a `$` in all synthetic types as this is a legal character for C++, but not Rust (thus we avoid collisions with user types).
2 parents 851c82e + c1601dc commit 2545459

30 files changed

+853
-341
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+22-15
Original file line numberDiff line numberDiff line change
@@ -471,21 +471,28 @@ fn trait_pointer_metadata(
471471
// type is assigned the correct name, size, namespace, and source location.
472472
// However, it does not describe the trait's methods.
473473

474-
let containing_scope = match trait_type.kind() {
475-
ty::Dynamic(ref data, ..) => {
476-
data.principal_def_id().map(|did| get_namespace_for_item(cx, did))
477-
}
478-
_ => {
479-
bug!(
480-
"debuginfo: unexpected trait-object type in \
481-
trait_pointer_metadata(): {:?}",
482-
trait_type
483-
);
484-
}
485-
};
474+
let (containing_scope, trait_type_name) = match trait_object_type {
475+
Some(trait_object_type) => match trait_object_type.kind() {
476+
ty::Adt(def, _) => (
477+
Some(get_namespace_for_item(cx, def.did)),
478+
compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
479+
),
480+
ty::RawPtr(_) | ty::Ref(..) => {
481+
(NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
482+
}
483+
_ => {
484+
bug!(
485+
"debuginfo: unexpected trait-object type in \
486+
trait_pointer_metadata(): {:?}",
487+
trait_object_type
488+
);
489+
}
490+
},
486491

487-
let trait_object_type = trait_object_type.unwrap_or(trait_type);
488-
let trait_type_name = compute_debuginfo_type_name(cx.tcx, trait_object_type, false);
492+
// No object type, use the trait type directly (no scope here since the type
493+
// will be wrapped in the dyn$ synthetic type).
494+
None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
495+
};
489496

490497
let file_metadata = unknown_file_metadata(cx);
491498

@@ -525,7 +532,7 @@ fn trait_pointer_metadata(
525532

526533
composite_type_metadata(
527534
cx,
528-
trait_object_type,
535+
trait_object_type.unwrap_or(trait_type),
529536
&trait_type_name[..],
530537
unique_type_id,
531538
member_descriptions,

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

+9-18
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
55
use self::metadata::{file_metadata, type_metadata, TypeMap};
66
use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
77
use self::namespace::mangled_name_of_instance;
8-
use self::type_names::compute_debuginfo_type_name;
98
use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
109

1110
use crate::abi::FnAbi;
@@ -311,10 +310,10 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
311310
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
312311
};
313312

314-
// Find the enclosing function, in case this is a closure.
315-
let def_key = self.tcx().def_key(def_id);
316-
let mut name = def_key.disambiguated_data.data.to_string();
313+
let mut name = String::new();
314+
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
317315

316+
// Find the enclosing function, in case this is a closure.
318317
let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
319318

320319
// Get_template_parameters() will append a `<...>` clause to the function
@@ -428,24 +427,16 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
428427
substs: SubstsRef<'tcx>,
429428
name_to_append_suffix_to: &mut String,
430429
) -> &'ll DIArray {
430+
type_names::push_generic_params(
431+
cx.tcx,
432+
cx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs),
433+
name_to_append_suffix_to,
434+
);
435+
431436
if substs.types().next().is_none() {
432437
return create_DIArray(DIB(cx), &[]);
433438
}
434439

435-
name_to_append_suffix_to.push('<');
436-
for (i, actual_type) in substs.types().enumerate() {
437-
if i != 0 {
438-
name_to_append_suffix_to.push(',');
439-
}
440-
441-
let actual_type =
442-
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
443-
// Add actual type name to <...> clause of function name
444-
let actual_type_name = compute_debuginfo_type_name(cx.tcx(), actual_type, true);
445-
name_to_append_suffix_to.push_str(&actual_type_name[..]);
446-
}
447-
name_to_append_suffix_to.push('>');
448-
449440
// Again, only create type information if full debuginfo is enabled
450441
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
451442
let names = get_parameter_names(cx, generics);

compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Namespace Handling.
22

33
use super::utils::{debug_context, DIB};
4+
use rustc_codegen_ssa::debuginfo::type_names;
45
use rustc_middle::ty::{self, Instance};
56

67
use crate::common::CodegenCx;
78
use crate::llvm;
89
use crate::llvm::debuginfo::DIScope;
910
use rustc_hir::def_id::DefId;
10-
use rustc_hir::definitions::DefPathData;
1111

1212
pub fn mangled_name_of_instance<'a, 'tcx>(
1313
cx: &CodegenCx<'a, 'tcx>,
@@ -27,25 +27,18 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
2727
.parent
2828
.map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent }));
2929

30-
let crate_name_as_str;
31-
let name_to_string;
32-
let namespace_name = match def_key.disambiguated_data.data {
33-
DefPathData::CrateRoot => {
34-
crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str();
35-
&*crate_name_as_str
36-
}
37-
data => {
38-
name_to_string = data.to_string();
39-
&*name_to_string
40-
}
30+
let namespace_name_string = {
31+
let mut output = String::new();
32+
type_names::push_item_name(cx.tcx, def_id, false, &mut output);
33+
output
4134
};
4235

4336
let scope = unsafe {
4437
llvm::LLVMRustDIBuilderCreateNameSpace(
4538
DIB(cx),
4639
parent_scope,
47-
namespace_name.as_ptr().cast(),
48-
namespace_name.len(),
40+
namespace_name_string.as_ptr().cast(),
41+
namespace_name_string.len(),
4942
false, // ExportSymbols (only relevant for C++ anonymous namespaces)
5043
)
5144
};

0 commit comments

Comments
 (0)