[debuginfo] Emit associated type bindings in trait object type names.

This commit is contained in:
Michael Woerister 2021-07-14 15:50:42 +02:00
parent b9197978a9
commit e6e1e095ff
4 changed files with 96 additions and 44 deletions

View File

@ -3734,6 +3734,7 @@ dependencies = [
"rustc_span",
"rustc_symbol_mangling",
"rustc_target",
"smallvec",
"tempfile",
"tracing",
]

View File

@ -16,6 +16,7 @@ libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
pathdiff = "0.2.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }

View File

@ -19,8 +19,9 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
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_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use smallvec::SmallVec;
use std::fmt::Write;
@ -188,63 +189,86 @@ pub fn push_debuginfo_type_name<'tcx>(
}
}
ty::Dynamic(ref trait_data, ..) => {
if cpp_like_names {
let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
let has_enclosing_parens = if cpp_like_names {
output.push_str("dyn$<");
false
} else {
output.push_str("dyn ");
}
if trait_data.len() > 1 && auto_traits.len() != 0 {
// We need enclosing parens
output.push_str("(dyn ");
true
} else {
output.push_str("dyn ");
false
}
};
if let Some(principal) = trait_data.principal() {
let principal =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
push_item_name(tcx, principal.def_id, qualified, output);
push_generic_params_internal(tcx, principal.substs, output, visited);
} else {
// The auto traits come ordered by `DefPathHash`, which guarantees stability if the
// environment is stable (e.g., incremental builds) but not otherwise (e.g.,
// updated compiler version, different target).
//
// To avoid that causing instabilities in test output, sort the auto-traits
// alphabetically.
let mut auto_traits: Vec<_> = trait_data
.iter()
.filter_map(|predicate| {
match tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
predicate,
) {
ty::ExistentialPredicate::AutoTrait(def_id) => {
let mut name = String::new();
push_item_name(tcx, def_id, true, &mut name);
Some(name)
}
_ => None,
}
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
(item_def_id, ty)
})
.collect();
auto_traits.sort();
for name in auto_traits {
output.push_str(&name);
if projection_bounds.len() != 0 {
pop_close_angle_bracket(output);
if cpp_like_names {
for (item_def_id, ty) in projection_bounds {
output.push_str(", ");
} else {
output.push_str(" + ");
if cpp_like_names {
output.push_str("assoc$<");
push_item_name(tcx, item_def_id, false, output);
output.push_str(", ");
push_debuginfo_type_name(tcx, ty, true, output, visited);
push_close_angle_bracket(tcx, output);
} else {
push_item_name(tcx, item_def_id, false, output);
output.push('=');
push_debuginfo_type_name(tcx, ty, true, output, visited);
}
}
push_close_angle_bracket(tcx, output);
}
// Remove the trailing joining characters. For cpp_like_names
// this is `, ` otherwise ` + `.
output.pop();
output.pop();
if !cpp_like_names {
output.pop();
if auto_traits.len() != 0 {
push_auto_trait_separator(cpp_like_names, output);
}
}
if auto_traits.len() != 0 {
let mut auto_traits: SmallVec<[String; 4]> = auto_traits
.into_iter()
.map(|def_id| {
let mut name = String::with_capacity(20);
push_item_name(tcx, def_id, true, &mut name);
name
})
.collect();
auto_traits.sort_unstable();
for auto_trait in auto_traits {
output.push_str(&auto_trait);
push_auto_trait_separator(cpp_like_names, output);
}
pop_auto_trait_separator(cpp_like_names, output);
}
if cpp_like_names {
push_close_angle_bracket(tcx, output);
} else if has_enclosing_parens {
output.push(')');
}
}
ty::FnDef(..) | ty::FnPtr(_) => {
@ -407,6 +431,20 @@ pub fn push_debuginfo_type_name<'tcx>(
}
push_close_angle_bracket(tcx, output);
}
fn auto_trait_separator(cpp_like_names: bool) -> &'static str {
if cpp_like_names { ", " } else { " + " }
}
fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
output.push_str(auto_trait_separator(cpp_like_names));
}
fn pop_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
let sep = auto_trait_separator(cpp_like_names);
assert!(output.ends_with(sep));
output.truncate(output.len() - sep.len());
}
}
pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
@ -555,6 +593,14 @@ fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) {
output.push('>');
}
fn pop_close_angle_bracket(output: &mut String) {
assert!(output.ends_with('>'));
output.pop();
if output.ends_with(' ') {
output.pop();
}
}
fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
tcx.sess.target.is_like_msvc
}

View File

@ -117,7 +117,11 @@
// gdb-check:type = &mut dyn type_names::Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
// gdb-command:whatis no_principal_trait
// gdb-check:type = alloc::boxed::Box<dyn core::marker::Send + core::marker::Sync, alloc::alloc::Global>
// gdb-check:type = alloc::boxed::Box<(dyn core::marker::Send + core::marker::Sync), alloc::alloc::Global>
// gdb-command:whatis has_associated_type_trait
// gdb-check:type = &(dyn type_names::Trait3<u32, AssocType=isize> + core::marker::Send)
// BARE FUNCTIONS
// gdb-command:whatis rust_fn
@ -224,7 +228,7 @@
// cdb-check:struct ref$<dyn$<type_names::Trait1> > ref_trait = [...]
// cdb-check:struct ref_mut$<dyn$<type_names::Trait1> > mut_ref_trait = [...]
// cdb-check:struct alloc::boxed::Box<dyn$<core::marker::Send, core::marker::Sync>, alloc::alloc::Global> no_principal_trait = [...]
// cdb-check:struct ref$<dyn$<type_names::Trait3> > has_associated_type_trait = struct ref$<dyn$<type_names::Trait3> >
// cdb-check:struct ref$<dyn$<type_names::Trait3<u32, assoc$<AssocType, isize> >, core::marker::Send> > has_associated_type_trait = struct ref$<dyn$<type_names::Trait3<u32, assoc$<AssocType, isize> >, core::marker::Send> >
// BARE FUNCTIONS
// cdb-command:dv /t *_fn*
@ -306,14 +310,14 @@ trait Trait1 {
trait Trait2<T1, T2> {
fn dummy(&self, _: T1, _: T2) {}
}
trait Trait3 {
trait Trait3<T> {
type AssocType;
fn dummy(&self) {}
fn dummy(&self) -> T { panic!() }
}
impl Trait1 for isize {}
impl<T1, T2> Trait2<T1, T2> for isize {}
impl Trait3 for isize {
impl<T> Trait3<T> for isize {
type AssocType = isize;
}
@ -404,8 +408,8 @@ fn main() {
let ref_trait = &0_isize as &dyn Trait1;
let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1;
let no_principal_trait = (box 0_isize) as Box<dyn Send + Sync>;
let has_associated_type_trait = &0_isize as &dyn Trait3<AssocType = isize>;
let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>;
let has_associated_type_trait = &0_isize as &(dyn Trait3<u32, AssocType = isize> + Send);
let generic_box_trait = (box 0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>;