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