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 = tcx
92 .type_of(def_generics.param_at(n, tcx).def_id)
93 .instantiate_identity()
94 .skip_norm_wip();
95 s.push_str(&encode_const(tcx, c, ct_ty, dict, options));
96 }
97 }
98 }
99 s.push('E');
100 }
101 s
102}
103
104fn encode_const<'tcx>(
107 tcx: TyCtxt<'tcx>,
108 ct: Const<'tcx>,
109 ct_ty: Ty<'tcx>,
110 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
111 options: EncodeTyOptions,
112) -> String {
113 let mut s = String::from('L');
115
116 match ct.kind() {
117 ty::ConstKind::Param(..) => {
119 s.push_str(&encode_ty(tcx, ct_ty, dict, options));
123 }
124
125 ty::ConstKind::Value(cv) => {
127 s.push_str(&encode_ty(tcx, cv.ty, dict, options));
131
132 match cv.ty.kind() {
136 ty::Int(ity) => {
137 let bits = cv
138 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
139 .expect("expected monomorphic const in cfi");
140 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
141 if val < 0 {
142 s.push('n');
143 }
144 let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
145 }
146 ty::Uint(_) => {
147 let val = cv
148 .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
149 .expect("expected monomorphic const in cfi");
150 let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
151 }
152 ty::Bool => {
153 let val = cv.try_to_bool().expect("expected monomorphic const in cfi");
154 let _ = s.write_fmt(format_args!("{0}", val))write!(s, "{val}");
155 }
156 _ => {
157 ::rustc_middle::util::bug::bug_fmt(format_args!("encode_const: unexpected type `{0:?}`",
cv.ty));bug!("encode_const: unexpected type `{:?}`", cv.ty);
158 }
159 }
160 }
161
162 _ => {
163 ::rustc_middle::util::bug::bug_fmt(format_args!("encode_const: unexpected kind `{0:?}`",
ct.kind()));bug!("encode_const: unexpected kind `{:?}`", ct.kind());
164 }
165 }
166
167 s.push('E');
169
170 compress(dict, DictKey::Const(ct), &mut s);
171
172 s
173}
174
175fn encode_fnsig<'tcx>(
178 tcx: TyCtxt<'tcx>,
179 fn_sig: &FnSig<'tcx>,
180 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
181 options: TypeIdOptions,
182) -> String {
183 let mut s = String::from("F");
185
186 let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
187 .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()));
188 match fn_sig.abi() {
189 ExternAbi::C { .. } => {
190 encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
191 }
192 _ => {
193 encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
194 }
195 }
196
197 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
199 .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()));
200 let mut type_folder = TransformTy::new(tcx, transform_ty_options);
201 let ty = fn_sig.output().fold_with(&mut type_folder);
202 s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
203
204 let tys = fn_sig.inputs();
206 if !tys.is_empty() {
207 for ty in tys {
208 let ty = ty.fold_with(&mut type_folder);
209 s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
210 }
211
212 if fn_sig.c_variadic() {
213 s.push('z');
214 }
215 } else if fn_sig.c_variadic() {
216 s.push('z');
217 } else {
218 s.push('v')
221 }
222
223 s.push('E');
225
226 s
227}
228
229fn encode_predicate<'tcx>(
232 tcx: TyCtxt<'tcx>,
233 predicate: ty::PolyExistentialPredicate<'tcx>,
234 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
235 options: EncodeTyOptions,
236) -> String {
237 let mut s = String::new();
240 match predicate.as_ref().skip_binder() {
241 ty::ExistentialPredicate::Trait(trait_ref) => {
242 let name = encode_ty_name(tcx, trait_ref.def_id);
243 let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
244 s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options));
245 }
246 ty::ExistentialPredicate::Projection(projection) => {
247 let name = encode_ty_name(tcx, projection.def_id);
248 let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
249 s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options));
250 match projection.term.kind() {
251 TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
252 TermKind::Const(c) => s.push_str(&encode_const(
253 tcx,
254 c,
255 tcx.type_of(projection.def_id)
256 .instantiate(tcx, projection.args)
257 .skip_norm_wip(),
258 dict,
259 options,
260 )),
261 }
262 }
263 ty::ExistentialPredicate::AutoTrait(def_id) => {
264 let name = encode_ty_name(tcx, *def_id);
265 let _ = s.write_fmt(format_args!("u{0}{1}", name.len(), name))write!(s, "u{}{}", name.len(), name);
266 }
267 };
268 compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
269 s
270}
271
272fn encode_predicates<'tcx>(
275 tcx: TyCtxt<'tcx>,
276 predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
277 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
278 options: EncodeTyOptions,
279) -> String {
280 let mut s = String::new();
282 let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates.iter().collect();
283 for predicate in predicates {
284 s.push_str(&encode_predicate(tcx, predicate, dict, options));
285 }
286 s
287}
288
289fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>) -> String {
291 let mut s = String::new();
293 match region.kind() {
294 RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => {
295 s.push_str("u6regionI");
296 let num = debruijn.index() as u64;
298 if num > 0 {
299 s.push_str(&to_disambiguator(num));
300 }
301 let _ = s.write_fmt(format_args!("{0}", r.var.index() as u64))write!(s, "{}", r.var.index() as u64);
303 s.push('E');
304 compress(dict, DictKey::Region(region), &mut s);
305 }
306 RegionKind::ReErased => {
307 s.push_str("u6region");
308 compress(dict, DictKey::Region(region), &mut s);
309 }
310 RegionKind::ReBound(ty::BoundVarIndexKind::Canonical, _)
311 | RegionKind::ReEarlyParam(..)
312 | RegionKind::ReLateParam(..)
313 | RegionKind::ReStatic
314 | RegionKind::ReError(_)
315 | RegionKind::ReVar(..)
316 | RegionKind::RePlaceholder(..) => {
317 ::rustc_middle::util::bug::bug_fmt(format_args!("encode_region: unexpected `{0:?}`",
region.kind()));bug!("encode_region: unexpected `{:?}`", region.kind());
318 }
319 }
320 s
321}
322
323#[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(325u32),
::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))]
326pub(crate) fn encode_ty<'tcx>(
327 tcx: TyCtxt<'tcx>,
328 ty: Ty<'tcx>,
329 dict: &mut FxHashMap<DictKey<'tcx>, usize>,
330 options: EncodeTyOptions,
331) -> String {
332 let mut typeid = String::new();
333
334 match ty.kind() {
335 ty::Bool => {
343 typeid.push('b');
344 }
345
346 ty::Int(..) | ty::Uint(..) => {
347 let mut s = String::from(match ty.kind() {
349 ty::Int(IntTy::I8) => "u2i8",
350 ty::Int(IntTy::I16) => "u3i16",
351 ty::Int(IntTy::I32) => "u3i32",
352 ty::Int(IntTy::I64) => "u3i64",
353 ty::Int(IntTy::I128) => "u4i128",
354 ty::Int(IntTy::Isize) => "u5isize",
355 ty::Uint(UintTy::U8) => "u2u8",
356 ty::Uint(UintTy::U16) => "u3u16",
357 ty::Uint(UintTy::U32) => "u3u32",
358 ty::Uint(UintTy::U64) => "u3u64",
359 ty::Uint(UintTy::U128) => "u4u128",
360 ty::Uint(UintTy::Usize) => "u5usize",
361 _ => bug!("encode_ty: unexpected `{:?}`", ty.kind()),
362 });
363 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
364 typeid.push_str(&s);
365 }
366
367 ty::Float(float_ty) => {
373 typeid.push_str(match float_ty {
374 FloatTy::F16 => "Dh",
375 FloatTy::F32 => "f",
376 FloatTy::F64 => "d",
377 FloatTy::F128 => "g",
378 });
379 }
380
381 ty::Char => {
382 let mut s = String::from("u4char");
384 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
385 typeid.push_str(&s);
386 }
387
388 ty::Str => {
389 let mut s = String::from("u3str");
391 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
392 typeid.push_str(&s);
393 }
394
395 ty::Never => {
396 let mut s = String::from("u5never");
398 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
399 typeid.push_str(&s);
400 }
401
402 _ if ty.is_unit() => {
405 typeid.push('v');
406 }
407
408 ty::Tuple(tys) => {
410 let mut s = String::from("u5tupleI");
412 for ty in tys.iter() {
413 s.push_str(&encode_ty(tcx, ty, dict, options));
414 }
415 s.push('E');
416 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
417 typeid.push_str(&s);
418 }
419
420 ty::Array(ty0, len) => {
421 let len = len.try_to_target_usize(tcx).expect("expected monomorphic const in cfi");
423 let mut s = String::from("A");
424 let _ = write!(s, "{len}");
425 s.push_str(&encode_ty(tcx, *ty0, dict, options));
426 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
427 typeid.push_str(&s);
428 }
429
430 ty::Pat(ty0, pat) => {
431 let mut s = String::from("u3patI");
433 s.push_str(&encode_ty(tcx, *ty0, dict, options));
434 write!(s, "{:?}", **pat).unwrap();
435 s.push('E');
436 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
437 typeid.push_str(&s);
438 }
439
440 ty::Slice(ty0) => {
441 let mut s = String::from("u5sliceI");
443 s.push_str(&encode_ty(tcx, *ty0, dict, options));
444 s.push('E');
445 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
446 typeid.push_str(&s);
447 }
448
449 ty::Adt(adt_def, args) => {
451 let mut s = String::new();
452 let def_id = adt_def.did();
453 if let Some(encoding) = find_attr!(tcx, def_id, CfiEncoding { encoding } => encoding) {
454 let encoding = encoding.as_str().trim();
455 s.push_str(&encoding);
457 let builtin_types = [
461 "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y", "n", "o",
462 "f", "d", "e", "g", "z", "Dh",
463 ];
464 if !builtin_types.contains(&encoding) {
465 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
466 }
467 } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
468 let name = tcx.item_name(def_id).to_string();
482 let _ = write!(s, "{}{}", name.len(), name);
483 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
484 } else {
485 let name = encode_ty_name(tcx, def_id);
488 let _ = write!(s, "u{}{}", name.len(), name);
489 s.push_str(&encode_args(tcx, args, def_id, false, dict, options));
490 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
491 }
492 typeid.push_str(&s);
493 }
494
495 ty::Foreign(def_id) => {
496 let mut s = String::new();
498
499 if let Some(encoding) = find_attr!(tcx, *def_id, CfiEncoding {encoding} => encoding) {
500 s.push_str(encoding.as_str().trim());
502 } else {
503 let name = tcx.item_name(*def_id).to_string();
504 let _ = write!(s, "{}{}", name.len(), name);
505 }
506 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
507 typeid.push_str(&s);
508 }
509
510 ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
512 let mut s = String::new();
515 let name = encode_ty_name(tcx, *def_id);
516 let _ = write!(s, "u{}{}", name.len(), name);
517 s.push_str(&encode_args(tcx, args, *def_id, false, dict, options));
518 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
519 typeid.push_str(&s);
520 }
521
522 ty::CoroutineClosure(def_id, args) => {
523 let mut s = String::new();
526 let name = encode_ty_name(tcx, *def_id);
527 let _ = write!(s, "u{}{}", name.len(), name);
528 let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
529 s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options));
530 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
531 typeid.push_str(&s);
532 }
533
534 ty::Coroutine(def_id, args, ..) => {
535 let mut s = String::new();
538 let name = encode_ty_name(tcx, *def_id);
539 let _ = write!(s, "u{}{}", name.len(), name);
540 s.push_str(&encode_args(
542 tcx,
543 tcx.mk_args(args.as_coroutine().parent_args()),
544 *def_id,
545 false,
546 dict,
547 options,
548 ));
549 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
550 typeid.push_str(&s);
551 }
552
553 ty::Ref(region, ty0, ..) => {
555 let mut s = String::new();
557 s.push_str("u3refI");
558 s.push_str(&encode_ty(tcx, *ty0, dict, options));
559 s.push('E');
560 compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s);
561 if ty.is_mutable_ptr() {
562 s = format!("{}{}", "U3mut", s);
563 compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
564 }
565 typeid.push_str(&s);
566 }
567
568 ty::RawPtr(ptr_ty, _mutbl) => {
569 let mut s = String::new();
572 s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
573 if !ty.is_mutable_ptr() {
574 s = format!("{}{}", "K", s);
575 compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
576 };
577 s = format!("{}{}", "P", s);
578 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
579 typeid.push_str(&s);
580 }
581
582 ty::FnPtr(sig_tys, hdr) => {
583 let mut s = String::from("P");
585 s.push_str(&encode_fnsig(
586 tcx,
587 &sig_tys.with(*hdr).skip_binder(),
588 dict,
589 TypeIdOptions::empty(),
590 ));
591 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
592 typeid.push_str(&s);
593 }
594
595 ty::UnsafeBinder(_) => {
597 todo!()
598 }
599
600 ty::Dynamic(predicates, region) => {
602 let mut s = String::from("u3dynI");
605 s.push_str(&encode_predicates(tcx, predicates, dict, options));
606 s.push_str(&encode_region(*region, dict));
607 s.push('E');
608 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
609 typeid.push_str(&s);
610 }
611
612 ty::Param(..) => {
614 let mut s = String::from("u5param");
616 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
617 typeid.push_str(&s);
618 }
619
620 ty::Alias(..)
622 | ty::Bound(..)
623 | ty::Error(..)
624 | ty::CoroutineWitness(..)
625 | ty::Infer(..)
626 | ty::Placeholder(..) => {
627 bug!("encode_ty: unexpected `{:?}`", ty.kind());
628 }
629 };
630
631 typeid
632}
633
634fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
636 let mut s = String::new();
673
674 let mut def_path = tcx.def_path(def_id);
676 def_path.data.reverse();
677 for disambiguated_data in &def_path.data {
678 s.push('N');
679 s.push_str(match disambiguated_data.data {
680 hir::definitions::DefPathData::Impl => "I", hir::definitions::DefPathData::ForeignMod => "F", hir::definitions::DefPathData::TypeNs(..) => "t",
683 hir::definitions::DefPathData::ValueNs(..) => "v",
684 hir::definitions::DefPathData::Closure => "C",
685 hir::definitions::DefPathData::Ctor => "c",
686 hir::definitions::DefPathData::AnonConst => "K",
687 hir::definitions::DefPathData::OpaqueTy => "i",
688 hir::definitions::DefPathData::SyntheticCoroutineBody => "s",
689 hir::definitions::DefPathData::NestedStatic => "n",
690 hir::definitions::DefPathData::CrateRoot
691 | hir::definitions::DefPathData::Use
692 | hir::definitions::DefPathData::GlobalAsm
693 | hir::definitions::DefPathData::MacroNs(..)
694 | hir::definitions::DefPathData::OpaqueLifetime(..)
695 | hir::definitions::DefPathData::LifetimeNs(..)
696 | hir::definitions::DefPathData::AnonAssocTy(..) => {
697 ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty_name: unexpected `{0:?}`",
disambiguated_data.data));bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
698 }
699 });
700 }
701
702 s.push('C');
704 s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
705 let crate_name = tcx.crate_name(def_path.krate).to_string();
706 let _ = s.write_fmt(format_args!("{0}{1}", crate_name.len(), crate_name))write!(s, "{}{}", crate_name.len(), crate_name);
707
708 def_path.data.reverse();
710 for disambiguated_data in &def_path.data {
711 let num = disambiguated_data.disambiguator as u64;
712 if num > 0 {
713 s.push_str(&to_disambiguator(num));
714 }
715
716 let name = disambiguated_data.data.to_string();
717 let _ = s.write_fmt(format_args!("{0}", name.len()))write!(s, "{}", name.len());
718
719 if let Some(first) = name.as_bytes().first() {
721 if first.is_ascii_digit() || *first == b'_' {
722 s.push('_');
723 }
724 } else {
725 ::rustc_middle::util::bug::bug_fmt(format_args!("encode_ty_name: invalid name `{0:?}`",
name));bug!("encode_ty_name: invalid name `{:?}`", name);
726 }
727
728 s.push_str(&name);
729 }
730
731 s
732}
733
734fn to_disambiguator(num: u64) -> String {
737 if let Some(num) = num.checked_sub(1) {
738 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("s{0}_",
num.to_base(ALPHANUMERIC_ONLY)))
})format!("s{}_", num.to_base(ALPHANUMERIC_ONLY))
739 } else {
740 "s_".to_string()
741 }
742}
743
744fn to_seq_id(num: usize) -> String {
747 if let Some(num) = num.checked_sub(1) {
748 (num as u64).to_base(CASE_INSENSITIVE).to_uppercase()
749 } else {
750 "".to_string()
751 }
752}