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, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, TermKind,
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: ty::PolyExistentialPredicate<'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.unpack() {
247 TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
248 TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)),
251 ty::ExistentialPredicate::AutoTrait(def_id) => {
252 let name = encode_ty_name(tcx, *def_id);
253 let _ = write!(s, "u{}{}", name.len(), &name);
256 compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
260 /// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for
261 /// Rust types that are not used at the FFI boundary.
262 fn encode_predicates<'tcx>(
264 predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
265 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
266 options: EncodeTyOptions,
268 // <predicate1[..predicateN]>E as part of vendor extended type
269 let mut s = String::new();
270 let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> =
271 predicates.iter().map(|predicate| predicate).collect();
272 for predicate in predicates {
273 s.push_str(&encode_predicate(tcx, predicate, dict, options));
278 /// Encodes a region using the Itanium C++ ABI as a vendor extended type.
279 fn encode_region<'tcx>(
281 region: Region<'tcx>,
282 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
283 _options: EncodeTyOptions,
285 // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
286 let mut s = String::new();
287 match region.kind() {
288 RegionKind::ReLateBound(debruijn, r) => {
289 s.push_str("u6regionI");
290 // Debruijn index, which identifies the binder, as region disambiguator
291 let num = debruijn.index() as u64;
293 s.push_str(&to_disambiguator(num));
295 // Index within the binder
296 let _ = write!(s, "{}", r.var.index() as u64);
298 compress(dict, DictKey::Region(region), &mut s);
300 RegionKind::ReErased => {
301 s.push_str("u6region");
302 compress(dict, DictKey::Region(region), &mut s);
304 RegionKind::ReEarlyBound(..)
305 | RegionKind::ReFree(..)
306 | RegionKind::ReStatic
307 | RegionKind::ReVar(..)
308 | RegionKind::RePlaceholder(..) => {
309 bug!("encode_region: unexpected `{:?}`", region.kind());
315 /// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
316 /// types that are not used at the FFI boundary.
317 fn encode_substs<'tcx>(
319 substs: SubstsRef<'tcx>,
320 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
321 options: EncodeTyOptions,
323 // [I<subst1..substN>E] as part of vendor extended type
324 let mut s = String::new();
325 let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
326 if !substs.is_empty() {
328 for subst in substs {
329 match subst.unpack() {
330 GenericArgKind::Lifetime(region) => {
331 s.push_str(&encode_region(tcx, region, dict, options));
333 GenericArgKind::Type(ty) => {
334 s.push_str(&encode_ty(tcx, ty, dict, options));
336 GenericArgKind::Const(c) => {
337 s.push_str(&encode_const(tcx, c, dict, options));
346 /// Encodes a ty:Ty name, including its crate and path disambiguators and names.
347 fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String {
348 // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
349 // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
351 // N<namespace-tagN>..N<namespace-tag1>
352 // C<crate-disambiguator><crate-name>
353 // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
355 // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
357 // pub type Type1 = impl Send;
358 // let _: Type1 = <Struct1<i32>>::foo;
359 // fn foo1(_: Type1) { }
361 // pub type Type2 = impl Send;
362 // let _: Type2 = <Trait1<i32>>::foo;
363 // fn foo2(_: Type2) { }
365 // pub type Type3 = impl Send;
366 // let _: Type3 = <i32 as Trait1<i32>>::foo;
367 // fn foo3(_: Type3) { }
369 // pub type Type4 = impl Send;
370 // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
371 // fn foo3(_: Type4) { }
375 // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
376 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
377 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
378 // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
380 // The reason for not using v0's extended form of paths is to use a consistent and simpler
381 // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e.,
382 // keep symbol names close to how methods are represented in error messages). See
383 // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
384 let mut s = String::new();
386 // Start and namespace tags
387 let mut def_path = tcx.def_path(def_id);
388 def_path.data.reverse();
389 for disambiguated_data in &def_path.data {
391 s.push_str(match disambiguated_data.data {
392 hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
393 hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
394 hir::definitions::DefPathData::TypeNs(..) => "t",
395 hir::definitions::DefPathData::ValueNs(..) => "v",
396 hir::definitions::DefPathData::ClosureExpr => "C",
397 hir::definitions::DefPathData::Ctor => "c",
398 hir::definitions::DefPathData::AnonConst => "k",
399 hir::definitions::DefPathData::ImplTrait => "i",
400 hir::definitions::DefPathData::CrateRoot
401 | hir::definitions::DefPathData::Use
402 | hir::definitions::DefPathData::GlobalAsm
403 | hir::definitions::DefPathData::MacroNs(..)
404 | hir::definitions::DefPathData::LifetimeNs(..) => {
405 bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
410 // Crate disambiguator and name
412 s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
413 let crate_name = tcx.crate_name(def_path.krate).to_string();
414 let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
416 // Disambiguators and names
417 def_path.data.reverse();
418 for disambiguated_data in &def_path.data {
419 let num = disambiguated_data.disambiguator as u64;
421 s.push_str(&to_disambiguator(num));
424 let name = disambiguated_data.data.to_string();
425 let _ = write!(s, "{}", name.len());
427 // Prepend a '_' if name starts with a digit or '_'
428 if let Some(first) = name.as_bytes().get(0) {
429 if first.is_ascii_digit() || *first == b'_' {
433 bug!("encode_ty_name: invalid name `{:?}`", name);
442 /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
443 /// Rust types that are not used at the FFI boundary.
447 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
448 options: EncodeTyOptions,
450 let mut typeid = String::new();
458 ty::Int(..) | ty::Uint(..) | ty::Float(..) => {
459 // u<length><type-name> as vendor extended type
460 let mut s = String::from(match ty.kind() {
461 ty::Int(IntTy::I8) => "u2i8",
462 ty::Int(IntTy::I16) => "u3i16",
463 ty::Int(IntTy::I32) => "u3i32",
464 ty::Int(IntTy::I64) => "u3i64",
465 ty::Int(IntTy::I128) => "u4i128",
466 ty::Int(IntTy::Isize) => "u5isize",
467 ty::Uint(UintTy::U8) => "u2u8",
468 ty::Uint(UintTy::U16) => "u3u16",
469 ty::Uint(UintTy::U32) => "u3u32",
470 ty::Uint(UintTy::U64) => "u3u64",
471 ty::Uint(UintTy::U128) => "u4u128",
472 ty::Uint(UintTy::Usize) => "u5usize",
473 ty::Float(FloatTy::F32) => "u3f32",
474 ty::Float(FloatTy::F64) => "u3f64",
477 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
482 // u4char as vendor extended type
483 let mut s = String::from("u4char");
484 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
489 // u3str as vendor extended type
490 let mut s = String::from("u3str");
491 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
496 // u5never as vendor extended type
497 let mut s = String::from("u5never");
498 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
503 // () in Rust is equivalent to void return type in C
504 _ if ty.is_unit() => {
510 // u5tupleI<element-type1..element-typeN>E as vendor extended type
511 let mut s = String::from("u5tupleI");
512 for ty in tys.iter() {
513 s.push_str(&encode_ty(tcx, ty, dict, options));
516 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
520 ty::Array(ty0, len) => {
521 // A<array-length><element-type>
522 let mut s = String::from("A");
523 let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap());
524 s.push_str(&encode_ty(tcx, *ty0, dict, options));
525 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
530 // u5sliceI<element-type>E as vendor extended type
531 let mut s = String::from("u5sliceI");
532 s.push_str(&encode_ty(tcx, *ty0, dict, options));
534 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
538 // User-defined types
539 ty::Adt(adt_def, substs) => {
540 let mut s = String::new();
541 let def_id = adt_def.0.did;
542 if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
543 // For cross-language CFI support, the encoding must be compatible at the FFI
544 // boundary. For instance:
547 // void foo(struct type1* bar) {}
553 // So, encode any repr(C) user-defined type for extern function types with the "C"
554 // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
555 // <name> is <unscoped-name>.
556 let name = tcx.item_name(def_id).to_string();
557 let _ = write!(s, "{}{}", name.len(), &name);
558 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
560 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
561 // <subst>, as vendor extended type.
562 let name = encode_ty_name(tcx, def_id);
563 let _ = write!(s, "u{}{}", name.len(), &name);
564 s.push_str(&encode_substs(tcx, substs, dict, options));
565 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
570 ty::Foreign(def_id) => {
571 // <length><name>, where <name> is <unscoped-name>
572 let mut s = String::new();
573 let name = tcx.item_name(*def_id).to_string();
574 let _ = write!(s, "{}{}", name.len(), &name);
575 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
580 ty::FnDef(def_id, substs)
581 | ty::Closure(def_id, substs)
582 | ty::Generator(def_id, substs, ..) => {
583 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
584 // as vendor extended type.
585 let mut s = String::new();
586 let name = encode_ty_name(tcx, *def_id);
587 let _ = write!(s, "u{}{}", name.len(), &name);
588 s.push_str(&encode_substs(tcx, substs, dict, options));
589 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
594 ty::Ref(region, ty0, ..) => {
595 // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type
596 let mut s = String::new();
597 s.push_str("u3refI");
598 s.push_str(&encode_ty(tcx, *ty0, dict, options));
600 compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s);
601 if ty.is_mutable_ptr() {
602 s = format!("{}{}", "U3mut", &s);
603 compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
609 // P[K]<element-type>
610 let mut s = String::new();
611 s.push_str(&encode_ty(tcx, tm.ty, dict, options));
612 if !ty.is_mutable_ptr() {
613 s = format!("{}{}", "K", &s);
614 compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s);
616 s = format!("{}{}", "P", &s);
617 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
621 ty::FnPtr(fn_sig) => {
622 // PF<return-type><parameter-type1..parameter-typeN>E
623 let mut s = String::from("P");
624 s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
625 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
630 ty::Dynamic(predicates, region, kind) => {
631 // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
632 // vendor extended type.
633 let mut s = String::from(match kind {
635 ty::DynStar => "u7dynstarI",
637 s.push_str(&encode_predicates(tcx, predicates, dict, options));
638 s.push_str(&encode_region(tcx, *region, dict, options));
640 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
647 | ty::GeneratorWitness(..)
651 | ty::Placeholder(..)
652 | ty::Projection(..) => {
653 bug!("encode_ty: unexpected `{:?}`", ty.kind());
660 // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
661 // c_void types into unit types unconditionally, and generalizes all pointers if
662 // TransformTyOptions::GENERALIZE_POINTERS option is set.
663 fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
675 | ty::Dynamic(..) => {}
677 _ if ty.is_unit() => {}
680 ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
683 ty::Array(ty0, len) => {
684 let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap();
685 ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len);
689 ty = tcx.mk_slice(transform_ty(tcx, *ty0, options));
692 ty::Adt(adt_def, substs) => {
693 if is_c_void_ty(tcx, ty) {
695 } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
697 ty = tcx.mk_adt(*adt_def, ty::List::empty());
698 } else if adt_def.repr().transparent() && adt_def.is_struct() {
699 let variant = adt_def.non_enum_variant();
700 let param_env = tcx.param_env(variant.def_id);
701 let field = variant.fields.iter().find(|field| {
702 let ty = tcx.type_of(field.did);
704 tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
708 // Transform repr(transparent) types without non-ZST field into ()
711 let ty0 = tcx.type_of(field.unwrap().did);
712 // Generalize any repr(transparent) user-defined type that is either a pointer
713 // or reference, and either references itself or any other type that contains or
714 // references itself, to avoid a reference cycle.
715 if ty0.is_any_ptr() && ty0.contains(ty) {
719 options | TransformTyOptions::GENERALIZE_POINTERS,
722 ty = transform_ty(tcx, ty0, options);
726 ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
730 ty::FnDef(def_id, substs) => {
731 ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options));
734 ty::Closure(def_id, substs) => {
735 ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options));
738 ty::Generator(def_id, substs, movability) => {
739 ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability);
742 ty::Ref(region, ty0, ..) => {
743 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
744 if ty.is_mutable_ptr() {
745 ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit());
747 ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit());
750 if ty.is_mutable_ptr() {
751 ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options));
753 ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options));
759 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
760 if ty.is_mutable_ptr() {
761 ty = tcx.mk_mut_ptr(tcx.mk_unit());
763 ty = tcx.mk_imm_ptr(tcx.mk_unit());
766 if ty.is_mutable_ptr() {
767 ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options));
769 ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options));
774 ty::FnPtr(fn_sig) => {
775 if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
776 ty = tcx.mk_imm_ptr(tcx.mk_unit());
778 let parameters: Vec<Ty<'tcx>> = fn_sig
782 .map(|ty| transform_ty(tcx, *ty, options))
784 let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
785 ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars(
800 | ty::GeneratorWitness(..)
804 | ty::Placeholder(..)
805 | ty::Projection(..) => {
806 bug!("transform_ty: unexpected `{:?}`", ty.kind());
813 /// Transforms substs for being encoded and used in the substitution dictionary.
814 fn transform_substs<'tcx>(
816 substs: SubstsRef<'tcx>,
817 options: TransformTyOptions,
818 ) -> SubstsRef<'tcx> {
819 let substs: Vec<GenericArg<'tcx>> = substs
822 if let GenericArgKind::Type(ty) = subst.unpack() {
823 if is_c_void_ty(tcx, ty) {
826 transform_ty(tcx, ty, options).into()
833 tcx.mk_substs(substs.iter())
836 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
837 /// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
838 pub fn typeid_for_fnabi<'tcx>(
840 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
841 options: TypeIdOptions,
843 // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
845 let mut typeid = String::from("_Z");
847 // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
848 // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
849 // code (i.e., 'TS') prefixed to the type encoding for the function.
850 typeid.push_str("TS");
852 // Function types are delimited by an "F..E" pair
855 // A dictionary of substitution candidates used for compression (see
856 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
857 let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
859 let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
860 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
863 encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
866 encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
870 // Encode the return type
871 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
872 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
873 let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options);
874 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
876 // Encode the parameter types
877 if !fn_abi.c_variadic {
878 if !fn_abi.args.is_empty() {
879 for arg in fn_abi.args.iter() {
880 let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
881 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
884 // Empty parameter lists, whether declared as () or conventionally as (void), are
885 // encoded with a void parameter specifier "v".
889 for n in 0..fn_abi.fixed_count as usize {
890 let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
891 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
897 // Close the "F..E" pair
903 /// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor
904 /// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
905 pub fn typeid_for_fnsig<'tcx>(
907 fn_sig: &FnSig<'tcx>,
908 options: TypeIdOptions,
910 // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
912 let mut typeid = String::from("_Z");
914 // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
915 // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
916 // code (i.e., 'TS') prefixed to the type encoding for the function.
917 typeid.push_str("TS");
919 // A dictionary of substitution candidates used for compression (see
920 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
921 let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
923 // Encode the function signature
924 typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));