Skip to content

Commit da56618

Browse files
Handle non-integer const generic parameters in debuginfo type names.
1 parent 95fb131 commit da56618

File tree

2 files changed

+90
-19
lines changed

2 files changed

+90
-19
lines changed

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+63-18
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@
1212
// * `"` is treated as the start of a string.
1313

1414
use rustc_data_structures::fx::FxHashSet;
15+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1516
use rustc_hir as hir;
1617
use rustc_hir::def_id::DefId;
1718
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
19+
use rustc_middle::ich::NodeIdHashingMode;
20+
use rustc_middle::ty::layout::IntegerExt;
1821
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
1922
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
20-
use rustc_target::abi::{TagEncoding, Variants};
23+
use rustc_target::abi::{Integer, TagEncoding, Variants};
2124

2225
use std::fmt::Write;
2326

@@ -47,7 +50,7 @@ pub fn push_debuginfo_type_name<'tcx>(
4750
) {
4851
// When targeting MSVC, emit C++ style type names for compatibility with
4952
// .natvis visualizers (and perhaps other existing native debuggers?)
50-
let cpp_like_names = tcx.sess.target.is_like_msvc;
53+
let cpp_like_names = cpp_like_names(tcx);
5154

5255
match *t.kind() {
5356
ty::Bool => output.push_str("bool"),
@@ -424,16 +427,14 @@ fn push_unqualified_item_name(
424427
disambiguated_data: DisambiguatedDefPathData,
425428
output: &mut String,
426429
) {
427-
let cpp_like_names = tcx.sess.target.is_like_msvc;
428-
429430
match disambiguated_data.data {
430431
DefPathData::CrateRoot => {
431432
output.push_str(&tcx.crate_name(def_id.krate).as_str());
432433
}
433434
DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
434435
// Generators look like closures, but we want to treat them differently
435436
// in the debug info.
436-
if cpp_like_names {
437+
if cpp_like_names(tcx) {
437438
write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
438439
} else {
439440
write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
@@ -444,7 +445,7 @@ fn push_unqualified_item_name(
444445
output.push_str(&name.as_str());
445446
}
446447
DefPathDataName::Anon { namespace } => {
447-
if cpp_like_names {
448+
if cpp_like_names(tcx) {
448449
write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
449450
} else {
450451
write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
@@ -478,19 +479,14 @@ fn push_generic_params_internal<'tcx>(
478479
match type_parameter {
479480
GenericArgKind::Type(type_parameter) => {
480481
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
481-
output.push_str(", ");
482-
}
483-
GenericArgKind::Const(const_parameter) => match const_parameter.val {
484-
ty::ConstKind::Param(param) => write!(output, "{}, ", param.name).unwrap(),
485-
_ => write!(
486-
output,
487-
"0x{:x}, ",
488-
const_parameter.eval_bits(tcx, ty::ParamEnv::reveal_all(), const_parameter.ty)
489-
)
490-
.unwrap(),
491-
},
482+
}
483+
GenericArgKind::Const(ct) => {
484+
push_const_param(tcx, ct, output);
485+
}
492486
other => bug!("Unexpected non-erasable generic: {:?}", other),
493487
}
488+
489+
output.push_str(", ");
494490
}
495491

496492
output.pop();
@@ -499,6 +495,51 @@ fn push_generic_params_internal<'tcx>(
499495
push_close_angle_bracket(tcx, output);
500496
}
501497

498+
fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) {
499+
match ct.val {
500+
ty::ConstKind::Param(param) => {
501+
write!(output, "{}", param.name)
502+
}
503+
_ => match ct.ty.kind() {
504+
ty::Int(ity) => {
505+
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
506+
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
507+
write!(output, "{}", val)
508+
}
509+
ty::Uint(_) => {
510+
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
511+
write!(output, "{}", val)
512+
}
513+
ty::Bool => {
514+
let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
515+
write!(output, "{}", val)
516+
}
517+
_ => {
518+
// If we cannot evaluate the constant to a known type, we fall back
519+
// to emitting a stable hash value of the constant. This isn't very pretty
520+
// but we get a deterministic, virtually unique value for the constant.
521+
let hcx = &mut tcx.create_stable_hashing_context();
522+
let mut hasher = StableHasher::new();
523+
hcx.while_hashing_spans(false, |hcx| {
524+
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
525+
ct.val.hash_stable(hcx, &mut hasher);
526+
});
527+
});
528+
// Let's only emit 64 bits of the hash value. That should be plenty for
529+
// avoiding collisions and will make the emitted type names shorter.
530+
let hash: u64 = hasher.finish();
531+
532+
if cpp_like_names(tcx) {
533+
write!(output, "CONST${:x}", hash)
534+
} else {
535+
write!(output, "{{CONST#{:x}}}", hash)
536+
}
537+
}
538+
},
539+
}
540+
.unwrap();
541+
}
542+
502543
pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) {
503544
let mut visited = FxHashSet::default();
504545
push_generic_params_internal(tcx, substs, output, &mut visited);
@@ -507,9 +548,13 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out
507548
fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) {
508549
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
509550
// so add a space to avoid confusion.
510-
if tcx.sess.target.is_like_msvc && output.ends_with('>') {
551+
if cpp_like_names(tcx) && output.ends_with('>') {
511552
output.push(' ')
512553
};
513554

514555
output.push('>');
515556
}
557+
558+
fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
559+
tcx.sess.target.is_like_msvc
560+
}

src/test/debuginfo/function-names.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333
// Generator
3434
// Generators don't seem to appear in GDB's symbol table.
3535

36+
// Const generic parameter
37+
// gdb-command:info functions -q function_names::const_generic_fn.*
38+
// gdb-check:[...]static fn function_names::const_generic_fn_bool();
39+
// gdb-check:[...]static fn function_names::const_generic_fn_non_int();
40+
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int();
41+
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int();
42+
3643
// === CDB TESTS ===================================================================================
3744

3845
// Top-level function
@@ -65,10 +72,18 @@
6572
// cdb-command:x a!function_names::*::generator*
6673
// cdb-check:[...] a!function_names::main::generator$1 (void)
6774

75+
// Const generic parameter
76+
// cdb-command:x a!function_names::const_generic_fn*
77+
// cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
78+
// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
79+
// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
80+
// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
81+
6882
#![allow(unused_variables)]
6983
#![feature(omit_gdb_pretty_printer_section)]
7084
#![omit_gdb_pretty_printer_section]
71-
#![feature(generators, generator_trait)]
85+
#![feature(const_generics, generators, generator_trait)]
86+
#![allow(incomplete_features)] // for const_generics
7287

7388
use Mod1::TestTrait2;
7489
use std::ops::Generator;
@@ -97,6 +112,12 @@ fn main() {
97112
// Generator
98113
let mut generator = || { yield; return; };
99114
Pin::new(&mut generator).resume(());
115+
116+
// Const generic functions
117+
const_generic_fn_bool::<false>();
118+
const_generic_fn_non_int::<{()}>();
119+
const_generic_fn_signed_int::<-7>();
120+
const_generic_fn_unsigned_int::<14>();
100121
}
101122

102123
struct TestStruct1;
@@ -173,3 +194,8 @@ fn generic_func<T>(value: T) -> T {
173194

174195
value
175196
}
197+
198+
fn const_generic_fn_bool<const C: bool>() {}
199+
fn const_generic_fn_non_int<const C: ()>() {}
200+
fn const_generic_fn_signed_int<const C: i64>() {}
201+
fn const_generic_fn_unsigned_int<const C: u32>() {}

0 commit comments

Comments
 (0)