]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_symbol_mangling/src/legacy.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / compiler / rustc_symbol_mangling / src / legacy.rs
1 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2 use rustc_hir::def_id::CrateNum;
3 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
4 use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
5 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
6 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable};
7 use rustc_middle::util::common::record_time;
8
9 use std::fmt::{self, Write};
10 use std::mem::{self, discriminant};
11
12 pub(super) fn mangle<'tcx>(
13     tcx: TyCtxt<'tcx>,
14     instance: Instance<'tcx>,
15     instantiating_crate: Option<CrateNum>,
16 ) -> String {
17     let def_id = instance.def_id();
18
19     // We want to compute the "type" of this item. Unfortunately, some
20     // kinds of items (e.g., closures) don't have an entry in the
21     // item-type array. So walk back up the find the closest parent
22     // that DOES have an entry.
23     let mut ty_def_id = def_id;
24     let instance_ty;
25     loop {
26         let key = tcx.def_key(ty_def_id);
27         match key.disambiguated_data.data {
28             DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
29                 instance_ty = tcx.type_of(ty_def_id);
30                 debug!(?instance_ty);
31                 break;
32             }
33             _ => {
34                 // if we're making a symbol for something, there ought
35                 // to be a value or type-def or something in there
36                 // *somewhere*
37                 ty_def_id.index = key.parent.unwrap_or_else(|| {
38                     bug!(
39                         "finding type for {:?}, encountered def-id {:?} with no \
40                          parent",
41                         def_id,
42                         ty_def_id
43                     );
44                 });
45             }
46         }
47     }
48
49     // Erase regions because they may not be deterministic when hashed
50     // and should not matter anyhow.
51     let instance_ty = tcx.erase_regions(instance_ty);
52
53     let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
54
55     let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false };
56     printer
57         .print_def_path(
58             def_id,
59             if let ty::InstanceDef::DropGlue(_, _) = instance.def {
60                 // Add the name of the dropped type to the symbol name
61                 &*instance.substs
62             } else {
63                 &[]
64             },
65         )
66         .unwrap();
67
68     if let ty::InstanceDef::VTableShim(..) = instance.def {
69         let _ = printer.write_str("{{vtable-shim}}");
70     }
71
72     if let ty::InstanceDef::ReifyShim(..) = instance.def {
73         let _ = printer.write_str("{{reify-shim}}");
74     }
75
76     printer.path.finish(hash)
77 }
78
79 fn get_symbol_hash<'tcx>(
80     tcx: TyCtxt<'tcx>,
81
82     // instance this name will be for
83     instance: Instance<'tcx>,
84
85     // type of the item, without any generic
86     // parameters substituted; this is
87     // included in the hash as a kind of
88     // safeguard.
89     item_type: Ty<'tcx>,
90
91     instantiating_crate: Option<CrateNum>,
92 ) -> u64 {
93     let def_id = instance.def_id();
94     let substs = instance.substs;
95     debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
96
97     tcx.with_stable_hashing_context(|mut hcx| {
98         let mut hasher = StableHasher::new();
99
100         record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
101             // the main symbol name is not necessarily unique; hash in the
102             // compiler's internal def-path, guaranteeing each symbol has a
103             // truly unique path
104             tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
105
106             // Include the main item-type. Note that, in this case, the
107             // assertions about `needs_subst` may not hold, but this item-type
108             // ought to be the same for every reference anyway.
109             assert!(!item_type.has_erasable_regions());
110             hcx.while_hashing_spans(false, |hcx| {
111                 item_type.hash_stable(hcx, &mut hasher);
112
113                 // If this is a function, we hash the signature as well.
114                 // This is not *strictly* needed, but it may help in some
115                 // situations, see the `run-make/a-b-a-linker-guard` test.
116                 if let ty::FnDef(..) = item_type.kind() {
117                     item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
118                 }
119
120                 // also include any type parameters (for generic items)
121                 substs.hash_stable(hcx, &mut hasher);
122
123                 if let Some(instantiating_crate) = instantiating_crate {
124                     tcx.def_path_hash(instantiating_crate.as_def_id())
125                         .stable_crate_id()
126                         .hash_stable(hcx, &mut hasher);
127                 }
128
129                 // We want to avoid accidental collision between different types of instances.
130                 // Especially, `VTableShim`s and `ReifyShim`s may overlap with their original
131                 // instances without this.
132                 discriminant(&instance.def).hash_stable(hcx, &mut hasher);
133             });
134         });
135
136         // 64 bits should be enough to avoid collisions.
137         hasher.finish::<u64>()
138     })
139 }
140
141 // Follow C++ namespace-mangling style, see
142 // https://en.wikipedia.org/wiki/Name_mangling for more info.
143 //
144 // It turns out that on macOS you can actually have arbitrary symbols in
145 // function names (at least when given to LLVM), but this is not possible
146 // when using unix's linker. Perhaps one day when we just use a linker from LLVM
147 // we won't need to do this name mangling. The problem with name mangling is
148 // that it seriously limits the available characters. For example we can't
149 // have things like &T in symbol names when one would theoretically
150 // want them for things like impls of traits on that type.
151 //
152 // To be able to work on all platforms and get *some* reasonable output, we
153 // use C++ name-mangling.
154 #[derive(Debug)]
155 struct SymbolPath {
156     result: String,
157     temp_buf: String,
158 }
159
160 impl SymbolPath {
161     fn new() -> Self {
162         let mut result =
163             SymbolPath { result: String::with_capacity(64), temp_buf: String::with_capacity(16) };
164         result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
165         result
166     }
167
168     fn finalize_pending_component(&mut self) {
169         if !self.temp_buf.is_empty() {
170             let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf);
171             self.temp_buf.clear();
172         }
173     }
174
175     fn finish(mut self, hash: u64) -> String {
176         self.finalize_pending_component();
177         // E = end name-sequence
178         let _ = write!(self.result, "17h{hash:016x}E");
179         self.result
180     }
181 }
182
183 struct SymbolPrinter<'tcx> {
184     tcx: TyCtxt<'tcx>,
185     path: SymbolPath,
186
187     // When `true`, `finalize_pending_component` isn't used.
188     // This is needed when recursing into `path_qualified`,
189     // or `path_generic_args`, as any nested paths are
190     // logically within one component.
191     keep_within_component: bool,
192 }
193
194 // HACK(eddyb) this relies on using the `fmt` interface to get
195 // `PrettyPrinter` aka pretty printing of e.g. types in paths,
196 // symbol names should have their own printing machinery.
197
198 impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
199     type Error = fmt::Error;
200
201     type Path = Self;
202     type Region = Self;
203     type Type = Self;
204     type DynExistential = Self;
205     type Const = Self;
206
207     fn tcx(&self) -> TyCtxt<'tcx> {
208         self.tcx
209     }
210
211     fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
212         Ok(self)
213     }
214
215     fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
216         match *ty.kind() {
217             // Print all nominal types as paths (unlike `pretty_print_type`).
218             ty::FnDef(def_id, substs)
219             | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
220             | ty::Closure(def_id, substs)
221             | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
222
223             // The `pretty_print_type` formatting of array size depends on
224             // -Zverbose flag, so we cannot reuse it here.
225             ty::Array(ty, size) => {
226                 self.write_str("[")?;
227                 self = self.print_type(ty)?;
228                 self.write_str("; ")?;
229                 if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
230                     write!(self, "{size}")?
231                 } else if let ty::ConstKind::Param(param) = size.kind() {
232                     self = param.print(self)?
233                 } else {
234                     self.write_str("_")?
235                 }
236                 self.write_str("]")?;
237                 Ok(self)
238             }
239
240             _ => self.pretty_print_type(ty),
241         }
242     }
243
244     fn print_dyn_existential(
245         mut self,
246         predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
247     ) -> Result<Self::DynExistential, Self::Error> {
248         let mut first = true;
249         for p in predicates {
250             if !first {
251                 write!(self, "+")?;
252             }
253             first = false;
254             self = p.print(self)?;
255         }
256         Ok(self)
257     }
258
259     fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
260         // only print integers
261         match (ct.kind(), ct.ty().kind()) {
262             (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => {
263                 // The `pretty_print_const` formatting depends on -Zverbose
264                 // flag, so we cannot reuse it here.
265                 let signed = matches!(ct.ty().kind(), ty::Int(_));
266                 write!(
267                     self,
268                     "{:#?}",
269                     ty::ConstInt::new(scalar, signed, ct.ty().is_ptr_sized_integral())
270                 )?;
271             }
272             _ => self.write_str("_")?,
273         }
274         Ok(self)
275     }
276
277     fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
278         self.write_str(self.tcx.crate_name(cnum).as_str())?;
279         Ok(self)
280     }
281     fn path_qualified(
282         self,
283         self_ty: Ty<'tcx>,
284         trait_ref: Option<ty::TraitRef<'tcx>>,
285     ) -> Result<Self::Path, Self::Error> {
286         // Similar to `pretty_path_qualified`, but for the other
287         // types that are printed as paths (see `print_type` above).
288         match self_ty.kind() {
289             ty::FnDef(..) | ty::Alias(..) | ty::Closure(..) | ty::Generator(..)
290                 if trait_ref.is_none() =>
291             {
292                 self.print_type(self_ty)
293             }
294
295             _ => self.pretty_path_qualified(self_ty, trait_ref),
296         }
297     }
298
299     fn path_append_impl(
300         self,
301         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
302         _disambiguated_data: &DisambiguatedDefPathData,
303         self_ty: Ty<'tcx>,
304         trait_ref: Option<ty::TraitRef<'tcx>>,
305     ) -> Result<Self::Path, Self::Error> {
306         self.pretty_path_append_impl(
307             |mut cx| {
308                 cx = print_prefix(cx)?;
309
310                 if cx.keep_within_component {
311                     // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
312                     cx.write_str("::")?;
313                 } else {
314                     cx.path.finalize_pending_component();
315                 }
316
317                 Ok(cx)
318             },
319             self_ty,
320             trait_ref,
321         )
322     }
323     fn path_append(
324         mut self,
325         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
326         disambiguated_data: &DisambiguatedDefPathData,
327     ) -> Result<Self::Path, Self::Error> {
328         self = print_prefix(self)?;
329
330         // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
331         if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
332             return Ok(self);
333         }
334
335         if self.keep_within_component {
336             // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
337             self.write_str("::")?;
338         } else {
339             self.path.finalize_pending_component();
340         }
341
342         write!(self, "{}", disambiguated_data.data)?;
343
344         Ok(self)
345     }
346     fn path_generic_args(
347         mut self,
348         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
349         args: &[GenericArg<'tcx>],
350     ) -> Result<Self::Path, Self::Error> {
351         self = print_prefix(self)?;
352
353         let args =
354             args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
355
356         if args.clone().next().is_some() {
357             self.generic_delimiters(|cx| cx.comma_sep(args))
358         } else {
359             Ok(self)
360         }
361     }
362 }
363
364 impl<'tcx> PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> {
365     fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
366         false
367     }
368     fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
369     where
370         T: Print<'tcx, Self, Output = Self, Error = Self::Error>,
371     {
372         if let Some(first) = elems.next() {
373             self = first.print(self)?;
374             for elem in elems {
375                 self.write_str(",")?;
376                 self = elem.print(self)?;
377             }
378         }
379         Ok(self)
380     }
381
382     fn generic_delimiters(
383         mut self,
384         f: impl FnOnce(Self) -> Result<Self, Self::Error>,
385     ) -> Result<Self, Self::Error> {
386         write!(self, "<")?;
387
388         let kept_within_component = mem::replace(&mut self.keep_within_component, true);
389         self = f(self)?;
390         self.keep_within_component = kept_within_component;
391
392         write!(self, ">")?;
393
394         Ok(self)
395     }
396 }
397
398 impl fmt::Write for SymbolPrinter<'_> {
399     fn write_str(&mut self, s: &str) -> fmt::Result {
400         // Name sanitation. LLVM will happily accept identifiers with weird names, but
401         // gas doesn't!
402         // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
403         // NVPTX assembly has more strict naming rules than gas, so additionally, dots
404         // are replaced with '$' there.
405
406         for c in s.chars() {
407             if self.path.temp_buf.is_empty() {
408                 match c {
409                     'a'..='z' | 'A'..='Z' | '_' => {}
410                     _ => {
411                         // Underscore-qualify anything that didn't start as an ident.
412                         self.path.temp_buf.push('_');
413                     }
414                 }
415             }
416             match c {
417                 // Escape these with $ sequences
418                 '@' => self.path.temp_buf.push_str("$SP$"),
419                 '*' => self.path.temp_buf.push_str("$BP$"),
420                 '&' => self.path.temp_buf.push_str("$RF$"),
421                 '<' => self.path.temp_buf.push_str("$LT$"),
422                 '>' => self.path.temp_buf.push_str("$GT$"),
423                 '(' => self.path.temp_buf.push_str("$LP$"),
424                 ')' => self.path.temp_buf.push_str("$RP$"),
425                 ',' => self.path.temp_buf.push_str("$C$"),
426
427                 '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
428                     // NVPTX doesn't support these characters in symbol names.
429                     self.path.temp_buf.push('$')
430                 }
431
432                 // '.' doesn't occur in types and functions, so reuse it
433                 // for ':' and '-'
434                 '-' | ':' => self.path.temp_buf.push('.'),
435
436                 // Avoid crashing LLVM in certain (LTO-related) situations, see #60925.
437                 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"),
438
439                 // These are legal symbols
440                 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
441
442                 _ => {
443                     self.path.temp_buf.push('$');
444                     for c in c.escape_unicode().skip(1) {
445                         match c {
446                             '{' => {}
447                             '}' => self.path.temp_buf.push('$'),
448                             c => self.path.temp_buf.push(c),
449                         }
450                     }
451                 }
452             }
453         }
454
455         Ok(())
456     }
457 }