Skip to main content

rustc_sanitizers/cfi/typeid/itanium_cxx_abi/
encode.rs

1//! Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
2//! C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
3//! are not used across the FFI boundary.
4//!
5//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
6//! see design document in the tracking issue #89653.
7
8use std::fmt::Write as _;
9
10use rustc_abi::{ExternAbi, Integer};
11use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, CASE_INSENSITIVE, ToBaseN};
12use rustc_data_structures::fx::FxHashMap;
13use rustc_hir as hir;
14use rustc_hir::find_attr;
15use rustc_middle::bug;
16use rustc_middle::ty::layout::IntegerExt;
17use rustc_middle::ty::{
18    self, Const, ExistentialPredicate, FloatTy, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
19    IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, TypeFoldable, UintTy,
20};
21use rustc_span::def_id::DefId;
22use tracing::instrument;
23
24use crate::cfi::typeid::TypeIdOptions;
25use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions};
26
27/// Options for encode_ty.
28pub(crate) type EncodeTyOptions = TypeIdOptions;
29
30/// Substitution dictionary key.
31#[derive(#[automatically_derived]
impl<'tcx> ::core::cmp::Eq for DictKey<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<TyQ>;
        let _: ::core::cmp::AssertParamIsEq<Region<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<Const<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<ExistentialPredicate<'tcx>>;
    }
}Eq, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for DictKey<'tcx> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            DictKey::Ty(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            DictKey::Region(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            DictKey::Const(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            DictKey::Predicate(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for DictKey<'tcx> {
    #[inline]
    fn eq(&self, other: &DictKey<'tcx>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (DictKey::Ty(__self_0, __self_1),
                    DictKey::Ty(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (DictKey::Region(__self_0), DictKey::Region(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (DictKey::Const(__self_0), DictKey::Const(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (DictKey::Predicate(__self_0), DictKey::Predicate(__arg1_0))
                    => __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq)]
32pub(crate) enum DictKey<'tcx> {
33    Ty(Ty<'tcx>, TyQ),
34    Region(Region<'tcx>),
35    Const(Const<'tcx>),
36    Predicate(ExistentialPredicate<'tcx>),
37}
38
39/// Type and extended type qualifiers.
40#[derive(#[automatically_derived]
impl ::core::cmp::Eq for TyQ {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for TyQ {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for TyQ {
    #[inline]
    fn eq(&self, other: &TyQ) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
41pub(crate) enum TyQ {
42    None,
43    Const,
44    Mut,
45}
46
47/// Substitutes a component if found in the substitution dictionary (see
48/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression>).
49fn compress<'tcx>(
50    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
51    key: DictKey<'tcx>,
52    comp: &mut String,
53) {
54    match dict.get(&key) {
55        Some(num) => {
56            comp.clear();
57            let _ = comp.write_fmt(format_args!("S{0}_", to_seq_id(*num)))write!(comp, "S{}_", to_seq_id(*num));
58        }
59        None => {
60            dict.insert(key, dict.len());
61        }
62    }
63}
64
65/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
66/// types that are not used at the FFI boundary.
67fn encode_args<'tcx>(
68    tcx: TyCtxt<'tcx>,
69    args: GenericArgsRef<'tcx>,
70    for_def: DefId,
71    has_erased_self: bool,
72    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
73    options: EncodeTyOptions,
74) -> String {
75    // [I<subst1..substN>E] as part of vendor extended type
76    let mut s = String::new();
77    let args: Vec<GenericArg<'_>> = args.iter().collect();
78    if !args.is_empty() {
79        s.push('I');
80        let def_generics = tcx.generics_of(for_def);
81        for (n, arg) in args.iter().enumerate() {
82            match arg.kind() {
83                GenericArgKind::Lifetime(region) => {
84                    s.push_str(&encode_region(region, dict));
85                }
86                GenericArgKind::Type(ty) => {
87                    s.push_str(&encode_ty(tcx, ty, dict, options));
88                }
89                GenericArgKind::Const(c) => {
90                    let n = n + (has_erased_self as usize);
91                    let ct_ty =
92                        tcx.type_of(def_generics.param_at(n, tcx).def_id).instantiate_identity();
93                    s.push_str(&encode_const(tcx, c, ct_ty, dict, options));
94                }
95            }
96        }
97        s.push('E');
98    }
99    s
100}
101
102/// Encodes a const using the Itanium C++ ABI as a literal argument (see
103/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
104fn encode_const<'tcx>(
105    tcx: TyCtxt<'tcx>,
106    ct: Const<'tcx>,
107    ct_ty: Ty<'tcx>,
108    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
109    options: EncodeTyOptions,
110) -> String {
111    // L<element-type>[n][<element-value>]E as literal argument
112    let mut s = String::from('L');
113
114    match ct.kind() {
115        // Const parameters
116        ty::ConstKind::Param(..) => {
117            // L<element-type>E as literal argument
118
119            // Element type
120            s.push_str(&encode_ty(tcx, ct_ty, dict, options));
121        }
122
123        // Literal arguments
124        ty::ConstKind::Value(cv) => {
125            // L<element-type>[n]<element-value>E as literal argument
126
127            // Element type
128            s.push_str(&encode_ty(tcx, cv.ty, dict, options));
129
130            // The only allowed types of const values are bool, u8, u16, u32,
131            // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The
132            // bool value false is encoded as 0 and true as 1.
133            match cv.ty.kind() {
134                ty::Int(ity) => {
135                    let bits = cv
136                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
137                        .expect("expected monomorphic const in cfi");
138                    let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
139                    if val < 0 {
140                        s.push('n');
141                    }
142                    let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
143                }
144                ty::Uint(_) => {
145                    let val = cv
146                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
147                        .expect("expected monomorphic const in cfi");
148                    let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
149                }
150                ty::Bool => {
151                    let val = cv.try_to_bool().expect("expected monomorphic const in cfi");
152                    let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
153                }
154                _ => {
155                    ::rustc_middle::util::bug::bug_fmt(format_args!("encode_const: unexpected type `{0:?}`",
        cv.ty));bug!("encode_const: unexpected type `{:?}`", cv.ty);
156                }
157            }
158        }
159
160        _ => {
161            ::rustc_middle::util::bug::bug_fmt(format_args!("encode_const: unexpected kind `{0:?}`",
        ct.kind()));bug!("encode_const: unexpected kind `{:?}`", ct.kind());
162        }
163    }
164
165    // Close the "L..E" pair
166    s.push('E');
167
168    compress(dict, DictKey::Const(ct), &mut s);
169
170    s
171}
172
173/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
174/// Rust types that are not used at the FFI boundary.
175fn encode_fnsig<'tcx>(
176    tcx: TyCtxt<'tcx>,
177    fn_sig: &FnSig<'tcx>,
178    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
179    options: TypeIdOptions,
180) -> String {
181    // Function types are delimited by an "F..E" pair
182    let mut s = String::from("F");
183
184    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
185        .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("encode_fnsig: invalid option(s) `{0:?}`",
        options.bits()))bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
186    match fn_sig.abi {
187        ExternAbi::C { .. } => {
188            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
189        }
190        _ => {
191            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
192        }
193    }
194
195    // Encode the return type
196    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
197        .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("encode_fnsig: invalid option(s) `{0:?}`",
        options.bits()))bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
198    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
199    let ty = fn_sig.output().fold_with(&mut type_folder);
200    s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
201
202    // Encode the parameter types
203    let tys = fn_sig.inputs();
204    if !tys.is_empty() {
205        for ty in tys {
206            let ty = ty.fold_with(&mut type_folder);
207            s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
208        }
209
210        if fn_sig.c_variadic {
211            s.push('z');
212        }
213    } else if fn_sig.c_variadic {
214        s.push('z');
215    } else {
216        // Empty parameter lists, whether declared as () or conventionally as (void), are
217        // encoded with a void parameter specifier "v".
218        s.push('v')
219    }
220
221    // Close the "F..E" pair
222    s.push('E');
223
224    s
225}
226
227/// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for
228/// Rust types that are not used at the FFI boundary.
229fn encode_predicate<'tcx>(
230    tcx: TyCtxt<'tcx>,
231    predicate: ty::PolyExistentialPredicate<'tcx>,
232    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
233    options: EncodeTyOptions,
234) -> String {
235    // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, as vendor
236    // extended type.
237    let mut s = String::new();
238    match predicate.as_ref().skip_binder() {
239        ty::ExistentialPredicate::Trait(trait_ref) => {
240            let name = encode_ty_name(tcx, trait_ref.def_id);
241            let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
242            s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options));
243        }
244        ty::ExistentialPredicate::Projection(projection) => {
245            let name = encode_ty_name(tcx, projection.def_id);
246            let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
247            s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options));
248            match projection.term.kind() {
249                TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
250                TermKind::Const(c) => s.push_str(&encode_const(
251                    tcx,
252                    c,
253                    tcx.type_of(projection.def_id).instantiate(tcx, projection.args),
254                    dict,
255                    options,
256                )),
257            }
258        }
259        ty::ExistentialPredicate::AutoTrait(def_id) => {
260            let name = encode_ty_name(tcx, *def_id);
261            let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
262        }
263    };
264    compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
265    s
266}
267
268/// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for
269/// Rust types that are not used at the FFI boundary.
270fn encode_predicates<'tcx>(
271    tcx: TyCtxt<'tcx>,
272    predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
273    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
274    options: EncodeTyOptions,
275) -> String {
276    // <predicate1[..predicateN]>E as part of vendor extended type
277    let mut s = String::new();
278    let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates.iter().collect();
279    for predicate in predicates {
280        s.push_str(&encode_predicate(tcx, predicate, dict, options));
281    }
282    s
283}
284
285/// Encodes a region using the Itanium C++ ABI as a vendor extended type.
286fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>) -> String {
287    // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
288    let mut s = String::new();
289    match region.kind() {
290        RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => {
291            s.push_str("u6regionI");
292            // Debruijn index, which identifies the binder, as region disambiguator
293            let num = debruijn.index() as u64;
294            if num > 0 {
295                s.push_str(&to_disambiguator(num));
296            }
297            // Index within the binder
298            let _ = s.write_fmt(format_args!("{0}", r.var.index() as u64))write!(s, "{}", r.var.index() as u64);
299            s.push('E');
300            compress(dict, DictKey::Region(region), &mut s);
301        }
302        RegionKind::ReErased => {
303            s.push_str("u6region");
304            compress(dict, DictKey::Region(region), &mut s);
305        }
306        RegionKind::ReBound(ty::BoundVarIndexKind::Canonical, _)
307        | RegionKind::ReEarlyParam(..)
308        | RegionKind::ReLateParam(..)
309        | RegionKind::ReStatic
310        | RegionKind::ReError(_)
311        | RegionKind::ReVar(..)
312        | RegionKind::RePlaceholder(..) => {
313            ::rustc_middle::util::bug::bug_fmt(format_args!("encode_region: unexpected `{0:?}`",
        region.kind()));bug!("encode_region: unexpected `{:?}`", region.kind());
314        }
315    }
316    s
317}
318
319/// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
320/// Rust types that are not used at the FFI boundary.
321#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("encode_ty",
                                    "rustc_sanitizers::cfi::typeid::itanium_cxx_abi::encode",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs"),
                                    ::tracing_core::__macro_support::Option::Some(321u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_sanitizers::cfi::typeid::itanium_cxx_abi::encode"),
                                    ::tracing_core::field::FieldSet::new(&["ty", "options"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&options)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: String = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let mut typeid = String::new();
            match ty.kind() {
                ty::Bool => { typeid.push('b'); }
                ty::Int(..) | ty::Uint(..) => {
                    let mut s =
                        String::from(match ty.kind() {
                                ty::Int(IntTy::I8) => "u2i8",
                                ty::Int(IntTy::I16) => "u3i16",
                                ty::Int(IntTy::I32) => "u3i32",
                                ty::Int(IntTy::I64) => "u3i64",
                                ty::Int(IntTy::I128) => "u4i128",
                                ty::Int(IntTy::Isize) => "u5isize",
                                ty::Uint(UintTy::U8) => "u2u8",
                                ty::Uint(UintTy::U16) => "u3u16",
                                ty::Uint(UintTy::U32) => "u3u32",
                                ty::Uint(UintTy::U64) => "u3u64",
                                ty::Uint(UintTy::U128) => "u4u128",
                                ty::Uint(UintTy::Usize) => "u5usize",
                                _ =>
                                    ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty: unexpected `{0:?}`",
                                            ty.kind())),
                            });
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Float(float_ty) => {
                    typeid.push_str(match float_ty {
                            FloatTy::F16 => "Dh",
                            FloatTy::F32 => "f",
                            FloatTy::F64 => "d",
                            FloatTy::F128 => "g",
                        });
                }
                ty::Char => {
                    let mut s = String::from("u4char");
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Str => {
                    let mut s = String::from("u3str");
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Never => {
                    let mut s = String::from("u5never");
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                _ if ty.is_unit() => { typeid.push('v'); }
                ty::Tuple(tys) => {
                    let mut s = String::from("u5tupleI");
                    for ty in tys.iter() {
                        s.push_str(&encode_ty(tcx, ty, dict, options));
                    }
                    s.push('E');
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Array(ty0, len) => {
                    let len =
                        len.try_to_target_usize(tcx).expect("expected monomorphic const in cfi");
                    let mut s = String::from("A");
                    let _ = s.write_fmt(format_args!("{0}", len));
                    s.push_str(&encode_ty(tcx, *ty0, dict, options));
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Pat(ty0, pat) => {
                    let mut s = String::from("u3patI");
                    s.push_str(&encode_ty(tcx, *ty0, dict, options));
                    s.write_fmt(format_args!("{0:?}", **pat)).unwrap();
                    s.push('E');
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Slice(ty0) => {
                    let mut s = String::from("u5sliceI");
                    s.push_str(&encode_ty(tcx, *ty0, dict, options));
                    s.push('E');
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Adt(adt_def, args) => {
                    let mut s = String::new();
                    let def_id = adt_def.did();
                    if let Some(encoding) =
                            {
                                {
                                    'done:
                                        {
                                        for i in
                                            ::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &tcx) {
                                            #[allow(unused_imports)]
                                            use rustc_hir::attrs::AttributeKind::*;
                                            let i: &rustc_hir::Attribute = i;
                                            match i {
                                                rustc_hir::Attribute::Parsed(CfiEncoding { encoding }) => {
                                                    break 'done Some(encoding);
                                                }
                                                rustc_hir::Attribute::Unparsed(..) =>
                                                    {}
                                                    #[deny(unreachable_patterns)]
                                                    _ => {}
                                            }
                                        }
                                        None
                                    }
                                }
                            } {
                        let encoding = encoding.as_str().trim();
                        s.push_str(&encoding);
                        let builtin_types =
                            ["v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m",
                                    "x", "y", "n", "o", "f", "d", "e", "g", "z", "Dh"];
                        if !builtin_types.contains(&encoding) {
                            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                        }
                    } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C)
                            && adt_def.repr().c() {
                        let name = tcx.item_name(def_id).to_string();
                        let _ =
                            s.write_fmt(format_args!("{0}{1}", name.len(), name));
                        compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    } else {
                        let name = encode_ty_name(tcx, def_id);
                        let _ =
                            s.write_fmt(format_args!("u{0}{1}", name.len(), name));
                        s.push_str(&encode_args(tcx, args, def_id, false, dict,
                                    options));
                        compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    }
                    typeid.push_str(&s);
                }
                ty::Foreign(def_id) => {
                    let mut s = String::new();
                    if let Some(encoding) =
                            {
                                {
                                    'done:
                                        {
                                        for i in
                                            ::rustc_hir::attrs::HasAttrs::get_attrs(*def_id, &tcx) {
                                            #[allow(unused_imports)]
                                            use rustc_hir::attrs::AttributeKind::*;
                                            let i: &rustc_hir::Attribute = i;
                                            match i {
                                                rustc_hir::Attribute::Parsed(CfiEncoding { encoding }) => {
                                                    break 'done Some(encoding);
                                                }
                                                rustc_hir::Attribute::Unparsed(..) =>
                                                    {}
                                                    #[deny(unreachable_patterns)]
                                                    _ => {}
                                            }
                                        }
                                        None
                                    }
                                }
                            } {
                        s.push_str(encoding.as_str().trim());
                    } else {
                        let name = tcx.item_name(*def_id).to_string();
                        let _ =
                            s.write_fmt(format_args!("{0}{1}", name.len(), name));
                    }
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
                    let mut s = String::new();
                    let name = encode_ty_name(tcx, *def_id);
                    let _ =
                        s.write_fmt(format_args!("u{0}{1}", name.len(), name));
                    s.push_str(&encode_args(tcx, args, *def_id, false, dict,
                                options));
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::CoroutineClosure(def_id, args) => {
                    let mut s = String::new();
                    let name = encode_ty_name(tcx, *def_id);
                    let _ =
                        s.write_fmt(format_args!("u{0}{1}", name.len(), name));
                    let parent_args =
                        tcx.mk_args(args.as_coroutine_closure().parent_args());
                    s.push_str(&encode_args(tcx, parent_args, *def_id, false,
                                dict, options));
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Coroutine(def_id, args, ..) => {
                    let mut s = String::new();
                    let name = encode_ty_name(tcx, *def_id);
                    let _ =
                        s.write_fmt(format_args!("u{0}{1}", name.len(), name));
                    s.push_str(&encode_args(tcx,
                                tcx.mk_args(args.as_coroutine().parent_args()), *def_id,
                                false, dict, options));
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Ref(region, ty0, ..) => {
                    let mut s = String::new();
                    s.push_str("u3refI");
                    s.push_str(&encode_ty(tcx, *ty0, dict, options));
                    s.push('E');
                    compress(dict,
                        DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None),
                        &mut s);
                    if ty.is_mutable_ptr() {
                        s =
                            ::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("{0}{1}", "U3mut", s))
                                });
                        compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
                    }
                    typeid.push_str(&s);
                }
                ty::RawPtr(ptr_ty, _mutbl) => {
                    let mut s = String::new();
                    s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
                    if !ty.is_mutable_ptr() {
                        s =
                            ::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("{0}{1}", "K", s))
                                });
                        compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
                    };
                    s =
                        ::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("{0}{1}", "P", s))
                            });
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::FnPtr(sig_tys, hdr) => {
                    let mut s = String::from("P");
                    s.push_str(&encode_fnsig(tcx,
                                &sig_tys.with(*hdr).skip_binder(), dict,
                                TypeIdOptions::empty()));
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::UnsafeBinder(_) => {
                    ::core::panicking::panic("not yet implemented")
                }
                ty::Dynamic(predicates, region) => {
                    let mut s = String::from("u3dynI");
                    s.push_str(&encode_predicates(tcx, predicates, dict,
                                options));
                    s.push_str(&encode_region(*region, dict));
                    s.push('E');
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Param(..) => {
                    let mut s = String::from("u5param");
                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
                    typeid.push_str(&s);
                }
                ty::Alias(..) | ty::Bound(..) | ty::Error(..) |
                    ty::CoroutineWitness(..) | ty::Infer(..) |
                    ty::Placeholder(..) => {
                    ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty: unexpected `{0:?}`",
                            ty.kind()));
                }
            };
            typeid
        }
    }
}#[instrument(level = "trace", skip(tcx, dict))]
322pub(crate) fn encode_ty<'tcx>(
323    tcx: TyCtxt<'tcx>,
324    ty: Ty<'tcx>,
325    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
326    options: EncodeTyOptions,
327) -> String {
328    let mut typeid = String::new();
329
330    match ty.kind() {
331        // Primitive types
332
333        // Rust's bool has the same layout as C17's _Bool, that is, its size and alignment are
334        // implementation-defined. Any bool can be cast into an integer, taking on the values 1
335        // (true) or 0 (false).
336        //
337        // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
338        ty::Bool => {
339            typeid.push('b');
340        }
341
342        ty::Int(..) | ty::Uint(..) => {
343            // u<length><type-name> as vendor extended type
344            let mut s = String::from(match ty.kind() {
345                ty::Int(IntTy::I8) => "u2i8",
346                ty::Int(IntTy::I16) => "u3i16",
347                ty::Int(IntTy::I32) => "u3i32",
348                ty::Int(IntTy::I64) => "u3i64",
349                ty::Int(IntTy::I128) => "u4i128",
350                ty::Int(IntTy::Isize) => "u5isize",
351                ty::Uint(UintTy::U8) => "u2u8",
352                ty::Uint(UintTy::U16) => "u3u16",
353                ty::Uint(UintTy::U32) => "u3u32",
354                ty::Uint(UintTy::U64) => "u3u64",
355                ty::Uint(UintTy::U128) => "u4u128",
356                ty::Uint(UintTy::Usize) => "u5usize",
357                _ => bug!("encode_ty: unexpected `{:?}`", ty.kind()),
358            });
359            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
360            typeid.push_str(&s);
361        }
362
363        // Rust's f16, f32, f64, and f126 half (16-bit), single (32-bit), double (64-bit), and
364        // quad (128-bit)  precision floating-point types have IEEE-754 binary16, binary32,
365        // binary64, and binary128 floating-point layouts, respectively.
366        //
367        // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#fixed-width-floating-point-types.)
368        ty::Float(float_ty) => {
369            typeid.push_str(match float_ty {
370                FloatTy::F16 => "Dh",
371                FloatTy::F32 => "f",
372                FloatTy::F64 => "d",
373                FloatTy::F128 => "g",
374            });
375        }
376
377        ty::Char => {
378            // u4char as vendor extended type
379            let mut s = String::from("u4char");
380            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
381            typeid.push_str(&s);
382        }
383
384        ty::Str => {
385            // u3str as vendor extended type
386            let mut s = String::from("u3str");
387            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
388            typeid.push_str(&s);
389        }
390
391        ty::Never => {
392            // u5never as vendor extended type
393            let mut s = String::from("u5never");
394            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
395            typeid.push_str(&s);
396        }
397
398        // Compound types
399        // () in Rust is equivalent to void return type in C
400        _ if ty.is_unit() => {
401            typeid.push('v');
402        }
403
404        // Sequence types
405        ty::Tuple(tys) => {
406            // u5tupleI<element-type1..element-typeN>E as vendor extended type
407            let mut s = String::from("u5tupleI");
408            for ty in tys.iter() {
409                s.push_str(&encode_ty(tcx, ty, dict, options));
410            }
411            s.push('E');
412            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
413            typeid.push_str(&s);
414        }
415
416        ty::Array(ty0, len) => {
417            // A<array-length><element-type>
418            let len = len.try_to_target_usize(tcx).expect("expected monomorphic const in cfi");
419            let mut s = String::from("A");
420            let _ = write!(s, "{len}");
421            s.push_str(&encode_ty(tcx, *ty0, dict, options));
422            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
423            typeid.push_str(&s);
424        }
425
426        ty::Pat(ty0, pat) => {
427            // u3patI<element-type><pattern>E as vendor extended type
428            let mut s = String::from("u3patI");
429            s.push_str(&encode_ty(tcx, *ty0, dict, options));
430            write!(s, "{:?}", **pat).unwrap();
431            s.push('E');
432            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
433            typeid.push_str(&s);
434        }
435
436        ty::Slice(ty0) => {
437            // u5sliceI<element-type>E as vendor extended type
438            let mut s = String::from("u5sliceI");
439            s.push_str(&encode_ty(tcx, *ty0, dict, options));
440            s.push('E');
441            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
442            typeid.push_str(&s);
443        }
444
445        // User-defined types
446        ty::Adt(adt_def, args) => {
447            let mut s = String::new();
448            let def_id = adt_def.did();
449            if let Some(encoding) = find_attr!(tcx, def_id, CfiEncoding { encoding } => encoding) {
450                let encoding = encoding.as_str().trim();
451                // Use user-defined CFI encoding for type
452                s.push_str(&encoding);
453                // Don't compress user-defined builtin types (see
454                // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-builtin and
455                // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
456                let builtin_types = [
457                    "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y", "n", "o",
458                    "f", "d", "e", "g", "z", "Dh",
459                ];
460                if !builtin_types.contains(&encoding) {
461                    compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
462                }
463            } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
464                // For cross-language LLVM CFI support, the encoding must be compatible at the FFI
465                // boundary. For instance:
466                //
467                //     struct type1 {};
468                //     void foo(struct type1* bar) {}
469                //
470                // Is encoded as:
471                //
472                //     _ZTSFvP5type1E
473                //
474                // So, encode any repr(C) user-defined type for extern function types with the "C"
475                // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
476                // <name> is <unscoped-name>.
477                let name = tcx.item_name(def_id).to_string();
478                let _ = write!(s, "{}{}", name.len(), name);
479                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
480            } else {
481                // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
482                // <subst>, as vendor extended type.
483                let name = encode_ty_name(tcx, def_id);
484                let _ = write!(s, "u{}{}", name.len(), name);
485                s.push_str(&encode_args(tcx, args, def_id, false, dict, options));
486                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
487            }
488            typeid.push_str(&s);
489        }
490
491        ty::Foreign(def_id) => {
492            // <length><name>, where <name> is <unscoped-name>
493            let mut s = String::new();
494
495            if let Some(encoding) = find_attr!(tcx, *def_id, CfiEncoding {encoding} => encoding) {
496                // Use user-defined CFI encoding for type
497                s.push_str(encoding.as_str().trim());
498            } else {
499                let name = tcx.item_name(*def_id).to_string();
500                let _ = write!(s, "{}{}", name.len(), name);
501            }
502            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
503            typeid.push_str(&s);
504        }
505
506        // Function types
507        ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
508            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
509            // as vendor extended type.
510            let mut s = String::new();
511            let name = encode_ty_name(tcx, *def_id);
512            let _ = write!(s, "u{}{}", name.len(), name);
513            s.push_str(&encode_args(tcx, args, *def_id, false, dict, options));
514            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
515            typeid.push_str(&s);
516        }
517
518        ty::CoroutineClosure(def_id, args) => {
519            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
520            // as vendor extended type.
521            let mut s = String::new();
522            let name = encode_ty_name(tcx, *def_id);
523            let _ = write!(s, "u{}{}", name.len(), name);
524            let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
525            s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options));
526            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
527            typeid.push_str(&s);
528        }
529
530        ty::Coroutine(def_id, args, ..) => {
531            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
532            // as vendor extended type.
533            let mut s = String::new();
534            let name = encode_ty_name(tcx, *def_id);
535            let _ = write!(s, "u{}{}", name.len(), name);
536            // Encode parent args only
537            s.push_str(&encode_args(
538                tcx,
539                tcx.mk_args(args.as_coroutine().parent_args()),
540                *def_id,
541                false,
542                dict,
543                options,
544            ));
545            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
546            typeid.push_str(&s);
547        }
548
549        // Pointer types
550        ty::Ref(region, ty0, ..) => {
551            // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type
552            let mut s = String::new();
553            s.push_str("u3refI");
554            s.push_str(&encode_ty(tcx, *ty0, dict, options));
555            s.push('E');
556            compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s);
557            if ty.is_mutable_ptr() {
558                s = format!("{}{}", "U3mut", s);
559                compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
560            }
561            typeid.push_str(&s);
562        }
563
564        ty::RawPtr(ptr_ty, _mutbl) => {
565            // FIXME: This can definitely not be so spaghettified.
566            // P[K]<element-type>
567            let mut s = String::new();
568            s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
569            if !ty.is_mutable_ptr() {
570                s = format!("{}{}", "K", s);
571                compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
572            };
573            s = format!("{}{}", "P", s);
574            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
575            typeid.push_str(&s);
576        }
577
578        ty::FnPtr(sig_tys, hdr) => {
579            // PF<return-type><parameter-type1..parameter-typeN>E
580            let mut s = String::from("P");
581            s.push_str(&encode_fnsig(
582                tcx,
583                &sig_tys.with(*hdr).skip_binder(),
584                dict,
585                TypeIdOptions::empty(),
586            ));
587            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
588            typeid.push_str(&s);
589        }
590
591        // FIXME(unsafe_binders): Implement this.
592        ty::UnsafeBinder(_) => {
593            todo!()
594        }
595
596        // Trait types
597        ty::Dynamic(predicates, region) => {
598            // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
599            // vendor extended type.
600            let mut s = String::from("u3dynI");
601            s.push_str(&encode_predicates(tcx, predicates, dict, options));
602            s.push_str(&encode_region(*region, dict));
603            s.push('E');
604            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
605            typeid.push_str(&s);
606        }
607
608        // Type parameters
609        ty::Param(..) => {
610            // u5param as vendor extended type
611            let mut s = String::from("u5param");
612            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
613            typeid.push_str(&s);
614        }
615
616        // Unexpected types
617        ty::Alias(..)
618        | ty::Bound(..)
619        | ty::Error(..)
620        | ty::CoroutineWitness(..)
621        | ty::Infer(..)
622        | ty::Placeholder(..) => {
623            bug!("encode_ty: unexpected `{:?}`", ty.kind());
624        }
625    };
626
627    typeid
628}
629
630/// Encodes a ty:Ty name, including its crate and path disambiguators and names.
631fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
632    // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
633    // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
634    //
635    // N<namespace-tagN>..N<namespace-tag1>
636    // C<crate-disambiguator><crate-name>
637    // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
638    //
639    // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
640    //
641    //     pub type Type1 = impl Send;
642    //     let _: Type1 = <Struct1<i32>>::foo;
643    //     fn foo1(_: Type1) { }
644    //
645    //     pub type Type2 = impl Send;
646    //     let _: Type2 = <Trait1<i32>>::foo;
647    //     fn foo2(_: Type2) { }
648    //
649    //     pub type Type3 = impl Send;
650    //     let _: Type3 = <i32 as Trait1<i32>>::foo;
651    //     fn foo3(_: Type3) { }
652    //
653    //     pub type Type4 = impl Send;
654    //     let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
655    //     fn foo3(_: Type4) { }
656    //
657    // Are encoded as:
658    //
659    //     _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
660    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
661    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
662    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
663    //
664    // The reason for not using v0's extended form of paths is to use a consistent and simpler
665    // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e.,
666    // keep symbol names close to how methods are represented in error messages). See
667    // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
668    let mut s = String::new();
669
670    // Start and namespace tags
671    let mut def_path = tcx.def_path(def_id);
672    def_path.data.reverse();
673    for disambiguated_data in &def_path.data {
674        s.push('N');
675        s.push_str(match disambiguated_data.data {
676            hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
677            hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
678            hir::definitions::DefPathData::TypeNs(..) => "t",
679            hir::definitions::DefPathData::ValueNs(..) => "v",
680            hir::definitions::DefPathData::Closure => "C",
681            hir::definitions::DefPathData::Ctor => "c",
682            hir::definitions::DefPathData::AnonConst => "K",
683            hir::definitions::DefPathData::LateAnonConst => "k",
684            hir::definitions::DefPathData::OpaqueTy => "i",
685            hir::definitions::DefPathData::SyntheticCoroutineBody => "s",
686            hir::definitions::DefPathData::NestedStatic => "n",
687            hir::definitions::DefPathData::CrateRoot
688            | hir::definitions::DefPathData::Use
689            | hir::definitions::DefPathData::GlobalAsm
690            | hir::definitions::DefPathData::MacroNs(..)
691            | hir::definitions::DefPathData::OpaqueLifetime(..)
692            | hir::definitions::DefPathData::LifetimeNs(..)
693            | hir::definitions::DefPathData::DesugaredAnonymousLifetime
694            | hir::definitions::DefPathData::AnonAssocTy(..) => {
695                ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty_name: unexpected `{0:?}`",
        disambiguated_data.data));bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
696            }
697        });
698    }
699
700    // Crate disambiguator and name
701    s.push('C');
702    s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
703    let crate_name = tcx.crate_name(def_path.krate).to_string();
704    let _ = s.write_fmt(format_args!("{0}{1}", crate_name.len(), crate_name))write!(s, "{}{}", crate_name.len(), crate_name);
705
706    // Disambiguators and names
707    def_path.data.reverse();
708    for disambiguated_data in &def_path.data {
709        let num = disambiguated_data.disambiguator as u64;
710        if num > 0 {
711            s.push_str(&to_disambiguator(num));
712        }
713
714        let name = disambiguated_data.data.to_string();
715        let _ = s.write_fmt(format_args!("{0}", name.len()))write!(s, "{}", name.len());
716
717        // Prepend a '_' if name starts with a digit or '_'
718        if let Some(first) = name.as_bytes().first() {
719            if first.is_ascii_digit() || *first == b'_' {
720                s.push('_');
721            }
722        } else {
723            ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty_name: invalid name `{0:?}`",
        name));bug!("encode_ty_name: invalid name `{:?}`", name);
724        }
725
726        s.push_str(&name);
727    }
728
729    s
730}
731
732/// Converts a number to a disambiguator (see
733/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
734fn to_disambiguator(num: u64) -> String {
735    if let Some(num) = num.checked_sub(1) {
736        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("s{0}_",
                num.to_base(ALPHANUMERIC_ONLY)))
    })format!("s{}_", num.to_base(ALPHANUMERIC_ONLY))
737    } else {
738        "s_".to_string()
739    }
740}
741
742/// Converts a number to a sequence number (see
743/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
744fn to_seq_id(num: usize) -> String {
745    if let Some(num) = num.checked_sub(1) {
746        (num as u64).to_base(CASE_INSENSITIVE).to_uppercase()
747    } else {
748        "".to_string()
749    }
750}