1use std::fmt::{self, Write};
2use std::mem;
3
4use rustc_data_structures::stable_hash::{StableHash, StableHasher};
5use rustc_hashes::Hash64;
6use rustc_hir::def_id::{CrateNum, DefId};
7use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
8use rustc_macros::StableHash;
9use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
10use rustc_middle::ty::{
11 self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
12 Unnormalized,
13};
14use rustc_span::bug;
15use tracing::debug;
16
17pub(super) fn mangle<'tcx>(
18 tcx: TyCtxt<'tcx>,
19 instance: Instance<'tcx>,
20 instantiating_crate: Option<CrateNum>,
21) -> String {
22 let def_id = instance.def_id();
23
24 let mut ty_def_id = def_id;
29 let instance_ty;
30 loop {
31 let key = tcx.def_key(ty_def_id);
32 match key.disambiguated_data.data {
33 DefPathData::TypeNs(_)
34 | DefPathData::ValueNs(_)
35 | DefPathData::Closure
36 | DefPathData::SyntheticCoroutineBody => {
37 instance_ty = tcx.type_of(ty_def_id).instantiate_identity().skip_norm_wip();
38 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_symbol_mangling/src/legacy.rs:38",
"rustc_symbol_mangling::legacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_symbol_mangling/src/legacy.rs"),
::tracing_core::__macro_support::Option::Some(38u32),
::tracing_core::__macro_support::Option::Some("rustc_symbol_mangling::legacy"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("instance_ty")
}> =
::tracing::__macro_support::FieldName::new("instance_ty");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instance_ty)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?instance_ty);
39 break;
40 }
41 DefPathData::GlobalAsm => {
42 instance_ty = tcx.types.unit;
44 break;
45 }
46 _ => {
47 ty_def_id.index = key.parent.unwrap_or_else(|| {
51 ::rustc_span::macros::bug_impl(None,
format_args!("finding type for {0:?}, encountered def-id {1:?} with no parent",
def_id, ty_def_id), Location::caller());bug!(
52 "finding type for {:?}, encountered def-id {:?} with no \
53 parent",
54 def_id,
55 ty_def_id
56 );
57 });
58 }
59 }
60 }
61
62 let instance_ty = tcx.erase_and_anonymize_regions(instance_ty);
65
66 let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
67
68 let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false };
69
70 p.print_def_path(
71 def_id,
72 if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, _))
73 | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, _))
74 | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_, _, _)) = instance.def
75 {
76 instance.args
78 } else if let ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, ty)) = instance.def {
79 let ty::Coroutine(_, cor_args) = ty.kind() else {
80 ::rustc_span::macros::bug_impl(None, format_args!("impossible case reached"),
Location::caller());bug!();
81 };
82 let drop_ty = cor_args.first().unwrap().expect_ty();
83 tcx.mk_args(&[GenericArg::from(drop_ty)])
84 } else {
85 ty::GenericArgs::empty()
86 },
87 )
88 .unwrap();
89
90 match instance.def {
91 ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) => {
92 p.write_str("{{tls-shim}}").unwrap();
93 }
94 ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) => {
95 p.write_str("{{vtable-shim}}").unwrap();
96 }
97 ty::InstanceKind::Shim(ty::ShimKind::Reify(_, reason)) => {
98 p.write_str("{{reify-shim").unwrap();
99 match reason {
100 Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(),
101 Some(ReifyReason::Vtable) => p.write_str("-vtable").unwrap(),
102 None => (),
103 }
104 p.write_str("}}").unwrap();
105 }
106 ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure {
109 receiver_by_ref,
110 ..
111 }) => {
112 p.write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" })
113 .unwrap();
114 }
115 _ => {}
116 }
117
118 if let ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) = instance.def {
119 let _ = p.write_str("{{drop-shim}}");
120 }
121
122 p.path.finish(hash)
123}
124
125fn get_symbol_hash<'tcx>(
126 tcx: TyCtxt<'tcx>,
127
128 instance: Instance<'tcx>,
130
131 item_type: Ty<'tcx>,
136
137 instantiating_crate: Option<CrateNum>,
138) -> Hash64 {
139 let def_id = instance.def_id();
140 let args = instance.args;
141 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_symbol_mangling/src/legacy.rs:141",
"rustc_symbol_mangling::legacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/1c3a6506966e21845b31de0b075d2527660db132/compiler/rustc_symbol_mangling/src/legacy.rs"),
::tracing_core::__macro_support::Option::Some(141u32),
::tracing_core::__macro_support::Option::Some("rustc_symbol_mangling::legacy"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("get_symbol_hash(def_id={0:?}, parameters={1:?})",
def_id, args) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, args);
142
143 tcx.with_stable_hashing_context(|mut hcx| {
144 let mut hasher = StableHasher::new();
145
146 tcx.def_path_hash(def_id).stable_hash(&mut hcx, &mut hasher);
150
151 if !!item_type.has_erasable_regions() {
::core::panicking::panic("assertion failed: !item_type.has_erasable_regions()")
};assert!(!item_type.has_erasable_regions());
155 hcx.while_hashing_spans(false, |hcx| {
156 item_type.stable_hash(hcx, &mut hasher);
157
158 if let ty::FnDef(..) = item_type.kind() {
162 item_type.fn_sig(tcx).stable_hash(hcx, &mut hasher);
163 }
164
165 args.stable_hash(hcx, &mut hasher);
167
168 if let Some(instantiating_crate) = instantiating_crate {
169 tcx.stable_crate_id(instantiating_crate).stable_hash(hcx, &mut hasher);
170 }
171
172 #[derive(const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for Tag {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
Tag::Item => 0u8.stable_hash(__hcx, __hasher),
Tag::Intrinsic => 1u8.stable_hash(__hcx, __hasher),
Tag::LlvmIntrinsic => 2u8.stable_hash(__hcx, __hasher),
Tag::Virtual => 3u8.stable_hash(__hcx, __hasher),
Tag::Shim => 4u8.stable_hash(__hcx, __hasher),
}
match *self {
Tag::Item => {}
Tag::Intrinsic => {}
Tag::LlvmIntrinsic => {}
Tag::Virtual => {}
Tag::Shim => {}
}
}
}
};StableHash)]
176 enum Tag {
177 Item,
178 Intrinsic,
179 LlvmIntrinsic,
180 Virtual,
181 Shim,
182 }
183 match instance.def {
184 ty::InstanceKind::Item(_) => Tag::Item,
185 ty::InstanceKind::Intrinsic(_) => Tag::Intrinsic,
186 ty::InstanceKind::LlvmIntrinsic(_) => Tag::LlvmIntrinsic,
187 ty::InstanceKind::Virtual(_, _) => Tag::Virtual,
188 ty::InstanceKind::Shim(_) => Tag::Shim,
189 }
190 .stable_hash(hcx, &mut hasher);
191 });
192
193 hasher.finish::<Hash64>()
195 })
196}
197
198#[derive(#[automatically_derived]impl ::core::fmt::Debug for SymbolPath {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SymbolPath result temp_buf", &self.result, &&self.temp_buf)
}
}Debug)]
212struct SymbolPath {
213 result: String,
214 temp_buf: String,
215}
216
217impl SymbolPath {
218 fn new() -> Self {
219 let mut result =
220 SymbolPath { result: String::with_capacity(64), temp_buf: String::with_capacity(16) };
221 result.result.push_str("_ZN"); result
223 }
224
225 fn finalize_pending_component(&mut self) {
226 if !self.temp_buf.is_empty() {
227 let _ = self.result.write_fmt(format_args!("{0}{1}", self.temp_buf.len(),
self.temp_buf))write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf);
228 self.temp_buf.clear();
229 }
230 }
231
232 fn finish(mut self, hash: Hash64) -> String {
233 self.finalize_pending_component();
234 let _ = self.result.write_fmt(format_args!("17h{0:016x}E", hash))write!(self.result, "17h{hash:016x}E");
236 self.result
237 }
238}
239
240struct LegacySymbolMangler<'tcx> {
241 tcx: TyCtxt<'tcx>,
242 path: SymbolPath,
243
244 keep_within_component: bool,
249}
250
251impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
256 fn tcx(&self) -> TyCtxt<'tcx> {
257 self.tcx
258 }
259
260 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
261 Ok(())
265 }
266
267 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
268 match *ty.kind() {
269 ty::Alias(
271 _,
272 ty::AliasTy {
273 kind: ty::Projection { def_id } | ty::Opaque { def_id }, args, ..
274 },
275 )
276 | ty::Closure(def_id, args)
277 | ty::CoroutineClosure(def_id, args)
278 | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
279
280 ty::FnDef(def_id, args) => self.print_def_path(def_id, args.no_bound_vars().unwrap()),
281
282 ty::Array(ty, size) => {
285 self.write_str("[")?;
286 self.print_type(ty)?;
287 self.write_str("; ")?;
288 if let Some(size) = size.try_to_target_usize(self.tcx()) {
289 self.write_fmt(format_args!("{0}", size))write!(self, "{size}")?
290 } else if let ty::ConstKind::Param(param) = size.kind() {
291 param.print(self)?
292 } else {
293 self.write_str("_")?
294 }
295 self.write_str("]")?;
296 Ok(())
297 }
298
299 ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
300 {
::core::panicking::panic_fmt(format_args!("unexpected inherent projection"));
}panic!("unexpected inherent projection")
301 }
302
303 _ => self.pretty_print_type(ty),
304 }
305 }
306
307 fn print_dyn_existential(
308 &mut self,
309 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
310 ) -> Result<(), PrintError> {
311 let mut first = true;
312 for p in predicates {
313 if !first {
314 self.write_fmt(format_args!("+"))write!(self, "+")?;
315 }
316 first = false;
317 p.print(self)?;
318 }
319 Ok(())
320 }
321
322 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
323 match ct.kind() {
325 ty::ConstKind::Value(cv) if cv.ty.is_integral() => {
326 let scalar = cv.to_leaf();
329 let signed = #[allow(non_exhaustive_omitted_patterns)] match cv.ty.kind() {
ty::Int(_) => true,
_ => false,
}matches!(cv.ty.kind(), ty::Int(_));
330 self.write_fmt(format_args!("{0:#?}",
ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())))write!(
331 self,
332 "{:#?}",
333 ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())
334 )?;
335 }
336 _ => self.write_str("_")?,
337 }
338 Ok(())
339 }
340
341 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
342 self.write_str(self.tcx.crate_name(cnum).as_str())?;
343 Ok(())
344 }
345
346 fn print_path_with_qualified(
347 &mut self,
348 self_ty: Ty<'tcx>,
349 trait_ref: Option<ty::TraitRef<'tcx>>,
350 ) -> Result<(), PrintError> {
351 match self_ty.kind() {
354 ty::FnDef(..)
355 | ty::Alias(..)
356 | ty::Closure(..)
357 | ty::CoroutineClosure(..)
358 | ty::Coroutine(..)
359 if trait_ref.is_none() =>
360 {
361 self.print_type(self_ty)
362 }
363
364 _ => self.pretty_print_path_with_qualified(self_ty, trait_ref),
365 }
366 }
367
368 fn print_path_with_impl(
369 &mut self,
370 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
371 self_ty: Ty<'tcx>,
372 trait_ref: Option<ty::TraitRef<'tcx>>,
373 ) -> Result<(), PrintError> {
374 self.pretty_print_path_with_impl(
375 |cx| {
376 print_prefix(cx)?;
377
378 if cx.keep_within_component {
379 cx.write_str("::")?;
381 } else {
382 cx.path.finalize_pending_component();
383 }
384
385 Ok(())
386 },
387 self_ty,
388 trait_ref,
389 )
390 }
391
392 fn print_path_with_simple(
393 &mut self,
394 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
395 disambiguated_data: &DisambiguatedDefPathData,
396 ) -> Result<(), PrintError> {
397 print_prefix(self)?;
398
399 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
401 return Ok(());
402 }
403
404 if self.keep_within_component {
405 self.write_str("::")?;
407 } else {
408 self.path.finalize_pending_component();
409 }
410
411 self.write_fmt(format_args!("{0}", disambiguated_data.data))write!(self, "{}", disambiguated_data.data)?;
412
413 Ok(())
414 }
415
416 fn print_path_with_generic_args(
417 &mut self,
418 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
419 args: ty::GenericArgs<'tcx>,
420 ) -> Result<(), PrintError> {
421 print_prefix(self)?;
422
423 let args = args.iter().filter(|arg| !#[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
GenericArgKind::Lifetime(_) => true,
_ => false,
}matches!(arg.kind(), GenericArgKind::Lifetime(_)));
424 if args.clone().next().is_some() {
425 self.generic_delimiters(|cx| cx.comma_sep(args))
426 } else {
427 Ok(())
428 }
429 }
430
431 fn print_impl_path(
432 &mut self,
433 impl_def_id: DefId,
434 args: ty::GenericArgs<'tcx>,
435 ) -> Result<(), PrintError> {
436 let self_ty = self.tcx.type_of(impl_def_id);
437 let impl_trait_ref = self.tcx.impl_opt_trait_ref(impl_def_id);
438 let generics = self.tcx.generics_of(impl_def_id);
439 let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
453 || &args.as_slice()[..generics.count()]
454 == self
455 .tcx
456 .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item(
457 self.tcx,
458 impl_def_id,
459 ))
460 .as_slice()
461 {
462 (
463 ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
464 self_ty.instantiate_identity().skip_norm_wip(),
465 impl_trait_ref
466 .map(|impl_trait_ref| impl_trait_ref.instantiate_identity().skip_norm_wip()),
467 )
468 } else {
469 if !!args.has_non_region_param() {
{
::core::panicking::panic_fmt(format_args!("should not be mangling partially substituted polymorphic instance: {0:?} {1:?}",
impl_def_id, args));
}
};assert!(
470 !args.has_non_region_param(),
471 "should not be mangling partially substituted \
472 polymorphic instance: {impl_def_id:?} {args:?}"
473 );
474 (
475 ty::TypingEnv::fully_monomorphized(),
476 self_ty.instantiate(self.tcx, args).skip_norm_wip(),
477 impl_trait_ref.map(|impl_trait_ref| {
478 impl_trait_ref.instantiate(self.tcx, args).skip_norm_wip()
479 }),
480 )
481 };
482
483 match &mut impl_trait_ref {
484 Some(impl_trait_ref) => {
485 {
match (&impl_trait_ref.self_ty(), &self_ty) {
(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!(impl_trait_ref.self_ty(), self_ty);
486 *impl_trait_ref = self
487 .tcx
488 .normalize_erasing_regions(typing_env, Unnormalized::new_wip(*impl_trait_ref));
489 self_ty = impl_trait_ref.self_ty();
490 }
491 None => {
492 self_ty =
493 self.tcx.normalize_erasing_regions(typing_env, Unnormalized::new_wip(self_ty));
494 }
495 }
496
497 self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
498 }
499}
500
501impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
502 fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
503 false
504 }
505
506 fn comma_sep_has_space(&self) -> bool {
508 false
509 }
510
511 fn generic_delimiters(
512 &mut self,
513 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
514 ) -> Result<(), PrintError> {
515 self.write_fmt(format_args!("<"))write!(self, "<")?;
516
517 let kept_within_component = mem::replace(&mut self.keep_within_component, true);
518 f(self)?;
519 self.keep_within_component = kept_within_component;
520
521 self.write_fmt(format_args!(">"))write!(self, ">")?;
522
523 Ok(())
524 }
525}
526
527impl fmt::Write for LegacySymbolMangler<'_> {
528 fn write_str(&mut self, s: &str) -> fmt::Result {
529 for c in s.chars() {
536 if self.path.temp_buf.is_empty() {
537 match c {
538 'a'..='z' | 'A'..='Z' | '_' => {}
539 _ => {
540 self.path.temp_buf.push('_');
542 }
543 }
544 }
545 match c {
546 '@' => self.path.temp_buf.push_str("$SP$"),
548 '*' => self.path.temp_buf.push_str("$BP$"),
549 '&' => self.path.temp_buf.push_str("$RF$"),
550 '<' => self.path.temp_buf.push_str("$LT$"),
551 '>' => self.path.temp_buf.push_str("$GT$"),
552 '(' => self.path.temp_buf.push_str("$LP$"),
553 ')' => self.path.temp_buf.push_str("$RP$"),
554 ',' => self.path.temp_buf.push_str("$C$"),
555
556 '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
557 self.path.temp_buf.push('$')
559 }
560
561 '-' | ':' => self.path.temp_buf.push('.'),
564
565 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"),
567
568 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
570
571 _ => {
572 self.path.temp_buf.push('$');
573 for c in c.escape_unicode().skip(1) {
574 match c {
575 '{' => {}
576 '}' => self.path.temp_buf.push('$'),
577 c => self.path.temp_buf.push(c),
578 }
579 }
580 }
581 }
582 }
583
584 Ok(())
585 }
586}