1use std::fmt::Write;
15
16use rustc_abi::Integer;
17use rustc_data_structures::fx::FxHashSet;
18use rustc_data_structures::stable_hash::{StableHash, StableHasher};
19use rustc_hashes::Hash64;
20use rustc_hir::def_id::DefId;
21use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
22use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability};
23use rustc_middle::bug;
24use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
25use rustc_middle::ty::{
26 self, ExistentialProjection, GenericArgKind, GenericArgsRef, Ty, TyCtxt, Unnormalized,
27};
28use smallvec::SmallVec;
29
30use crate::debuginfo::wants_c_like_enum_debuginfo;
31
32pub fn compute_debuginfo_type_name<'tcx>(
37 tcx: TyCtxt<'tcx>,
38 t: Ty<'tcx>,
39 qualified: bool,
40) -> String {
41 let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
42
43 let mut result = String::with_capacity(64);
44 let mut visited = FxHashSet::default();
45 push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
46 result
47}
48
49fn push_debuginfo_type_name<'tcx>(
52 tcx: TyCtxt<'tcx>,
53 t: Ty<'tcx>,
54 qualified: bool,
55 output: &mut String,
56 visited: &mut FxHashSet<Ty<'tcx>>,
57) {
58 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
61
62 match *t.kind() {
63 ty::Bool => output.push_str("bool"),
64 ty::Char => output.push_str("char"),
65 ty::Str => {
66 if cpp_like_debuginfo {
67 output.push_str("str$")
68 } else {
69 output.push_str("str")
70 }
71 }
72 ty::Never => {
73 if cpp_like_debuginfo {
74 output.push_str("never$");
75 } else {
76 output.push('!');
77 }
78 }
79 ty::Int(int_ty) => output.push_str(int_ty.name_str()),
80 ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
81 ty::Float(float_ty) => output.push_str(float_ty.name_str()),
82 ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
83 ty::Adt(def, args) => {
84 let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
86 match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)) {
87 Ok(layout) => {
88 if !wants_c_like_enum_debuginfo(tcx, layout) {
89 Some(layout)
90 } else {
91 None
94 }
95 }
96 Err(e) => {
97 tcx.dcx().fatal(e.to_string());
101 }
102 }
103 } else {
104 None
106 };
107
108 if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
109 msvc_enum_fallback(
110 tcx,
111 ty_and_layout,
112 &|output, visited| {
113 push_item_name(tcx, def.did(), true, output);
114 push_generic_args_internal(tcx, args, output, visited);
115 },
116 output,
117 visited,
118 );
119 } else {
120 push_item_name(tcx, def.did(), qualified, output);
121 push_generic_args_internal(tcx, args, output, visited);
122 }
123 }
124 ty::Tuple(component_types) => {
125 if cpp_like_debuginfo {
126 output.push_str("tuple$<");
127 } else {
128 output.push('(');
129 }
130
131 for component_type in component_types {
132 push_debuginfo_type_name(tcx, component_type, true, output, visited);
133 push_arg_separator(cpp_like_debuginfo, output);
134 }
135 if !component_types.is_empty() {
136 pop_arg_separator(output);
137 }
138
139 if cpp_like_debuginfo {
140 push_close_angle_bracket(cpp_like_debuginfo, output);
141 } else {
142 output.push(')');
143 }
144 }
145 ty::RawPtr(inner_type, mutbl) => {
146 if cpp_like_debuginfo {
147 match mutbl {
148 Mutability::Not => output.push_str("ptr_const$<"),
149 Mutability::Mut => output.push_str("ptr_mut$<"),
150 }
151 } else {
152 output.push('*');
153 match mutbl {
154 Mutability::Not => output.push_str("const "),
155 Mutability::Mut => output.push_str("mut "),
156 }
157 }
158
159 push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
160
161 if cpp_like_debuginfo {
162 push_close_angle_bracket(cpp_like_debuginfo, output);
163 }
164 }
165 ty::Ref(_, inner_type, mutbl) => {
166 if cpp_like_debuginfo {
167 match mutbl {
168 Mutability::Not => output.push_str("ref$<"),
169 Mutability::Mut => output.push_str("ref_mut$<"),
170 }
171 } else {
172 output.push('&');
173 output.push_str(mutbl.prefix_str());
174 }
175
176 push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
177
178 if cpp_like_debuginfo {
179 push_close_angle_bracket(cpp_like_debuginfo, output);
180 }
181 }
182 ty::Array(inner_type, len) => {
183 if cpp_like_debuginfo {
184 output.push_str("array$<");
185 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
186 match len.kind() {
187 ty::ConstKind::Param(param) => output.write_fmt(format_args!(",{0}>", param.name))write!(output, ",{}>", param.name).unwrap(),
188 _ => output.write_fmt(format_args!(",{0}>",
len.try_to_target_usize(tcx).expect("expected monomorphic const in codegen")))write!(
189 output,
190 ",{}>",
191 len.try_to_target_usize(tcx)
192 .expect("expected monomorphic const in codegen")
193 )
194 .unwrap(),
195 }
196 } else {
197 output.push('[');
198 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
199 match len.kind() {
200 ty::ConstKind::Param(param) => output.write_fmt(format_args!("; {0}]", param.name))write!(output, "; {}]", param.name).unwrap(),
201 _ => output.write_fmt(format_args!("; {0}]",
len.try_to_target_usize(tcx).expect("expected monomorphic const in codegen")))write!(
202 output,
203 "; {}]",
204 len.try_to_target_usize(tcx)
205 .expect("expected monomorphic const in codegen")
206 )
207 .unwrap(),
208 }
209 }
210 }
211 ty::Pat(inner_type, pat) => {
212 if cpp_like_debuginfo {
213 output.push_str("pat$<");
214 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
215 output.write_fmt(format_args!(",{0:?}>", pat))write!(output, ",{:?}>", pat).unwrap();
217 } else {
218 output.write_fmt(format_args!("{0:?}", t))write!(output, "{:?}", t).unwrap();
219 }
220 }
221 ty::Slice(inner_type) => {
222 if cpp_like_debuginfo {
223 output.push_str("slice2$<");
224 } else {
225 output.push('[');
226 }
227
228 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
229
230 if cpp_like_debuginfo {
231 push_close_angle_bracket(cpp_like_debuginfo, output);
232 } else {
233 output.push(']');
234 }
235 }
236 ty::Dynamic(trait_data, ..) => {
237 let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
238
239 let has_enclosing_parens = if cpp_like_debuginfo {
240 output.push_str("dyn$<");
241 false
242 } else if trait_data.len() > 1 && auto_traits.len() != 0 {
243 output.push_str("(dyn ");
245 true
246 } else {
247 output.push_str("dyn ");
248 false
249 };
250
251 if let Some(principal) = trait_data.principal() {
252 let principal = tcx.normalize_erasing_late_bound_regions(
253 ty::TypingEnv::fully_monomorphized(),
254 principal,
255 );
256 push_item_name(tcx, principal.def_id, qualified, output);
257 let principal_has_generic_params =
258 push_generic_args_internal(tcx, principal.args, output, visited);
259
260 let projection_bounds: SmallVec<[_; 4]> = trait_data
261 .projection_bounds()
262 .map(|bound| {
263 let ExistentialProjection { def_id: item_def_id, term, .. } =
264 tcx.instantiate_bound_regions_with_erased(bound);
265 (item_def_id, term)
266 })
267 .collect();
268
269 if !projection_bounds.is_empty() {
270 if principal_has_generic_params {
271 pop_close_angle_bracket(output);
274 push_arg_separator(cpp_like_debuginfo, output);
277 } else {
278 output.push('<');
281 }
282
283 for (item_def_id, term) in projection_bounds {
284 if cpp_like_debuginfo {
285 output.push_str("assoc$<");
286 push_item_name(tcx, item_def_id, false, output);
287 push_arg_separator(cpp_like_debuginfo, output);
288 push_debuginfo_term_name(tcx, term, true, output, visited);
289 push_close_angle_bracket(cpp_like_debuginfo, output);
290 } else {
291 push_item_name(tcx, item_def_id, false, output);
292 output.push('=');
293 push_debuginfo_term_name(tcx, term, true, output, visited);
294 }
295 push_arg_separator(cpp_like_debuginfo, output);
296 }
297
298 pop_arg_separator(output);
299 push_close_angle_bracket(cpp_like_debuginfo, output);
300 }
301
302 if auto_traits.len() != 0 {
303 push_auto_trait_separator(cpp_like_debuginfo, output);
304 }
305 }
306
307 if auto_traits.len() != 0 {
308 let mut auto_traits: SmallVec<[String; 4]> = auto_traits
309 .into_iter()
310 .map(|def_id| {
311 let mut name = String::with_capacity(20);
312 push_item_name(tcx, def_id, true, &mut name);
313 name
314 })
315 .collect();
316 auto_traits.sort_unstable();
317
318 for auto_trait in auto_traits {
319 output.push_str(&auto_trait);
320 push_auto_trait_separator(cpp_like_debuginfo, output);
321 }
322
323 pop_auto_trait_separator(output);
324 }
325
326 if cpp_like_debuginfo {
327 push_close_angle_bracket(cpp_like_debuginfo, output);
328 } else if has_enclosing_parens {
329 output.push(')');
330 }
331 }
332 ty::FnDef(..) | ty::FnPtr(..) => {
333 if !visited.insert(t) {
347 output.push_str(if cpp_like_debuginfo {
348 "recursive_type$"
349 } else {
350 "<recursive_type>"
351 });
352 return;
353 }
354
355 let sig = tcx.normalize_erasing_late_bound_regions(
356 ty::TypingEnv::fully_monomorphized(),
357 t.fn_sig(tcx),
358 );
359
360 if cpp_like_debuginfo {
361 if sig.output().is_unit() {
363 output.push_str("void");
364 } else {
365 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
366 }
367 output.push_str(" (*)(");
368 } else {
369 output.push_str(sig.safety().prefix_str());
370
371 if sig.abi() != rustc_abi::ExternAbi::Rust {
372 let _ = output.write_fmt(format_args!("extern {0} ", sig.abi()))write!(output, "extern {} ", sig.abi());
373 }
374
375 output.push_str("fn(");
376 }
377
378 if !sig.inputs().is_empty() {
380 for ¶meter_type in sig.inputs() {
381 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
382 push_arg_separator(cpp_like_debuginfo, output);
383 }
384 pop_arg_separator(output);
385 }
386
387 if sig.c_variadic() {
388 if !sig.inputs().is_empty() {
389 output.push_str(", ...");
390 } else {
391 output.push_str("...");
392 }
393 }
394
395 output.push(')');
396
397 if !cpp_like_debuginfo && !sig.output().is_unit() {
398 output.push_str(" -> ");
399 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
400 }
401
402 visited.remove(&t);
412 }
413 ty::Closure(def_id, args)
414 | ty::CoroutineClosure(def_id, args)
415 | ty::Coroutine(def_id, args, ..) => {
416 if cpp_like_debuginfo && t.is_coroutine() {
421 let ty_and_layout =
422 tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)).unwrap();
423 msvc_enum_fallback(
424 tcx,
425 ty_and_layout,
426 &|output, visited| {
427 push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
428 },
429 output,
430 visited,
431 );
432 } else {
433 push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
434 }
435 }
436 ty::UnsafeBinder(inner) => {
437 if cpp_like_debuginfo {
438 output.push_str("unsafe$<");
439 } else {
440 output.push_str("unsafe ");
441 }
442
443 push_debuginfo_type_name(tcx, inner.skip_binder(), qualified, output, visited);
444
445 if cpp_like_debuginfo {
446 push_close_angle_bracket(cpp_like_debuginfo, output);
447 }
448 }
449 ty::Param(_)
450 | ty::Error(_)
451 | ty::Infer(_)
452 | ty::Placeholder(..)
453 | ty::Alias(..)
454 | ty::Bound(..)
455 | ty::CoroutineWitness(..) => {
456 ::rustc_middle::util::bug::bug_fmt(format_args!("debuginfo: Trying to create type name for unexpected type: {0:?}",
t));bug!(
457 "debuginfo: Trying to create type name for \
458 unexpected type: {:?}",
459 t
460 );
461 }
462 }
463
464 fn msvc_enum_fallback<'tcx>(
469 tcx: TyCtxt<'tcx>,
470 ty_and_layout: TyAndLayout<'tcx>,
471 push_inner: &dyn Fn(&mut String, &mut FxHashSet<Ty<'tcx>>),
472 output: &mut String,
473 visited: &mut FxHashSet<Ty<'tcx>>,
474 ) {
475 if !!wants_c_like_enum_debuginfo(tcx, ty_and_layout) {
::core::panicking::panic("assertion failed: !wants_c_like_enum_debuginfo(tcx, ty_and_layout)")
};assert!(!wants_c_like_enum_debuginfo(tcx, ty_and_layout));
476 output.push_str("enum2$<");
477 push_inner(output, visited);
478 push_close_angle_bracket(true, output);
479 }
480
481 const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
482
483 fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
484 if cpp_like_debuginfo {
485 push_arg_separator(cpp_like_debuginfo, output);
486 } else {
487 output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
488 }
489 }
490
491 fn pop_auto_trait_separator(output: &mut String) {
492 if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) {
493 output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len());
494 } else {
495 pop_arg_separator(output);
496 }
497 }
498}
499
500pub enum VTableNameKind {
501 GlobalVariable,
503 Type,
505}
506
507pub fn compute_debuginfo_vtable_name<'tcx>(
521 tcx: TyCtxt<'tcx>,
522 t: Ty<'tcx>,
523 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
524 kind: VTableNameKind,
525) -> String {
526 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
527
528 let mut vtable_name = String::with_capacity(64);
529
530 if cpp_like_debuginfo {
531 vtable_name.push_str("impl$<");
532 } else {
533 vtable_name.push('<');
534 }
535
536 let mut visited = FxHashSet::default();
537 push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
538
539 if cpp_like_debuginfo {
540 vtable_name.push_str(", ");
541 } else {
542 vtable_name.push_str(" as ");
543 }
544
545 if let Some(trait_ref) = trait_ref {
546 let trait_ref = tcx.normalize_erasing_regions(
547 ty::TypingEnv::fully_monomorphized(),
548 Unnormalized::new_wip(trait_ref),
549 );
550 push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
551 visited.clear();
552 push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
553 } else {
554 vtable_name.push('_');
555 }
556
557 push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
558
559 let suffix = match (cpp_like_debuginfo, kind) {
560 (true, VTableNameKind::GlobalVariable) => "::vtable$",
561 (false, VTableNameKind::GlobalVariable) => "::{vtable}",
562 (true, VTableNameKind::Type) => "::vtable_type$",
563 (false, VTableNameKind::Type) => "::{vtable_type}",
564 };
565
566 vtable_name.reserve_exact(suffix.len());
567 vtable_name.push_str(suffix);
568
569 vtable_name
570}
571
572pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
573 let def_key = tcx.def_key(def_id);
574 if qualified && let Some(parent) = def_key.parent {
575 push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
576 output.push_str("::");
577 }
578
579 push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
580}
581
582fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
583 use CoroutineDesugaring::*;
584 use CoroutineKind::*;
585 use CoroutineSource::*;
586 match coroutine_kind {
587 Some(Desugared(Gen, Block)) => "gen_block",
588 Some(Desugared(Gen, Closure)) => "gen_closure",
589 Some(Desugared(Gen, Fn)) => "gen_fn",
590 Some(Desugared(Async, Block)) => "async_block",
591 Some(Desugared(Async, Closure)) => "async_closure",
592 Some(Desugared(Async, Fn)) => "async_fn",
593 Some(Desugared(AsyncGen, Block)) => "async_gen_block",
594 Some(Desugared(AsyncGen, Closure)) => "async_gen_closure",
595 Some(Desugared(AsyncGen, Fn)) => "async_gen_fn",
596 Some(Coroutine(_)) => "coroutine",
597 None => "closure",
598 }
599}
600
601fn push_disambiguated_special_name(
602 label: &str,
603 disambiguator: u32,
604 cpp_like_debuginfo: bool,
605 output: &mut String,
606) {
607 if cpp_like_debuginfo {
608 output.write_fmt(format_args!("{0}${1}", label, disambiguator))write!(output, "{label}${disambiguator}").unwrap();
609 } else {
610 output.write_fmt(format_args!("{{{0}#{1}}}", label, disambiguator))write!(output, "{{{label}#{disambiguator}}}").unwrap();
611 }
612}
613
614fn push_unqualified_item_name(
615 tcx: TyCtxt<'_>,
616 def_id: DefId,
617 disambiguated_data: DisambiguatedDefPathData,
618 output: &mut String,
619) {
620 match disambiguated_data.data {
621 DefPathData::CrateRoot => {
622 output.push_str(tcx.crate_name(def_id.krate).as_str());
623 }
624 DefPathData::Closure => {
625 let label = coroutine_kind_label(tcx.coroutine_kind(def_id));
626
627 push_disambiguated_special_name(
628 label,
629 disambiguated_data.disambiguator,
630 cpp_like_debuginfo(tcx),
631 output,
632 );
633 }
634 _ => match disambiguated_data.data.name() {
635 DefPathDataName::Named(name) => {
636 output.push_str(name.as_str());
637 }
638 DefPathDataName::Anon { namespace } => {
639 push_disambiguated_special_name(
640 namespace.as_str(),
641 disambiguated_data.disambiguator,
642 cpp_like_debuginfo(tcx),
643 output,
644 );
645 }
646 },
647 };
648}
649
650pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) {
651 let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
652 let mut visited = FxHashSet::default();
653 push_generic_args_internal(tcx, args, output, &mut visited);
654}
655
656fn push_generic_args_internal<'tcx>(
657 tcx: TyCtxt<'tcx>,
658 args: GenericArgsRef<'tcx>,
659 output: &mut String,
660 visited: &mut FxHashSet<Ty<'tcx>>,
661) -> bool {
662 tcx.assert_fully_normalized(ty::TypingEnv::fully_monomorphized(), args);
663 let mut args = args.non_erasable_generics().peekable();
664 if args.peek().is_none() {
665 return false;
666 }
667 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
668
669 output.push('<');
670
671 for arg in args {
672 match arg {
673 GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited),
674 GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
675 other => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected non-erasable generic: {0:?}",
other))bug!("Unexpected non-erasable generic: {:?}", other),
676 }
677
678 push_arg_separator(cpp_like_debuginfo, output);
679 }
680 pop_arg_separator(output);
681 push_close_angle_bracket(cpp_like_debuginfo, output);
682
683 true
684}
685
686fn push_debuginfo_term_name<'tcx>(
687 tcx: TyCtxt<'tcx>,
688 term: ty::Term<'tcx>,
689 qualified: bool,
690 output: &mut String,
691 visited: &mut FxHashSet<Ty<'tcx>>,
692) {
693 match term.kind() {
694 ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited),
695 ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
696 }
697}
698
699fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
700 match ct.kind() {
701 ty::ConstKind::Param(param) => {
702 output.write_fmt(format_args!("{0}", param.name))write!(output, "{}", param.name)
703 }
704 ty::ConstKind::Value(cv) => {
705 match cv.ty.kind() {
706 ty::Int(ity) => {
707 let bits = cv
708 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
709 .expect("expected monomorphic const in codegen");
710 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
711 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
712 }
713 ty::Uint(_) => {
714 let val = cv
715 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
716 .expect("expected monomorphic const in codegen");
717 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
718 }
719 ty::Bool => {
720 let val = cv.try_to_bool().expect("expected monomorphic const in codegen");
721 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
722 }
723 _ => {
724 let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
731 let mut hasher = StableHasher::new();
732 hcx.while_hashing_spans(false, |hcx| cv.stable_hash(hcx, &mut hasher));
733 hasher.finish::<Hash64>()
734 });
735
736 if cpp_like_debuginfo(tcx) {
737 output.write_fmt(format_args!("CONST${0:x}", hash_short))write!(output, "CONST${hash_short:x}")
738 } else {
739 output.write_fmt(format_args!("{{CONST#{0:x}}}", hash_short))write!(output, "{{CONST#{hash_short:x}}}")
740 }
741 }
742 }
743 }
744 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Invalid `Const` during codegen: {0:?}",
ct))bug!("Invalid `Const` during codegen: {:?}", ct),
745 }
746 .unwrap();
747}
748
749fn push_closure_or_coroutine_name<'tcx>(
750 tcx: TyCtxt<'tcx>,
751 def_id: DefId,
752 args: GenericArgsRef<'tcx>,
753 qualified: bool,
754 output: &mut String,
755 visited: &mut FxHashSet<Ty<'tcx>>,
756) {
757 let def_key = tcx.def_key(def_id);
760 let coroutine_kind = tcx.coroutine_kind(def_id);
761
762 if qualified {
763 let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
764 push_item_name(tcx, parent_def_id, true, output);
765 output.push_str("::");
766 }
767
768 let mut label = String::with_capacity(20);
769 (&mut label).write_fmt(format_args!("{0}_env",
coroutine_kind_label(coroutine_kind)))write!(&mut label, "{}_env", coroutine_kind_label(coroutine_kind)).unwrap();
770
771 push_disambiguated_special_name(
772 &label,
773 def_key.disambiguated_data.disambiguator,
774 cpp_like_debuginfo(tcx),
775 output,
776 );
777
778 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
784 let generics = tcx.generics_of(enclosing_fn_def_id);
785
786 let args = args.truncate_to(tcx, generics);
791 push_generic_args_internal(tcx, args, output, visited);
792}
793
794fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
795 if cpp_like_debuginfo && output.ends_with('>') {
798 output.push(' ')
799 };
800
801 output.push('>');
802}
803
804fn pop_close_angle_bracket(output: &mut String) {
805 if !output.ends_with('>') {
{
::core::panicking::panic_fmt(format_args!("\'output\' does not end with \'>\': {0}",
output));
}
};assert!(output.ends_with('>'), "'output' does not end with '>': {output}");
806 output.pop();
807 if output.ends_with(' ') {
808 output.pop();
809 }
810}
811
812fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
813 if cpp_like_debuginfo {
817 output.push(',');
818 } else {
819 output.push_str(", ");
820 };
821}
822
823fn pop_arg_separator(output: &mut String) {
824 if output.ends_with(' ') {
825 output.pop();
826 }
827
828 if !output.ends_with(',') {
::core::panicking::panic("assertion failed: output.ends_with(\',\')")
};assert!(output.ends_with(','));
829
830 output.pop();
831}
832
833pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
835 tcx.sess.target.is_like_msvc
836}