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 TermKind
, 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
.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
<Binder
<'tcx
, ExistentialPredicate
<'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
<Binder
<'tcx
, ExistentialPredicate
<'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 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
));