1
Fork 0

Auto merge of #87153 - michaelwoerister:debuginfo-names-dyn-trait-projection-bounds, r=wesleywiser

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

This PR updates debuginfo type name generation for trait objects to include associated type bindings and auto trait bounds -- so that, for example, the debuginfo type name of `&dyn Iterator<Item=Foo>` and `&dyn Iterator<Item=Bar>` don't both map to just `&dyn Iterator` anymore.

The following table shows examples of debuginfo type names before and after the PR:
| type | before |  after |
|------|---------|-------|
| `&dyn Iterator<Item=u32>>` | `&dyn Iterator` | `&dyn Iterator<Item=u32>` |
| `&(dyn Iterator<Item=u32>> + Sync)` | `&dyn Iterator` | `&(dyn Iterator<Item=u32> + Sync)` |
| `&(dyn SomeTrait<bool, i8, Bar=u32>> + Send)` | `&dyn SomeTrait<bool, i8>` | `&(dyn SomeTrait<bool, i8, Bar=u32>> + Send)`  |

For targets that need C++-like type names, we use `assoc$<Item,u32>` instead of `Item=u32`:
| type | before |  after |
|------|---------|-------|
| `&dyn Iterator<Item=u32>>` | `ref$<dyn$<Iterator> >` | `ref$<dyn$<Iterator<assoc$<Item,u32> > > >` |
| `&(dyn Iterator<Item=u32>> + Sync)` | `ref$<dyn$<Iterator> >` | `ref$<dyn$<Iterator<assoc$<Item,u32> >,Sync> >` |
| `&(dyn SomeTrait<bool, i8, Bar=u32>> + Send)` | `ref$<dyn$<SomeTrait<bool, i8> > >` | `ref$<dyn$<SomeTrait<bool,i8,assoc$<Bar,u32> > >,Send> >`  |

