From 28343be42fc699c080968c76061fc2da781b30b9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Jul 2021 15:12:49 +0200 Subject: [PATCH] Handle non-integer const generic parameters in debuginfo type names. --- .../src/debuginfo/type_names.rs | 81 ++++++++++++++----- src/test/debuginfo/function-names.rs | 30 ++++++- 2 files changed, 91 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index b3c14d9072cce..25268d9a5552f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -12,12 +12,15 @@ // * `"` is treated as the start of a string. use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_middle::ich::NodeIdHashingMode; +use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; -use rustc_target::abi::{TagEncoding, Variants}; +use rustc_target::abi::{Integer, TagEncoding, Variants}; use std::fmt::Write; @@ -47,7 +50,7 @@ pub fn push_debuginfo_type_name<'tcx>( ) { // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = tcx.sess.target.is_like_msvc; + let cpp_like_names = cpp_like_names(tcx); match *t.kind() { ty::Bool => output.push_str("bool"), @@ -424,8 +427,6 @@ fn push_unqualified_item_name( disambiguated_data: DisambiguatedDefPathData, output: &mut String, ) { - let cpp_like_names = tcx.sess.target.is_like_msvc; - match disambiguated_data.data { DefPathData::CrateRoot => { output.push_str(&tcx.crate_name(def_id.krate).as_str()); @@ -433,7 +434,7 @@ fn push_unqualified_item_name( DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => { // Generators look like closures, but we want to treat them differently // in the debug info. - if cpp_like_names { + if cpp_like_names(tcx) { write!(output, "generator${}", disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap(); @@ -444,7 +445,7 @@ fn push_unqualified_item_name( output.push_str(&name.as_str()); } DefPathDataName::Anon { namespace } => { - if cpp_like_names { + if cpp_like_names(tcx) { write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator) @@ -478,19 +479,14 @@ fn push_generic_params_internal<'tcx>( match type_parameter { GenericArgKind::Type(type_parameter) => { push_debuginfo_type_name(tcx, type_parameter, true, output, visited); - output.push_str(", "); - } - GenericArgKind::Const(const_parameter) => match const_parameter.val { - ty::ConstKind::Param(param) => write!(output, "{}, ", param.name).unwrap(), - _ => write!( - output, - "0x{:x}, ", - const_parameter.eval_bits(tcx, ty::ParamEnv::reveal_all(), const_parameter.ty) - ) - .unwrap(), - }, + } + GenericArgKind::Const(ct) => { + push_const_param(tcx, ct, output); + } other => bug!("Unexpected non-erasable generic: {:?}", other), } + + output.push_str(", "); } output.pop(); @@ -499,6 +495,51 @@ fn push_generic_params_internal<'tcx>( push_close_angle_bracket(tcx, output); } +fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) { + match ct.val { + ty::ConstKind::Param(param) => { + write!(output, "{}", param.name) + } + _ => match ct.ty.kind() { + ty::Int(ity) => { + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty); + let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; + write!(output, "{}", val) + } + ty::Uint(_) => { + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty); + write!(output, "{}", val) + } + ty::Bool => { + let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); + write!(output, "{}", val) + } + _ => { + // If we cannot evaluate the constant to a known type, we fall back + // to emitting a stable hash value of the constant. This isn't very pretty + // but we get a deterministic, virtually unique value for the constant. + let hcx = &mut tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ct.val.hash_stable(hcx, &mut hasher); + }); + }); + // Let's only emit 64 bits of the hash value. That should be plenty for + // avoiding collisions and will make the emitted type names shorter. + let hash: u64 = hasher.finish(); + + if cpp_like_names(tcx) { + write!(output, "CONST${:x}", hash) + } else { + write!(output, "{{CONST#{:x}}}", hash) + } + } + }, + } + .unwrap(); +} + pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) { let mut visited = FxHashSet::default(); 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 fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) { // MSVC debugger always treats `>>` as a shift, even when parsing templates, // so add a space to avoid confusion. - if tcx.sess.target.is_like_msvc && output.ends_with('>') { + if cpp_like_names(tcx) && output.ends_with('>') { output.push(' ') }; output.push('>'); } + +fn cpp_like_names(tcx: TyCtxt<'_>) -> bool { + tcx.sess.target.is_like_msvc +} diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs index 26317f5c3ff32..20a49f0bd26eb 100644 --- a/src/test/debuginfo/function-names.rs +++ b/src/test/debuginfo/function-names.rs @@ -33,6 +33,13 @@ // Generator // Generators don't seem to appear in GDB's symbol table. +// Const generic parameter +// gdb-command:info functions -q function_names::const_generic_fn.* +// gdb-check:[...]static fn function_names::const_generic_fn_bool(); +// gdb-check:[...]static fn function_names::const_generic_fn_non_int(); +// gdb-check:[...]static fn function_names::const_generic_fn_signed_int(); +// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int(); + // === CDB TESTS =================================================================================== // Top-level function @@ -49,9 +56,9 @@ // Trait implementations // cdb-command:x a!function_names::*::trait_function* -// cdb-check:[...] a!function_names::impl$6::trait_function (void) // cdb-check:[...] a!function_names::impl$3::trait_function (void) // cdb-check:[...] a!function_names::impl$1::trait_function (void) +// cdb-check:[...] a!function_names::impl$6::trait_function (void) // cdb-check:[...] a!function_names::impl$5::trait_function3 (void) // cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void) @@ -65,10 +72,18 @@ // cdb-command:x a!function_names::*::generator* // cdb-check:[...] a!function_names::main::generator$1 (void) +// Const generic parameter +// cdb-command:x a!function_names::const_generic_fn* +// cdb-check:[...] a!function_names::const_generic_fn_bool (void) +// cdb-check:[...] a!function_names::const_generic_fn_non_int (void) +// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void) +// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void) + #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] -#![feature(generators, generator_trait)] +#![feature(const_generics, generators, generator_trait)] +#![allow(incomplete_features)] // for const_generics use Mod1::TestTrait2; use std::ops::Generator; @@ -97,6 +112,12 @@ fn main() { // Generator let mut generator = || { yield; return; }; Pin::new(&mut generator).resume(()); + + // Const generic functions + const_generic_fn_bool::(); + const_generic_fn_non_int::<{()}>(); + const_generic_fn_signed_int::<-7>(); + const_generic_fn_unsigned_int::<14>(); } struct TestStruct1; @@ -173,3 +194,8 @@ fn generic_func(value: T) -> T { value } + +fn const_generic_fn_bool() {} +fn const_generic_fn_non_int() {} +fn const_generic_fn_signed_int() {} +fn const_generic_fn_unsigned_int() {}