1use std::fmt::{self, Write};
2use std::mem::{self, discriminant};
3
4use rustc_data_structures::stable_hasher::{HashStable, 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};
13use tracing::debug;
14
15pub(super) fn mangle<'tcx>(
16 tcx: TyCtxt<'tcx>,
17 instance: Instance<'tcx>,
18 instantiating_crate: Option<CrateNum>,
19) -> String {
20 let def_id = instance.def_id();
21
22 let mut ty_def_id = def_id;
27 let instance_ty;
28 loop {
29 let key = tcx.def_key(ty_def_id);
30 match key.disambiguated_data.data {
31 DefPathData::TypeNs(_)
32 | DefPathData::ValueNs(_)
33 | DefPathData::Closure
34 | DefPathData::SyntheticCoroutineBody => {
35 instance_ty = tcx.type_of(ty_def_id).instantiate_identity();
36 {
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:36",
"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(36u32),
::tracing_core::__macro_support::Option::Some("rustc_symbol_mangling::legacy"),
::tracing_core::field::FieldSet::new(&["instance_ty"],
::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};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&instance_ty)
as &dyn Value))])
});
} else { ; }
};debug!(?instance_ty);
37 break;
38 }
39 _ => {
40 ty_def_id.index = key.parent.unwrap_or_else(|| {
44 ::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!(
45 "finding type for {:?}, encountered def-id {:?} with no \
46 parent",
47 def_id,
48 ty_def_id
49 );
50 });
51 }
52 }
53 }
54
55 let instance_ty = tcx.erase_and_anonymize_regions(instance_ty);
58
59 let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
60
61 let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false };
62 p.print_def_path(
63 def_id,
64 if let ty::InstanceKind::DropGlue(_, _)
65 | ty::InstanceKind::AsyncDropGlueCtorShim(_, _)
66 | ty::InstanceKind::FutureDropPollShim(_, _, _) = instance.def
67 {
68 &*instance.args
70 } else if let ty::InstanceKind::AsyncDropGlue(_, ty) = instance.def {
71 let ty::Coroutine(_, cor_args) = ty.kind() else {
72 ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
73 };
74 let drop_ty = cor_args.first().unwrap().expect_ty();
75 tcx.mk_args(&[GenericArg::from(drop_ty)])
76 } else {
77 &[]
78 },
79 )
80 .unwrap();
81
82 match instance.def {
83 ty::InstanceKind::ThreadLocalShim(..) => {
84 p.write_str("{{tls-shim}}").unwrap();
85 }
86 ty::InstanceKind::VTableShim(..) => {
87 p.write_str("{{vtable-shim}}").unwrap();
88 }
89 ty::InstanceKind::ReifyShim(_, reason) => {
90 p.write_str("{{reify-shim").unwrap();
91 match reason {
92 Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(),
93 Some(ReifyReason::Vtable) => p.write_str("-vtable").unwrap(),
94 None => (),
95 }
96 p.write_str("}}").unwrap();
97 }
98 ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } => {
101 p.write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" })
102 .unwrap();
103 }
104 _ => {}
105 }
106
107 if let ty::InstanceKind::FutureDropPollShim(..) = instance.def {
108 let _ = p.write_str("{{drop-shim}}");
109 }
110
111 p.path.finish(hash)
112}
113
114fn get_symbol_hash<'tcx>(
115 tcx: TyCtxt<'tcx>,
116
117 instance: Instance<'tcx>,
119
120 item_type: Ty<'tcx>,
125
126 instantiating_crate: Option<CrateNum>,
127) -> Hash64 {
128 let def_id = instance.def_id();
129 let args = instance.args;
130 {
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:130",
"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(130u32),
::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};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("get_symbol_hash(def_id={0:?}, parameters={1:?})",
def_id, args) as &dyn Value))])
});
} else { ; }
};debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, args);
131
132 tcx.with_stable_hashing_context(|mut hcx| {
133 let mut hasher = StableHasher::new();
134
135 tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
139
140 if !!item_type.has_erasable_regions() {
::core::panicking::panic("assertion failed: !item_type.has_erasable_regions()")
};assert!(!item_type.has_erasable_regions());
144 hcx.while_hashing_spans(false, |hcx| {
145 item_type.hash_stable(hcx, &mut hasher);
146
147 if let ty::FnDef(..) = item_type.kind() {
151 item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
152 }
153
154 args.hash_stable(hcx, &mut hasher);
156
157 if let Some(instantiating_crate) = instantiating_crate {
158 tcx.stable_crate_id(instantiating_crate).hash_stable(hcx, &mut hasher);
159 }
160
161 discriminant(&instance.def).hash_stable(hcx, &mut hasher);
165 });
166
167 hasher.finish::<Hash64>()
169 })
170}
171
172#[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)]
186struct SymbolPath {
187 result: String,
188 temp_buf: String,
189}
190
191impl SymbolPath {
192 fn new() -> Self {
193 let mut result =
194 SymbolPath { result: String::with_capacity(64), temp_buf: String::with_capacity(16) };
195 result.result.push_str("_ZN"); result
197 }
198
199 fn finalize_pending_component(&mut self) {
200 if !self.temp_buf.is_empty() {
201 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);
202 self.temp_buf.clear();
203 }
204 }
205
206 fn finish(mut self, hash: Hash64) -> String {
207 self.finalize_pending_component();
208 let _ = self.result.write_fmt(format_args!("17h{0:016x}E", hash))write!(self.result, "17h{hash:016x}E");
210 self.result
211 }
212}
213
214struct LegacySymbolMangler<'tcx> {
215 tcx: TyCtxt<'tcx>,
216 path: SymbolPath,
217
218 keep_within_component: bool,
223}
224
225impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
230 fn tcx(&self) -> TyCtxt<'tcx> {
231 self.tcx
232 }
233
234 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
235 Ok(())
239 }
240
241 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
242 match *ty.kind() {
243 ty::FnDef(def_id, args)
245 | ty::Alias(ty::AliasTy {
246 kind: ty::Projection { def_id } | ty::Opaque { def_id },
247 args,
248 ..
249 })
250 | ty::Closure(def_id, args)
251 | ty::CoroutineClosure(def_id, args)
252 | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
253
254 ty::Array(ty, size) => {
257 self.write_str("[")?;
258 self.print_type(ty)?;
259 self.write_str("; ")?;
260 if let Some(size) = size.try_to_target_usize(self.tcx()) {
261 self.write_fmt(format_args!("{0}", size))write!(self, "{size}")?
262 } else if let ty::ConstKind::Param(param) = size.kind() {
263 param.print(self)?
264 } else {
265 self.write_str("_")?
266 }
267 self.write_str("]")?;
268 Ok(())
269 }
270
271 ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
272 {
::core::panicking::panic_fmt(format_args!("unexpected inherent projection"));
}panic!("unexpected inherent projection")
273 }
274
275 _ => self.pretty_print_type(ty),
276 }
277 }
278
279 fn print_dyn_existential(
280 &mut self,
281 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
282 ) -> Result<(), PrintError> {
283 let mut first = true;
284 for p in predicates {
285 if !first {
286 self.write_fmt(format_args!("+"))write!(self, "+")?;
287 }
288 first = false;
289 p.print(self)?;
290 }
291 Ok(())
292 }
293
294 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
295 match ct.kind() {
297 ty::ConstKind::Value(cv) if cv.ty.is_integral() => {
298 let scalar = cv.to_leaf();
301 let signed = #[allow(non_exhaustive_omitted_patterns)] match cv.ty.kind() {
ty::Int(_) => true,
_ => false,
}matches!(cv.ty.kind(), ty::Int(_));
302 self.write_fmt(format_args!("{0:#?}",
ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())))write!(
303 self,
304 "{:#?}",
305 ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())
306 )?;
307 }
308 _ => self.write_str("_")?,
309 }
310 Ok(())
311 }
312
313 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
314 self.write_str(self.tcx.crate_name(cnum).as_str())?;
315 Ok(())
316 }
317
318 fn print_path_with_qualified(
319 &mut self,
320 self_ty: Ty<'tcx>,
321 trait_ref: Option<ty::TraitRef<'tcx>>,
322 ) -> Result<(), PrintError> {
323 match self_ty.kind() {
326 ty::FnDef(..)
327 | ty::Alias(..)
328 | ty::Closure(..)
329 | ty::CoroutineClosure(..)
330 | ty::Coroutine(..)
331 if trait_ref.is_none() =>
332 {
333 self.print_type(self_ty)
334 }
335
336 _ => self.pretty_print_path_with_qualified(self_ty, trait_ref),
337 }
338 }
339
340 fn print_path_with_impl(
341 &mut self,
342 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
343 self_ty: Ty<'tcx>,
344 trait_ref: Option<ty::TraitRef<'tcx>>,
345 ) -> Result<(), PrintError> {
346 self.pretty_print_path_with_impl(
347 |cx| {
348 print_prefix(cx)?;
349
350 if cx.keep_within_component {
351 cx.write_str("::")?;
353 } else {
354 cx.path.finalize_pending_component();
355 }
356
357 Ok(())
358 },
359 self_ty,
360 trait_ref,
361 )
362 }
363
364 fn print_path_with_simple(
365 &mut self,
366 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
367 disambiguated_data: &DisambiguatedDefPathData,
368 ) -> Result<(), PrintError> {
369 print_prefix(self)?;
370
371 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
373 return Ok(());
374 }
375
376 if self.keep_within_component {
377 self.write_str("::")?;
379 } else {
380 self.path.finalize_pending_component();
381 }
382
383 self.write_fmt(format_args!("{0}", disambiguated_data.data))write!(self, "{}", disambiguated_data.data)?;
384
385 Ok(())
386 }
387
388 fn print_path_with_generic_args(
389 &mut self,
390 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
391 args: &[GenericArg<'tcx>],
392 ) -> Result<(), PrintError> {
393 print_prefix(self)?;
394
395 let args =
396 args.iter().cloned().filter(|arg| !#[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
GenericArgKind::Lifetime(_) => true,
_ => false,
}matches!(arg.kind(), GenericArgKind::Lifetime(_)));
397 if args.clone().next().is_some() {
398 self.generic_delimiters(|cx| cx.comma_sep(args))
399 } else {
400 Ok(())
401 }
402 }
403
404 fn print_impl_path(
405 &mut self,
406 impl_def_id: DefId,
407 args: &'tcx [GenericArg<'tcx>],
408 ) -> Result<(), PrintError> {
409 let self_ty = self.tcx.type_of(impl_def_id);
410 let impl_trait_ref = self.tcx.impl_opt_trait_ref(impl_def_id);
411 let generics = self.tcx.generics_of(impl_def_id);
412 let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
426 || &args[..generics.count()]
427 == self
428 .tcx
429 .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item(
430 self.tcx,
431 impl_def_id,
432 ))
433 .as_slice()
434 {
435 (
436 ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
437 self_ty.instantiate_identity(),
438 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
439 )
440 } else {
441 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!(
442 !args.has_non_region_param(),
443 "should not be mangling partially substituted \
444 polymorphic instance: {impl_def_id:?} {args:?}"
445 );
446 (
447 ty::TypingEnv::fully_monomorphized(),
448 self_ty.instantiate(self.tcx, args),
449 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
450 )
451 };
452
453 match &mut impl_trait_ref {
454 Some(impl_trait_ref) => {
455 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);
456 *impl_trait_ref = self.tcx.normalize_erasing_regions(typing_env, *impl_trait_ref);
457 self_ty = impl_trait_ref.self_ty();
458 }
459 None => {
460 self_ty = self.tcx.normalize_erasing_regions(typing_env, self_ty);
461 }
462 }
463
464 self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
465 }
466}
467
468impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
469 fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
470 false
471 }
472
473 fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError>
475 where
476 T: Print<'tcx, Self>,
477 {
478 if let Some(first) = elems.next() {
479 first.print(self)?;
480 for elem in elems {
481 self.write_str(",")?;
482 elem.print(self)?;
483 }
484 }
485 Ok(())
486 }
487
488 fn generic_delimiters(
489 &mut self,
490 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
491 ) -> Result<(), PrintError> {
492 self.write_fmt(format_args!("<"))write!(self, "<")?;
493
494 let kept_within_component = mem::replace(&mut self.keep_within_component, true);
495 f(self)?;
496 self.keep_within_component = kept_within_component;
497
498 self.write_fmt(format_args!(">"))write!(self, ">")?;
499
500 Ok(())
501 }
502}
503
504impl fmt::Write for LegacySymbolMangler<'_> {
505 fn write_str(&mut self, s: &str) -> fmt::Result {
506 for c in s.chars() {
513 if self.path.temp_buf.is_empty() {
514 match c {
515 'a'..='z' | 'A'..='Z' | '_' => {}
516 _ => {
517 self.path.temp_buf.push('_');
519 }
520 }
521 }
522 match c {
523 '@' => self.path.temp_buf.push_str("$SP$"),
525 '*' => self.path.temp_buf.push_str("$BP$"),
526 '&' => self.path.temp_buf.push_str("$RF$"),
527 '<' => self.path.temp_buf.push_str("$LT$"),
528 '>' => self.path.temp_buf.push_str("$GT$"),
529 '(' => self.path.temp_buf.push_str("$LP$"),
530 ')' => self.path.temp_buf.push_str("$RP$"),
531 ',' => self.path.temp_buf.push_str("$C$"),
532
533 '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
534 self.path.temp_buf.push('$')
536 }
537
538 '-' | ':' => self.path.temp_buf.push('.'),
541
542 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"),
544
545 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
547
548 _ => {
549 self.path.temp_buf.push('$');
550 for c in c.escape_unicode().skip(1) {
551 match c {
552 '{' => {}
553 '}' => self.path.temp_buf.push('$'),
554 c => self.path.temp_buf.push(c),
555 }
556 }
557 }
558 }
559 }
560
561 Ok(())
562 }
563}