Skip to main content

rustc_transmute/
lib.rs

1//! Checks whether one type's representation can be reinterpreted as another.
2//!
3//! The analysis converts compiler layouts into trees of bytes, references, and
4//! definition markers. It prunes destination paths that may carry safety invariants unless
5//! safety is assumed, then converts the trees into deterministic finite automata.
6//! Comparing the automata produces an [`Answer`]; reference transitions can leave
7//! [`Condition`]s for the trait solver to discharge.
8
9// tidy-alphabetical-start
10#![cfg_attr(bootstrap, feature(never_type))]
11#![cfg_attr(test, feature(test))]
12#![feature(option_into_flat_iter)]
13// tidy-alphabetical-end
14
15pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
16
17pub mod layout;
18mod maybe_transmutable;
19
20/// Proof obligations supplied by the caller rather than checked by the analysis.
21///
22/// This mirrors `core::mem::Assume`. A `true` field transfers the corresponding
23/// obligation to the caller; the default leaves all four obligations to the compiler.
24#[derive(#[automatically_derived]
impl ::core::marker::Copy for Assume { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Assume { }
#[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)]
25pub struct Assume {
26    pub alignment: bool,
27    pub lifetimes: bool,
28    pub safety: bool,
29    pub validity: bool,
30}
31
32/// The result of a transmutability query under the supplied [`Assume`] options.
33#[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_fields_are_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::marker::StructuralPartialEq for Answer<R, T> {
}
#[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)]
34pub enum Answer<R, T> {
35    /// The analysis requires no further conditions.
36    Yes,
37    /// The analysis could not establish transmutability.
38    No(Reason<T>),
39    /// Transmutability depends on conditions that the trait solver must discharge.
40    If(Condition<R, T>),
41}
42
43/// A condition which must hold for safe transmutation to be possible.
44#[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_fields_are_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::marker::StructuralPartialEq for Condition<R, T> {
}
#[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)]
45pub enum Condition<R, T> {
46    /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
47    Transmutable { src: T, dst: T },
48
49    /// The region `long` must outlive `short`.
50    Outlives { long: R, short: R },
51
52    /// The type `ty` must satisfy `Freeze`.
53    Immutable { ty: T },
54
55    /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
56    IfAll(Vec<Condition<R, T>>),
57
58    /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
59    IfAny(Vec<Condition<R, T>>),
60}
61
62/// Answers "why wasn't the source type transmutable into the destination type?"
63#[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_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<T>;
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
    Reason<T> {
}
#[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)]
64pub enum Reason<T> {
65    /// The layout of the source type is not yet supported.
66    SrcIsNotYetSupported,
67    /// The layout of the destination type is not yet supported.
68    DstIsNotYetSupported,
69    /// The layout of the destination type is bit-incompatible with the source type.
70    DstIsBitIncompatible,
71    /// The destination type is uninhabited.
72    DstUninhabited,
73    /// The destination type may carry safety invariants.
74    DstMayHaveSafetyInvariants,
75    /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
76    DstIsTooBig,
77    /// The destination referent is larger than the source referent.
78    DstRefIsTooBig {
79        /// The referent of the source type.
80        src: T,
81        /// The size of the source type's referent.
82        src_size: usize,
83        /// The too-large referent of the destination type.
84        dst: T,
85        /// The size of the destination type's referent.
86        dst_size: usize,
87    },
88    /// The destination referent requires stricter alignment than the source referent.
89    DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
90    /// Can't go from shared pointer to unique pointer
91    DstIsMoreUnique,
92    /// Encountered a type error
93    TypeError,
94    /// The layout of src is unknown
95    SrcLayoutUnknown,
96    /// The layout of dst is unknown
97    DstLayoutUnknown,
98    /// The size of src is overflow
99    SrcSizeOverflow,
100    /// The size of dst is overflow
101    DstSizeOverflow,
102}
103
104#[cfg(feature = "rustc")]
105mod rustc {
106    use rustc_hir::attrs::lang_items::LangItem;
107    use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
108
109    use super::*;
110
111    pub struct TransmuteTypeEnv<'tcx> {
112        tcx: TyCtxt<'tcx>,
113    }
114
115    impl<'tcx> TransmuteTypeEnv<'tcx> {
116        pub fn new(tcx: TyCtxt<'tcx>) -> Self {
117            Self { tcx }
118        }
119
120        pub fn is_transmutable(
121            &mut self,
122            src: Ty<'tcx>,
123            dst: Ty<'tcx>,
124            assume: crate::Assume,
125        ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
126            crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx)
127                .answer()
128        }
129    }
130
131    impl Assume {
132        /// Constructs an `Assume` from a given const-`Assume`.
133        pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
134            use rustc_middle::ty::ScalarInt;
135            use rustc_span::sym;
136
137            let cv = ct.try_to_value()?;
138            let adt_def = cv.ty.ty_adt_def()?;
139
140            if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
141                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!(
142                    "The given `const` was not marked with the `{}` lang item.",
143                    LangItem::TransmuteOpts.name()
144                ));
145                return Some(Self {
146                    alignment: true,
147                    lifetimes: true,
148                    safety: true,
149                    validity: true,
150                });
151            }
152
153            let variant = adt_def.non_enum_variant();
154            let fields = cv.to_branch();
155
156            let get_field = |name| {
157                let (field_idx, _) = variant
158                    .fields
159                    .iter()
160                    .enumerate()
161                    .find(|(_, field_def)| name == field_def.name)
162                    .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("There were no fields named `{0}`.",
            name));
}panic!("There were no fields named `{name}`."));
163                fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE)
164            };
165
166            Some(Self {
167                alignment: get_field(sym::alignment)?,
168                lifetimes: get_field(sym::lifetimes)?,
169                safety: get_field(sym::safety)?,
170                validity: get_field(sym::validity)?,
171            })
172        }
173    }
174}
175
176#[cfg(feature = "rustc")]
177pub use rustc::*;