]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Port pgo.sh to Python
[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::GeneratorWitness(..) => {
418             bug!(
419                 "debuginfo: Trying to create type name for \
420                   unexpected type: {:?}",
421                 t
422             );
423         }
424     }
425
426     /// MSVC names enums differently than other platforms so that the debugging visualization
427     // format (natvis) is able to understand enums and render the active variant correctly in the
428     // debugger. For more information, look in
429     // rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
430     fn msvc_enum_fallback<'tcx>(
431         ty_and_layout: TyAndLayout<'tcx>,
432         push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
433         output: &mut String,
434         visited: &mut FxHashSet<Ty<'tcx>>,
435     ) {
436         debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
437         output.push_str("enum2$<");
438         push_inner(output, visited);
439         push_close_angle_bracket(true, output);
440     }
441
442     const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
443
444     fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
445         if cpp_like_debuginfo {
446             push_arg_separator(cpp_like_debuginfo, output);
447         } else {
448             output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
449         }
450     }
451
452     fn pop_auto_trait_separator(output: &mut String) {
453         if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) {
454             output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len());
455         } else {
456             pop_arg_separator(output);
457         }
458     }
459 }
460
461 pub enum VTableNameKind {
462     // Is the name for the const/static holding the vtable?
463     GlobalVariable,
464     // Is the name for the type of the vtable?
465     Type,
466 }
467
468 /// Computes a name for the global variable storing a vtable (or the type of that global variable).
469 ///
470 /// The name is of the form:
471 ///
472 /// `<path::to::SomeType as path::to::SomeTrait>::{vtable}`
473 ///
474 /// or, when generating C++-like names:
475 ///
476 /// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
477 ///
478 /// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just
479 /// `{vtable}`, so that the type and the corresponding global variable get assigned different
480 /// names.
481 pub fn compute_debuginfo_vtable_name<'tcx>(
482     tcx: TyCtxt<'tcx>,
483     t: Ty<'tcx>,
484     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
485     kind: VTableNameKind,
486 ) -> String {
487     let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
488
489     let mut vtable_name = String::with_capacity(64);
490
491     if cpp_like_debuginfo {
492         vtable_name.push_str("impl$<");
493     } else {
494         vtable_name.push('<');
495     }
496
497     let mut visited = FxHashSet::default();
498     push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
499
500     if cpp_like_debuginfo {
501         vtable_name.push_str(", ");
502     } else {
503         vtable_name.push_str(" as ");
504     }
505
506     if let Some(trait_ref) = trait_ref {
507         let trait_ref =
508             tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
509         push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
510         visited.clear();
511         push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
512     } else {
513         vtable_name.push('_');
514     }
515
516     push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
517
518     let suffix = match (cpp_like_debuginfo, kind) {
519         (true, VTableNameKind::GlobalVariable) => "::vtable$",
520         (false, VTableNameKind::GlobalVariable) => "::{vtable}",
521         (true, VTableNameKind::Type) => "::vtable_type$",
522         (false, VTableNameKind::Type) => "::{vtable_type}",
523     };
524
525     vtable_name.reserve_exact(suffix.len());
526     vtable_name.push_str(suffix);
527
528     vtable_name
529 }
530
531 pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
532     let def_key = tcx.def_key(def_id);
533     if qualified {
534         if let Some(parent) = def_key.parent {
535             push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
536             output.push_str("::");
537         }
538     }
539
540     push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
541 }
542
543 fn generator_kind_label(generator_kind: Option<GeneratorKind>) -> &'static str {
544     match generator_kind {
545         Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) => "async_block",
546         Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) => "async_closure",
547         Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) => "async_fn",
548         Some(GeneratorKind::Gen) => "generator",
549         None => "closure",
550     }
551 }
552
553 fn push_disambiguated_special_name(
554     label: &str,
555     disambiguator: u32,
556     cpp_like_debuginfo: bool,
557     output: &mut String,
558 ) {
559     if cpp_like_debuginfo {
560         write!(output, "{}${}", label, disambiguator).unwrap();
561     } else {
562         write!(output, "{{{}#{}}}", label, disambiguator).unwrap();
563     }
564 }
565
566 fn push_unqualified_item_name(
567     tcx: TyCtxt<'_>,
568     def_id: DefId,
569     disambiguated_data: DisambiguatedDefPathData,
570     output: &mut String,
571 ) {
572     match disambiguated_data.data {
573         DefPathData::CrateRoot => {
574             output.push_str(tcx.crate_name(def_id.krate).as_str());
575         }
576         DefPathData::ClosureExpr => {
577             let label = generator_kind_label(tcx.generator_kind(def_id));
578
579             push_disambiguated_special_name(
580                 label,
581                 disambiguated_data.disambiguator,
582                 cpp_like_debuginfo(tcx),
583                 output,
584             );
585         }
586         _ => match disambiguated_data.data.name() {
587             DefPathDataName::Named(name) => {
588                 output.push_str(name.as_str());
589             }
590             DefPathDataName::Anon { namespace } => {
591                 push_disambiguated_special_name(
592                     namespace.as_str(),
593                     disambiguated_data.disambiguator,
594                     cpp_like_debuginfo(tcx),
595                     output,
596                 );
597             }
598         },
599     };
600 }
601
602 fn push_generic_params_internal<'tcx>(
603     tcx: TyCtxt<'tcx>,
604     substs: SubstsRef<'tcx>,
605     output: &mut String,
606     visited: &mut FxHashSet<Ty<'tcx>>,
607 ) -> bool {
608     if substs.non_erasable_generics().next().is_none() {
609         return false;
610     }
611
612     debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
613
614     let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
615
616     output.push('<');
617
618     for type_parameter in substs.non_erasable_generics() {
619         match type_parameter {
620             GenericArgKind::Type(type_parameter) => {
621                 push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
622             }
623             GenericArgKind::Const(ct) => {
624                 push_const_param(tcx, ct, output);
625             }
626             other => bug!("Unexpected non-erasable generic: {:?}", other),
627         }
628
629         push_arg_separator(cpp_like_debuginfo, output);
630     }
631     pop_arg_separator(output);
632     push_close_angle_bracket(cpp_like_debuginfo, output);
633
634     true
635 }
636
637 fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
638     match ct.kind() {
639         ty::ConstKind::Param(param) => {
640             write!(output, "{}", param.name)
641         }
642         _ => match ct.ty().kind() {
643             ty::Int(ity) => {
644                 let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
645                 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
646                 write!(output, "{}", val)
647             }
648             ty::Uint(_) => {
649                 let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
650                 write!(output, "{}", val)
651             }
652             ty::Bool => {
653                 let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
654                 write!(output, "{}", val)
655             }
656             _ => {
657                 // If we cannot evaluate the constant to a known type, we fall back
658                 // to emitting a stable hash value of the constant. This isn't very pretty
659                 // but we get a deterministic, virtually unique value for the constant.
660                 //
661                 // Let's only emit 64 bits of the hash value. That should be plenty for
662                 // avoiding collisions and will make the emitted type names shorter.
663                 let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
664                     let mut hasher = StableHasher::new();
665                     let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
666                     hcx.while_hashing_spans(false, |hcx| {
667                         ct.to_valtree().hash_stable(hcx, &mut hasher)
668                     });
669                     let hash: u64 = hasher.finish();
670                     hash
671                 });
672
673                 if cpp_like_debuginfo(tcx) {
674                     write!(output, "CONST${:x}", hash_short)
675                 } else {
676                     write!(output, "{{CONST#{:x}}}", hash_short)
677                 }
678             }
679         },
680     }
681     .unwrap();
682 }
683
684 pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) {
685     let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
686     let mut visited = FxHashSet::default();
687     push_generic_params_internal(tcx, substs, output, &mut visited);
688 }
689
690 fn push_closure_or_generator_name<'tcx>(
691     tcx: TyCtxt<'tcx>,
692     def_id: DefId,
693     substs: SubstsRef<'tcx>,
694     qualified: bool,
695     output: &mut String,
696     visited: &mut FxHashSet<Ty<'tcx>>,
697 ) {
698     // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
699     // "{async_fn_env#0}<T1, T2, ...>", etc.
700     let def_key = tcx.def_key(def_id);
701     let generator_kind = tcx.generator_kind(def_id);
702
703     if qualified {
704         let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
705         push_item_name(tcx, parent_def_id, true, output);
706         output.push_str("::");
707     }
708
709     let mut label = String::with_capacity(20);
710     write!(&mut label, "{}_env", generator_kind_label(generator_kind)).unwrap();
711
712     push_disambiguated_special_name(
713         &label,
714         def_key.disambiguated_data.disambiguator,
715         cpp_like_debuginfo(tcx),
716         output,
717     );
718
719     // We also need to add the generic arguments of the async fn/generator or
720     // the enclosing function (for closures or async blocks), so that we end
721     // up with a unique name for every instantiation.
722
723     // Find the generics of the enclosing function, as defined in the source code.
724     let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
725     let generics = tcx.generics_of(enclosing_fn_def_id);
726
727     // Truncate the substs to the length of the above generics. This will cut off
728     // anything closure- or generator-specific.
729     let substs = substs.truncate_to(tcx, generics);
730     push_generic_params_internal(tcx, substs, output, visited);
731 }
732
733 fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
734     // MSVC debugger always treats `>>` as a shift, even when parsing templates,
735     // so add a space to avoid confusion.
736     if cpp_like_debuginfo && output.ends_with('>') {
737         output.push(' ')
738     };
739
740     output.push('>');
741 }
742
743 fn pop_close_angle_bracket(output: &mut String) {
744     assert!(output.ends_with('>'), "'output' does not end with '>': {}", output);
745     output.pop();
746     if output.ends_with(' ') {
747         output.pop();
748     }
749 }
750
751 fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
752     // Natvis does not always like having spaces between parts of the type name
753     // and this causes issues when we need to write a typename in natvis, for example
754     // as part of a cast like the `HashMap` visualizer does.
755     if cpp_like_debuginfo {
756         output.push(',');
757     } else {
758         output.push_str(", ");
759     };
760 }
761
762 fn pop_arg_separator(output: &mut String) {
763     if output.ends_with(' ') {
764         output.pop();
765     }
766
767     assert!(output.ends_with(','));
768
769     output.pop();
770 }
771
772 /// Check if we should generate C++ like names and debug information.
773 pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
774     tcx.sess.target.is_like_msvc
775 }