1use 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
27pub(crate) type EncodeTyOptions = TypeIdOptions;
29
30#[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#[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
47fn 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
65fn 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 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
102fn 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 let mut s = String::from('L');
113
114 match ct.kind() {
115 ty::ConstKind::Param(..) => {
117 s.push_str(&encode_ty(tcx, ct_ty, dict, options));
121 }
122
123 ty::ConstKind::Value(cv) => {
125 s.push_str(&encode_ty(tcx, cv.ty, dict, options));
129
130 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 s.push('E');
167
168 compress(dict, DictKey::Const(ct), &mut s);
169
170 s
171}
172
173fn 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 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 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 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 s.push('v')
219 }
220
221 s.push('E');
223
224 s
225}
226
227fn 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 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
268fn 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 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
285fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>) -> String {
287 let mut s = String::new();
289 match region.kind() {
290 RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => {
291 s.push_str("u6regionI");
292 let num = debruijn.index() as u64;
294 if num > 0 {
295 s.push_str(&to_disambiguator(num));
296 }
297 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#[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 ty::Bool => {
339 typeid.push('b');
340 }
341
342 ty::Int(..) | ty::Uint(..) => {
343 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 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 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 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 let mut s = String::from("u5never");
394 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
395 typeid.push_str(&s);
396 }
397
398 _ if ty.is_unit() => {
401 typeid.push('v');
402 }
403
404 ty::Tuple(tys) => {
406 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 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 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 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 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 s.push_str(&encoding);
453 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 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 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 let mut s = String::new();
494
495 if let Some(encoding) = find_attr!(tcx, *def_id, CfiEncoding {encoding} => encoding) {
496 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 ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
508 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 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 let mut s = String::new();
534 let name = encode_ty_name(tcx, *def_id);
535 let _ = write!(s, "u{}{}", name.len(), name);
536 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 ty::Ref(region, ty0, ..) => {
551 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 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 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 ty::UnsafeBinder(_) => {
593 todo!()
594 }
595
596 ty::Dynamic(predicates, region) => {
598 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 ty::Param(..) => {
610 let mut s = String::from("u5param");
612 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
613 typeid.push_str(&s);
614 }
615
616 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
630fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
632 let mut s = String::new();
669
670 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", hir::definitions::DefPathData::ForeignMod => "F", 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 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 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 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
732fn 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
742fn 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}