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