The PR also adds self-profiling measurements for debuginfo type name generation (re. https://github.com/rust-lang/rust/issues/86431). It looks like the compiler spends up to 0.5% of its time in that task, so the potential for optimizing it via caching seems limited.

However, the perf run also shows [the biggest regression](https://perf.rust-lang.org/detailed-query.html?commit=585e91c718b0b2c5319e1fffd0ff1e62aaf7ccc2&base_commit=b9197978a90be6f7570741eabe2da175fec75375&benchmark=tokio-webpush-simple-debug&run_name=incr-unchanged) in a test case that does not even invoke the code in question. This suggests that the length of the names we generate here can affect performance by influencing how much data the linker has to copy around.

Fixes https://github.com/rust-lang/rust/issues/86134.
This commit is contained in:
bors 2021-07-19 21:25:43 +00:00
commit 014026d1a7
10 changed files with 183 additions and 109 deletions

View file

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

View file

@ -16,6 +16,7 @@ libc = "0.2.50"
jobserver = "0.1.22" jobserver = "0.1.22"
tempfile = "3.2" tempfile = "3.2"
pathdiff = "0.2.0" pathdiff = "0.2.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_serialize = { path = "../rustc_serialize" } rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" } 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::ich::NodeIdHashingMode;
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; 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 rustc_target::abi::{Integer, TagEncoding, Variants};
use smallvec::SmallVec;
use std::fmt::Write; use std::fmt::Write;
@ -33,6 +34,8 @@ pub fn compute_debuginfo_type_name<'tcx>(
t: Ty<'tcx>, t: Ty<'tcx>,
qualified: bool, qualified: bool,
) -> String { ) -> String {
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
let mut result = String::with_capacity(64); let mut result = String::with_capacity(64);
let mut visited = FxHashSet::default(); let mut visited = FxHashSet::default();
push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited); push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
@ -41,7 +44,7 @@ pub fn compute_debuginfo_type_name<'tcx>(
// Pushes the name of the type as it should be stored in debuginfo on the // Pushes the name of the type as it should be stored in debuginfo on the
// `output` String. See also compute_debuginfo_type_name(). // `output` String. See also compute_debuginfo_type_name().
pub fn push_debuginfo_type_name<'tcx>( fn push_debuginfo_type_name<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
t: Ty<'tcx>, t: Ty<'tcx>,
qualified: bool, qualified: bool,
@ -84,25 +87,14 @@ pub fn push_debuginfo_type_name<'tcx>(
for component_type in component_types { for component_type in component_types {
push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
output.push(','); push_arg_separator(cpp_like_names, output);
// Natvis does not always like having spaces between parts of the type name
// and this causes issues when we need to write a typename in natvis, for example
// as part of a cast like the `HashMap` visualizer does.
if !cpp_like_names {
output.push(' ');
}
} }
if !component_types.is_empty() { if !component_types.is_empty() {
output.pop(); pop_arg_separator(output);
if !cpp_like_names {
output.pop();
}
} }
if cpp_like_names { if cpp_like_names {
push_close_angle_bracket(tcx, output); push_close_angle_bracket(cpp_like_names, output);
} else { } else {
output.push(')'); output.push(')');
} }
@ -124,7 +116,7 @@ pub fn push_debuginfo_type_name<'tcx>(
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
if cpp_like_names { if cpp_like_names {
push_close_angle_bracket(tcx, output); push_close_angle_bracket(cpp_like_names, output);
} }
} }
ty::Ref(_, inner_type, mutbl) => { ty::Ref(_, inner_type, mutbl) => {
@ -150,7 +142,7 @@ pub fn push_debuginfo_type_name<'tcx>(
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
if cpp_like_names && !is_slice_or_str { if cpp_like_names && !is_slice_or_str {
push_close_angle_bracket(tcx, output); push_close_angle_bracket(cpp_like_names, output);
} }
} }
ty::Array(inner_type, len) => { ty::Array(inner_type, len) => {
@ -182,69 +174,97 @@ pub fn push_debuginfo_type_name<'tcx>(
push_debuginfo_type_name(tcx, inner_type, true, output, visited); push_debuginfo_type_name(tcx, inner_type, true, output, visited);
if cpp_like_names { if cpp_like_names {
push_close_angle_bracket(tcx, output); push_close_angle_bracket(cpp_like_names, output);
} else { } else {
output.push(']'); output.push(']');
} }
} }
ty::Dynamic(ref trait_data, ..) => { 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$<"); output.push_str("dyn$<");
false
} else {
if trait_data.len() > 1 && auto_traits.len() != 0 {
// We need enclosing parens because there is more than one trait
output.push_str("(dyn ");
true
} else { } else {
output.push_str("dyn "); output.push_str("dyn ");
false
} }
};
if let Some(principal) = trait_data.principal() { if let Some(principal) = trait_data.principal() {
let principal = let principal =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
push_item_name(tcx, principal.def_id, qualified, output); push_item_name(tcx, principal.def_id, qualified, output);
let principal_has_generic_params =
push_generic_params_internal(tcx, principal.substs, output, visited); push_generic_params_internal(tcx, principal.substs, output, visited);
} else {
// The auto traits come ordered by `DefPathHash`, which guarantees stability if the let projection_bounds: SmallVec<[_; 4]> = trait_data
// environment is stable (e.g., incremental builds) but not otherwise (e.g., .projection_bounds()
// updated compiler version, different target). .map(|bound| {
// let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
// To avoid that causing instabilities in test output, sort the auto-traits (item_def_id, ty)
// 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,
}
}) })
.collect(); .collect();
auto_traits.sort();
for name in auto_traits { if projection_bounds.len() != 0 {
output.push_str(&name); if principal_has_generic_params {
// push_generic_params_internal() above added a `>` but we actually
// want to add more items to that list, so remove that again.
pop_close_angle_bracket(output);
}
for (item_def_id, ty) in projection_bounds {
push_arg_separator(cpp_like_names, output);
if cpp_like_names { if cpp_like_names {
output.push_str(", "); output.push_str("assoc$<");
push_item_name(tcx, item_def_id, false, output);
push_arg_separator(cpp_like_names, output);
push_debuginfo_type_name(tcx, ty, true, output, visited);
push_close_angle_bracket(cpp_like_names, output);
} else { } else {
output.push_str(" + "); push_item_name(tcx, item_def_id, false, output);
output.push('=');
push_debuginfo_type_name(tcx, ty, true, output, visited);
} }
} }
// Remove the trailing joining characters. For cpp_like_names push_close_angle_bracket(cpp_like_names, output);
// 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(output);
} }
if cpp_like_names { if cpp_like_names {
push_close_angle_bracket(tcx, output); push_close_angle_bracket(cpp_like_names, output);
} else if has_enclosing_parens {
output.push(')');
} }
} }
ty::FnDef(..) | ty::FnPtr(_) => { ty::FnDef(..) | ty::FnPtr(_) => {
@ -296,10 +316,9 @@ pub fn push_debuginfo_type_name<'tcx>(
if !sig.inputs().is_empty() { if !sig.inputs().is_empty() {
for &parameter_type in sig.inputs() { for &parameter_type in sig.inputs() {
push_debuginfo_type_name(tcx, parameter_type, true, output, visited); push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
output.push_str(", "); push_arg_separator(cpp_like_names, output);
} }
output.pop(); pop_arg_separator(output);
output.pop();
} }
if sig.c_variadic { if sig.c_variadic {
@ -405,7 +424,25 @@ pub fn push_debuginfo_type_name<'tcx>(
output.push_str(&format!(", {}", variant)); output.push_str(&format!(", {}", variant));
} }
} }
push_close_angle_bracket(tcx, output); push_close_angle_bracket(true, output);
}
const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
if cpp_like_names {
push_arg_separator(cpp_like_names, output);
} else {
output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
}
}
fn pop_auto_trait_separator(output: &mut String) {
if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) {
output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len());
} else {
pop_arg_separator(output);
}
} }
} }
@ -466,13 +503,15 @@ fn push_generic_params_internal<'tcx>(
substs: SubstsRef<'tcx>, substs: SubstsRef<'tcx>,
output: &mut String, output: &mut String,
visited: &mut FxHashSet<Ty<'tcx>>, visited: &mut FxHashSet<Ty<'tcx>>,
) { ) -> bool {
if substs.non_erasable_generics().next().is_none() { if substs.non_erasable_generics().next().is_none() {
return; return false;
} }
debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs)); debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
let cpp_like_names = cpp_like_names(tcx);
output.push('<'); output.push('<');
for type_parameter in substs.non_erasable_generics() { for type_parameter in substs.non_erasable_generics() {
@ -486,13 +525,12 @@ fn push_generic_params_internal<'tcx>(
other => bug!("Unexpected non-erasable generic: {:?}", other), other => bug!("Unexpected non-erasable generic: {:?}", other),
} }
output.push_str(", "); push_arg_separator(cpp_like_names, output);
} }
pop_arg_separator(output);
push_close_angle_bracket(cpp_like_names, output);
output.pop(); true
output.pop();
push_close_angle_bracket(tcx, output);
} }
fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) { fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) {
@ -541,20 +579,50 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
} }
pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) { pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) {
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
let mut visited = FxHashSet::default(); let mut visited = FxHashSet::default();
push_generic_params_internal(tcx, substs, output, &mut visited); push_generic_params_internal(tcx, substs, output, &mut visited);
} }
fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) { fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) {
// MSVC debugger always treats `>>` as a shift, even when parsing templates, // MSVC debugger always treats `>>` as a shift, even when parsing templates,
// so add a space to avoid confusion. // so add a space to avoid confusion.
if cpp_like_names(tcx) && output.ends_with('>') { if cpp_like_names && output.ends_with('>') {
output.push(' ') output.push(' ')
}; };
output.push('>'); output.push('>');
} }
fn pop_close_angle_bracket(output: &mut String) {
assert!(output.ends_with('>'), "'output' does not end with '>': {}", output);
output.pop();
if output.ends_with(' ') {
output.pop();
}
}
fn push_arg_separator(cpp_like_names: bool, output: &mut String) {
// Natvis does not always like having spaces between parts of the type name
// and this causes issues when we need to write a typename in natvis, for example
// as part of a cast like the `HashMap` visualizer does.
if cpp_like_names {
output.push(',');
} else {
output.push_str(", ");
};
}
fn pop_arg_separator(output: &mut String) {
if output.ends_with(' ') {
output.pop();
}
assert!(output.ends_with(','));
output.pop();
}
fn cpp_like_names(tcx: TyCtxt<'_>) -> bool { fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
tcx.sess.target.is_like_msvc tcx.sess.target.is_like_msvc
} }

