]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_codegen_ssa / src / debuginfo / type_names.rs
CommitLineData
d9579d0f
AL
1// Type Names for Debug Info.
2
5e7ed085 3// Notes on targeting MSVC:
136023e0
XL
4// In general, MSVC's debugger attempts to parse all arguments as C++ expressions,
5// even if the argument is explicitly a symbol name.
6// As such, there are many things that cause parsing issues:
7// * `#` is treated as a special character for macros.
8// * `{` or `<` at the beginning of a name is treated as an operator.
9// * `>>` is always treated as a right-shift.
10// * `[` in a name is treated like a regex bracket expression (match any char
11// within the brackets).
12// * `"` is treated as the start of a string.
13
532ac7d7 14use rustc_data_structures::fx::FxHashSet;
136023e0 15use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
dfeec247 16use rustc_hir::def_id::DefId;
136023e0 17use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
5099ac24 18use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
5e7ed085 19use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
136023e0 20use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
5e7ed085 21use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
136023e0
XL
22use rustc_target::abi::{Integer, TagEncoding, Variants};
23use smallvec::SmallVec;
d9579d0f 24
5e7ed085 25use std::borrow::Cow;
1b1a35ee
XL
26use std::fmt::Write;
27
5e7ed085
FG
28use crate::debuginfo::wants_c_like_enum_debuginfo;
29
d9579d0f 30// Compute the name of the type as it should be stored in debuginfo. Does not do
0731742a 31// any caching, i.e., calling the function twice with the same type will also do
d9579d0f 32// the work twice. The `qualified` parameter only affects the first level of the
0731742a 33// type name, further levels (i.e., type parameters) are always fully qualified.
dc9dc135
XL
34pub fn compute_debuginfo_type_name<'tcx>(
35 tcx: TyCtxt<'tcx>,
36 t: Ty<'tcx>,
37 qualified: bool,
38) -> String {
136023e0
XL
39 let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
40
d9579d0f 41 let mut result = String::with_capacity(64);
532ac7d7 42 let mut visited = FxHashSet::default();
48663c56 43 push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
d9579d0f
AL
44 result
45}
46
47// Pushes the name of the type as it should be stored in debuginfo on the
48// `output` String. See also compute_debuginfo_type_name().
136023e0 49fn push_debuginfo_type_name<'tcx>(
dc9dc135
XL
50 tcx: TyCtxt<'tcx>,
51 t: Ty<'tcx>,
52 qualified: bool,
53 output: &mut String,
54 visited: &mut FxHashSet<Ty<'tcx>>,
55) {
3b2f2976
XL
56 // When targeting MSVC, emit C++ style type names for compatibility with
57 // .natvis visualizers (and perhaps other existing native debuggers?)
a2a8927a 58 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
3b2f2976 59
1b1a35ee 60 match *t.kind() {
b7449926
XL
61 ty::Bool => output.push_str("bool"),
62 ty::Char => output.push_str("char"),
63 ty::Str => output.push_str("str"),
136023e0 64 ty::Never => {
a2a8927a 65 if cpp_like_debuginfo {
136023e0
XL
66 output.push_str("never$");
67 } else {
68 output.push('!');
69 }
70 }
60c5eb7d
XL
71 ty::Int(int_ty) => output.push_str(int_ty.name_str()),
72 ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
73 ty::Float(float_ty) => output.push_str(float_ty.name_str()),
48663c56 74 ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
b7449926 75 ty::Adt(def, substs) => {
5e7ed085
FG
76 // `layout_for_cpp_like_fallback` will be `Some` if we want to use the fallback encoding.
77 let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
78 match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
79 Ok(layout) => {
80 if !wants_c_like_enum_debuginfo(layout) {
81 Some(layout)
82 } else {
83 // This is a C-like enum so we don't want to use the fallback encoding
84 // for the name.
85 None
86 }
87 }
88 Err(e) => {
89 // Computing the layout can still fail here, e.g. if the target architecture
90 // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
91 tcx.sess.fatal(&format!("{}", e));
92 }
93 }
17df50a5 94 } else {
5e7ed085
FG
95 // We are not emitting cpp-like debuginfo or this isn't even an enum.
96 None
97 };
98
99 if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
100 msvc_enum_fallback(
101 tcx,
102 ty_and_layout,
103 &|output, visited| {
104 push_item_name(tcx, def.did(), true, output);
105 push_generic_params_internal(tcx, substs, output, visited);
106 },
107 output,
108 visited,
109 );
110 } else {
111 push_item_name(tcx, def.did(), qualified, output);
136023e0 112 push_generic_params_internal(tcx, substs, output, visited);
17df50a5 113 }
dfeec247 114 }
b7449926 115 ty::Tuple(component_types) => {
a2a8927a 116 if cpp_like_debuginfo {
136023e0 117 output.push_str("tuple$<");
f035d41b
XL
118 } else {
119 output.push('(');
120 }
121
f9f354fc 122 for component_type in component_types {
5e7ed085 123 push_debuginfo_type_name(tcx, component_type, true, output, visited);
a2a8927a 124 push_arg_separator(cpp_like_debuginfo, output);
d9579d0f
AL
125 }
126 if !component_types.is_empty() {
136023e0 127 pop_arg_separator(output);
d9579d0f 128 }
f035d41b 129
a2a8927a
XL
130 if cpp_like_debuginfo {
131 push_close_angle_bracket(cpp_like_debuginfo, output);
f035d41b
XL
132 } else {
133 output.push(')');
134 }
dfeec247
XL
135 }
136 ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
a2a8927a 137 if cpp_like_debuginfo {
136023e0 138 match mutbl {
5099ac24
FG
139 Mutability::Not => output.push_str("ptr_const$<"),
140 Mutability::Mut => output.push_str("ptr_mut$<"),
136023e0
XL
141 }
142 } else {
3b2f2976 143 output.push('*');
136023e0 144 match mutbl {
5099ac24
FG
145 Mutability::Not => output.push_str("const "),
146 Mutability::Mut => output.push_str("mut "),
136023e0 147 }
d9579d0f
AL
148 }
149
136023e0 150 push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
3b2f2976 151
a2a8927a
XL
152 if cpp_like_debuginfo {
153 push_close_angle_bracket(cpp_like_debuginfo, output);
3b2f2976 154 }
dfeec247 155 }
b7449926 156 ty::Ref(_, inner_type, mutbl) => {
136023e0
XL
157 // Slices and `&str` are treated like C++ pointers when computing debug
158 // info for MSVC debugger. However, wrapping these types' names in a synthetic type
159 // causes the .natvis engine for WinDbg to fail to display their data, so we opt these
160 // types out to aid debugging in MSVC.
3c0e092e 161 let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
136023e0 162
a2a8927a 163 if !cpp_like_debuginfo {
3b2f2976 164 output.push('&');
136023e0
XL
165 output.push_str(mutbl.prefix_str());
166 } else if !is_slice_or_str {
167 match mutbl {
5099ac24
FG
168 Mutability::Not => output.push_str("ref$<"),
169 Mutability::Mut => output.push_str("ref_mut$<"),
136023e0 170 }
3b2f2976 171 }
d9579d0f 172
136023e0 173 push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
3b2f2976 174
a2a8927a
XL
175 if cpp_like_debuginfo && !is_slice_or_str {
176 push_close_angle_bracket(cpp_like_debuginfo, output);
3b2f2976 177 }
dfeec247 178 }
b7449926 179 ty::Array(inner_type, len) => {
a2a8927a 180 if cpp_like_debuginfo {
136023e0
XL
181 output.push_str("array$<");
182 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
5099ac24 183 match len.val() {
136023e0
XL
184 ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
185 _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
186 .unwrap(),
187 }
188 } else {
189 output.push('[');
190 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
5099ac24 191 match len.val() {
136023e0
XL
192 ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
193 _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
194 .unwrap(),
195 }
196 }
dfeec247 197 }
b7449926 198 ty::Slice(inner_type) => {
a2a8927a 199 if cpp_like_debuginfo {
136023e0 200 output.push_str("slice$<");
3b2f2976
XL
201 } else {
202 output.push('[');
203 }
204
48663c56 205 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
3b2f2976 206
a2a8927a
XL
207 if cpp_like_debuginfo {
208 push_close_angle_bracket(cpp_like_debuginfo, output);
3b2f2976
XL
209 } else {
210 output.push(']');
211 }
dfeec247 212 }
b7449926 213 ty::Dynamic(ref trait_data, ..) => {
136023e0
XL
214 let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
215
a2a8927a 216 let has_enclosing_parens = if cpp_like_debuginfo {
136023e0
XL
217 output.push_str("dyn$<");
218 false
219 } else {
220 if trait_data.len() > 1 && auto_traits.len() != 0 {
221 // We need enclosing parens because there is more than one trait
222 output.push_str("(dyn ");
223 true
224 } else {
225 output.push_str("dyn ");
226 false
227 }
228 };
229
0731742a 230 if let Some(principal) = trait_data.principal() {
fc512014
XL
231 let principal =
232 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
136023e0
XL
233 push_item_name(tcx, principal.def_id, qualified, output);
234 let principal_has_generic_params =
235 push_generic_params_internal(tcx, principal.substs, output, visited);
236
237 let projection_bounds: SmallVec<[_; 4]> = trait_data
238 .projection_bounds()
239 .map(|bound| {
5e7ed085
FG
240 let ExistentialProjection { item_def_id, term, .. } =
241 tcx.erase_late_bound_regions(bound);
5099ac24
FG
242 // FIXME(associated_const_equality): allow for consts here
243 (item_def_id, term.ty().unwrap())
136023e0
XL
244 })
245 .collect();
246
247 if projection_bounds.len() != 0 {
248 if principal_has_generic_params {
249 // push_generic_params_internal() above added a `>` but we actually
5e7ed085 250 // want to add more items to that list, so remove that again...
136023e0 251 pop_close_angle_bracket(output);
5e7ed085
FG
252 // .. and add a comma to separate the regular generic args from the
253 // associated types.
254 push_arg_separator(cpp_like_debuginfo, output);
255 } else {
256 // push_generic_params_internal() did not add `<...>`, so we open
257 // angle brackets here.
258 output.push('<');
136023e0
XL
259 }
260
261 for (item_def_id, ty) in projection_bounds {
a2a8927a 262 if cpp_like_debuginfo {
136023e0
XL
263 output.push_str("assoc$<");
264 push_item_name(tcx, item_def_id, false, output);
a2a8927a 265 push_arg_separator(cpp_like_debuginfo, output);
136023e0 266 push_debuginfo_type_name(tcx, ty, true, output, visited);
a2a8927a 267 push_close_angle_bracket(cpp_like_debuginfo, output);
136023e0
XL
268 } else {
269 push_item_name(tcx, item_def_id, false, output);
270 output.push('=');
271 push_debuginfo_type_name(tcx, ty, true, output, visited);
272 }
5e7ed085 273 push_arg_separator(cpp_like_debuginfo, output);
136023e0
XL
274 }
275
5e7ed085 276 pop_arg_separator(output);
a2a8927a 277 push_close_angle_bracket(cpp_like_debuginfo, output);
136023e0
XL
278 }
279
280 if auto_traits.len() != 0 {
a2a8927a 281 push_auto_trait_separator(cpp_like_debuginfo, output);
136023e0
XL
282 }
283 }
284
285 if auto_traits.len() != 0 {
286 let mut auto_traits: SmallVec<[String; 4]> = auto_traits
287 .into_iter()
288 .map(|def_id| {
289 let mut name = String::with_capacity(20);
290 push_item_name(tcx, def_id, true, &mut name);
291 name
292 })
293 .collect();
294 auto_traits.sort_unstable();
295
296 for auto_trait in auto_traits {
297 output.push_str(&auto_trait);
a2a8927a 298 push_auto_trait_separator(cpp_like_debuginfo, output);
136023e0
XL
299 }
300
301 pop_auto_trait_separator(output);
302 }
303
a2a8927a
XL
304 if cpp_like_debuginfo {
305 push_close_angle_bracket(cpp_like_debuginfo, output);
136023e0
XL
306 } else if has_enclosing_parens {
307 output.push(')');
0731742a 308 }
dfeec247 309 }
b7449926 310 ty::FnDef(..) | ty::FnPtr(_) => {
532ac7d7
XL
311 // We've encountered a weird 'recursive type'
312 // Currently, the only way to generate such a type
313 // is by using 'impl trait':
314 //
315 // fn foo() -> impl Copy { foo }
316 //
317 // There's not really a sensible name we can generate,
318 // since we don't include 'impl trait' types (e.g. ty::Opaque)
319 // in the output
320 //
321 // Since we need to generate *something*, we just
322 // use a dummy string that should make it clear
323 // that something unusual is going on
324 if !visited.insert(t) {
a2a8927a 325 output.push_str(if cpp_like_debuginfo {
136023e0
XL
326 "recursive_type$"
327 } else {
328 "<recursive_type>"
329 });
532ac7d7
XL
330 return;
331 }
332
136023e0
XL
333 let sig =
334 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
d9579d0f 335
a2a8927a 336 if cpp_like_debuginfo {
136023e0
XL
337 // Format as a C++ function pointer: return_type (*)(params...)
338 if sig.output().is_unit() {
339 output.push_str("void");
340 } else {
341 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
342 }
343 output.push_str(" (*)(");
344 } else {
345 output.push_str(sig.unsafety.prefix_str());
346
347 if sig.abi != rustc_target::spec::abi::Abi::Rust {
348 output.push_str("extern \"");
349 output.push_str(sig.abi.name());
350 output.push_str("\" ");
351 }
d9579d0f 352
136023e0
XL
353 output.push_str("fn(");
354 }
d9579d0f 355
476ff2be
SL
356 if !sig.inputs().is_empty() {
357 for &parameter_type in sig.inputs() {
48663c56 358 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
a2a8927a 359 push_arg_separator(cpp_like_debuginfo, output);
d9579d0f 360 }
136023e0 361 pop_arg_separator(output);
d9579d0f
AL
362 }
363
532ac7d7 364 if sig.c_variadic {
476ff2be 365 if !sig.inputs().is_empty() {
d9579d0f
AL
366 output.push_str(", ...");
367 } else {
368 output.push_str("...");
369 }
370 }
371
372 output.push(')');
373
a2a8927a 374 if !cpp_like_debuginfo && !sig.output().is_unit() {
5bcae85e 375 output.push_str(" -> ");
48663c56 376 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
d9579d0f 377 }
532ac7d7 378
532ac7d7
XL
379 // We only keep the type in 'visited'
380 // for the duration of the body of this method.
381 // It's fine for a particular function type
382 // to show up multiple times in one overall type
383 // (e.g. MyType<fn() -> u8, fn() -> u8>
384 //
385 // We only care about avoiding recursing
386 // directly back to the type we're currently
387 // processing
5099ac24 388 visited.remove(&t);
dfeec247 389 }
5099ac24
FG
390 ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
391 // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
392 // "{async_fn_env#0}<T1, T2, ...>", etc.
5e7ed085
FG
393 // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
394 // an artificial `enum$<>` type, as defined in msvc_enum_fallback().
395 if cpp_like_debuginfo && t.is_generator() {
396 let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
397 msvc_enum_fallback(
398 tcx,
399 ty_and_layout,
400 &|output, visited| {
401 push_closure_or_generator_name(tcx, def_id, substs, true, output, visited);
402 },
403 output,
404 visited,
405 );
406 } else {
407 push_closure_or_generator_name(tcx, def_id, substs, qualified, output, visited);
136023e0 408 }
ea8adc8c 409 }
3dfed10e
XL
410 // Type parameters from polymorphized functions.
411 ty::Param(_) => {
5e7ed085 412 write!(output, "{:?}", t).unwrap();
3dfed10e 413 }
f035d41b 414 ty::Error(_)
dfeec247
XL
415 | ty::Infer(_)
416 | ty::Placeholder(..)
dfeec247
XL
417 | ty::Projection(..)
418 | ty::Bound(..)
419 | ty::Opaque(..)
3dfed10e 420 | ty::GeneratorWitness(..) => {
dfeec247
XL
421 bug!(
422 "debuginfo: Trying to create type name for \
423 unexpected type: {:?}",
424 t
425 );
d9579d0f
AL
426 }
427 }
428
17df50a5
XL
429 /// MSVC names enums differently than other platforms so that the debugging visualization
430 // format (natvis) is able to understand enums and render the active variant correctly in the
431 // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
432 // `EnumMemberDescriptionFactor::create_member_descriptions`.
a2a8927a 433 fn msvc_enum_fallback<'tcx>(
17df50a5 434 tcx: TyCtxt<'tcx>,
5e7ed085
FG
435 ty_and_layout: TyAndLayout<'tcx>,
436 push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
17df50a5
XL
437 output: &mut String,
438 visited: &mut FxHashSet<Ty<'tcx>>,
439 ) {
5e7ed085
FG
440 debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
441 let ty = ty_and_layout.ty;
17df50a5 442
136023e0 443 output.push_str("enum$<");
5e7ed085
FG
444 push_inner(output, visited);
445
446 let variant_name = |variant_index| match ty.kind() {
447 ty::Adt(adt_def, _) => {
448 debug_assert!(adt_def.is_enum());
449 Cow::from(adt_def.variant(variant_index).name.as_str())
450 }
451 ty::Generator(..) => GeneratorSubsts::variant_name(variant_index),
452 _ => unreachable!(),
453 };
136023e0 454
17df50a5
XL
455 if let Variants::Multiple {
456 tag_encoding: TagEncoding::Niche { dataful_variant, .. },
457 tag,
458 variants,
459 ..
5e7ed085 460 } = &ty_and_layout.variants
17df50a5
XL
461 {
462 let dataful_variant_layout = &variants[*dataful_variant];
463
464 // calculate the range of values for the dataful variant
465 let dataful_discriminant_range =
04454e1e 466 dataful_variant_layout.largest_niche().unwrap().valid_range;
17df50a5 467
94222f64 468 let min = dataful_discriminant_range.start;
04454e1e 469 let min = tag.size(&tcx).truncate(min);
17df50a5 470
94222f64 471 let max = dataful_discriminant_range.end;
04454e1e 472 let max = tag.size(&tcx).truncate(max);
17df50a5 473
5e7ed085
FG
474 let dataful_variant_name = variant_name(*dataful_variant);
475 write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();
476 } else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants {
136023e0
XL
477 // Uninhabited enums can't be constructed and should never need to be visualized so
478 // skip this step for them.
5e7ed085
FG
479 if !ty_and_layout.abi.is_uninhabited() {
480 write!(output, ", {}", variant_name(*variant_idx)).unwrap();
136023e0
XL
481 }
482 }
483 push_close_angle_bracket(true, output);
484 }
485
486 const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
487
a2a8927a
XL
488 fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
489 if cpp_like_debuginfo {
490 push_arg_separator(cpp_like_debuginfo, output);
17df50a5 491 } else {
136023e0 492 output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
17df50a5
XL
493 }
494 }
495
136023e0
XL
496 fn pop_auto_trait_separator(output: &mut String) {
497 if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) {
498 output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len());
499 } else {
500 pop_arg_separator(output);
501 }
502 }
503}
504
5099ac24
FG
505pub enum VTableNameKind {
506 // Is the name for the const/static holding the vtable?
507 GlobalVariable,
508 // Is the name for the type of the vtable?
509 Type,
510}
511
512/// Computes a name for the global variable storing a vtable (or the type of that global variable).
c295e0f8
XL
513///
514/// The name is of the form:
515///
516/// `<path::to::SomeType as path::to::SomeTrait>::{vtable}`
517///
518/// or, when generating C++-like names:
519///
520/// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
5099ac24
FG
521///
522/// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just
523/// `{vtable}`, so that the type and the corresponding global variable get assigned different
524/// names.
c295e0f8
XL
525pub fn compute_debuginfo_vtable_name<'tcx>(
526 tcx: TyCtxt<'tcx>,
527 t: Ty<'tcx>,
528 trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
5099ac24 529 kind: VTableNameKind,
c295e0f8 530) -> String {
a2a8927a 531 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
c295e0f8
XL
532
533 let mut vtable_name = String::with_capacity(64);
534
a2a8927a 535 if cpp_like_debuginfo {
c295e0f8
XL
536 vtable_name.push_str("impl$<");
537 } else {
538 vtable_name.push('<');
539 }
540
541 let mut visited = FxHashSet::default();
542 push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
543
a2a8927a 544 if cpp_like_debuginfo {
c295e0f8
XL
545 vtable_name.push_str(", ");
546 } else {
547 vtable_name.push_str(" as ");
548 }
549
550 if let Some(trait_ref) = trait_ref {
551 let trait_ref =
552 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
553 push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
554 visited.clear();
555 push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
556 } else {
557 vtable_name.push_str("_");
558 }
559
a2a8927a 560 push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
c295e0f8 561
5099ac24
FG
562 let suffix = match (cpp_like_debuginfo, kind) {
563 (true, VTableNameKind::GlobalVariable) => "::vtable$",
564 (false, VTableNameKind::GlobalVariable) => "::{vtable}",
565 (true, VTableNameKind::Type) => "::vtable_type$",
566 (false, VTableNameKind::Type) => "::{vtable_type}",
567 };
c295e0f8
XL
568
569 vtable_name.reserve_exact(suffix.len());
570 vtable_name.push_str(suffix);
571
572 vtable_name
573}
574
a2a8927a 575pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
136023e0
XL
576 let def_key = tcx.def_key(def_id);
577 if qualified {
578 if let Some(parent) = def_key.parent {
579 push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
580 output.push_str("::");
581 }
582 }
583
584 push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
585}
586
5099ac24
FG
587fn generator_kind_label(generator_kind: Option<GeneratorKind>) -> &'static str {
588 match generator_kind {
589 Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) => "async_block",
590 Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) => "async_closure",
591 Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) => "async_fn",
592 Some(GeneratorKind::Gen) => "generator",
593 None => "closure",
594 }
595}
596
597fn push_disambiguated_special_name(
598 label: &str,
599 disambiguator: u32,
600 cpp_like_debuginfo: bool,
601 output: &mut String,
602) {
603 if cpp_like_debuginfo {
604 write!(output, "{}${}", label, disambiguator).unwrap();
605 } else {
606 write!(output, "{{{}#{}}}", label, disambiguator).unwrap();
607 }
608}
609
136023e0 610fn push_unqualified_item_name(
a2a8927a 611 tcx: TyCtxt<'_>,
136023e0
XL
612 def_id: DefId,
613 disambiguated_data: DisambiguatedDefPathData,
614 output: &mut String,
615) {
616 match disambiguated_data.data {
617 DefPathData::CrateRoot => {
a2a8927a 618 output.push_str(tcx.crate_name(def_id.krate).as_str());
136023e0 619 }
5099ac24
FG
620 DefPathData::ClosureExpr => {
621 let label = generator_kind_label(tcx.generator_kind(def_id));
622
623 push_disambiguated_special_name(
624 label,
625 disambiguated_data.disambiguator,
626 cpp_like_debuginfo(tcx),
627 output,
628 );
54a0048b 629 }
136023e0
XL
630 _ => match disambiguated_data.data.name() {
631 DefPathDataName::Named(name) => {
a2a8927a 632 output.push_str(name.as_str());
136023e0
XL
633 }
634 DefPathDataName::Anon { namespace } => {
5099ac24
FG
635 push_disambiguated_special_name(
636 namespace.as_str(),
637 disambiguated_data.disambiguator,
638 cpp_like_debuginfo(tcx),
639 output,
640 );
136023e0
XL
641 }
642 },
643 };
644}
645
136023e0
XL
646fn push_generic_params_internal<'tcx>(
647 tcx: TyCtxt<'tcx>,
648 substs: SubstsRef<'tcx>,
649 output: &mut String,
650 visited: &mut FxHashSet<Ty<'tcx>>,
651) -> bool {
652 if substs.non_erasable_generics().next().is_none() {
653 return false;
d9579d0f
AL
654 }
655
136023e0
XL
656 debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
657
a2a8927a 658 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
136023e0
XL
659
660 output.push('<');
661
662 for type_parameter in substs.non_erasable_generics() {
663 match type_parameter {
664 GenericArgKind::Type(type_parameter) => {
665 push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
666 }
667 GenericArgKind::Const(ct) => {
668 push_const_param(tcx, ct, output);
669 }
670 other => bug!("Unexpected non-erasable generic: {:?}", other),
d9579d0f
AL
671 }
672
a2a8927a 673 push_arg_separator(cpp_like_debuginfo, output);
136023e0
XL
674 }
675 pop_arg_separator(output);
a2a8927a 676 push_close_angle_bracket(cpp_like_debuginfo, output);
136023e0
XL
677
678 true
679}
d9579d0f 680
5099ac24
FG
681fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
682 match ct.val() {
136023e0
XL
683 ty::ConstKind::Param(param) => {
684 write!(output, "{}", param.name)
d9579d0f 685 }
5099ac24 686 _ => match ct.ty().kind() {
136023e0 687 ty::Int(ity) => {
5099ac24 688 let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
136023e0
XL
689 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
690 write!(output, "{}", val)
691 }
692 ty::Uint(_) => {
5099ac24 693 let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
136023e0
XL
694 write!(output, "{}", val)
695 }
696 ty::Bool => {
697 let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
698 write!(output, "{}", val)
699 }
700 _ => {
701 // If we cannot evaluate the constant to a known type, we fall back
702 // to emitting a stable hash value of the constant. This isn't very pretty
703 // but we get a deterministic, virtually unique value for the constant.
704 let hcx = &mut tcx.create_stable_hashing_context();
705 let mut hasher = StableHasher::new();
5e7ed085 706 hcx.while_hashing_spans(false, |hcx| ct.val().hash_stable(hcx, &mut hasher));
136023e0
XL
707 // Let's only emit 64 bits of the hash value. That should be plenty for
708 // avoiding collisions and will make the emitted type names shorter.
709 let hash: u64 = hasher.finish();
710
a2a8927a 711 if cpp_like_debuginfo(tcx) {
136023e0
XL
712 write!(output, "CONST${:x}", hash)
713 } else {
714 write!(output, "{{CONST#{:x}}}", hash)
715 }
716 }
717 },
718 }
719 .unwrap();
720}
d9579d0f 721
136023e0
XL
722pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) {
723 let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
724 let mut visited = FxHashSet::default();
725 push_generic_params_internal(tcx, substs, output, &mut visited);
726}
727
5e7ed085
FG
728fn push_closure_or_generator_name<'tcx>(
729 tcx: TyCtxt<'tcx>,
730 def_id: DefId,
731 substs: SubstsRef<'tcx>,
732 qualified: bool,
733 output: &mut String,
734 visited: &mut FxHashSet<Ty<'tcx>>,
735) {
736 // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
737 // "{async_fn_env#0}<T1, T2, ...>", etc.
738 let def_key = tcx.def_key(def_id);
739 let generator_kind = tcx.generator_kind(def_id);
740
741 if qualified {
742 let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
743 push_item_name(tcx, parent_def_id, true, output);
744 output.push_str("::");
745 }
746
747 let mut label = String::with_capacity(20);
748 write!(&mut label, "{}_env", generator_kind_label(generator_kind)).unwrap();
749
750 push_disambiguated_special_name(
751 &label,
752 def_key.disambiguated_data.disambiguator,
753 cpp_like_debuginfo(tcx),
754 output,
755 );
756
757 // We also need to add the generic arguments of the async fn/generator or
758 // the enclosing function (for closures or async blocks), so that we end
759 // up with a unique name for every instantiation.
760
761 // Find the generics of the enclosing function, as defined in the source code.
762 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
763 let generics = tcx.generics_of(enclosing_fn_def_id);
764
765 // Truncate the substs to the length of the above generics. This will cut off
766 // anything closure- or generator-specific.
767 let substs = substs.truncate_to(tcx, generics);
768 push_generic_params_internal(tcx, substs, output, visited);
769}
770
a2a8927a 771fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
136023e0
XL
772 // MSVC debugger always treats `>>` as a shift, even when parsing templates,
773 // so add a space to avoid confusion.
a2a8927a 774 if cpp_like_debuginfo && output.ends_with('>') {
136023e0
XL
775 output.push(' ')
776 };
777
778 output.push('>');
779}
780
781fn pop_close_angle_bracket(output: &mut String) {
782 assert!(output.ends_with('>'), "'output' does not end with '>': {}", output);
783 output.pop();
784 if output.ends_with(' ') {
d9579d0f 785 output.pop();
136023e0
XL
786 }
787}
d9579d0f 788
a2a8927a 789fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
136023e0
XL
790 // Natvis does not always like having spaces between parts of the type name
791 // and this causes issues when we need to write a typename in natvis, for example
792 // as part of a cast like the `HashMap` visualizer does.
a2a8927a 793 if cpp_like_debuginfo {
136023e0
XL
794 output.push(',');
795 } else {
796 output.push_str(", ");
797 };
798}
799
800fn pop_arg_separator(output: &mut String) {
801 if output.ends_with(' ') {
802 output.pop();
d9579d0f 803 }
136023e0
XL
804
805 assert!(output.ends_with(','));
806
807 output.pop();
808}
809
a2a8927a
XL
810/// Check if we should generate C++ like names and debug information.
811pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
136023e0 812 tcx.sess.target.is_like_msvc
d9579d0f 813}