From e6e1e095ffc3cd6f305a2470b1e162680e678014 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Jul 2021 15:50:42 +0200 Subject: [PATCH] [debuginfo] Emit associated type bindings in trait object type names. --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 1 + .../src/debuginfo/type_names.rs | 120 ++++++++++++------ src/test/debuginfo/type-names.rs | 18 ++- 4 files changed, 96 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0aa132fe29ad5..ff0cdb33cbc74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3734,6 +3734,7 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "smallvec", "tempfile", "tracing", ] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 6a6f93d50d364..a11098b11c6eb 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -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" } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 25268d9a5552f..41cbd29ffb354 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -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 } diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index d1f322fa76cca..ebd68b46a2825 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -117,7 +117,11 @@ // gdb-check:type = &mut dyn type_names::Trait2> // gdb-command:whatis no_principal_trait -// gdb-check:type = alloc::boxed::Box +// 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 + core::marker::Send) + // BARE FUNCTIONS // gdb-command:whatis rust_fn @@ -224,7 +228,7 @@ // cdb-check:struct ref$ > ref_trait = [...] // cdb-check:struct ref_mut$ > mut_ref_trait = [...] // cdb-check:struct alloc::boxed::Box, alloc::alloc::Global> no_principal_trait = [...] -// cdb-check:struct ref$ > has_associated_type_trait = struct ref$ > +// cdb-check:struct ref$ >, core::marker::Send> > has_associated_type_trait = struct ref$ >, core::marker::Send> > // BARE FUNCTIONS // cdb-command:dv /t *_fn* @@ -306,14 +310,14 @@ trait Trait1 { trait Trait2 { fn dummy(&self, _: T1, _: T2) {} } -trait Trait3 { +trait Trait3 { type AssocType; - fn dummy(&self) {} + fn dummy(&self) -> T { panic!() } } impl Trait1 for isize {} impl Trait2 for isize {} -impl Trait3 for isize { +impl Trait3 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; - let has_associated_type_trait = &0_isize as &dyn Trait3; + let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>; + let has_associated_type_trait = &0_isize as &(dyn Trait3 + Send); let generic_box_trait = (box 0_isize) as Box>; let generic_ref_trait = (&0_isize) as &dyn Trait2;