]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Rollup merge of #105243 - RalfJung:no-op-let, r=Mark-Simulacrum
[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                         tcx.sess.fatal(&format!("{}", e));
97                     }
98                 }
99             } else {
100                 // We are not emitting cpp-like debuginfo or this isn't even an enum.
101                 None
102             };
103
104             if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
105                 msvc_enum_fallback(
106                     ty_and_layout,
107                     &|output, visited| {
108                         push_item_name(tcx, def.did(), true, output);
109                         push_generic_params_internal(tcx, substs, output, visited);
110                     },
111                     output,
112                     visited,
113                 );
114             } else {
115                 push_item_name(tcx, def.did(), qualified, output);
116                 push_generic_params_internal(tcx, substs, output, visited);
117             }
118         }
119         ty::Tuple(component_types) => {
120             if cpp_like_debuginfo {
121                 output.push_str("tuple$<");
122             } else {
123                 output.push('(');
124             }
125
126             for component_type in component_types {
127                 push_debuginfo_type_name(tcx, component_type, true, output, visited);
128                 push_arg_separator(cpp_like_debuginfo, output);
129             }
130             if !component_types.is_empty() {
131                 pop_arg_separator(output);
132             }
133
134             if cpp_like_debuginfo {
135                 push_close_angle_bracket(cpp_like_debuginfo, output);
136             } else {
137                 output.push(')');
138             }
139         }
140         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
141             if cpp_like_debuginfo {
142                 match mutbl {
143                     Mutability::Not => output.push_str("ptr_const$<"),
144                     Mutability::Mut => output.push_str("ptr_mut$<"),
145                 }
146             } else {
147                 output.push('*');
148                 match mutbl {
149                     Mutability::Not => output.push_str("const "),
150                     Mutability::Mut => output.push_str("mut "),
151                 }
152             }
153
154             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
155
156             if cpp_like_debuginfo {
157                 push_close_angle_bracket(cpp_like_debuginfo, output);
158             }
159         }
160         ty::Ref(_, inner_type, mutbl) => {
161             if cpp_like_debuginfo {
162                 match mutbl {
163                     Mutability::Not => output.push_str("ref$<"),
164                     Mutability::Mut => output.push_str("ref_mut$<"),
165                 }
166             } else {
167                 output.push('&');
168                 output.push_str(mutbl.prefix_str());
169             }
170
171             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
172
173             if cpp_like_debuginfo {
174                 push_close_angle_bracket(cpp_like_debuginfo, output);
175             }
176         }
177         ty::Array(inner_type, len) => {
178             if cpp_like_debuginfo {
179                 output.push_str("array$<");
180                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
181                 match len.kind() {
182                     ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
183                     _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
184                         .unwrap(),
185                 }
186             } else {
187                 output.push('[');
188                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
189                 match len.kind() {
190                     ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
191                     _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
192                         .unwrap(),
193                 }
194             }
195         }
196         ty::Slice(inner_type) => {
197             if cpp_like_debuginfo {
198                 output.push_str("slice2$<");
199             } else {
200                 output.push('[');
201             }
202
203             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
204
205             if cpp_like_debuginfo {
206                 push_close_angle_bracket(cpp_like_debuginfo, output);
207             } else {
208                 output.push(']');
209             }
210         }
211         ty::Dynamic(ref trait_data, ..) => {
212             let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
213
214             let has_enclosing_parens = if cpp_like_debuginfo {
215                 output.push_str("dyn$<");
216                 false
217             } else {
218                 if trait_data.len() > 1 && auto_traits.len() != 0 {
219                     // We need enclosing parens because there is more than one trait
220                     output.push_str("(dyn ");
221                     true
222                 } else {
223                     output.push_str("dyn ");
224                     false
225                 }
226             };
227
228             if let Some(principal) = trait_data.principal() {
229                 let principal =
230                     tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
231                 push_item_name(tcx, principal.def_id, qualified, output);
232                 let principal_has_generic_params =
233                     push_generic_params_internal(tcx, principal.substs, output, visited);
234
235                 let projection_bounds: SmallVec<[_; 4]> = trait_data
236                     .projection_bounds()
237                     .map(|bound| {
238                         let ExistentialProjection { item_def_id, term, .. } =
239                             tcx.erase_late_bound_regions(bound);
240                         // FIXME(associated_const_equality): allow for consts here
241                         (item_def_id, term.ty().unwrap())
242                     })
243                     .collect();
244
245                 if projection_bounds.len() != 0 {
246                     if principal_has_generic_params {
247                         // push_generic_params_internal() above added a `>` but we actually
248                         // want to add more items to that list, so remove that again...
249                         pop_close_angle_bracket(output);
250                         // .. and add a comma to separate the regular generic args from the
251                         // associated types.
252                         push_arg_separator(cpp_like_debuginfo, output);
253                     } else {
254                         // push_generic_params_internal() did not add `<...>`, so we open
255                         // angle brackets here.
256                         output.push('<');
257                     }
258
259                     for (item_def_id, ty) in projection_bounds {
260                         if cpp_like_debuginfo {
261                             output.push_str("assoc$<");
262                             push_item_name(tcx, item_def_id, false, output);
263                             push_arg_separator(cpp_like_debuginfo, output);
264                             push_debuginfo_type_name(tcx, ty, true, output, visited);
265                             push_close_angle_bracket(cpp_like_debuginfo, output);
266                         } else {
267                             push_item_name(tcx, item_def_id, false, output);
268                             output.push('=');
269                             push_debuginfo_type_name(tcx, ty, true, output, visited);
270                         }
271                         push_arg_separator(cpp_like_debuginfo, output);
272                     }
273
274                     pop_arg_separator(output);
275                     push_close_angle_bracket(cpp_like_debuginfo, output);
276                 }
277
278                 if auto_traits.len() != 0 {
279                     push_auto_trait_separator(cpp_like_debuginfo, output);
280                 }
281             }
282
283             if auto_traits.len() != 0 {
284                 let mut auto_traits: SmallVec<[String; 4]> = auto_traits
285                     .into_iter()
286                     .map(|def_id| {
287                         let mut name = String::with_capacity(20);
288                         push_item_name(tcx, def_id, true, &mut name);
289                         name
290                     })
291                     .collect();
292                 auto_traits.sort_unstable();
293
294                 for auto_trait in auto_traits {
295                     output.push_str(&auto_trait);
296                     push_auto_trait_separator(cpp_like_debuginfo, output);
297                 }
298
299                 pop_auto_trait_separator(output);
300             }
301
302             if cpp_like_debuginfo {
303                 push_close_angle_bracket(cpp_like_debuginfo, output);
304             } else if has_enclosing_parens {
305                 output.push(')');
306             }
307         }
308         ty::FnDef(..) | ty::FnPtr(_) => {
309             // We've encountered a weird 'recursive type'
310             // Currently, the only way to generate such a type
311             // is by using 'impl trait':
312             //
313             // fn foo() -> impl Copy { foo }
314             //
315             // There's not really a sensible name we can generate,
316             // since we don't include 'impl trait' types (e.g. ty::Opaque)
317             // in the output
318             //
319             // Since we need to generate *something*, we just
320             // use a dummy string that should make it clear
321             // that something unusual is going on
322             if !visited.insert(t) {
323                 output.push_str(if cpp_like_debuginfo {
324                     "recursive_type$"
325                 } else {
326                     "<recursive_type>"
327                 });
328                 return;
329             }
330
331             let sig =
332                 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
333
334             if cpp_like_debuginfo {
335                 // Format as a C++ function pointer: return_type (*)(params...)
336                 if sig.output().is_unit() {
337                     output.push_str("void");
338                 } else {
339                     push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
340                 }
341                 output.push_str(" (*)(");
342             } else {
343                 output.push_str(sig.unsafety.prefix_str());
344
345                 if sig.abi != rustc_target::spec::abi::Abi::Rust {
346                     output.push_str("extern \"");
347                     output.push_str(sig.abi.name());
348                     output.push_str("\" ");
349                 }
350
351                 output.push_str("fn(");
352             }
353
354             if !sig.inputs().is_empty() {
355                 for &parameter_type in sig.inputs() {
356                     push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
357                     push_arg_separator(cpp_like_debuginfo, output);
358                 }
359                 pop_arg_separator(output);
360             }
361
362             if sig.c_variadic {
363                 if !sig.inputs().is_empty() {
364                     output.push_str(", ...");
365                 } else {
366                     output.push_str("...");
367                 }
368             }
369
370             output.push(')');
371
372             if !cpp_like_debuginfo && !sig.output().is_unit() {
373                 output.push_str(" -> ");
374                 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
375             }
376
377             // We only keep the type in 'visited'
378             // for the duration of the body of this method.
379             // It's fine for a particular function type
380             // to show up multiple times in one overall type
381             // (e.g. MyType<fn() -> u8, fn() -> u8>
382             //
383             // We only care about avoiding recursing
384             // directly back to the type we're currently
385             // processing
386             visited.remove(&t);
387         }
388         ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
389             // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
390             // "{async_fn_env#0}<T1, T2, ...>", etc.
391             // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
392             // an artificial `enum2$<>` type, as defined in msvc_enum_fallback().
393             if cpp_like_debuginfo && t.is_generator() {
394                 let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
395                 msvc_enum_fallback(
396                     ty_and_layout,
397                     &|output, visited| {
398                         push_closure_or_generator_name(tcx, def_id, substs, true, output, visited);
399                     },
400                     output,
401                     visited,
402                 );
403             } else {
404                 push_closure_or_generator_name(tcx, def_id, substs, qualified, output, visited);
405             }
406         }
407         // Type parameters from polymorphized functions.
408         ty::Param(_) => {
409             write!(output, "{:?}", t).unwrap();
410         }
411         ty::Error(_)
412         | ty::Infer(_)
413         | ty::Placeholder(..)
414         | ty::Projection(..)
415         | ty::Bound(..)
416         | ty::Opaque(..)
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_str("_");
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 }