rustc_middle/query/
erase.rs

1use std::ffi::OsStr;
2use std::intrinsics::transmute_unchecked;
3use std::mem::MaybeUninit;
4
5use rustc_span::ErrorGuaranteed;
6
7use crate::query::CyclePlaceholder;
8use crate::ty::adjustment::CoerceUnsizedInfo;
9use crate::ty::{self, Ty, TyCtxt};
10use crate::{mir, traits};
11
12#[derive(Copy, Clone)]
13pub struct Erased<T: Copy> {
14    // We use `MaybeUninit` here so we can store any value
15    // in `data` since we aren't actually storing a `T`.
16    data: MaybeUninit<T>,
17}
18
19pub trait EraseType: Copy {
20    type Result: Copy;
21}
22
23// Allow `type_alias_bounds` since compilation will fail without `EraseType`.
24#[allow(type_alias_bounds)]
25pub type Erase<T: EraseType> = Erased<impl Copy>;
26
27#[inline(always)]
28#[define_opaque(Erase)]
29pub fn erase<T: EraseType>(src: T) -> Erase<T> {
30    // Ensure the sizes match
31    const {
32        if size_of::<T>() != size_of::<T::Result>() {
33            panic!("size of T must match erased type T::Result")
34        }
35    };
36
37    Erased::<<T as EraseType>::Result> {
38        // `transmute_unchecked` is needed here because it does not have `transmute`'s size check
39        // (and thus allows to transmute between `T` and `MaybeUninit<T::Result>`) (we do the size
40        // check ourselves in the `const` block above).
41        //
42        // `transmute_copy` is also commonly used for this (and it would work here since
43        // `EraseType: Copy`), but `transmute_unchecked` better explains the intent.
44        //
45        // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
46        data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Result>>(src) },
47    }
48}
49
50/// Restores an erased value.
51#[inline(always)]
52#[define_opaque(Erase)]
53pub fn restore<T: EraseType>(value: Erase<T>) -> T {
54    let value: Erased<<T as EraseType>::Result> = value;
55    // See comment in `erase` for why we use `transmute_unchecked`.
56    //
57    // SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance
58    // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of
59    // the right size.
60    unsafe { transmute_unchecked::<MaybeUninit<T::Result>, T>(value.data) }
61}
62
63impl<T> EraseType for &'_ T {
64    type Result = [u8; size_of::<&'static ()>()];
65}
66
67impl<T> EraseType for &'_ [T] {
68    type Result = [u8; size_of::<&'static [()]>()];
69}
70
71impl EraseType for &'_ OsStr {
72    type Result = [u8; size_of::<&'static OsStr>()];
73}
74
75impl<T> EraseType for &'_ ty::List<T> {
76    type Result = [u8; size_of::<&'static ty::List<()>>()];
77}
78
79impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> {
80    type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
81}
82
83impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> {
84    type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
85}
86
87impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
88    type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
89}
90
91impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
92    type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
93}
94
95impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
96    type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
97}
98
99impl<T> EraseType for Result<&'_ [T], rustc_errors::ErrorGuaranteed> {
100    type Result = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()];
101}
102
103impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> {
104    type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
105}
106
107impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
108    type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
109}
110
111impl<T> EraseType for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> {
112    type Result = [u8; size_of::<
113        Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>,
114    >()];
115}
116
117impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuaranteed> {
118    type Result =
119        [u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
120}
121
122impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
123    type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
124}
125
126impl EraseType
127    for Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, rustc_errors::ErrorGuaranteed>
128{
129    type Result = [u8; size_of::<
130        Result<Option<ty::EarlyBinder<'static, ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
131    >()];
132}
133
134impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
135    type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
136}
137
138impl EraseType for Result<bool, &ty::layout::LayoutError<'_>> {
139    type Result = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
140}
141
142impl EraseType for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>> {
143    type Result = [u8; size_of::<
144        Result<
145            rustc_abi::TyAndLayout<'static, Ty<'static>>,
146            &'static ty::layout::LayoutError<'static>,
147        >,
148    >()];
149}
150
151impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
152    type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
153}
154
155impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
156    type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
157}
158
159impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> {
160    type Result = [u8; size_of::<
161        Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>,
162    >()];
163}
164
165impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
166    type Result =
167        [u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
168}
169
170impl EraseType for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
171    type Result = [u8; size_of::<Result<ty::EarlyBinder<'static, Ty<'_>>, CyclePlaceholder>>()];
172}
173
174impl<T> EraseType for Option<&'_ T> {
175    type Result = [u8; size_of::<Option<&'static ()>>()];
176}
177
178impl<T> EraseType for Option<&'_ [T]> {
179    type Result = [u8; size_of::<Option<&'static [()]>>()];
180}
181
182impl EraseType for Option<&'_ OsStr> {
183    type Result = [u8; size_of::<Option<&'static OsStr>>()];
184}
185
186impl EraseType for Option<mir::DestructuredConstant<'_>> {
187    type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
188}
189
190impl EraseType for Option<ty::ImplTraitHeader<'_>> {
191    type Result = [u8; size_of::<Option<ty::ImplTraitHeader<'static>>>()];
192}
193
194impl EraseType for Option<ty::EarlyBinder<'_, Ty<'_>>> {
195    type Result = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
196}
197
198impl EraseType for rustc_hir::MaybeOwner<'_> {
199    type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
200}
201
202impl<T: EraseType> EraseType for ty::EarlyBinder<'_, T> {
203    type Result = T::Result;
204}
205
206impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
207    type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
208}
209
210impl EraseType for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
211    type Result =
212        [u8; size_of::<ty::Binder<'static, ty::CoroutineWitnessTypes<TyCtxt<'static>>>>()];
213}
214
215impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
216    type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
217}
218
219impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
220    type Result = [u8; size_of::<(&'static (), &'static ())>()];
221}
222
223impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) {
224    type Result = [u8; size_of::<(&'static (), &'static [()])>()];
225}
226
227impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) {
228    type Result = [u8; size_of::<(&'static [()], &'static [()])>()];
229}
230
231impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) {
232    type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
233}
234
235macro_rules! trivial {
236    ($($ty:ty),+ $(,)?) => {
237        $(
238            impl EraseType for $ty {
239                type Result = [u8; size_of::<$ty>()];
240            }
241        )*
242    }
243}
244
245trivial! {
246    (),
247    bool,
248    Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>,
249    Option<rustc_ast::expand::allocator::AllocatorKind>,
250    Option<rustc_attr_data_structures::ConstStability>,
251    Option<rustc_attr_data_structures::DefaultBodyStability>,
252    Option<rustc_attr_data_structures::Stability>,
253    Option<rustc_data_structures::svh::Svh>,
254    Option<rustc_hir::def::DefKind>,
255    Option<rustc_hir::CoroutineKind>,
256    Option<rustc_hir::HirId>,
257    Option<rustc_middle::middle::stability::DeprecationEntry>,
258    Option<rustc_middle::ty::AsyncDestructor>,
259    Option<rustc_middle::ty::Destructor>,
260    Option<rustc_middle::ty::ImplTraitInTraitData>,
261    Option<rustc_middle::ty::ScalarInt>,
262    Option<rustc_span::def_id::CrateNum>,
263    Option<rustc_span::def_id::DefId>,
264    Option<rustc_span::def_id::LocalDefId>,
265    Option<rustc_span::Span>,
266    Option<rustc_abi::FieldIdx>,
267    Option<rustc_target::spec::PanicStrategy>,
268    Option<usize>,
269    Option<rustc_middle::ty::IntrinsicDef>,
270    Result<(), rustc_errors::ErrorGuaranteed>,
271    Result<(), rustc_middle::traits::query::NoSolution>,
272    Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
273    rustc_abi::ReprOptions,
274    rustc_ast::expand::allocator::AllocatorKind,
275    rustc_attr_data_structures::ConstStability,
276    rustc_attr_data_structures::DefaultBodyStability,
277    rustc_attr_data_structures::Deprecation,
278    rustc_attr_data_structures::Stability,
279    rustc_data_structures::svh::Svh,
280    rustc_errors::ErrorGuaranteed,
281    rustc_hir::Constness,
282    rustc_hir::def_id::DefId,
283    rustc_hir::def_id::DefIndex,
284    rustc_hir::def_id::LocalDefId,
285    rustc_hir::def_id::LocalModDefId,
286    rustc_hir::def::DefKind,
287    rustc_hir::Defaultness,
288    rustc_hir::definitions::DefKey,
289    rustc_hir::CoroutineKind,
290    rustc_hir::HirId,
291    rustc_hir::IsAsync,
292    rustc_hir::ItemLocalId,
293    rustc_hir::LangItem,
294    rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
295    rustc_hir::OwnerId,
296    rustc_hir::Upvar,
297    rustc_index::bit_set::FiniteBitSet<u32>,
298    rustc_middle::middle::dependency_format::Linkage,
299    rustc_middle::middle::exported_symbols::SymbolExportInfo,
300    rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
301    rustc_middle::middle::resolve_bound_vars::ResolvedArg,
302    rustc_middle::middle::stability::DeprecationEntry,
303    rustc_middle::mir::ConstQualifs,
304    rustc_middle::mir::interpret::AllocId,
305    rustc_middle::mir::interpret::CtfeProvenance,
306    rustc_middle::mir::interpret::ErrorHandled,
307    rustc_middle::thir::ExprId,
308    rustc_middle::traits::CodegenObligationError,
309    rustc_middle::traits::EvaluationResult,
310    rustc_middle::traits::OverflowError,
311    rustc_middle::traits::query::NoSolution,
312    rustc_middle::traits::WellFormedLoc,
313    rustc_middle::ty::adjustment::CoerceUnsizedInfo,
314    rustc_middle::ty::AssocItem,
315    rustc_middle::ty::AssocItemContainer,
316    rustc_middle::ty::Asyncness,
317    rustc_middle::ty::AsyncDestructor,
318    rustc_middle::ty::BoundVariableKind,
319    rustc_middle::ty::AnonConstKind,
320    rustc_middle::ty::DeducedParamAttrs,
321    rustc_middle::ty::Destructor,
322    rustc_middle::ty::fast_reject::SimplifiedType,
323    rustc_middle::ty::ImplPolarity,
324    rustc_middle::ty::Representability,
325    rustc_middle::ty::UnusedGenericParams,
326    rustc_middle::ty::util::AlwaysRequiresDrop,
327    rustc_middle::ty::Visibility<rustc_span::def_id::DefId>,
328    rustc_session::config::CrateType,
329    rustc_session::config::EntryFnType,
330    rustc_session::config::OptLevel,
331    rustc_session::config::SymbolManglingVersion,
332    rustc_session::cstore::CrateDepKind,
333    rustc_session::cstore::ExternCrate,
334    rustc_session::cstore::LinkagePreference,
335    rustc_session::Limits,
336    rustc_session::lint::LintExpectationId,
337    rustc_span::def_id::CrateNum,
338    rustc_span::def_id::DefPathHash,
339    rustc_span::ExpnHash,
340    rustc_span::ExpnId,
341    rustc_span::Span,
342    rustc_span::Symbol,
343    rustc_span::Ident,
344    rustc_target::spec::PanicStrategy,
345    rustc_type_ir::Variance,
346    u32,
347    usize,
348}
349
350macro_rules! tcx_lifetime {
351    ($($($fake_path:ident)::+),+ $(,)?) => {
352        $(
353            impl<'tcx> EraseType for $($fake_path)::+<'tcx> {
354                type Result = [u8; size_of::<$($fake_path)::+<'static>>()];
355            }
356        )*
357    }
358}
359
360tcx_lifetime! {
361    rustc_middle::middle::exported_symbols::ExportedSymbol,
362    rustc_middle::mir::Const,
363    rustc_middle::mir::DestructuredConstant,
364    rustc_middle::mir::ConstAlloc,
365    rustc_middle::mir::ConstValue,
366    rustc_middle::mir::interpret::GlobalId,
367    rustc_middle::mir::interpret::LitToConstInput,
368    rustc_middle::mir::interpret::EvalStaticInitializerRawResult,
369    rustc_middle::mir::mono::MonoItemPartitions,
370    rustc_middle::traits::query::MethodAutoderefStepsResult,
371    rustc_middle::traits::query::type_op::AscribeUserType,
372    rustc_middle::traits::query::type_op::Eq,
373    rustc_middle::traits::query::type_op::ProvePredicate,
374    rustc_middle::traits::query::type_op::Subtype,
375    rustc_middle::ty::AdtDef,
376    rustc_middle::ty::AliasTy,
377    rustc_middle::ty::ClauseKind,
378    rustc_middle::ty::ClosureTypeInfo,
379    rustc_middle::ty::Const,
380    rustc_middle::ty::DestructuredConst,
381    rustc_middle::ty::ExistentialTraitRef,
382    rustc_middle::ty::FnSig,
383    rustc_middle::ty::GenericArg,
384    rustc_middle::ty::GenericPredicates,
385    rustc_middle::ty::ConstConditions,
386    rustc_middle::ty::inhabitedness::InhabitedPredicate,
387    rustc_middle::ty::Instance,
388    rustc_middle::ty::InstanceKind,
389    rustc_middle::ty::layout::FnAbiError,
390    rustc_middle::ty::layout::LayoutError,
391    rustc_middle::ty::ParamEnv,
392    rustc_middle::ty::Predicate,
393    rustc_middle::ty::SymbolName,
394    rustc_middle::ty::TraitRef,
395    rustc_middle::ty::Ty,
396    rustc_middle::ty::UnevaluatedConst,
397    rustc_middle::ty::ValTree,
398    rustc_middle::ty::VtblEntry,
399}