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