1#![cfg_attr(test, feature(test))]
3#![feature(never_type)]
4pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
7
8pub mod layout;
9mod maybe_transmutable;
10
11#[derive(#[automatically_derived]
impl ::core::marker::Copy for Assume { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Assume {
#[inline]
fn clone(&self) -> Assume {
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Assume {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "Assume",
"alignment", &self.alignment, "lifetimes", &self.lifetimes,
"safety", &self.safety, "validity", &&self.validity)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for Assume {
#[inline]
fn default() -> Assume {
Assume {
alignment: ::core::default::Default::default(),
lifetimes: ::core::default::Default::default(),
safety: ::core::default::Default::default(),
validity: ::core::default::Default::default(),
}
}
}Default)]
12pub struct Assume {
13 pub alignment: bool,
14 pub lifetimes: bool,
15 pub safety: bool,
16 pub validity: bool,
17}
18
19#[derive(#[automatically_derived]
impl<R: ::core::fmt::Debug, T: ::core::fmt::Debug> ::core::fmt::Debug for
Answer<R, T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Answer::Yes => ::core::fmt::Formatter::write_str(f, "Yes"),
Answer::No(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "No",
&__self_0),
Answer::If(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "If",
&__self_0),
}
}
}Debug, #[automatically_derived]
impl<R: ::core::hash::Hash, T: ::core::hash::Hash> ::core::hash::Hash for
Answer<R, T> {
#[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 {
Answer::No(__self_0) => ::core::hash::Hash::hash(__self_0, state),
Answer::If(__self_0) => ::core::hash::Hash::hash(__self_0, state),
_ => {}
}
}
}Hash, #[automatically_derived]
impl<R: ::core::cmp::Eq, T: ::core::cmp::Eq> ::core::cmp::Eq for Answer<R, T>
{
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Reason<T>>;
let _: ::core::cmp::AssertParamIsEq<Condition<R, T>>;
}
}Eq, #[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
::core::cmp::PartialEq for Answer<R, T> {
#[inline]
fn eq(&self, other: &Answer<R, T>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Answer::No(__self_0), Answer::No(__arg1_0)) =>
__self_0 == __arg1_0,
(Answer::If(__self_0), Answer::If(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl<R: ::core::clone::Clone, T: ::core::clone::Clone> ::core::clone::Clone
for Answer<R, T> {
#[inline]
fn clone(&self) -> Answer<R, T> {
match self {
Answer::Yes => Answer::Yes,
Answer::No(__self_0) =>
Answer::No(::core::clone::Clone::clone(__self_0)),
Answer::If(__self_0) =>
Answer::If(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
22pub enum Answer<R, T> {
23 Yes,
24 No(Reason<T>),
25 If(Condition<R, T>),
26}
27
28#[derive(#[automatically_derived]
impl<R: ::core::fmt::Debug, T: ::core::fmt::Debug> ::core::fmt::Debug for
Condition<R, T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Condition::Transmutable { src: __self_0, dst: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Transmutable", "src", __self_0, "dst", &__self_1),
Condition::Outlives { long: __self_0, short: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Outlives", "long", __self_0, "short", &__self_1),
Condition::Immutable { ty: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Immutable", "ty", &__self_0),
Condition::IfAll(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "IfAll",
&__self_0),
Condition::IfAny(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "IfAny",
&__self_0),
}
}
}Debug, #[automatically_derived]
impl<R: ::core::hash::Hash, T: ::core::hash::Hash> ::core::hash::Hash for
Condition<R, T> {
#[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 {
Condition::Transmutable { src: __self_0, dst: __self_1 } => {
::core::hash::Hash::hash(__self_0, state);
::core::hash::Hash::hash(__self_1, state)
}
Condition::Outlives { long: __self_0, short: __self_1 } => {
::core::hash::Hash::hash(__self_0, state);
::core::hash::Hash::hash(__self_1, state)
}
Condition::Immutable { ty: __self_0 } =>
::core::hash::Hash::hash(__self_0, state),
Condition::IfAll(__self_0) =>
::core::hash::Hash::hash(__self_0, state),
Condition::IfAny(__self_0) =>
::core::hash::Hash::hash(__self_0, state),
}
}
}Hash, #[automatically_derived]
impl<R: ::core::cmp::Eq, T: ::core::cmp::Eq> ::core::cmp::Eq for
Condition<R, T> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<T>;
let _: ::core::cmp::AssertParamIsEq<R>;
let _: ::core::cmp::AssertParamIsEq<Vec<Condition<R, T>>>;
let _: ::core::cmp::AssertParamIsEq<Vec<Condition<R, T>>>;
}
}Eq, #[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
::core::cmp::PartialEq for Condition<R, T> {
#[inline]
fn eq(&self, other: &Condition<R, T>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Condition::Transmutable { src: __self_0, dst: __self_1 },
Condition::Transmutable { src: __arg1_0, dst: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(Condition::Outlives { long: __self_0, short: __self_1 },
Condition::Outlives { long: __arg1_0, short: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(Condition::Immutable { ty: __self_0 }, Condition::Immutable {
ty: __arg1_0 }) => __self_0 == __arg1_0,
(Condition::IfAll(__self_0), Condition::IfAll(__arg1_0)) =>
__self_0 == __arg1_0,
(Condition::IfAny(__self_0), Condition::IfAny(__arg1_0)) =>
__self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl<R: ::core::clone::Clone, T: ::core::clone::Clone> ::core::clone::Clone
for Condition<R, T> {
#[inline]
fn clone(&self) -> Condition<R, T> {
match self {
Condition::Transmutable { src: __self_0, dst: __self_1 } =>
Condition::Transmutable {
src: ::core::clone::Clone::clone(__self_0),
dst: ::core::clone::Clone::clone(__self_1),
},
Condition::Outlives { long: __self_0, short: __self_1 } =>
Condition::Outlives {
long: ::core::clone::Clone::clone(__self_0),
short: ::core::clone::Clone::clone(__self_1),
},
Condition::Immutable { ty: __self_0 } =>
Condition::Immutable {
ty: ::core::clone::Clone::clone(__self_0),
},
Condition::IfAll(__self_0) =>
Condition::IfAll(::core::clone::Clone::clone(__self_0)),
Condition::IfAny(__self_0) =>
Condition::IfAny(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
30pub enum Condition<R, T> {
31 Transmutable { src: T, dst: T },
33
34 Outlives { long: R, short: R },
36
37 Immutable { ty: T },
39
40 IfAll(Vec<Condition<R, T>>),
42
43 IfAny(Vec<Condition<R, T>>),
45}
46
47#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Reason<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Reason::SrcIsNotYetSupported =>
::core::fmt::Formatter::write_str(f, "SrcIsNotYetSupported"),
Reason::DstIsNotYetSupported =>
::core::fmt::Formatter::write_str(f, "DstIsNotYetSupported"),
Reason::DstIsBitIncompatible =>
::core::fmt::Formatter::write_str(f, "DstIsBitIncompatible"),
Reason::DstUninhabited =>
::core::fmt::Formatter::write_str(f, "DstUninhabited"),
Reason::DstMayHaveSafetyInvariants =>
::core::fmt::Formatter::write_str(f,
"DstMayHaveSafetyInvariants"),
Reason::DstIsTooBig =>
::core::fmt::Formatter::write_str(f, "DstIsTooBig"),
Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 } =>
::core::fmt::Formatter::debug_struct_field4_finish(f,
"DstRefIsTooBig", "src", __self_0, "src_size", __self_1,
"dst", __self_2, "dst_size", &__self_3),
Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"DstHasStricterAlignment", "src_min_align", __self_0,
"dst_min_align", &__self_1),
Reason::DstIsMoreUnique =>
::core::fmt::Formatter::write_str(f, "DstIsMoreUnique"),
Reason::TypeError =>
::core::fmt::Formatter::write_str(f, "TypeError"),
Reason::SrcLayoutUnknown =>
::core::fmt::Formatter::write_str(f, "SrcLayoutUnknown"),
Reason::DstLayoutUnknown =>
::core::fmt::Formatter::write_str(f, "DstLayoutUnknown"),
Reason::SrcSizeOverflow =>
::core::fmt::Formatter::write_str(f, "SrcSizeOverflow"),
Reason::DstSizeOverflow =>
::core::fmt::Formatter::write_str(f, "DstSizeOverflow"),
}
}
}Debug, #[automatically_derived]
impl<T: ::core::hash::Hash> ::core::hash::Hash for Reason<T> {
#[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 {
Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 } => {
::core::hash::Hash::hash(__self_0, state);
::core::hash::Hash::hash(__self_1, state);
::core::hash::Hash::hash(__self_2, state);
::core::hash::Hash::hash(__self_3, state)
}
Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 } => {
::core::hash::Hash::hash(__self_0, state);
::core::hash::Hash::hash(__self_1, state)
}
_ => {}
}
}
}Hash, #[automatically_derived]
impl<T: ::core::cmp::Eq> ::core::cmp::Eq for Reason<T> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<T>;
let _: ::core::cmp::AssertParamIsEq<usize>;
}
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Reason<T> {
#[inline]
fn eq(&self, other: &Reason<T>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 }, Reason::DstRefIsTooBig {
src: __arg1_0,
src_size: __arg1_1,
dst: __arg1_2,
dst_size: __arg1_3 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2 && __self_3 == __arg1_3,
(Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 },
Reason::DstHasStricterAlignment {
src_min_align: __arg1_0, dst_min_align: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl<T: ::core::cmp::PartialOrd> ::core::cmp::PartialOrd for Reason<T> {
#[inline]
fn partial_cmp(&self, other: &Reason<T>)
-> ::core::option::Option<::core::cmp::Ordering> {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
match (self, other) {
(Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 }, Reason::DstRefIsTooBig {
src: __arg1_0,
src_size: __arg1_1,
dst: __arg1_2,
dst_size: __arg1_3 }) =>
match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
{
::core::option::Option::Some(::core::cmp::Ordering::Equal)
=>
match ::core::cmp::PartialOrd::partial_cmp(__self_1,
__arg1_1) {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
=>
match ::core::cmp::PartialOrd::partial_cmp(__self_2,
__arg1_2) {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
=> ::core::cmp::PartialOrd::partial_cmp(__self_3, __arg1_3),
cmp => cmp,
},
cmp => cmp,
},
cmp => cmp,
},
(Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 },
Reason::DstHasStricterAlignment {
src_min_align: __arg1_0, dst_min_align: __arg1_1 }) =>
match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
{
::core::option::Option::Some(::core::cmp::Ordering::Equal)
=> ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
cmp => cmp,
},
_ =>
::core::cmp::PartialOrd::partial_cmp(&__self_discr,
&__arg1_discr),
}
}
}PartialOrd, #[automatically_derived]
impl<T: ::core::cmp::Ord> ::core::cmp::Ord for Reason<T> {
#[inline]
fn cmp(&self, other: &Reason<T>) -> ::core::cmp::Ordering {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
::core::cmp::Ordering::Equal =>
match (self, other) {
(Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 }, Reason::DstRefIsTooBig {
src: __arg1_0,
src_size: __arg1_1,
dst: __arg1_2,
dst_size: __arg1_3 }) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
match ::core::cmp::Ord::cmp(__self_1, __arg1_1) {
::core::cmp::Ordering::Equal =>
match ::core::cmp::Ord::cmp(__self_2, __arg1_2) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_3, __arg1_3),
cmp => cmp,
},
cmp => cmp,
},
cmp => cmp,
},
(Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 },
Reason::DstHasStricterAlignment {
src_min_align: __arg1_0, dst_min_align: __arg1_1 }) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_1, __arg1_1),
cmp => cmp,
},
_ => ::core::cmp::Ordering::Equal,
},
cmp => cmp,
}
}
}Ord, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Reason<T> {
#[inline]
fn clone(&self) -> Reason<T> {
match self {
Reason::SrcIsNotYetSupported => Reason::SrcIsNotYetSupported,
Reason::DstIsNotYetSupported => Reason::DstIsNotYetSupported,
Reason::DstIsBitIncompatible => Reason::DstIsBitIncompatible,
Reason::DstUninhabited => Reason::DstUninhabited,
Reason::DstMayHaveSafetyInvariants =>
Reason::DstMayHaveSafetyInvariants,
Reason::DstIsTooBig => Reason::DstIsTooBig,
Reason::DstRefIsTooBig {
src: __self_0,
src_size: __self_1,
dst: __self_2,
dst_size: __self_3 } =>
Reason::DstRefIsTooBig {
src: ::core::clone::Clone::clone(__self_0),
src_size: ::core::clone::Clone::clone(__self_1),
dst: ::core::clone::Clone::clone(__self_2),
dst_size: ::core::clone::Clone::clone(__self_3),
},
Reason::DstHasStricterAlignment {
src_min_align: __self_0, dst_min_align: __self_1 } =>
Reason::DstHasStricterAlignment {
src_min_align: ::core::clone::Clone::clone(__self_0),
dst_min_align: ::core::clone::Clone::clone(__self_1),
},
Reason::DstIsMoreUnique => Reason::DstIsMoreUnique,
Reason::TypeError => Reason::TypeError,
Reason::SrcLayoutUnknown => Reason::SrcLayoutUnknown,
Reason::DstLayoutUnknown => Reason::DstLayoutUnknown,
Reason::SrcSizeOverflow => Reason::SrcSizeOverflow,
Reason::DstSizeOverflow => Reason::DstSizeOverflow,
}
}
}Clone)]
49pub enum Reason<T> {
50 SrcIsNotYetSupported,
52 DstIsNotYetSupported,
54 DstIsBitIncompatible,
56 DstUninhabited,
58 DstMayHaveSafetyInvariants,
60 DstIsTooBig,
62 DstRefIsTooBig {
64 src: T,
66 src_size: usize,
68 dst: T,
70 dst_size: usize,
72 },
73 DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
75 DstIsMoreUnique,
77 TypeError,
79 SrcLayoutUnknown,
81 DstLayoutUnknown,
83 SrcSizeOverflow,
85 DstSizeOverflow,
87}
88
89#[cfg(feature = "rustc")]
90mod rustc {
91 use rustc_hir::lang_items::LangItem;
92 use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
93
94 use super::*;
95
96 pub struct TransmuteTypeEnv<'tcx> {
97 tcx: TyCtxt<'tcx>,
98 }
99
100 impl<'tcx> TransmuteTypeEnv<'tcx> {
101 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
102 Self { tcx }
103 }
104
105 pub fn is_transmutable(
106 &mut self,
107 src: Ty<'tcx>,
108 dst: Ty<'tcx>,
109 assume: crate::Assume,
110 ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
111 crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx)
112 .answer()
113 }
114 }
115
116 impl Assume {
117 pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
119 use rustc_middle::ty::ScalarInt;
120 use rustc_span::sym;
121
122 let cv = ct.try_to_value()?;
123 let adt_def = cv.ty.ty_adt_def()?;
124
125 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
126 tcx.dcx().delayed_bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("The given `const` was not marked with the `{0}` lang item.",
LangItem::TransmuteOpts.name()))
})format!(
127 "The given `const` was not marked with the `{}` lang item.",
128 LangItem::TransmuteOpts.name()
129 ));
130 return Some(Self {
131 alignment: true,
132 lifetimes: true,
133 safety: true,
134 validity: true,
135 });
136 }
137
138 let variant = adt_def.non_enum_variant();
139 let fields = cv.to_branch();
140
141 let get_field = |name| {
142 let (field_idx, _) = variant
143 .fields
144 .iter()
145 .enumerate()
146 .find(|(_, field_def)| name == field_def.name)
147 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("There were no fields named `{0}`.",
name));
}panic!("There were no fields named `{name}`."));
148 fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE)
149 };
150
151 Some(Self {
152 alignment: get_field(sym::alignment)?,
153 lifetimes: get_field(sym::lifetimes)?,
154 safety: get_field(sym::safety)?,
155 validity: get_field(sym::validity)?,
156 })
157 }
158 }
159}
160
161#[cfg(feature = "rustc")]
162pub use rustc::*;