1use std::fmt::Write;
15
16use rustc_abi::Integer;
17use rustc_data_structures::fx::FxHashSet;
18use rustc_data_structures::stable_hasher::{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() {
379 for ¶meter_type in sig.inputs() {
380 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
381 push_arg_separator(cpp_like_debuginfo, output);
382 }
383 pop_arg_separator(output);
384 }
385
386 if sig.c_variadic() {
387 if !sig.inputs().is_empty() {
388 output.push_str(", ...");
389 } else {
390 output.push_str("...");
391 }
392 }
393
394 output.push(')');
395
396 if !cpp_like_debuginfo && !sig.output().is_unit() {
397 output.push_str(" -> ");
398 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
399 }
400
401 visited.remove(&t);
411 }
412 ty::Closure(def_id, args)
413 | ty::CoroutineClosure(def_id, args)
414 | ty::Coroutine(def_id, args, ..) => {
415 if cpp_like_debuginfo && t.is_coroutine() {
420 let ty_and_layout =
421 tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)).unwrap();
422 msvc_enum_fallback(
423 tcx,
424 ty_and_layout,
425 &|output, visited| {
426 push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
427 },
428 output,
429 visited,
430 );
431 } else {
432 push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
433 }
434 }
435 ty::UnsafeBinder(inner) => {
436 if cpp_like_debuginfo {
437 output.push_str("unsafe$<");
438 } else {
439 output.push_str("unsafe ");
440 }
441
442 push_debuginfo_type_name(tcx, inner.skip_binder(), qualified, output, visited);
443
444 if cpp_like_debuginfo {
445 push_close_angle_bracket(cpp_like_debuginfo, output);
446 }
447 }
448 ty::Param(_)
449 | ty::Error(_)
450 | ty::Infer(_)
451 | ty::Placeholder(..)
452 | ty::Alias(..)
453 | ty::Bound(..)
454 | ty::CoroutineWitness(..) => {
455 ::rustc_middle::util::bug::bug_fmt(format_args!("debuginfo: Trying to create type name for unexpected type: {0:?}",
t));bug!(
456 "debuginfo: Trying to create type name for \
457 unexpected type: {:?}",
458 t
459 );
460 }
461 }
462
463 fn msvc_enum_fallback<'tcx>(
468 tcx: TyCtxt<'tcx>,
469 ty_and_layout: TyAndLayout<'tcx>,
470 push_inner: &dyn Fn(&mut String, &mut FxHashSet<Ty<'tcx>>),
471 output: &mut String,
472 visited: &mut FxHashSet<Ty<'tcx>>,
473 ) {
474 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));
475 output.push_str("enum2$<");
476 push_inner(output, visited);
477 push_close_angle_bracket(true, output);
478 }
479
480 const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
481
482 fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
483 if cpp_like_debuginfo {
484 push_arg_separator(cpp_like_debuginfo, output);
485 } else {
486 output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
487 }
488 }
489
490 fn pop_auto_trait_separator(output: &mut String) {
491 if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) {
492 output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len());
493 } else {
494 pop_arg_separator(output);
495 }
496 }
497}
498
499pub enum VTableNameKind {
500 GlobalVariable,
502 Type,
504}
505
506pub fn compute_debuginfo_vtable_name<'tcx>(
520 tcx: TyCtxt<'tcx>,
521 t: Ty<'tcx>,
522 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
523 kind: VTableNameKind,
524) -> String {
525 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
526
527 let mut vtable_name = String::with_capacity(64);
528
529 if cpp_like_debuginfo {
530 vtable_name.push_str("impl$<");
531 } else {
532 vtable_name.push('<');
533 }
534
535 let mut visited = FxHashSet::default();
536 push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
537
538 if cpp_like_debuginfo {
539 vtable_name.push_str(", ");
540 } else {
541 vtable_name.push_str(" as ");
542 }
543
544 if let Some(trait_ref) = trait_ref {
545 let trait_ref = tcx.normalize_erasing_regions(
546 ty::TypingEnv::fully_monomorphized(),
547 Unnormalized::new_wip(trait_ref),
548 );
549 push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
550 visited.clear();
551 push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
552 } else {
553 vtable_name.push('_');
554 }
555
556 push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
557
558 let suffix = match (cpp_like_debuginfo, kind) {
559 (true, VTableNameKind::GlobalVariable) => "::vtable$",
560 (false, VTableNameKind::GlobalVariable) => "::{vtable}",
561 (true, VTableNameKind::Type) => "::vtable_type$",
562 (false, VTableNameKind::Type) => "::{vtable_type}",
563 };
564
565 vtable_name.reserve_exact(suffix.len());
566 vtable_name.push_str(suffix);
567
568 vtable_name
569}
570
571pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
572 let def_key = tcx.def_key(def_id);
573 if qualified && let Some(parent) = def_key.parent {
574 push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
575 output.push_str("::");
576 }
577
578 push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
579}
580
581fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
582 use CoroutineDesugaring::*;
583 use CoroutineKind::*;
584 use CoroutineSource::*;
585 match coroutine_kind {
586 Some(Desugared(Gen, Block)) => "gen_block",
587 Some(Desugared(Gen, Closure)) => "gen_closure",
588 Some(Desugared(Gen, Fn)) => "gen_fn",
589 Some(Desugared(Async, Block)) => "async_block",
590 Some(Desugared(Async, Closure)) => "async_closure",
591 Some(Desugared(Async, Fn)) => "async_fn",
592 Some(Desugared(AsyncGen, Block)) => "async_gen_block",
593 Some(Desugared(AsyncGen, Closure)) => "async_gen_closure",
594 Some(Desugared(AsyncGen, Fn)) => "async_gen_fn",
595 Some(Coroutine(_)) => "coroutine",
596 None => "closure",
597 }
598}
599
600fn push_disambiguated_special_name(
601 label: &str,
602 disambiguator: u32,
603 cpp_like_debuginfo: bool,
604 output: &mut String,
605) {
606 if cpp_like_debuginfo {
607 output.write_fmt(format_args!("{0}${1}", label, disambiguator))write!(output, "{label}${disambiguator}").unwrap();
608 } else {
609 output.write_fmt(format_args!("{{{0}#{1}}}", label, disambiguator))write!(output, "{{{label}#{disambiguator}}}").unwrap();
610 }
611}
612
613fn push_unqualified_item_name(
614 tcx: TyCtxt<'_>,
615 def_id: DefId,
616 disambiguated_data: DisambiguatedDefPathData,
617 output: &mut String,
618) {
619 match disambiguated_data.data {
620 DefPathData::CrateRoot => {
621 output.push_str(tcx.crate_name(def_id.krate).as_str());
622 }
623 DefPathData::Closure => {
624 let label = coroutine_kind_label(tcx.coroutine_kind(def_id));
625
626 push_disambiguated_special_name(
627 label,
628 disambiguated_data.disambiguator,
629 cpp_like_debuginfo(tcx),
630 output,
631 );
632 }
633 _ => match disambiguated_data.data.name() {
634 DefPathDataName::Named(name) => {
635 output.push_str(name.as_str());
636 }
637 DefPathDataName::Anon { namespace } => {
638 push_disambiguated_special_name(
639 namespace.as_str(),
640 disambiguated_data.disambiguator,
641 cpp_like_debuginfo(tcx),
642 output,
643 );
644 }
645 },
646 };
647}
648
649pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) {
650 let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
651 let mut visited = FxHashSet::default();
652 push_generic_args_internal(tcx, args, output, &mut visited);
653}
654
655fn push_generic_args_internal<'tcx>(
656 tcx: TyCtxt<'tcx>,
657 args: GenericArgsRef<'tcx>,
658 output: &mut String,
659 visited: &mut FxHashSet<Ty<'tcx>>,
660) -> bool {
661 match (&args,
&tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(),
Unnormalized::new_wip(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!(
662 args,
663 tcx.normalize_erasing_regions(
664 ty::TypingEnv::fully_monomorphized(),
665 Unnormalized::new_wip(args)
666 )
667 );
668 let mut args = args.non_erasable_generics().peekable();
669 if args.peek().is_none() {
670 return false;
671 }
672 let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
673
674 output.push('<');
675
676 for arg in args {
677 match arg {
678 GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited),
679 GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
680 other => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected non-erasable generic: {0:?}",
other))bug!("Unexpected non-erasable generic: {:?}", other),
681 }
682
683 push_arg_separator(cpp_like_debuginfo, output);
684 }
685 pop_arg_separator(output);
686 push_close_angle_bracket(cpp_like_debuginfo, output);
687
688 true
689}
690
691fn push_debuginfo_term_name<'tcx>(
692 tcx: TyCtxt<'tcx>,
693 term: ty::Term<'tcx>,
694 qualified: bool,
695 output: &mut String,
696 visited: &mut FxHashSet<Ty<'tcx>>,
697) {
698 match term.kind() {
699 ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited),
700 ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
701 }
702}
703
704fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
705 match ct.kind() {
706 ty::ConstKind::Param(param) => {
707 output.write_fmt(format_args!("{0}", param.name))write!(output, "{}", param.name)
708 }
709 ty::ConstKind::Value(cv) => {
710 match cv.ty.kind() {
711 ty::Int(ity) => {
712 let bits = cv
713 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
714 .expect("expected monomorphic const in codegen");
715 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
716 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
717 }
718 ty::Uint(_) => {
719 let val = cv
720 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
721 .expect("expected monomorphic const in codegen");
722 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
723 }
724 ty::Bool => {
725 let val = cv.try_to_bool().expect("expected monomorphic const in codegen");
726 output.write_fmt(format_args!("{0}", val))write!(output, "{val}")
727 }
728 _ => {
729 let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
736 let mut hasher = StableHasher::new();
737 hcx.while_hashing_spans(false, |hcx| cv.stable_hash(hcx, &mut hasher));
738 hasher.finish::<Hash64>()
739 });
740
741 if cpp_like_debuginfo(tcx) {
742 output.write_fmt(format_args!("CONST${0:x}", hash_short))write!(output, "CONST${hash_short:x}")
743 } else {
744 output.write_fmt(format_args!("{{CONST#{0:x}}}", hash_short))write!(output, "{{CONST#{hash_short:x}}}")
745 }
746 }
747 }
748 }
749 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Invalid `Const` during codegen: {0:?}",
ct))bug!("Invalid `Const` during codegen: {:?}", ct),
750 }
751 .unwrap();
752}
753
754fn push_closure_or_coroutine_name<'tcx>(
755 tcx: TyCtxt<'tcx>,
756 def_id: DefId,
757 args: GenericArgsRef<'tcx>,
758 qualified: bool,
759 output: &mut String,
760 visited: &mut FxHashSet<Ty<'tcx>>,
761) {
762 let def_key = tcx.def_key(def_id);
765 let coroutine_kind = tcx.coroutine_kind(def_id);
766
767 if qualified {
768 let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
769 push_item_name(tcx, parent_def_id, true, output);
770 output.push_str("::");
771 }
772
773 let mut label = String::with_capacity(20);
774 (&mut label).write_fmt(format_args!("{0}_env",
coroutine_kind_label(coroutine_kind)))write!(&mut label, "{}_env", coroutine_kind_label(coroutine_kind)).unwrap();
775
776 push_disambiguated_special_name(
777 &label,
778 def_key.disambiguated_data.disambiguator,
779 cpp_like_debuginfo(tcx),
780 output,
781 );
782
783 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
789 let generics = tcx.generics_of(enclosing_fn_def_id);
790
791 let args = args.truncate_to(tcx, generics);
796 push_generic_args_internal(tcx, args, output, visited);
797}
798
799fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
800 if cpp_like_debuginfo && output.ends_with('>') {
803 output.push(' ')
804 };
805
806 output.push('>');
807}
808
809fn pop_close_angle_bracket(output: &mut String) {
810 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}");
811 output.pop();
812 if output.ends_with(' ') {
813 output.pop();
814 }
815}
816
817fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
818 if cpp_like_debuginfo {
822 output.push(',');
823 } else {
824 output.push_str(", ");
825 };
826}
827
828fn pop_arg_separator(output: &mut String) {
829 if output.ends_with(' ') {
830 output.pop();
831 }
832
833 if !output.ends_with(',') {
::core::panicking::panic("assertion failed: output.ends_with(\',\')")
};assert!(output.ends_with(','));
834
835 output.pop();
836}
837
838pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
840 tcx.sess.target.is_like_msvc
841}