]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_symbol_mangling/src/v0.rs
Rollup merge of #95446 - notseanray:master, r=Mark-Simulacrum
[rust.git] / compiler / rustc_symbol_mangling / src / v0.rs
1 use rustc_data_structures::base_n;
2 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
3 use rustc_data_structures::intern::Interned;
4 use rustc_hir as hir;
5 use rustc_hir::def::CtorKind;
6 use rustc_hir::def_id::{CrateNum, DefId};
7 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
8 use rustc_middle::ty::layout::IntegerExt;
9 use rustc_middle::ty::print::{Print, Printer};
10 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
11 use rustc_middle::ty::{
12     self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy,
13 };
14 use rustc_span::symbol::kw;
15 use rustc_target::abi::call::FnAbi;
16 use rustc_target::abi::Integer;
17 use rustc_target::spec::abi::Abi;
18
19 use std::fmt::Write;
20 use std::iter;
21 use std::ops::Range;
22
23 pub(super) fn mangle<'tcx>(
24     tcx: TyCtxt<'tcx>,
25     instance: Instance<'tcx>,
26     instantiating_crate: Option<CrateNum>,
27 ) -> String {
28     let def_id = instance.def_id();
29     // FIXME(eddyb) this should ideally not be needed.
30     let substs = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs);
31
32     let prefix = "_R";
33     let mut cx = &mut SymbolMangler {
34         tcx,
35         start_offset: prefix.len(),
36         paths: FxHashMap::default(),
37         types: FxHashMap::default(),
38         consts: FxHashMap::default(),
39         binders: vec![],
40         out: String::from(prefix),
41     };
42
43     // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance.
44     let shim_kind = match instance.def {
45         ty::InstanceDef::VtableShim(_) => Some("vtable"),
46         ty::InstanceDef::ReifyShim(_) => Some("reify"),
47
48         _ => None,
49     };
50
51     cx = if let Some(shim_kind) = shim_kind {
52         cx.path_append_ns(|cx| cx.print_def_path(def_id, substs), 'S', 0, shim_kind).unwrap()
53     } else {
54         cx.print_def_path(def_id, substs).unwrap()
55     };
56     if let Some(instantiating_crate) = instantiating_crate {
57         cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap();
58     }
59     std::mem::take(&mut cx.out)
60 }
61
62 pub(super) fn mangle_typeid_for_fnabi<'tcx>(
63     _tcx: TyCtxt<'tcx>,
64     fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
65 ) -> String {
66     // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
67     // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
68     // associated with a type identifier (i.e., test type membership).
69     //
70     // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
71     // type metadata identifiers for function pointers. The typeinfo name encoding is a
72     // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
73     //
74     // For cross-language LLVM CFI support, a compatible encoding must be used by either
75     //
76     //  a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
77     //     type encodings[4]), or at least types used at the FFI boundary.
78     //  b. Reducing the types to the least common denominator between types used by Clang (or at
79     //     least types used at the FFI boundary) and Rust compilers (if even possible).
80     //  c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
81     //     possibly other compilers).
82     //
83     // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
84     // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
85     // code. Option (c) would require changes to Clang to use the new ABI.
86     //
87     // [1] https://llvm.org/docs/TypeMetadata.html
88     // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
89     // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
90     // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
91     //
92     // FIXME(rcvalle): See comment above.
93     let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
94     format!("typeid{}", arg_count)
95 }
96
97 pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
98     tcx: TyCtxt<'tcx>,
99     trait_ref: ty::PolyExistentialTraitRef<'tcx>,
100 ) -> String {
101     // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`.
102     let mut cx = &mut SymbolMangler {
103         tcx,
104         start_offset: 0,
105         paths: FxHashMap::default(),
106         types: FxHashMap::default(),
107         consts: FxHashMap::default(),
108         binders: vec![],
109         out: String::new(),
110     };
111     cx = cx.print_def_path(trait_ref.def_id(), &[]).unwrap();
112     std::mem::take(&mut cx.out)
113 }
114
115 struct BinderLevel {
116     /// The range of distances from the root of what's
117     /// being printed, to the lifetimes in a binder.
118     /// Specifically, a `BrAnon(i)` lifetime has depth
119     /// `lifetime_depths.start + i`, going away from the
120     /// the root and towards its use site, as `i` increases.
121     /// This is used to flatten rustc's pairing of `BrAnon`
122     /// (intra-binder disambiguation) with a `DebruijnIndex`
123     /// (binder addressing), to "true" de Bruijn indices,
124     /// by subtracting the depth of a certain lifetime, from
125     /// the innermost depth at its use site.
126     lifetime_depths: Range<u32>,
127 }
128
129 struct SymbolMangler<'tcx> {
130     tcx: TyCtxt<'tcx>,
131     binders: Vec<BinderLevel>,
132     out: String,
133
134     /// The length of the prefix in `out` (e.g. 2 for `_R`).
135     start_offset: usize,
136     /// The values are start positions in `out`, in bytes.
137     paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>,
138     types: FxHashMap<Ty<'tcx>, usize>,
139     consts: FxHashMap<ty::Const<'tcx>, usize>,
140 }
141
142 impl<'tcx> SymbolMangler<'tcx> {
143     fn push(&mut self, s: &str) {
144         self.out.push_str(s);
145     }
146
147     /// Push a `_`-terminated base 62 integer, using the format
148     /// specified in the RFC as `<base-62-number>`, that is:
149     /// * `x = 0` is encoded as just the `"_"` terminator
150     /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`,
151     ///   e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
152     fn push_integer_62(&mut self, x: u64) {
153         if let Some(x) = x.checked_sub(1) {
154             base_n::push_str(x as u128, 62, &mut self.out);
155         }
156         self.push("_");
157     }
158
159     /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is:
160     /// * `x = 0` is encoded as `""` (nothing)
161     /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)`
162     ///   e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc.
163     fn push_opt_integer_62(&mut self, tag: &str, x: u64) {
164         if let Some(x) = x.checked_sub(1) {
165             self.push(tag);
166             self.push_integer_62(x);
167         }
168     }
169
170     fn push_disambiguator(&mut self, dis: u64) {
171         self.push_opt_integer_62("s", dis);
172     }
173
174     fn push_ident(&mut self, ident: &str) {
175         let mut use_punycode = false;
176         for b in ident.bytes() {
177             match b {
178                 b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {}
179                 0x80..=0xff => use_punycode = true,
180                 _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident),
181             }
182         }
183
184         let punycode_string;
185         let ident = if use_punycode {
186             self.push("u");
187
188             // FIXME(eddyb) we should probably roll our own punycode implementation.
189             let mut punycode_bytes = match punycode::encode(ident) {
190                 Ok(s) => s.into_bytes(),
191                 Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
192             };
193
194             // Replace `-` with `_`.
195             if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') {
196                 *c = b'_';
197             }
198
199             // FIXME(eddyb) avoid rechecking UTF-8 validity.
200             punycode_string = String::from_utf8(punycode_bytes).unwrap();
201             &punycode_string
202         } else {
203             ident
204         };
205
206         let _ = write!(self.out, "{}", ident.len());
207
208         // Write a separating `_` if necessary (leading digit or `_`).
209         if let Some('_' | '0'..='9') = ident.chars().next() {
210             self.push("_");
211         }
212
213         self.push(ident);
214     }
215
216     fn path_append_ns<'a>(
217         mut self: &'a mut Self,
218         print_prefix: impl FnOnce(&'a mut Self) -> Result<&'a mut Self, !>,
219         ns: char,
220         disambiguator: u64,
221         name: &str,
222     ) -> Result<&'a mut Self, !> {
223         self.push("N");
224         self.out.push(ns);
225         self = print_prefix(self)?;
226         self.push_disambiguator(disambiguator as u64);
227         self.push_ident(name);
228         Ok(self)
229     }
230
231     fn print_backref(&mut self, i: usize) -> Result<&mut Self, !> {
232         self.push("B");
233         self.push_integer_62((i - self.start_offset) as u64);
234         Ok(self)
235     }
236
237     fn in_binder<'a, T>(
238         mut self: &'a mut Self,
239         value: &ty::Binder<'tcx, T>,
240         print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>,
241     ) -> Result<&'a mut Self, !>
242     where
243         T: TypeFoldable<'tcx>,
244     {
245         let regions = if value.has_late_bound_regions() {
246             self.tcx.collect_referenced_late_bound_regions(value)
247         } else {
248             FxHashSet::default()
249         };
250
251         let mut lifetime_depths =
252             self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i);
253
254         let lifetimes = regions
255             .into_iter()
256             .map(|br| match br {
257                 ty::BrAnon(i) => i,
258                 _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
259             })
260             .max()
261             .map_or(0, |max| max + 1);
262
263         self.push_opt_integer_62("G", lifetimes as u64);
264         lifetime_depths.end += lifetimes;
265
266         self.binders.push(BinderLevel { lifetime_depths });
267         self = print_value(self, value.as_ref().skip_binder())?;
268         self.binders.pop();
269
270         Ok(self)
271     }
272 }
273
274 impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
275     type Error = !;
276
277     type Path = Self;
278     type Region = Self;
279     type Type = Self;
280     type DynExistential = Self;
281     type Const = Self;
282
283     fn tcx(&self) -> TyCtxt<'tcx> {
284         self.tcx
285     }
286
287     fn print_def_path(
288         mut self,
289         def_id: DefId,
290         substs: &'tcx [GenericArg<'tcx>],
291     ) -> Result<Self::Path, Self::Error> {
292         if let Some(&i) = self.paths.get(&(def_id, substs)) {
293             return self.print_backref(i);
294         }
295         let start = self.out.len();
296
297         self = self.default_print_def_path(def_id, substs)?;
298
299         // Only cache paths that do not refer to an enclosing
300         // binder (which would change depending on context).
301         if !substs.iter().any(|k| k.has_escaping_bound_vars()) {
302             self.paths.insert((def_id, substs), start);
303         }
304         Ok(self)
305     }
306
307     fn print_impl_path(
308         mut self,
309         impl_def_id: DefId,
310         substs: &'tcx [GenericArg<'tcx>],
311         mut self_ty: Ty<'tcx>,
312         mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
313     ) -> Result<Self::Path, Self::Error> {
314         let key = self.tcx.def_key(impl_def_id);
315         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
316
317         let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
318         if !substs.is_empty() {
319             param_env = EarlyBinder(param_env).subst(self.tcx, substs);
320         }
321
322         match &mut impl_trait_ref {
323             Some(impl_trait_ref) => {
324                 assert_eq!(impl_trait_ref.self_ty(), self_ty);
325                 *impl_trait_ref = self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref);
326                 self_ty = impl_trait_ref.self_ty();
327             }
328             None => {
329                 self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty);
330             }
331         }
332
333         self.push(match impl_trait_ref {
334             Some(_) => "X",
335             None => "M",
336         });
337
338         // Encode impl generic params if the substitutions contain parameters (implying
339         // polymorphization is enabled) and this isn't an inherent impl.
340         if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
341             self = self.path_generic_args(
342                 |this| {
343                     this.path_append_ns(
344                         |cx| cx.print_def_path(parent_def_id, &[]),
345                         'I',
346                         key.disambiguated_data.disambiguator as u64,
347                         "",
348                     )
349                 },
350                 substs,
351             )?;
352         } else {
353             self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
354             self = self.print_def_path(parent_def_id, &[])?;
355         }
356
357         self = self_ty.print(self)?;
358
359         if let Some(trait_ref) = impl_trait_ref {
360             self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
361         }
362
363         Ok(self)
364     }
365
366     fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
367         let i = match *region {
368             // Erased lifetimes use the index 0, for a
369             // shorter mangling of `L_`.
370             ty::ReErased => 0,
371
372             // Late-bound lifetimes use indices starting at 1,
373             // see `BinderLevel` for more details.
374             ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
375                 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
376                 let depth = binder.lifetime_depths.start + i;
377
378                 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth)
379             }
380
381             _ => bug!("symbol_names: non-erased region `{:?}`", region),
382         };
383         self.push("L");
384         self.push_integer_62(i as u64);
385         Ok(self)
386     }
387
388     fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
389         // Basic types, never cached (single-character).
390         let basic_type = match ty.kind() {
391             ty::Bool => "b",
392             ty::Char => "c",
393             ty::Str => "e",
394             ty::Tuple(_) if ty.is_unit() => "u",
395             ty::Int(IntTy::I8) => "a",
396             ty::Int(IntTy::I16) => "s",
397             ty::Int(IntTy::I32) => "l",
398             ty::Int(IntTy::I64) => "x",
399             ty::Int(IntTy::I128) => "n",
400             ty::Int(IntTy::Isize) => "i",
401             ty::Uint(UintTy::U8) => "h",
402             ty::Uint(UintTy::U16) => "t",
403             ty::Uint(UintTy::U32) => "m",
404             ty::Uint(UintTy::U64) => "y",
405             ty::Uint(UintTy::U128) => "o",
406             ty::Uint(UintTy::Usize) => "j",
407             ty::Float(FloatTy::F32) => "f",
408             ty::Float(FloatTy::F64) => "d",
409             ty::Never => "z",
410
411             // Placeholders (should be demangled as `_`).
412             ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => "p",
413
414             _ => "",
415         };
416         if !basic_type.is_empty() {
417             self.push(basic_type);
418             return Ok(self);
419         }
420
421         if let Some(&i) = self.types.get(&ty) {
422             return self.print_backref(i);
423         }
424         let start = self.out.len();
425
426         match *ty.kind() {
427             // Basic types, handled above.
428             ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => {
429                 unreachable!()
430             }
431             ty::Tuple(_) if ty.is_unit() => unreachable!(),
432
433             // Placeholders, also handled as part of basic types.
434             ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
435                 unreachable!()
436             }
437
438             ty::Ref(r, ty, mutbl) => {
439                 self.push(match mutbl {
440                     hir::Mutability::Not => "R",
441                     hir::Mutability::Mut => "Q",
442                 });
443                 if !r.is_erased() {
444                     self = r.print(self)?;
445                 }
446                 self = ty.print(self)?;
447             }
448
449             ty::RawPtr(mt) => {
450                 self.push(match mt.mutbl {
451                     hir::Mutability::Not => "P",
452                     hir::Mutability::Mut => "O",
453                 });
454                 self = mt.ty.print(self)?;
455             }
456
457             ty::Array(ty, len) => {
458                 self.push("A");
459                 self = ty.print(self)?;
460                 self = self.print_const(len)?;
461             }
462             ty::Slice(ty) => {
463                 self.push("S");
464                 self = ty.print(self)?;
465             }
466
467             ty::Tuple(tys) => {
468                 self.push("T");
469                 for ty in tys.iter() {
470                     self = ty.print(self)?;
471                 }
472                 self.push("E");
473             }
474
475             // Mangle all nominal types as paths.
476             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
477             | ty::FnDef(def_id, substs)
478             | ty::Opaque(def_id, substs)
479             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
480             | ty::Closure(def_id, substs)
481             | ty::Generator(def_id, substs, _) => {
482                 self = self.print_def_path(def_id, substs)?;
483             }
484             ty::Foreign(def_id) => {
485                 self = self.print_def_path(def_id, &[])?;
486             }
487
488             ty::FnPtr(sig) => {
489                 self.push("F");
490                 self = self.in_binder(&sig, |mut cx, sig| {
491                     if sig.unsafety == hir::Unsafety::Unsafe {
492                         cx.push("U");
493                     }
494                     match sig.abi {
495                         Abi::Rust => {}
496                         Abi::C { unwind: false } => cx.push("KC"),
497                         abi => {
498                             cx.push("K");
499                             let name = abi.name();
500                             if name.contains('-') {
501                                 cx.push_ident(&name.replace('-', "_"));
502                             } else {
503                                 cx.push_ident(name);
504                             }
505                         }
506                     }
507                     for &ty in sig.inputs() {
508                         cx = ty.print(cx)?;
509                     }
510                     if sig.c_variadic {
511                         cx.push("v");
512                     }
513                     cx.push("E");
514                     sig.output().print(cx)
515                 })?;
516             }
517
518             ty::Dynamic(predicates, r) => {
519                 self.push("D");
520                 self = self.print_dyn_existential(predicates)?;
521                 self = r.print(self)?;
522             }
523
524             ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
525         }
526
527         // Only cache types that do not refer to an enclosing
528         // binder (which would change depending on context).
529         if !ty.has_escaping_bound_vars() {
530             self.types.insert(ty, start);
531         }
532         Ok(self)
533     }
534
535     fn print_dyn_existential(
536         mut self,
537         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
538     ) -> Result<Self::DynExistential, Self::Error> {
539         // Okay, so this is a bit tricky. Imagine we have a trait object like
540         // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the
541         // output looks really close to the syntax, where the `Bar = &'a ()` bit
542         // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we
543         // actually desugar these into two separate `ExistentialPredicate`s. We
544         // can't enter/exit the "binder scope" twice though, because then we
545         // would mangle the binders twice. (Also, side note, we merging these
546         // two is kind of difficult, because of potential HRTBs in the Projection
547         // predicate.)
548         //
549         // Also worth mentioning: imagine that we instead had
550         // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is
551         // under the same binders as `Foo`. Currently, this doesn't matter,
552         // because only *auto traits* are allowed other than the principal trait
553         // and all auto traits don't have any generics. Two things could
554         // make this not an "okay" mangling:
555         // 1) Instead of mangling only *used*
556         // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a
557         // valid trait predicate);
558         // 2) We allow multiple "principal" traits in the future, or at least
559         // allow in any form another trait predicate that can take generics.
560         //
561         // Here we assume that predicates have the following structure:
562         // [<Trait> [{<Projection>}]] [{<Auto>}]
563         // Since any predicates after the first one shouldn't change the binders,
564         // just put them all in the binders of the first.
565         self = self.in_binder(&predicates[0], |mut cx, _| {
566             for predicate in predicates.iter() {
567                 // It would be nice to be able to validate bound vars here, but
568                 // projections can actually include bound vars from super traits
569                 // because of HRTBs (only in the `Self` type). Also, auto traits
570                 // could have different bound vars *anyways*.
571                 match predicate.as_ref().skip_binder() {
572                     ty::ExistentialPredicate::Trait(trait_ref) => {
573                         // Use a type that can't appear in defaults of type parameters.
574                         let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0));
575                         let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self);
576                         cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
577                     }
578                     ty::ExistentialPredicate::Projection(projection) => {
579                         let name = cx.tcx.associated_item(projection.item_def_id).name;
580                         cx.push("p");
581                         cx.push_ident(name.as_str());
582                         cx = match projection.term {
583                             ty::Term::Ty(ty) => ty.print(cx),
584                             ty::Term::Const(c) => c.print(cx),
585                         }?;
586                     }
587                     ty::ExistentialPredicate::AutoTrait(def_id) => {
588                         cx = cx.print_def_path(*def_id, &[])?;
589                     }
590                 }
591             }
592             Ok(cx)
593         })?;
594
595         self.push("E");
596         Ok(self)
597     }
598
599     fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
600         // We only mangle a typed value if the const can be evaluated.
601         let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
602         match ct.kind() {
603             ty::ConstKind::Value(_) => {}
604
605             // Placeholders (should be demangled as `_`).
606             // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore
607             // a path), even for it we still need to encode a placeholder, as
608             // the path could refer back to e.g. an `impl` using the constant.
609             ty::ConstKind::Unevaluated(_)
610             | ty::ConstKind::Param(_)
611             | ty::ConstKind::Infer(_)
612             | ty::ConstKind::Bound(..)
613             | ty::ConstKind::Placeholder(_)
614             | ty::ConstKind::Error(_) => {
615                 // Never cached (single-character).
616                 self.push("p");
617                 return Ok(self);
618             }
619         }
620
621         if let Some(&i) = self.consts.get(&ct) {
622             return self.print_backref(i);
623         }
624
625         let start = self.out.len();
626         let ty = ct.ty();
627
628         match ty.kind() {
629             ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
630                 self = ty.print(self)?;
631
632                 let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty);
633
634                 // Negative integer values are mangled using `n` as a "sign prefix".
635                 if let ty::Int(ity) = ty.kind() {
636                     let val =
637                         Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
638                     if val < 0 {
639                         self.push("n");
640                     }
641                     bits = val.unsigned_abs();
642                 }
643
644                 let _ = write!(self.out, "{:x}_", bits);
645             }
646
647             // FIXME(valtrees): Remove the special case for `str`
648             // here and fully support unsized constants.
649             ty::Ref(_, inner_ty, mutbl) => {
650                 self.push(match mutbl {
651                     hir::Mutability::Not => "R",
652                     hir::Mutability::Mut => "Q",
653                 });
654
655                 match inner_ty.kind() {
656                     ty::Str if *mutbl == hir::Mutability::Not => {
657                         match ct.kind() {
658                             ty::ConstKind::Value(valtree) => {
659                                 let slice =
660                                     valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
661                                         bug!(
662                                         "expected to get raw bytes from valtree {:?} for type {:}",
663                                         valtree, ty
664                                     )
665                                     });
666                                 let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
667
668                                 self.push("e");
669
670                                 // FIXME(eddyb) use a specialized hex-encoding loop.
671                                 for byte in s.bytes() {
672                                     let _ = write!(self.out, "{:02x}", byte);
673                                 }
674
675                                 self.push("_");
676                             }
677
678                             _ => {
679                                 bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
680                             }
681                         }
682                     }
683                     _ => {
684                         let pointee_ty = ct
685                             .ty()
686                             .builtin_deref(true)
687                             .expect("tried to dereference on non-ptr type")
688                             .ty;
689                         let dereferenced_const =
690                             self.tcx.mk_const(ty::ConstS { kind: ct.kind(), ty: pointee_ty });
691                         self = dereferenced_const.print(self)?;
692                     }
693                 }
694             }
695
696             ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
697                 let contents = self.tcx.destructure_const(ct);
698                 let fields = contents.fields.iter().copied();
699
700                 let print_field_list = |mut this: Self| {
701                     for field in fields.clone() {
702                         this = field.print(this)?;
703                     }
704                     this.push("E");
705                     Ok(this)
706                 };
707
708                 match *ct.ty().kind() {
709                     ty::Array(..) | ty::Slice(_) => {
710                         self.push("A");
711                         self = print_field_list(self)?;
712                     }
713                     ty::Tuple(..) => {
714                         self.push("T");
715                         self = print_field_list(self)?;
716                     }
717                     ty::Adt(def, substs) => {
718                         let variant_idx =
719                             contents.variant.expect("destructed const of adt without variant idx");
720                         let variant_def = &def.variant(variant_idx);
721
722                         self.push("V");
723                         self = self.print_def_path(variant_def.def_id, substs)?;
724
725                         match variant_def.ctor_kind {
726                             CtorKind::Const => {
727                                 self.push("U");
728                             }
729                             CtorKind::Fn => {
730                                 self.push("T");
731                                 self = print_field_list(self)?;
732                             }
733                             CtorKind::Fictive => {
734                                 self.push("S");
735                                 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
736                                     // HACK(eddyb) this mimics `path_append`,
737                                     // instead of simply using `field_def.ident`,
738                                     // just to be able to handle disambiguators.
739                                     let disambiguated_field =
740                                         self.tcx.def_key(field_def.did).disambiguated_data;
741                                     let field_name = disambiguated_field.data.get_opt_name();
742                                     self.push_disambiguator(
743                                         disambiguated_field.disambiguator as u64,
744                                     );
745                                     self.push_ident(field_name.unwrap_or(kw::Empty).as_str());
746
747                                     self = field.print(self)?;
748                                 }
749                                 self.push("E");
750                             }
751                         }
752                     }
753                     _ => unreachable!(),
754                 }
755             }
756             _ => {
757                 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct);
758             }
759         }
760
761         // Only cache consts that do not refer to an enclosing
762         // binder (which would change depending on context).
763         if !ct.has_escaping_bound_vars() {
764             self.consts.insert(ct, start);
765         }
766         Ok(self)
767     }
768
769     fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
770         self.push("C");
771         let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
772         self.push_disambiguator(stable_crate_id.to_u64());
773         let name = self.tcx.crate_name(cnum);
774         self.push_ident(name.as_str());
775         Ok(self)
776     }
777
778     fn path_qualified(
779         mut self,
780         self_ty: Ty<'tcx>,
781         trait_ref: Option<ty::TraitRef<'tcx>>,
782     ) -> Result<Self::Path, Self::Error> {
783         assert!(trait_ref.is_some());
784         let trait_ref = trait_ref.unwrap();
785
786         self.push("Y");
787         self = self_ty.print(self)?;
788         self.print_def_path(trait_ref.def_id, trait_ref.substs)
789     }
790
791     fn path_append_impl(
792         self,
793         _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
794         _: &DisambiguatedDefPathData,
795         _: Ty<'tcx>,
796         _: Option<ty::TraitRef<'tcx>>,
797     ) -> Result<Self::Path, Self::Error> {
798         // Inlined into `print_impl_path`
799         unreachable!()
800     }
801
802     fn path_append(
803         self,
804         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
805         disambiguated_data: &DisambiguatedDefPathData,
806     ) -> Result<Self::Path, Self::Error> {
807         let ns = match disambiguated_data.data {
808             // Extern block segments can be skipped, names from extern blocks
809             // are effectively living in their parent modules.
810             DefPathData::ForeignMod => return print_prefix(self),
811
812             // Uppercase categories are more stable than lowercase ones.
813             DefPathData::TypeNs(_) => 't',
814             DefPathData::ValueNs(_) => 'v',
815             DefPathData::ClosureExpr => 'C',
816             DefPathData::Ctor => 'c',
817             DefPathData::AnonConst => 'k',
818             DefPathData::ImplTrait => 'i',
819
820             // These should never show up as `path_append` arguments.
821             DefPathData::CrateRoot
822             | DefPathData::Use
823             | DefPathData::GlobalAsm
824             | DefPathData::Impl
825             | DefPathData::MacroNs(_)
826             | DefPathData::LifetimeNs(_) => {
827                 bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
828             }
829         };
830
831         let name = disambiguated_data.data.get_opt_name();
832
833         self.path_append_ns(
834             print_prefix,
835             ns,
836             disambiguated_data.disambiguator as u64,
837             name.unwrap_or(kw::Empty).as_str(),
838         )
839     }
840
841     fn path_generic_args(
842         mut self,
843         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
844         args: &[GenericArg<'tcx>],
845     ) -> Result<Self::Path, Self::Error> {
846         // Don't print any regions if they're all erased.
847         let print_regions = args.iter().any(|arg| match arg.unpack() {
848             GenericArgKind::Lifetime(r) => !r.is_erased(),
849             _ => false,
850         });
851         let args = args.iter().cloned().filter(|arg| match arg.unpack() {
852             GenericArgKind::Lifetime(_) => print_regions,
853             _ => true,
854         });
855
856         if args.clone().next().is_none() {
857             return print_prefix(self);
858         }
859
860         self.push("I");
861         self = print_prefix(self)?;
862         for arg in args {
863             match arg.unpack() {
864                 GenericArgKind::Lifetime(lt) => {
865                     self = lt.print(self)?;
866                 }
867                 GenericArgKind::Type(ty) => {
868                     self = ty.print(self)?;
869                 }
870                 GenericArgKind::Const(c) => {
871                     self.push("K");
872                     self = c.print(self)?;
873                 }
874             }
875         }
876         self.push("E");
877
878         Ok(self)
879     }
880 }