View file

@ -52,21 +52,21 @@
// cdb-command:x a!function_names::*::impl_function* // cdb-command:x a!function_names::*::impl_function*
// cdb-check:[...] a!function_names::Mod1::TestStruct2::impl_function (void) // cdb-check:[...] a!function_names::Mod1::TestStruct2::impl_function (void)
// cdb-check:[...] a!function_names::TestStruct1::impl_function (void) // cdb-check:[...] a!function_names::TestStruct1::impl_function (void)
// cdb-check:[...] a!function_names::GenericStruct<i32, i32>::impl_function<i32, i32> (void) // cdb-check:[...] a!function_names::GenericStruct<i32,i32>::impl_function<i32,i32> (void)
// Trait implementations // Trait implementations
// cdb-command:x a!function_names::*::trait_function* // cdb-command:x a!function_names::*::trait_function*
// cdb-check:[...] a!function_names::impl$3::trait_function<i32> (void) // cdb-check:[...] a!function_names::impl$3::trait_function<i32> (void)
// cdb-check:[...] a!function_names::impl$6::trait_function<i32,1> (void)
// cdb-check:[...] a!function_names::impl$1::trait_function (void) // cdb-check:[...] a!function_names::impl$1::trait_function (void)
// cdb-check:[...] a!function_names::impl$6::trait_function<i32, 1> (void)
// cdb-check:[...] a!function_names::impl$5::trait_function3<function_names::TestStruct1> (void) // cdb-check:[...] a!function_names::impl$5::trait_function3<function_names::TestStruct1> (void)
// cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void) // cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void)
// Closure // Closure
// cdb-command:x a!function_names::*::closure* // cdb-command:x a!function_names::*::closure*
// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0<i32,i32> (void)
// cdb-check:[...] a!function_names::main::closure$0 (void) // cdb-check:[...] a!function_names::main::closure$0 (void)
// cdb-check:[...] a!function_names::generic_func::closure$0<i32> (void) // cdb-check:[...] a!function_names::generic_func::closure$0<i32> (void)
// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0<i32, i32> (void)
// Generator // Generator
// cdb-command:x a!function_names::*::generator* // cdb-command:x a!function_names::*::generator*

