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