1use std::fmt::{self, Write};
2use std::mem::{self, discriminant};
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_middle::bug;
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 tracing::debug;
15
16pub(super) fn mangle<'tcx>(
17 tcx: TyCtxt<'tcx>,
18 instance: Instance<'tcx>,
19 instantiating_crate: Option<CrateNum>,
20) -> String {
21 let def_id = instance.def_id();
22
23 let mut ty_def_id = def_id;
28 let instance_ty;
29 loop {
30 let key = tcx.def_key(ty_def_id);
31 match key.disambiguated_data.data {
32 DefPathData::TypeNs(_)
33 | DefPathData::ValueNs(_)
34 | DefPathData::Closure
35 | DefPathData::SyntheticCoroutineBody => {
36 instance_ty = tcx.type_of(ty_def_id).instantiate_identity().skip_norm_wip();
37 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_symbol_mangling/src/legacy.rs:37",
"rustc_symbol_mangling::legacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_symbol_mangling/src/legacy.rs"),
::tracing_core::__macro_support::Option::Some(37u32),
::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);
38 break;
39 }
40 DefPathData::GlobalAsm => {
41 instance_ty = tcx.types.unit;
43 break;
44 }
45 _ => {
46 ty_def_id.index = key.parent.unwrap_or_else(|| {
50 ::rustc_middle::util::bug::bug_fmt(format_args!("finding type for {0:?}, encountered def-id {1:?} with no parent",
def_id, ty_def_id));bug!(
51 "finding type for {:?}, encountered def-id {:?} with no \
52 parent",
53 def_id,
54 ty_def_id
55 );
56 });
57 }
58 }
59 }
60
61 let instance_ty = tcx.erase_and_anonymize_regions(instance_ty);
64
65 let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
66
67 let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false };
68 p.print_def_path(
69 def_id,
70 if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, _))
71 | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, _))
72 | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_, _, _)) = instance.def
73 {
74 &*instance.args
76 } else if let ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, ty)) = instance.def {
77 let ty::Coroutine(_, cor_args) = ty.kind() else {
78 ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
79 };
80 let drop_ty = cor_args.first().unwrap().expect_ty();
81 tcx.mk_args(&[GenericArg::from(drop_ty)])
82 } else {
83 &[]
84 },
85 )
86 .unwrap();
87
88 match instance.def {
89 ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) => {
90 p.write_str("{{tls-shim}}").unwrap();
91 }
92 ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) => {
93 p.write_str("{{vtable-shim}}").unwrap();
94 }
95 ty::InstanceKind::Shim(ty::ShimKind::Reify(_, reason)) => {
96 p.write_str("{{reify-shim").unwrap();
97 match reason {
98 Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(),
99 Some(ReifyReason::Vtable) => p.write_str("-vtable").unwrap(),
100 None => (),
101 }
102 p.write_str("}}").unwrap();
103 }
104 ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure {
107 receiver_by_ref,
108 ..
109 }) => {
110 p.write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" })
111 .unwrap();
112 }
113 _ => {}
114 }
115
116 if let ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) = instance.def {
117 let _ = p.write_str("{{drop-shim}}");
118 }
119
120 p.path.finish(hash)
121}
122
123fn get_symbol_hash<'tcx>(
124 tcx: TyCtxt<'tcx>,
125
126 instance: Instance<'tcx>,
128
129 item_type: Ty<'tcx>,
134
135 instantiating_crate: Option<CrateNum>,
136) -> Hash64 {
137 let def_id = instance.def_id();
138 let args = instance.args;
139 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_symbol_mangling/src/legacy.rs:139",
"rustc_symbol_mangling::legacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_symbol_mangling/src/legacy.rs"),
::tracing_core::__macro_support::Option::Some(139u32),
::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);
140
141 tcx.with_stable_hashing_context(|mut hcx| {
142 let mut hasher = StableHasher::new();
143
144 tcx.def_path_hash(def_id).stable_hash(&mut hcx, &mut hasher);
148
149 if !!item_type.has_erasable_regions() {
::core::panicking::panic("assertion failed: !item_type.has_erasable_regions()")
};assert!(!item_type.has_erasable_regions());
153 hcx.while_hashing_spans(false, |hcx| {
154 item_type.stable_hash(hcx, &mut hasher);
155
156 if let ty::FnDef(..) = item_type.kind() {
160 item_type.fn_sig(tcx).stable_hash(hcx, &mut hasher);
161 }
162
163 args.stable_hash(hcx, &mut hasher);
165
166 if let Some(instantiating_crate) = instantiating_crate {
167 tcx.stable_crate_id(instantiating_crate).stable_hash(hcx, &mut hasher);
168 }
169
170 discriminant(&instance.def).stable_hash(hcx, &mut hasher);
174 });
175
176 hasher.finish::<Hash64>()
178 })
179}
180
181#[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", &self.result, "temp_buf", &&self.temp_buf)
}
}Debug)]
195struct SymbolPath {
196 result: String,
197 temp_buf: String,
198}
199
200impl SymbolPath {
201 fn new() -> Self {
202 let mut result =
203 SymbolPath { result: String::with_capacity(64), temp_buf: String::with_capacity(16) };
204 result.result.push_str("_ZN"); result
206 }
207
208 fn finalize_pending_component(&mut self) {
209 if !self.temp_buf.is_empty() {
210 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);
211 self.temp_buf.clear();
212 }
213 }
214
215 fn finish(mut self, hash: Hash64) -> String {
216 self.finalize_pending_component();
217 let _ = self.result.write_fmt(format_args!("17h{0:016x}E", hash))write!(self.result, "17h{hash:016x}E");
219 self.result
220 }
221}
222
223struct LegacySymbolMangler<'tcx> {
224 tcx: TyCtxt<'tcx>,
225 path: SymbolPath,
226
227 keep_within_component: bool,
232}
233
234impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
239 fn tcx(&self) -> TyCtxt<'tcx> {
240 self.tcx
241 }
242
243 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
244 Ok(())
248 }
249
250 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
251 match *ty.kind() {
252 ty::Alias(
254 _,
255 ty::AliasTy {
256 kind: ty::Projection { def_id } | ty::Opaque { def_id }, args, ..
257 },
258 )
259 | ty::Closure(def_id, args)
260 | ty::CoroutineClosure(def_id, args)
261 | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
262
263 ty::FnDef(def_id, args) => self.print_def_path(def_id, args.no_bound_vars().unwrap()),
264
265 ty::Array(ty, size) => {
268 self.write_str("[")?;
269 self.print_type(ty)?;
270 self.write_str("; ")?;
271 if let Some(size) = size.try_to_target_usize(self.tcx()) {
272 self.write_fmt(format_args!("{0}", size))write!(self, "{size}")?
273 } else if let ty::ConstKind::Param(param) = size.kind() {
274 param.print(self)?
275 } else {
276 self.write_str("_")?
277 }
278 self.write_str("]")?;
279 Ok(())
280 }
281
282 ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
283 {
::core::panicking::panic_fmt(format_args!("unexpected inherent projection"));
}panic!("unexpected inherent projection")
284 }
285
286 _ => self.pretty_print_type(ty),
287 }
288 }
289
290 fn print_dyn_existential(
291 &mut self,
292 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
293 ) -> Result<(), PrintError> {
294 let mut first = true;
295 for p in predicates {
296 if !first {
297 self.write_fmt(format_args!("+"))write!(self, "+")?;
298 }
299 first = false;
300 p.print(self)?;
301 }
302 Ok(())
303 }
304
305 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
306 match ct.kind() {
308 ty::ConstKind::Value(cv) if cv.ty.is_integral() => {
309 let scalar = cv.to_leaf();
312 let signed = #[allow(non_exhaustive_omitted_patterns)] match cv.ty.kind() {
ty::Int(_) => true,
_ => false,
}matches!(cv.ty.kind(), ty::Int(_));
313 self.write_fmt(format_args!("{0:#?}",
ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())))write!(
314 self,
315 "{:#?}",
316 ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())
317 )?;
318 }
319 _ => self.write_str("_")?,
320 }
321 Ok(())
322 }
323
324 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
325 self.write_str(self.tcx.crate_name(cnum).as_str())?;
326 Ok(())
327 }
328
329 fn print_path_with_qualified(
330 &mut self,
331 self_ty: Ty<'tcx>,
332 trait_ref: Option<ty::TraitRef<'tcx>>,
333 ) -> Result<(), PrintError> {
334 match self_ty.kind() {
337 ty::FnDef(..)
338 | ty::Alias(..)
339 | ty::Closure(..)
340 | ty::CoroutineClosure(..)
341 | ty::Coroutine(..)
342 if trait_ref.is_none() =>
343 {
344 self.print_type(self_ty)
345 }
346
347 _ => self.pretty_print_path_with_qualified(self_ty, trait_ref),
348 }
349 }
350
351 fn print_path_with_impl(
352 &mut self,
353 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
354 self_ty: Ty<'tcx>,
355 trait_ref: Option<ty::TraitRef<'tcx>>,
356 ) -> Result<(), PrintError> {
357 self.pretty_print_path_with_impl(
358 |cx| {
359 print_prefix(cx)?;
360
361 if cx.keep_within_component {
362 cx.write_str("::")?;
364 } else {
365 cx.path.finalize_pending_component();
366 }
367
368 Ok(())
369 },
370 self_ty,
371 trait_ref,
372 )
373 }
374
375 fn print_path_with_simple(
376 &mut self,
377 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
378 disambiguated_data: &DisambiguatedDefPathData,
379 ) -> Result<(), PrintError> {
380 print_prefix(self)?;
381
382 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
384 return Ok(());
385 }
386
387 if self.keep_within_component {
388 self.write_str("::")?;
390 } else {
391 self.path.finalize_pending_component();
392 }
393
394 self.write_fmt(format_args!("{0}", disambiguated_data.data))write!(self, "{}", disambiguated_data.data)?;
395
396 Ok(())
397 }
398
399 fn print_path_with_generic_args(
400 &mut self,
401 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
402 args: &[GenericArg<'tcx>],
403 ) -> Result<(), PrintError> {
404 print_prefix(self)?;
405
406 let args =
407 args.iter().cloned().filter(|arg| !#[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
GenericArgKind::Lifetime(_) => true,
_ => false,
}matches!(arg.kind(), GenericArgKind::Lifetime(_)));
408 if args.clone().next().is_some() {
409 self.generic_delimiters(|cx| cx.comma_sep(args))
410 } else {
411 Ok(())
412 }
413 }
414
415 fn print_impl_path(
416 &mut self,
417 impl_def_id: DefId,
418 args: &'tcx [GenericArg<'tcx>],
419 ) -> Result<(), PrintError> {
420 let self_ty = self.tcx.type_of(impl_def_id);
421 let impl_trait_ref = self.tcx.impl_opt_trait_ref(impl_def_id);
422 let generics = self.tcx.generics_of(impl_def_id);
423 let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
437 || &args[..generics.count()]
438 == self
439 .tcx
440 .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item(
441 self.tcx,
442 impl_def_id,
443 ))
444 .as_slice()
445 {
446 (
447 ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
448 self_ty.instantiate_identity().skip_norm_wip(),
449 impl_trait_ref
450 .map(|impl_trait_ref| impl_trait_ref.instantiate_identity().skip_norm_wip()),
451 )
452 } else {
453 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!(
454 !args.has_non_region_param(),
455 "should not be mangling partially substituted \
456 polymorphic instance: {impl_def_id:?} {args:?}"
457 );
458 (
459 ty::TypingEnv::fully_monomorphized(),
460 self_ty.instantiate(self.tcx, args).skip_norm_wip(),
461 impl_trait_ref.map(|impl_trait_ref| {
462 impl_trait_ref.instantiate(self.tcx, args).skip_norm_wip()
463 }),
464 )
465 };
466
467 match &mut impl_trait_ref {
468 Some(impl_trait_ref) => {
469 {
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);
470 *impl_trait_ref = self
471 .tcx
472 .normalize_erasing_regions(typing_env, Unnormalized::new_wip(*impl_trait_ref));
473 self_ty = impl_trait_ref.self_ty();
474 }
475 None => {
476 self_ty =
477 self.tcx.normalize_erasing_regions(typing_env, Unnormalized::new_wip(self_ty));
478 }
479 }
480
481 self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
482 }
483}
484
485impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
486 fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
487 false
488 }
489
490 fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError>
492 where
493 T: Print<Self>,
494 {
495 if let Some(first) = elems.next() {
496 first.print(self)?;
497 for elem in elems {
498 self.write_str(",")?;
499 elem.print(self)?;
500 }
501 }
502 Ok(())
503 }
504
505 fn generic_delimiters(
506 &mut self,
507 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
508 ) -> Result<(), PrintError> {
509 self.write_fmt(format_args!("<"))write!(self, "<")?;
510
511 let kept_within_component = mem::replace(&mut self.keep_within_component, true);
512 f(self)?;
513 self.keep_within_component = kept_within_component;
514
515 self.write_fmt(format_args!(">"))write!(self, ">")?;
516
517 Ok(())
518 }
519}
520
521impl fmt::Write for LegacySymbolMangler<'_> {
522 fn write_str(&mut self, s: &str) -> fmt::Result {
523 for c in s.chars() {
530 if self.path.temp_buf.is_empty() {
531 match c {
532 'a'..='z' | 'A'..='Z' | '_' => {}
533 _ => {
534 self.path.temp_buf.push('_');
536 }
537 }
538 }
539 match c {
540 '@' => self.path.temp_buf.push_str("$SP$"),
542 '*' => self.path.temp_buf.push_str("$BP$"),
543 '&' => self.path.temp_buf.push_str("$RF$"),
544 '<' => self.path.temp_buf.push_str("$LT$"),
545 '>' => self.path.temp_buf.push_str("$GT$"),
546 '(' => self.path.temp_buf.push_str("$LP$"),
547 ')' => self.path.temp_buf.push_str("$RP$"),
548 ',' => self.path.temp_buf.push_str("$C$"),
549
550 '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
551 self.path.temp_buf.push('$')
553 }
554
555 '-' | ':' => self.path.temp_buf.push('.'),
558
559 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"),
561
562 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
564
565 _ => {
566 self.path.temp_buf.push('$');
567 for c in c.escape_unicode().skip(1) {
568 match c {
569 '{' => {}
570 '}' => self.path.temp_buf.push('$'),
571 c => self.path.temp_buf.push(c),
572 }
573 }
574 }
575 }
576 }
577
578 Ok(())
579 }
580}