View file

@ -44,21 +44,21 @@
// cdb-command:g // cdb-command:g
// cdb-command:dx int_int // cdb-command:dx int_int
// cdb-check:int_int [Type: generic_struct::AGenericStruct<i32, i32>] // cdb-check:int_int [Type: generic_struct::AGenericStruct<i32,i32>]
// cdb-check:[...]key : 0 [Type: int] // cdb-check:[...]key : 0 [Type: int]
// cdb-check:[...]value : 1 [Type: int] // cdb-check:[...]value : 1 [Type: int]
// cdb-command:dx int_float // cdb-command:dx int_float
// cdb-check:int_float [Type: generic_struct::AGenericStruct<i32, f64>] // cdb-check:int_float [Type: generic_struct::AGenericStruct<i32,f64>]
// cdb-check:[...]key : 2 [Type: int] // cdb-check:[...]key : 2 [Type: int]
// cdb-check:[...]value : 3.500000 [Type: double] // cdb-check:[...]value : 3.500000 [Type: double]
// cdb-command:dx float_int // cdb-command:dx float_int
// cdb-check:float_int [Type: generic_struct::AGenericStruct<f64, i32>] // cdb-check:float_int [Type: generic_struct::AGenericStruct<f64,i32>]
// cdb-check:[...]key : 4.500000 [Type: double] // cdb-check:[...]key : 4.500000 [Type: double]
// cdb-check:[...]value : 5 [Type: int] // cdb-check:[...]value : 5 [Type: int]
// cdb-command:dx float_int_float // cdb-command:dx float_int_float
// cdb-check:float_int_float [Type: generic_struct::AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64> >] // cdb-check:float_int_float [Type: generic_struct::AGenericStruct<f64,generic_struct::AGenericStruct<i32,f64> >]
// cdb-check:[...]key : 6.500000 [Type: double] // cdb-check:[...]key : 6.500000 [Type: double]
// cdb-check:[...]value [Type: generic_struct::AGenericStruct<i32, f64>] // cdb-check:[...]value [Type: generic_struct::AGenericStruct<i32,f64>]
#![feature(omit_gdb_pretty_printer_section)] #![feature(omit_gdb_pretty_printer_section)]

