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