1 // For more information about type metadata and type metadata identifiers for cross-language LLVM
2 // CFI support, see Type metadata in the design document in the tracking issue #89653.
4 // FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
5 // builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
6 // calling convention to use this encoding for cross-language LLVM CFI.
8 use bitflags::bitflags;
9 use core::fmt::Display;
10 use rustc_data_structures::base_n;
11 use rustc_data_structures::fx::FxHashMap;
13 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
14 use rustc_middle::ty::{
15 self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
16 Term, Ty, TyCtxt, UintTy,
18 use rustc_span::def_id::DefId;
19 use rustc_span::symbol::sym;
20 use rustc_target::abi::call::{Conv, FnAbi};
21 use rustc_target::spec::abi::Abi;
22 use std::fmt::Write as _;
24 /// Type and extended type qualifiers.
25 #[derive(Eq, Hash, PartialEq)]
32 /// Substitution dictionary key.
33 #[derive(Eq, Hash, PartialEq)]
38 Predicate(ExistentialPredicate<'tcx>),
42 /// Options for typeid_for_fnabi and typeid_for_fnsig.
43 pub struct TypeIdOptions: u32 {
45 const GENERALIZE_POINTERS = 1;
46 const GENERALIZE_REPR_C = 2;
50 /// Options for encode_ty.
51 type EncodeTyOptions = TypeIdOptions;
53 /// Options for transform_ty.
54 type TransformTyOptions = TypeIdOptions;
56 /// Converts a number to a disambiguator (see
57 /// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
58 fn to_disambiguator(num: u64) -> String {
59 if let Some(num) = num.checked_sub(1) {
60 format!("s{}_", base_n::encode(num as u128, 62))
66 /// Converts a number to a sequence number (see
67 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
68 fn to_seq_id(num: usize) -> String {
69 if let Some(num) = num.checked_sub(1) {
70 base_n::encode(num as u128, 36).to_uppercase()
76 /// Substitutes a component if found in the substitution dictionary (see
77 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression>).
79 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
83 match dict.get(&key) {
86 let _ = write!(comp, "S{}_", to_seq_id(*num));
89 dict.insert(key, dict.len());
94 // FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
95 // along with other is_c_type methods.
96 /// Returns whether a `ty::Ty` is `c_void`.
97 fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
99 ty::Adt(adt_def, ..) => {
100 let def_id = adt_def.0.did;
101 let crate_name = tcx.crate_name(def_id.krate);
102 if tcx.item_name(def_id).as_str() == "c_void"
103 && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
114 /// Encodes a const using the Itanium C++ ABI as a literal argument (see
115 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
116 fn encode_const<'tcx>(
119 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
120 options: EncodeTyOptions,
122 // L<element-type>[n]<element-value>E as literal argument
123 let mut s = String::from('L');
126 s.push_str(&encode_ty(tcx, c.ty(), dict, options));
128 // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16,
129 // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1.
130 fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) {
134 let _ = write!(s, "{}", value);
137 fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
138 let _ = write!(s, "{}", value);
141 if let Some(scalar_int) = c.kind().try_to_scalar_int() {
142 let signed = c.ty().is_signed();
143 match scalar_int.size().bits() {
144 8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
145 16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0),
146 32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0),
147 64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0),
148 128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0),
149 8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()),
150 16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()),
151 32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()),
152 64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()),
153 128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()),
155 bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits());
159 bug!("encode_const: unexpected type `{:?}`", c.ty());
162 // Close the "L..E" pair
165 compress(dict, DictKey::Const(c), &mut s);
170 /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
171 /// Rust types that are not used at the FFI boundary.
172 fn encode_fnsig<'tcx>(
174 fn_sig: &FnSig<'tcx>,
175 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
176 options: TypeIdOptions,
178 // Function types are delimited by an "F..E" pair
179 let mut s = String::from("F");
181 let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
182 .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
185 encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
188 encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
192 // Encode the return type
193 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
194 .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
195 let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options);
196 s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
198 // Encode the parameter types
199 let tys = fn_sig.inputs();
202 let ty = transform_ty(tcx, *ty, transform_ty_options);
203 s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
206 if fn_sig.c_variadic {
210 if fn_sig.c_variadic {
213 // Empty parameter lists, whether declared as () or conventionally as (void), are
214 // encoded with a void parameter specifier "v".
219 // Close the "F..E" pair
225 /// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for
226 /// Rust types that are not used at the FFI boundary.
227 fn encode_predicate<'tcx>(
229 predicate: Binder<'tcx, ExistentialPredicate<'tcx>>,
230 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
231 options: EncodeTyOptions,
233 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, as vendor
235 let mut s = String::new();
236 match predicate.as_ref().skip_binder() {
237 ty::ExistentialPredicate::Trait(trait_ref) => {
238 let name = encode_ty_name(tcx, trait_ref.def_id);
239 let _ = write!(s, "u{}{}", name.len(), &name);
240 s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options));
242 ty::ExistentialPredicate::Projection(projection) => {
243 let name = encode_ty_name(tcx, projection.item_def_id);
244 let _ = write!(s, "u{}{}", name.len(), &name);
245 s.push_str(&encode_substs(tcx, projection.substs, dict, options));
246 match projection.term {
248 s.push_str(&encode_ty(tcx, ty, dict, options));
251 s.push_str(&encode_const(tcx, c, dict, options));
255 ty::ExistentialPredicate::AutoTrait(def_id) => {
256 let name = encode_ty_name(tcx, *def_id);
257 let _ = write!(s, "u{}{}", name.len(), &name);
260 compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
264 /// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for
265 /// Rust types that are not used at the FFI boundary.
266 fn encode_predicates<'tcx>(
268 predicates: &List<Binder<'tcx, ExistentialPredicate<'tcx>>>,
269 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
270 options: EncodeTyOptions,
272 // <predicate1[..predicateN]>E as part of vendor extended type
273 let mut s = String::new();
274 let predicates: Vec<Binder<'tcx, ExistentialPredicate<'tcx>>> =
275 predicates.iter().map(|predicate| predicate).collect();
276 for predicate in predicates {
277 s.push_str(&encode_predicate(tcx, predicate, dict, options));
282 /// Encodes a region using the Itanium C++ ABI as a vendor extended type.
283 fn encode_region<'tcx>(
285 region: Region<'tcx>,
286 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
287 _options: EncodeTyOptions,
289 // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
290 let mut s = String::new();
291 match region.kind() {
292 RegionKind::ReLateBound(debruijn, r) => {
293 s.push_str("u6regionI");
294 // Debruijn index, which identifies the binder, as region disambiguator
295 let num = debruijn.index() as u64;
297 s.push_str(&to_disambiguator(num));
299 // Index within the binder
300 let _ = write!(s, "{}", r.var.index() as u64);
302 compress(dict, DictKey::Region(region), &mut s);
304 RegionKind::ReErased => {
305 s.push_str("u6region");
306 compress(dict, DictKey::Region(region), &mut s);
308 RegionKind::ReEarlyBound(..)
309 | RegionKind::ReFree(..)
310 | RegionKind::ReStatic
311 | RegionKind::ReVar(..)
312 | RegionKind::RePlaceholder(..)
313 | RegionKind::ReEmpty(..) => {
314 bug!("encode_region: unexpected `{:?}`", region.kind());
320 /// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
321 /// types that are not used at the FFI boundary.
322 fn encode_substs<'tcx>(
324 substs: SubstsRef<'tcx>,
325 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
326 options: EncodeTyOptions,
328 // [I<subst1..substN>E] as part of vendor extended type
329 let mut s = String::new();
330 let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
331 if !substs.is_empty() {
333 for subst in substs {
334 match subst.unpack() {
335 GenericArgKind::Lifetime(region) => {
336 s.push_str(&encode_region(tcx, region, dict, options));
338 GenericArgKind::Type(ty) => {
339 s.push_str(&encode_ty(tcx, ty, dict, options));
341 GenericArgKind::Const(c) => {
342 s.push_str(&encode_const(tcx, c, dict, options));
351 /// Encodes a ty:Ty name, including its crate and path disambiguators and names.
352 fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String {
353 // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
354 // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
356 // N<namespace-tagN>..N<namespace-tag1>
357 // C<crate-disambiguator><crate-name>
358 // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
360 // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
362 // pub type Type1 = impl Send;
363 // let _: Type1 = <Struct1<i32>>::foo;
364 // fn foo1(_: Type1) { }
366 // pub type Type2 = impl Send;
367 // let _: Type2 = <Trait1<i32>>::foo;
368 // fn foo2(_: Type2) { }
370 // pub type Type3 = impl Send;
371 // let _: Type3 = <i32 as Trait1<i32>>::foo;
372 // fn foo3(_: Type3) { }
374 // pub type Type4 = impl Send;
375 // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
376 // fn foo3(_: Type4) { }
380 // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
381 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
382 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
383 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
385 // The reason for not using v0's extended form of paths is to use a consistent and simpler
386 // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e.,
387 // keep symbol names close to how methods are represented in error messages). See
388 // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
389 let mut s = String::new();
391 // Start and namespace tags
392 let mut def_path = tcx.def_path(def_id);
393 def_path.data.reverse();
394 for disambiguated_data in &def_path.data {
396 s.push_str(match disambiguated_data.data {
397 hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
398 hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
399 hir::definitions::DefPathData::TypeNs(..) => "t",
400 hir::definitions::DefPathData::ValueNs(..) => "v",
401 hir::definitions::DefPathData::ClosureExpr => "C",
402 hir::definitions::DefPathData::Ctor => "c",
403 hir::definitions::DefPathData::AnonConst => "k",
404 hir::definitions::DefPathData::ImplTrait => "i",
405 hir::definitions::DefPathData::CrateRoot
406 | hir::definitions::DefPathData::Use
407 | hir::definitions::DefPathData::GlobalAsm
408 | hir::definitions::DefPathData::MacroNs(..)
409 | hir::definitions::DefPathData::LifetimeNs(..) => {
410 bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
415 // Crate disambiguator and name
417 s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
418 let crate_name = tcx.crate_name(def_path.krate).to_string();
419 let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
421 // Disambiguators and names
422 def_path.data.reverse();
423 for disambiguated_data in &def_path.data {
424 let num = disambiguated_data.disambiguator as u64;
426 s.push_str(&to_disambiguator(num));
429 let name = disambiguated_data.data.to_string();
430 let _ = write!(s, "{}", name.len());
432 // Prepend a '_' if name starts with a digit or '_'
433 if let Some(first) = name.as_bytes().get(0) {
434 if first.is_ascii_digit() || *first == b'_' {
438 bug!("encode_ty_name: invalid name `{:?}`", name);
447 /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
448 /// Rust types that are not used at the FFI boundary.
452 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
453 options: EncodeTyOptions,
455 let mut typeid = String::new();
463 ty::Int(..) | ty::Uint(..) | ty::Float(..) => {
464 // u<length><type-name> as vendor extended type
465 let mut s = String::from(match ty.kind() {
466 ty::Int(IntTy::I8) => "u2i8",
467 ty::Int(IntTy::I16) => "u3i16",
468 ty::Int(IntTy::I32) => "u3i32",
469 ty::Int(IntTy::I64) => "u3i64",
470 ty::Int(IntTy::I128) => "u4i128",
471 ty::Int(IntTy::Isize) => "u5isize",
472 ty::Uint(UintTy::U8) => "u2u8",
473 ty::Uint(UintTy::U16) => "u3u16",
474 ty::Uint(UintTy::U32) => "u3u32",
475 ty::Uint(UintTy::U64) => "u3u64",
476 ty::Uint(UintTy::U128) => "u4u128",
477 ty::Uint(UintTy::Usize) => "u5usize",
478 ty::Float(FloatTy::F32) => "u3f32",
479 ty::Float(FloatTy::F64) => "u3f64",
482 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
487 // u4char as vendor extended type
488 let mut s = String::from("u4char");
489 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
494 // u3str as vendor extended type
495 let mut s = String::from("u3str");
496 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
501 // u5never as vendor extended type
502 let mut s = String::from("u5never");
503 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
508 // () in Rust is equivalent to void return type in C
509 _ if ty.is_unit() => {
515 // u5tupleI<element-type1..element-typeN>E as vendor extended type
516 let mut s = String::from("u5tupleI");
517 for ty in tys.iter() {
518 s.push_str(&encode_ty(tcx, ty, dict, options));
521 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
525 ty::Array(ty0, len) => {
526 // A<array-length><element-type>
527 let mut s = String::from("A");
528 let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap());
529 s.push_str(&encode_ty(tcx, *ty0, dict, options));
530 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
535 // u5sliceI<element-type>E as vendor extended type
536 let mut s = String::from("u5sliceI");
537 s.push_str(&encode_ty(tcx, *ty0, dict, options));
539 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
543 // User-defined types
544 ty::Adt(adt_def, substs) => {
545 let mut s = String::new();
546 let def_id = adt_def.0.did;
547 if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
548 // For for cross-language CFI support, the encoding must be compatible at the FFI
549 // boundary. For instance:
552 // void foo(struct type1* bar) {}
558 // So, encode any repr(C) user-defined type for extern function types with the "C"
559 // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
560 // <name> is <unscoped-name>.
561 let name = tcx.item_name(def_id).to_string();
562 let _ = write!(s, "{}{}", name.len(), &name);
563 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
565 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
566 // <subst>, as vendor extended type.
567 let name = encode_ty_name(tcx, def_id);
568 let _ = write!(s, "u{}{}", name.len(), &name);
569 s.push_str(&encode_substs(tcx, substs, dict, options));
570 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
575 ty::Foreign(def_id) => {
576 // <length><name>, where <name> is <unscoped-name>
577 let mut s = String::new();
578 let name = tcx.item_name(*def_id).to_string();
579 let _ = write!(s, "{}{}", name.len(), &name);
580 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
585 ty::FnDef(def_id, substs)
586 | ty::Closure(def_id, substs)
587 | ty::Generator(def_id, substs, ..) => {
588 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
589 // as vendor extended type.
590 let mut s = String::new();
591 let name = encode_ty_name(tcx, *def_id);
592 let _ = write!(s, "u{}{}", name.len(), &name);
593 s.push_str(&encode_substs(tcx, substs, dict, options));
594 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
599 ty::Ref(region, ty0, ..) => {
600 // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type
601 let mut s = String::new();
602 s.push_str("u3refI");
603 s.push_str(&encode_ty(tcx, *ty0, dict, options));
605 compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s);
606 if ty.is_mutable_ptr() {
607 s = format!("{}{}", "U3mut", &s);
608 compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
614 // P[K]<element-type>
615 let mut s = String::new();
616 s.push_str(&encode_ty(tcx, tm.ty, dict, options));
617 if !ty.is_mutable_ptr() {
618 s = format!("{}{}", "K", &s);
619 compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s);
621 s = format!("{}{}", "P", &s);
622 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
626 ty::FnPtr(fn_sig) => {
627 // PF<return-type><parameter-type1..parameter-typeN>E
628 let mut s = String::from("P");
629 s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
630 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
635 ty::Dynamic(predicates, region) => {
636 // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
637 // vendor extended type.
638 let mut s = String::from("u3dynI");
639 s.push_str(&encode_predicates(tcx, predicates, dict, options));
640 s.push_str(&encode_region(tcx, *region, dict, options));
642 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
649 | ty::GeneratorWitness(..)
653 | ty::Placeholder(..)
654 | ty::Projection(..) => {
655 bug!("encode_ty: unexpected `{:?}`", ty.kind());
662 // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
663 // c_void types into unit types unconditionally, and generalizes all pointers if
664 // TransformTyOptions::GENERALIZE_POINTERS option is set.
665 fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
677 | ty::Dynamic(..) => {}
679 _ if ty.is_unit() => {}
682 ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
685 ty::Array(ty0, len) => {
686 let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap();
687 ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len);
691 ty = tcx.mk_slice(transform_ty(tcx, *ty0, options));
694 ty::Adt(adt_def, substs) => {
695 if is_c_void_ty(tcx, ty) {
697 } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
699 ty = tcx.mk_adt(*adt_def, ty::List::empty());
700 } else if adt_def.repr().transparent() && adt_def.is_struct() {
701 let variant = adt_def.non_enum_variant();
702 let param_env = tcx.param_env(variant.def_id);
703 let field = variant.fields.iter().find(|field| {
704 let ty = tcx.type_of(field.did);
706 tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
710 // Transform repr(transparent) types without non-ZST field into ()
713 let ty0 = tcx.type_of(field.unwrap().did);
714 // Generalize any repr(transparent) user-defined type that is either a pointer
715 // or reference, and either references itself or any other type that contains or
716 // references itself, to avoid a reference cycle.
717 if ty0.is_any_ptr() && ty0.contains(ty) {
721 options | TransformTyOptions::GENERALIZE_POINTERS,
724 ty = transform_ty(tcx, ty0, options);
728 ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
732 ty::FnDef(def_id, substs) => {
733 ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options));
736 ty::Closure(def_id, substs) => {
737 ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options));
740 ty::Generator(def_id, substs, movability) => {
741 ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability);
744 ty::Ref(region, ty0, ..) => {
745 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
746 if ty.is_mutable_ptr() {
747 ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit());
749 ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit());
752 if ty.is_mutable_ptr() {
753 ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options));
755 ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options));
761 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
762 if ty.is_mutable_ptr() {
763 ty = tcx.mk_mut_ptr(tcx.mk_unit());
765 ty = tcx.mk_imm_ptr(tcx.mk_unit());
768 if ty.is_mutable_ptr() {
769 ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options));
771 ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options));
776 ty::FnPtr(fn_sig) => {
777 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
778 ty = tcx.mk_imm_ptr(tcx.mk_unit());
780 let parameters: Vec<Ty<'tcx>> = fn_sig
784 .map(|ty| transform_ty(tcx, *ty, options))
786 let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
787 ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars(
802 | ty::GeneratorWitness(..)
806 | ty::Placeholder(..)
807 | ty::Projection(..) => {
808 bug!("transform_ty: unexpected `{:?}`", ty.kind());
815 /// Transforms substs for being encoded and used in the substitution dictionary.
816 fn transform_substs<'tcx>(
818 substs: SubstsRef<'tcx>,
819 options: TransformTyOptions,
820 ) -> SubstsRef<'tcx> {
821 let substs: Vec<GenericArg<'tcx>> = substs
824 if let GenericArgKind::Type(ty) = subst.unpack() {
825 if is_c_void_ty(tcx, ty) {
828 transform_ty(tcx, ty, options).into()
835 tcx.mk_substs(substs.iter())
838 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
839 /// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
840 pub fn typeid_for_fnabi<'tcx>(
842 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
843 options: TypeIdOptions,
845 // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
847 let mut typeid = String::from("_Z");
849 // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
850 // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
851 // code (i.e., 'TS') prefixed to the type encoding for the function.
852 typeid.push_str("TS");
854 // Function types are delimited by an "F..E" pair
857 // A dictionary of substitution candidates used for compression (see
858 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
859 let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
861 let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
862 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
865 encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
868 encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
872 // Encode the return type
873 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
874 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
875 let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options);
876 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
878 // Encode the parameter types
879 if !fn_abi.c_variadic {
880 if !fn_abi.args.is_empty() {
881 for arg in fn_abi.args.iter() {
882 let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
883 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
886 // Empty parameter lists, whether declared as () or conventionally as (void), are
887 // encoded with a void parameter specifier "v".
891 for n in 0..fn_abi.fixed_count {
892 let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
893 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
899 // Close the "F..E" pair
905 /// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor
906 /// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
907 pub fn typeid_for_fnsig<'tcx>(
909 fn_sig: &FnSig<'tcx>,
910 options: TypeIdOptions,
912 // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
914 let mut typeid = String::from("_Z");
916 // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
917 // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
918 // code (i.e., 'TS') prefixed to the type encoding for the function.
919 typeid.push_str("TS");
921 // A dictionary of substitution candidates used for compression (see
922 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
923 let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
925 // Encode the function signature
926 typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));