View file

@ -87,8 +87,8 @@
// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$] // cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
// cdb-command: dx -r2 l,! // cdb-command: dx -r2 l,!
// cdb-check:l,! : $T2 [Type: enum$<core::result::Result<u32, enum$<msvc_pretty_enums::Empty> >, Ok>] // cdb-check:l,! : $T2 [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
// cdb-check: [+0x000] Ok [Type: enum$<core::result::Result<u32, enum$<msvc_pretty_enums::Empty> >, Ok>::Ok] // cdb-check: [+0x000] Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>::Ok]
// cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int]
pub enum CStyleEnum { pub enum CStyleEnum {

View file

@ -10,7 +10,7 @@
// cdb-command: g // cdb-command: g
// cdb-command: dx hash_set,d // cdb-command: dx hash_set,d
// cdb-check:hash_set,d [...] : { len=15 } [Type: [...]::HashSet<u64, [...]>] // cdb-check:hash_set,d [...] : { len=15 } [Type: [...]::HashSet<u64,[...]>]
// cdb-check: [len] : 15 [Type: [...]] // cdb-check: [len] : 15 [Type: [...]]
// cdb-check: [capacity] : [...] // cdb-check: [capacity] : [...]
// cdb-check: [[...]] [...] : 0 [Type: u64] // cdb-check: [[...]] [...] : 0 [Type: u64]
@ -44,7 +44,7 @@
// cdb-check: [[...]] [...] : 14 [Type: u64] // cdb-check: [[...]] [...] : 14 [Type: u64]
// cdb-command: dx hash_map,d // cdb-command: dx hash_map,d
// cdb-check:hash_map,d [...] : { len=15 } [Type: [...]::HashMap<u64, u64, [...]>] // cdb-check:hash_map,d [...] : { len=15 } [Type: [...]::HashMap<u64,u64,[...]>]
// cdb-check: [len] : 15 [Type: [...]] // cdb-check: [len] : 15 [Type: [...]]
// cdb-check: [capacity] : [...] // cdb-check: [capacity] : [...]
// cdb-check: ["0x0"] : 0 [Type: unsigned __int64] // cdb-check: ["0x0"] : 0 [Type: unsigned __int64]

View file

@ -79,7 +79,7 @@
// cdb-check: [3] : 3 [Type: int] // cdb-check: [3] : 3 [Type: int]
// cdb-command: dx vec,d // cdb-command: dx vec,d
// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>] // cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64,alloc::alloc::Global>]
// cdb-check: [len] : 4 [Type: [...]] // cdb-check: [len] : 4 [Type: [...]]
// cdb-check: [capacity] : [...] [Type: [...]] // cdb-check: [capacity] : [...] [Type: [...]]
// cdb-check: [0] : 4 [Type: unsigned __int64] // cdb-check: [0] : 4 [Type: unsigned __int64]

View file

@ -7,11 +7,11 @@
// cdb-command: g // cdb-command: g
// cdb-command: dx x,d // cdb-command: dx x,d
// cdb-check:x,d : Ok [Type: enum$<core::result::Result<i32, str> >] // cdb-check:x,d : Ok [Type: enum$<core::result::Result<i32,str> >]
// cdb-check: [...] __0 : -3 [Type: int] // cdb-check: [...] __0 : -3 [Type: int]
// cdb-command: dx y // cdb-command: dx y
// cdb-check:y : Err [Type: enum$<core::result::Result<i32, str> >] // cdb-check:y : Err [Type: enum$<core::result::Result<i32,str> >]
// cdb-check: [...] __0 : "Some error message" [Type: str] // cdb-check: [...] __0 : "Some error message" [Type: str]
fn main() fn main()

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-check:type = &mut dyn type_names::Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
// gdb-command:whatis no_principal_trait // 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 // BARE FUNCTIONS
// gdb-command:whatis rust_fn // gdb-command:whatis rust_fn
@ -169,7 +173,7 @@
// 0-sized structs appear to be optimized away in some cases, so only check the structs that do // 0-sized structs appear to be optimized away in some cases, so only check the structs that do
// actually appear. // actually appear.
// cdb-command:dv /t *_struct // cdb-command:dv /t *_struct
// cdb-check:struct type_names::GenericStruct<enum$<type_names::mod1::Enum2>, f64> mut_generic_struct = [...] // cdb-check:struct type_names::GenericStruct<enum$<type_names::mod1::Enum2>,f64> mut_generic_struct = [...]
// ENUMS // ENUMS
// cdb-command:dv /t *_enum_* // cdb-command:dv /t *_enum_*
@ -186,15 +190,15 @@
// BOX // BOX
// cdb-command:dv /t box* // cdb-command:dv /t box*
// cdb-check:struct tuple$<alloc::boxed::Box<f32, alloc::alloc::Global>,i32> box1 = [...] // cdb-check:struct tuple$<alloc::boxed::Box<f32,alloc::alloc::Global>,i32> box1 = [...]
// cdb-check:struct tuple$<alloc::boxed::Box<enum$<type_names::mod1::mod2::Enum3<f32> >, alloc::alloc::Global>,i32> box2 = [...] // cdb-check:struct tuple$<alloc::boxed::Box<enum$<type_names::mod1::mod2::Enum3<f32> >,alloc::alloc::Global>,i32> box2 = [...]
// REFERENCES // REFERENCES
// cdb-command:dv /t *ref* // cdb-command:dv /t *ref*
// cdb-check:struct tuple$<ref$<type_names::Struct1>,i32> ref1 = [...] // cdb-check:struct tuple$<ref$<type_names::Struct1>,i32> ref1 = [...]
// cdb-check:struct tuple$<ref$<type_names::GenericStruct<char, type_names::Struct1> >,i32> ref2 = [...] // cdb-check:struct tuple$<ref$<type_names::GenericStruct<char,type_names::Struct1> >,i32> ref2 = [...]
// cdb-check:struct tuple$<ref_mut$<type_names::Struct1>,i32> mut_ref1 = [...] // cdb-check:struct tuple$<ref_mut$<type_names::Struct1>,i32> mut_ref1 = [...]
// cdb-check:struct tuple$<ref_mut$<type_names::GenericStruct<enum$<type_names::mod1::Enum2>, f64> >,i32> mut_ref2 = [...] // cdb-check:struct tuple$<ref_mut$<type_names::GenericStruct<enum$<type_names::mod1::Enum2>,f64> >,i32> mut_ref2 = [...]
// RAW POINTERS // RAW POINTERS
// cdb-command:dv /t *_ptr* // cdb-command:dv /t *_ptr*
@ -209,31 +213,31 @@
// cdb-command:dv /t *vec* // cdb-command:dv /t *vec*
// cdb-check:struct tuple$<array$<type_names::Struct1,3>,i16> fixed_size_vec1 = [...] // cdb-check:struct tuple$<array$<type_names::Struct1,3>,i16> fixed_size_vec1 = [...]
// cdb-check:struct tuple$<array$<usize,3>,i16> fixed_size_vec2 = [...] // cdb-check:struct tuple$<array$<usize,3>,i16> fixed_size_vec2 = [...]
// cdb-check:struct alloc::vec::Vec<usize, alloc::alloc::Global> vec1 = [...] // cdb-check:struct alloc::vec::Vec<usize,alloc::alloc::Global> vec1 = [...]
// cdb-check:struct alloc::vec::Vec<enum$<type_names::mod1::Enum2>, alloc::alloc::Global> vec2 = [...] // cdb-check:struct alloc::vec::Vec<enum$<type_names::mod1::Enum2>,alloc::alloc::Global> vec2 = [...]
// cdb-command:dv /t slice* // cdb-command:dv /t slice*
// cdb-check:struct slice$<usize> slice1 = [...] // cdb-check:struct slice$<usize> slice1 = [...]
// cdb-check:struct slice$<enum$<type_names::mod1::Enum2> > slice2 = [...] // cdb-check:struct slice$<enum$<type_names::mod1::Enum2> > slice2 = [...]
// TRAITS // TRAITS
// cdb-command:dv /t *_trait // cdb-command:dv /t *_trait
// cdb-check:struct ref_mut$<dyn$<type_names::Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize> > > > generic_mut_ref_trait = [...] // cdb-check:struct ref_mut$<dyn$<type_names::Trait2<type_names::mod1::mod2::Struct3,type_names::GenericStruct<usize,isize> > > > generic_mut_ref_trait = [...]
// cdb-check:struct ref$<dyn$<type_names::Trait2<type_names::Struct1, type_names::Struct1> > > generic_ref_trait = [...] // cdb-check:struct ref$<dyn$<type_names::Trait2<type_names::Struct1,type_names::Struct1> > > generic_ref_trait = [...]
// cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait2<i32, type_names::mod1::Struct2> >, alloc::alloc::Global> generic_box_trait = [...] // cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait2<i32,type_names::mod1::Struct2> >,alloc::alloc::Global> generic_box_trait = [...]
// cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait1>, alloc::alloc::Global> box_trait = [...] // cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait1>,alloc::alloc::Global> box_trait = [...]
// cdb-check:struct ref$<dyn$<type_names::Trait1> > ref_trait = [...] // 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 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 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 // BARE FUNCTIONS
// cdb-command:dv /t *_fn* // cdb-command:dv /t *_fn*
// cdb-check:struct tuple$<type_names::mod1::Struct2 (*)(type_names::GenericStruct<u16, u8>),usize> unsafe_fn_with_return_value = [...] // cdb-check:struct tuple$<type_names::mod1::Struct2 (*)(type_names::GenericStruct<u16,u8>),usize> unsafe_fn_with_return_value = [...]
// cdb-check:struct tuple$<type_names::Struct1 (*)(),usize> extern_c_fn_with_return_value = [...] // cdb-check:struct tuple$<type_names::Struct1 (*)(),usize> extern_c_fn_with_return_value = [...]
// cdb-check:struct tuple$<usize (*)(f64),usize> rust_fn_with_return_value = [...] // cdb-check:struct tuple$<usize (*)(f64),usize> rust_fn_with_return_value = [...]
// cdb-check:struct tuple$<void (*)(enum$<core::result::Result<char, f64> >),usize> unsafe_fn = [...] // cdb-check:struct tuple$<void (*)(enum$<core::result::Result<char,f64> >),usize> unsafe_fn = [...]
// cdb-check:struct tuple$<void (*)(isize),usize> extern_c_fn = [...] // cdb-check:struct tuple$<void (*)(isize),usize> extern_c_fn = [...]
// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >, enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>),usize> rust_fn = [...] // cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>),usize> rust_fn = [...]
// cdb-command:dv /t *_function* // cdb-command:dv /t *_function*
// cdb-check:struct tuple$<isize (*)(ptr_const$<u8>, ...),usize> variadic_function = [...] // cdb-check:struct tuple$<isize (*)(ptr_const$<u8>, ...),usize> variadic_function = [...]
// cdb-check:struct tuple$<type_names::mod1::mod2::Struct3 (*)(type_names::mod1::mod2::Struct3),usize> generic_function_struct3 = [...] // cdb-check:struct tuple$<type_names::mod1::mod2::Struct3 (*)(type_names::mod1::mod2::Struct3),usize> generic_function_struct3 = [...]
@ -306,14 +310,14 @@ trait Trait1 {
trait Trait2<T1, T2> { trait Trait2<T1, T2> {
fn dummy(&self, _: T1, _: T2) {} fn dummy(&self, _: T1, _: T2) {}
} }
trait Trait3 { trait Trait3<T> {
type AssocType; type AssocType;
fn dummy(&self) {} fn dummy(&self) -> T { panic!() }
} }
impl Trait1 for isize {} impl Trait1 for isize {}
impl<T1, T2> Trait2<T1, T2> for isize {} impl<T1, T2> Trait2<T1, T2> for isize {}
impl Trait3 for isize { impl<T> Trait3<T> for isize {
type AssocType = isize; type AssocType = isize;
} }
@ -404,8 +408,8 @@ fn main() {
let ref_trait = &0_isize as &dyn Trait1; let ref_trait = &0_isize as &dyn Trait1;
let mut mut_int1 = 0_isize; let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1; let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1;
let no_principal_trait = (box 0_isize) as Box<dyn Send + Sync>; 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 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_box_trait = (box 0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>; let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>;