]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_utils/symbol_names/v0.rs
rustc_codegen_utils: don't ignore `Ctor` path components in symbols.
[rust.git] / src / librustc_codegen_utils / symbol_names / v0.rs
1 use rustc::hir;
2 use rustc::hir::def_id::{CrateNum, DefId};
3 use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
4 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
5 use rustc::ty::print::{Printer, Print};
6 use rustc::ty::subst::{Kind, Subst, UnpackedKind};
7 use rustc_data_structures::base_n;
8 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
9 use rustc_mir::monomorphize::Instance;
10 use rustc_target::spec::abi::Abi;
11 use syntax::ast::{IntTy, UintTy, FloatTy};
12
13 use std::fmt::Write;
14 use std::ops::Range;
15
16 pub(super) fn mangle(
17     tcx: TyCtxt<'_, 'tcx, 'tcx>,
18     instance: Instance<'tcx>,
19     instantiating_crate: Option<CrateNum>,
20     compress: bool,
21 ) -> String {
22     let def_id = instance.def_id();
23     // FIXME(eddyb) this should ideally not be needed.
24     let substs =
25         tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs);
26
27     let prefix = "_R";
28     let mut cx = SymbolMangler {
29         tcx,
30         compress: if compress {
31             Some(Box::new(CompressionCaches {
32                 start_offset: prefix.len(),
33
34                 paths: FxHashMap::default(),
35                 types: FxHashMap::default(),
36                 consts: FxHashMap::default(),
37             }))
38         } else {
39             None
40         },
41         binders: vec![],
42         out: String::from(prefix),
43     };
44     cx = if instance.is_vtable_shim() {
45         cx.path_append_ns(
46             |cx| cx.print_def_path(def_id, substs),
47             'S',
48             0,
49             "",
50         ).unwrap()
51     } else {
52         cx.print_def_path(def_id, substs).unwrap()
53     };
54     if let Some(instantiating_crate) = instantiating_crate {
55         cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap();
56     }
57     cx.out
58 }
59
60 struct CompressionCaches<'tcx> {
61     // The length of the prefix in `out` (e.g. 2 for `_R`).
62     start_offset: usize,
63
64     // The values are start positions in `out`, in bytes.
65     paths: FxHashMap<(DefId, &'tcx [Kind<'tcx>]), usize>,
66     types: FxHashMap<Ty<'tcx>, usize>,
67     consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
68 }
69
70 struct BinderLevel {
71     /// The range of distances from the root of what's
72     /// being printed, to the lifetimes in a binder.
73     /// Specifically, a `BrAnon(i)` lifetime has depth
74     /// `lifetime_depths.start + i`, going away from the
75     /// the root and towards its use site, as `i` increases.
76     /// This is used to flatten rustc's pairing of `BrAnon`
77     /// (intra-binder disambiguation) with a `DebruijnIndex`
78     /// (binder addressing), to "true" de Bruijn indices,
79     /// by subtracting the depth of a certain lifetime, from
80     /// the innermost depth at its use site.
81     lifetime_depths: Range<u32>,
82 }
83
84 struct SymbolMangler<'a, 'tcx> {
85     tcx: TyCtxt<'a, 'tcx, 'tcx>,
86     compress: Option<Box<CompressionCaches<'tcx>>>,
87     binders: Vec<BinderLevel>,
88     out: String,
89 }
90
91 impl SymbolMangler<'_, 'tcx> {
92     fn push(&mut self, s: &str) {
93         self.out.push_str(s);
94     }
95
96     /// Push a `_`-terminated base 62 integer, using the format
97     /// specified in the RFC as `<base-62-number>`, that is:
98     /// * `x = 0` is encoded as just the `"_"` terminator
99     /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`,
100     ///   e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
101     fn push_integer_62(&mut self, x: u64) {
102         if let Some(x) = x.checked_sub(1) {
103             base_n::push_str(x as u128, 62, &mut self.out);
104         }
105         self.push("_");
106     }
107
108     /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is:
109     /// * `x = 0` is encoded as `""` (nothing)
110     /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)`
111     ///   e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc.
112     fn push_opt_integer_62(&mut self, tag: &str, x: u64) {
113         if let Some(x) = x.checked_sub(1) {
114             self.push(tag);
115             self.push_integer_62(x);
116         }
117     }
118
119     fn push_disambiguator(&mut self, dis: u64) {
120         self.push_opt_integer_62("s", dis);
121     }
122
123     fn push_ident(&mut self, ident: &str) {
124         let mut use_punycode = false;
125         for b in ident.bytes() {
126             match b {
127                 b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {}
128                 0x80..=0xff => use_punycode = true,
129                 _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident),
130             }
131         }
132
133         let punycode_string;
134         let ident = if use_punycode {
135             self.push("u");
136
137             // FIXME(eddyb) we should probably roll our own punycode implementation.
138             let mut punycode_bytes = match ::punycode::encode(ident) {
139                 Ok(s) => s.into_bytes(),
140                 Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
141             };
142
143             // Replace `-` with `_`.
144             if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') {
145                 *c = b'_';
146             }
147
148             // FIXME(eddyb) avoid rechecking UTF-8 validity.
149             punycode_string = String::from_utf8(punycode_bytes).unwrap();
150             &punycode_string
151         } else {
152             ident
153         };
154
155         let _ = write!(self.out, "{}", ident.len());
156
157         // Write a separating `_` if necessary (leading digit or `_`).
158         match ident.chars().next() {
159             Some('_') | Some('0'..='9') => {
160                 self.push("_");
161             }
162             _ => {}
163         }
164
165         self.push(ident);
166     }
167
168     fn path_append_ns(
169         mut self,
170         print_prefix: impl FnOnce(Self) -> Result<Self, !>,
171         ns: char,
172         disambiguator: u64,
173         name: &str,
174     ) -> Result<Self, !> {
175         self.push("N");
176         self.out.push(ns);
177         self = print_prefix(self)?;
178         self.push_disambiguator(disambiguator as u64);
179         self.push_ident(name);
180         Ok(self)
181     }
182
183     fn print_backref(mut self, i: usize) -> Result<Self, !> {
184         self.push("B");
185         self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64);
186         Ok(self)
187     }
188
189     fn in_binder<T>(
190         mut self,
191         value: &ty::Binder<T>,
192         print_value: impl FnOnce(Self, &T) -> Result<Self, !>
193     ) -> Result<Self, !>
194         where T: TypeFoldable<'tcx>
195     {
196         let regions = if value.has_late_bound_regions() {
197             self.tcx.collect_referenced_late_bound_regions(value)
198         } else {
199             FxHashSet::default()
200         };
201
202         let mut lifetime_depths =
203             self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i);
204
205         let lifetimes = regions.into_iter().map(|br| {
206             match br {
207                 ty::BrAnon(i) => i + 1,
208                 _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
209             }
210         }).max().unwrap_or(0);
211
212         self.push_opt_integer_62("G", lifetimes as u64);
213         lifetime_depths.end += lifetimes;
214
215         self.binders.push(BinderLevel { lifetime_depths });
216         self = print_value(self, value.skip_binder())?;
217         self.binders.pop();
218
219         Ok(self)
220     }
221 }
222
223 impl Printer<'tcx, 'tcx> for SymbolMangler<'_, 'tcx> {
224     type Error = !;
225
226     type Path = Self;
227     type Region = Self;
228     type Type = Self;
229     type DynExistential = Self;
230     type Const = Self;
231
232     fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
233         self.tcx
234     }
235
236     fn print_def_path(
237         mut self,
238         def_id: DefId,
239         substs: &'tcx [Kind<'tcx>],
240     ) -> Result<Self::Path, Self::Error> {
241         if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) {
242             return self.print_backref(i);
243         }
244         let start = self.out.len();
245
246         self = self.default_print_def_path(def_id, substs)?;
247
248         // Only cache paths that do not refer to an enclosing
249         // binder (which would change depending on context).
250         if !substs.iter().any(|k| k.has_escaping_bound_vars()) {
251             if let Some(c) = &mut self.compress {
252                 c.paths.insert((def_id, substs), start);
253             }
254         }
255         Ok(self)
256     }
257
258     fn print_impl_path(
259         self,
260         impl_def_id: DefId,
261         substs: &'tcx [Kind<'tcx>],
262         mut self_ty: Ty<'tcx>,
263         mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
264     ) -> Result<Self::Path, Self::Error> {
265         let key = self.tcx.def_key(impl_def_id);
266         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
267
268         let mut param_env = self.tcx.param_env(impl_def_id)
269             .with_reveal_all();
270         if !substs.is_empty() {
271             param_env = param_env.subst(self.tcx, substs);
272         }
273
274         match &mut impl_trait_ref {
275             Some(impl_trait_ref) => {
276                 assert_eq!(impl_trait_ref.self_ty(), self_ty);
277                 *impl_trait_ref =
278                     self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref);
279                 self_ty = impl_trait_ref.self_ty();
280             }
281             None => {
282                 self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty);
283             }
284         }
285
286         self.path_append_impl(
287             |cx| cx.print_def_path(parent_def_id, &[]),
288             &key.disambiguated_data,
289             self_ty,
290             impl_trait_ref,
291         )
292     }
293
294     fn print_region(
295         mut self,
296         region: ty::Region<'_>,
297     ) -> Result<Self::Region, Self::Error> {
298         let i = match *region {
299             // Erased lifetimes use the index 0, for a
300             // shorter mangling of `L_`.
301             ty::ReErased => 0,
302
303             // Late-bound lifetimes use indices starting at 1,
304             // see `BinderLevel` for more details.
305             ty::ReLateBound(debruijn, ty::BrAnon(i)) => {
306                 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
307                 let depth = binder.lifetime_depths.start + i;
308
309                 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth)
310             }
311
312             _ => bug!("symbol_names: non-erased region `{:?}`", region),
313         };
314         self.push("L");
315         self.push_integer_62(i as u64);
316         Ok(self)
317     }
318
319     fn print_type(
320         mut self,
321         ty: Ty<'tcx>,
322     ) -> Result<Self::Type, Self::Error> {
323         // Basic types, never cached (single-character).
324         let basic_type = match ty.sty {
325             ty::Bool => "b",
326             ty::Char => "c",
327             ty::Str => "e",
328             ty::Tuple(_) if ty.is_unit() => "u",
329             ty::Int(IntTy::I8) => "a",
330             ty::Int(IntTy::I16) => "s",
331             ty::Int(IntTy::I32) => "l",
332             ty::Int(IntTy::I64) => "x",
333             ty::Int(IntTy::I128) => "n",
334             ty::Int(IntTy::Isize) => "i",
335             ty::Uint(UintTy::U8) => "h",
336             ty::Uint(UintTy::U16) => "t",
337             ty::Uint(UintTy::U32) => "m",
338             ty::Uint(UintTy::U64) => "y",
339             ty::Uint(UintTy::U128) => "o",
340             ty::Uint(UintTy::Usize) => "j",
341             ty::Float(FloatTy::F32) => "f",
342             ty::Float(FloatTy::F64) => "d",
343             ty::Never => "z",
344
345             // Placeholders (should be demangled as `_`).
346             ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) |
347             ty::Infer(_) | ty::Error => "p",
348
349             _ => "",
350         };
351         if !basic_type.is_empty() {
352             self.push(basic_type);
353             return Ok(self);
354         }
355
356         if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) {
357             return self.print_backref(i);
358         }
359         let start = self.out.len();
360
361         match ty.sty {
362             // Basic types, handled above.
363             ty::Bool | ty::Char | ty::Str |
364             ty::Int(_) | ty::Uint(_) | ty::Float(_) |
365             ty::Never => unreachable!(),
366             ty::Tuple(_) if ty.is_unit() => unreachable!(),
367
368             // Placeholders, also handled as part of basic types.
369             ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) |
370             ty::Infer(_) | ty::Error => unreachable!(),
371
372             ty::Ref(r, ty, mutbl) => {
373                 self.push(match mutbl {
374                     hir::MutImmutable => "R",
375                     hir::MutMutable => "Q",
376                 });
377                 if *r != ty::ReErased {
378                     self = r.print(self)?;
379                 }
380                 self = ty.print(self)?;
381             }
382
383             ty::RawPtr(mt) => {
384                 self.push(match mt.mutbl {
385                     hir::MutImmutable => "P",
386                     hir::MutMutable => "O",
387                 });
388                 self = mt.ty.print(self)?;
389             }
390
391             ty::Array(ty, len) => {
392                 self.push("A");
393                 self = ty.print(self)?;
394                 self = self.print_const(len)?;
395             }
396             ty::Slice(ty) => {
397                 self.push("S");
398                 self = ty.print(self)?;
399             }
400
401             ty::Tuple(tys) => {
402                 self.push("T");
403                 for ty in tys.iter().map(|k| k.expect_ty()) {
404                     self = ty.print(self)?;
405                 }
406                 self.push("E");
407             }
408
409             // Mangle all nominal types as paths.
410             ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) |
411             ty::FnDef(def_id, substs) |
412             ty::Opaque(def_id, substs) |
413             ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
414             ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
415             ty::Closure(def_id, ty::ClosureSubsts { substs }) |
416             ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
417                 self = self.print_def_path(def_id, substs)?;
418             }
419             ty::Foreign(def_id) => {
420                 self = self.print_def_path(def_id, &[])?;
421             }
422
423             ty::FnPtr(sig) => {
424                 self.push("F");
425                 self = self.in_binder(&sig, |mut cx, sig| {
426                     if sig.unsafety == hir::Unsafety::Unsafe {
427                         cx.push("U");
428                     }
429                     match sig.abi {
430                         Abi::Rust => {}
431                         Abi::C => cx.push("KC"),
432                         abi => {
433                             cx.push("K");
434                             let name = abi.name();
435                             if name.contains('-') {
436                                 cx.push_ident(&name.replace('-', "_"));
437                             } else {
438                                 cx.push_ident(name);
439                             }
440                         }
441                     }
442                     for &ty in sig.inputs() {
443                         cx = ty.print(cx)?;
444                     }
445                     if sig.c_variadic {
446                         cx.push("v");
447                     }
448                     cx.push("E");
449                     sig.output().print(cx)
450                 })?;
451             }
452
453             ty::Dynamic(predicates, r) => {
454                 self.push("D");
455                 self = self.in_binder(&predicates, |cx, predicates| {
456                     cx.print_dyn_existential(predicates)
457                 })?;
458                 self = r.print(self)?;
459             }
460
461             ty::GeneratorWitness(_) => {
462                 bug!("symbol_names: unexpected `GeneratorWitness`")
463             }
464         }
465
466         // Only cache types that do not refer to an enclosing
467         // binder (which would change depending on context).
468         if !ty.has_escaping_bound_vars() {
469             if let Some(c) = &mut self.compress {
470                 c.types.insert(ty, start);
471             }
472         }
473         Ok(self)
474     }
475
476     fn print_dyn_existential(
477         mut self,
478         predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
479     ) -> Result<Self::DynExistential, Self::Error> {
480         for predicate in predicates {
481             match *predicate {
482                 ty::ExistentialPredicate::Trait(trait_ref) => {
483                     // Use a type that can't appear in defaults of type parameters.
484                     let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0));
485                     let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self);
486                     self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
487                 }
488                 ty::ExistentialPredicate::Projection(projection) => {
489                     let name = self.tcx.associated_item(projection.item_def_id).ident;
490                     self.push("p");
491                     self.push_ident(&name.as_str());
492                     self = projection.ty.print(self)?;
493                 }
494                 ty::ExistentialPredicate::AutoTrait(def_id) => {
495                     self = self.print_def_path(def_id, &[])?;
496                 }
497             }
498         }
499         self.push("E");
500         Ok(self)
501     }
502
503     fn print_const(
504         mut self,
505         ct: &'tcx ty::Const<'tcx>,
506     ) -> Result<Self::Const, Self::Error> {
507         if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) {
508             return self.print_backref(i);
509         }
510         let start = self.out.len();
511
512         match ct.ty.sty {
513             ty::Uint(_) => {}
514             _ => {
515                 bug!("symbol_names: unsupported constant of type `{}` ({:?})",
516                     ct.ty, ct);
517             }
518         }
519         self = ct.ty.print(self)?;
520
521         if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) {
522             let _ = write!(self.out, "{:x}_", bits);
523         } else {
524             // NOTE(eddyb) despite having the path, we need to
525             // encode a placeholder, as the path could refer
526             // back to e.g. an `impl` using the constant.
527             self.push("p");
528         }
529
530         // Only cache consts that do not refer to an enclosing
531         // binder (which would change depending on context).
532         if !ct.has_escaping_bound_vars() {
533             if let Some(c) = &mut self.compress {
534                 c.consts.insert(ct, start);
535             }
536         }
537         Ok(self)
538     }
539
540     fn path_crate(
541         mut self,
542         cnum: CrateNum,
543     ) -> Result<Self::Path, Self::Error> {
544         self.push("C");
545         let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
546         self.push_disambiguator(fingerprint.to_smaller_hash());
547         let name = self.tcx.original_crate_name(cnum).as_str();
548         self.push_ident(&name);
549         Ok(self)
550     }
551     fn path_qualified(
552         mut self,
553         self_ty: Ty<'tcx>,
554         trait_ref: Option<ty::TraitRef<'tcx>>,
555     ) -> Result<Self::Path, Self::Error> {
556         assert!(trait_ref.is_some());
557         let trait_ref = trait_ref.unwrap();
558
559         self.push("Y");
560         self = self_ty.print(self)?;
561         self.print_def_path(trait_ref.def_id, trait_ref.substs)
562     }
563
564     fn path_append_impl(
565         mut self,
566         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
567         disambiguated_data: &DisambiguatedDefPathData,
568         self_ty: Ty<'tcx>,
569         trait_ref: Option<ty::TraitRef<'tcx>>,
570     ) -> Result<Self::Path, Self::Error> {
571         self.push(match trait_ref {
572             Some(_) => "X",
573             None => "M",
574         });
575         self.push_disambiguator(disambiguated_data.disambiguator as u64);
576         self = print_prefix(self)?;
577         self = self_ty.print(self)?;
578         if let Some(trait_ref) = trait_ref {
579             self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
580         }
581         Ok(self)
582     }
583     fn path_append(
584         self,
585         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
586         disambiguated_data: &DisambiguatedDefPathData,
587     ) -> Result<Self::Path, Self::Error> {
588         let ns = match disambiguated_data.data {
589             // Uppercase categories are more stable than lowercase ones.
590             DefPathData::TypeNs(_) => 't',
591             DefPathData::ValueNs(_) => 'v',
592             DefPathData::ClosureExpr => 'C',
593             DefPathData::Ctor => 'c',
594             DefPathData::AnonConst => 'k',
595             DefPathData::ImplTrait => 'i',
596
597             // These should never show up as `path_append` arguments.
598             DefPathData::CrateRoot
599             | DefPathData::Misc
600             | DefPathData::Impl
601             | DefPathData::MacroNs(_)
602             | DefPathData::LifetimeNs(_)
603             | DefPathData::GlobalMetaData(_) => {
604                 bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
605             }
606         };
607
608         let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str());
609
610         self.path_append_ns(
611             print_prefix,
612             ns,
613             disambiguated_data.disambiguator as u64,
614             name.as_ref().map_or("", |s| &s[..])
615         )
616     }
617     fn path_generic_args(
618         mut self,
619         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
620         args: &[Kind<'tcx>],
621     ) -> Result<Self::Path, Self::Error> {
622         // Don't print any regions if they're all erased.
623         let print_regions = args.iter().any(|arg| {
624             match arg.unpack() {
625                 UnpackedKind::Lifetime(r) => *r != ty::ReErased,
626                 _ => false,
627             }
628         });
629         let args = args.iter().cloned().filter(|arg| {
630             match arg.unpack() {
631                 UnpackedKind::Lifetime(_) => print_regions,
632                 _ => true,
633             }
634         });
635
636         if args.clone().next().is_none() {
637             return print_prefix(self);
638         }
639
640         self.push("I");
641         self = print_prefix(self)?;
642         for arg in args {
643             match arg.unpack() {
644                 UnpackedKind::Lifetime(lt) => {
645                     self = lt.print(self)?;
646                 }
647                 UnpackedKind::Type(ty) => {
648                     self = ty.print(self)?;
649                 }
650                 UnpackedKind::Const(c) => {
651                     self.push("K");
652                     // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`.
653                     // self = c.print(self)?;
654                     self = self.print_const(c)?;
655                 }
656             }
657         }
658         self.push("E");
659
660         Ok(self)
661     }
662 }