Skip to main content

rustc_transmute/maybe_transmutable/
mod.rs

1use tracing::{debug, instrument, trace};
2
3pub(crate) mod query_context;
4#[cfg(test)]
5mod tests;
6
7use crate::layout::{self, Def, Dfa, Reference, Tree, dfa, union};
8use crate::maybe_transmutable::query_context::QueryContext;
9use crate::{Answer, Condition, Map, Reason};
10
11pub(crate) struct MaybeTransmutableQuery<L, C>
12where
13    C: QueryContext,
14{
15    src: L,
16    dst: L,
17    assume: crate::Assume,
18    context: C,
19}
20
21impl<L, C> MaybeTransmutableQuery<L, C>
22where
23    C: QueryContext,
24{
25    pub(crate) fn new(src: L, dst: L, assume: crate::Assume, context: C) -> Self {
26        Self { src, dst, assume, context }
27    }
28}
29
30#[cfg(feature = "rustc")]
31mod rustc {
32    use rustc_middle::ty::layout::LayoutCx;
33    use rustc_middle::ty::{Ty, TyCtxt, TypingEnv};
34
35    use super::*;
36    use crate::layout::tree::rustc::Err;
37
38    impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
39        /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
40        /// then computes an answer using those trees.
41        {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("answer",
                                    "rustc_transmute::maybe_transmutable::rustc",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(41u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable::rustc"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("src")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("src");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("dst")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("dst");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.src)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.dst)
                                                            as &dyn ::tracing::field::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:
                    Answer<<TyCtxt<'tcx> as QueryContext>::Region,
                    <TyCtxt<'tcx> as QueryContext>::Type> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let Self { src, dst, assume, context } = self;
            let layout_cx =
                LayoutCx::new(context, TypingEnv::fully_monomorphized());
            let src = Tree::from_ty(src, layout_cx);
            let dst = Tree::from_ty(dst, layout_cx);
            match (src, dst) {
                (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => {
                    Answer::No(Reason::TypeError)
                }
                (Err(Err::UnknownLayout), _) =>
                    Answer::No(Reason::SrcLayoutUnknown),
                (_, Err(Err::UnknownLayout)) =>
                    Answer::No(Reason::DstLayoutUnknown),
                (Err(Err::NotYetSupported), _) =>
                    Answer::No(Reason::SrcIsNotYetSupported),
                (_, Err(Err::NotYetSupported)) =>
                    Answer::No(Reason::DstIsNotYetSupported),
                (Err(Err::SizeOverflow), _) =>
                    Answer::No(Reason::SrcSizeOverflow),
                (_, Err(Err::SizeOverflow)) =>
                    Answer::No(Reason::DstSizeOverflow),
                (Ok(src), Ok(dst)) =>
                    MaybeTransmutableQuery {
                            src,
                            dst,
                            assume,
                            context,
                        }.answer(),
            }
        }
    }
}#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
42        pub(crate) fn answer(
43            self,
44        ) -> Answer<<TyCtxt<'tcx> as QueryContext>::Region, <TyCtxt<'tcx> as QueryContext>::Type>
45        {
46            let Self { src, dst, assume, context } = self;
47
48            let layout_cx = LayoutCx::new(context, TypingEnv::fully_monomorphized());
49
50            // Convert `src` and `dst` from their rustc representations, to `Tree`-based
51            // representations.
52            let src = Tree::from_ty(src, layout_cx);
53            let dst = Tree::from_ty(dst, layout_cx);
54
55            match (src, dst) {
56                (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => {
57                    Answer::No(Reason::TypeError)
58                }
59                (Err(Err::UnknownLayout), _) => Answer::No(Reason::SrcLayoutUnknown),
60                (_, Err(Err::UnknownLayout)) => Answer::No(Reason::DstLayoutUnknown),
61                (Err(Err::NotYetSupported), _) => Answer::No(Reason::SrcIsNotYetSupported),
62                (_, Err(Err::NotYetSupported)) => Answer::No(Reason::DstIsNotYetSupported),
63                (Err(Err::SizeOverflow), _) => Answer::No(Reason::SrcSizeOverflow),
64                (_, Err(Err::SizeOverflow)) => Answer::No(Reason::DstSizeOverflow),
65                (Ok(src), Ok(dst)) => MaybeTransmutableQuery { src, dst, assume, context }.answer(),
66            }
67        }
68    }
69}
70
71impl<C>
72    MaybeTransmutableQuery<
73        Tree<<C as QueryContext>::Def, <C as QueryContext>::Region, <C as QueryContext>::Type>,
74        C,
75    >
76where
77    C: QueryContext,
78{
79    /// Answers whether a `Tree` is transmutable into another `Tree`.
80    ///
81    /// Removes definition markers from both trees and, unless safety is assumed,
82    /// prunes destination paths that may carry safety invariants. It then converts
83    /// the remaining layouts to `Dfa`s and compares them.
84    #[inline(always)]
85    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("answer",
                                    "rustc_transmute::maybe_transmutable",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(85u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("src")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("src");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("dst")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("dst");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.src)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.dst)
                                                            as &dyn ::tracing::field::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:
                    Answer<<C as QueryContext>::Region,
                    <C as QueryContext>::Type> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let Self { src, dst, assume, context } = self;
            let src = src.prune(&|_def| false);
            if src.is_inhabited() && !dst.is_inhabited() {
                return Answer::No(Reason::DstUninhabited);
            }
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:98",
                                    "rustc_transmute::maybe_transmutable",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(98u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                                    ::tracing_core::field::FieldSet::new(&["message",
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("src")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("src");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("pruned src")
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&src)
                                                        as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            let dst =
                if assume.safety {
                    dst.prune(&|_def| false)
                } else { dst.prune(&|def| def.has_safety_invariants()) };
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:108",
                                    "rustc_transmute::maybe_transmutable",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(108u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                                    ::tracing_core::field::FieldSet::new(&["message",
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("dst")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("dst");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("pruned dst")
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&dst)
                                                        as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            let src =
                match Dfa::from_tree(src) {
                    Ok(src) => src,
                    Err(layout::Uninhabited) => return Answer::Yes,
                };
            let dst =
                match Dfa::from_tree(dst) {
                    Ok(dst) => dst,
                    Err(layout::Uninhabited) =>
                        return Answer::No(Reason::DstMayHaveSafetyInvariants),
                };
            MaybeTransmutableQuery { src, dst, assume, context }.answer()
        }
    }
}#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
86    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
87        let Self { src, dst, assume, context } = self;
88
89        // Keep every source representation while removing its definition markers.
90        // Reference nodes remain intact; mutable destination references also generate
91        // a reverse transmutability obligation for their referents.
92        let src = src.prune(&|_def| false);
93
94        if src.is_inhabited() && !dst.is_inhabited() {
95            return Answer::No(Reason::DstUninhabited);
96        }
97
98        trace!(?src, "pruned src");
99
100        // Remove destination definition markers. Unless the caller assumes safety,
101        // prune paths whose definitions may carry safety invariants.
102        let dst = if assume.safety {
103            dst.prune(&|_def| false)
104        } else {
105            dst.prune(&|def| def.has_safety_invariants())
106        };
107
108        trace!(?dst, "pruned dst");
109
110        // Convert `src` from a tree-based representation to a DFA-based
111        // representation. If the conversion fails because `src` is uninhabited,
112        // conclude that the transmutation is acceptable, because instances of
113        // the `src` type do not exist.
114        let src = match Dfa::from_tree(src) {
115            Ok(src) => src,
116            Err(layout::Uninhabited) => return Answer::Yes,
117        };
118
119        // An inhabited source and an originally uninhabited destination were
120        // rejected above. If the pruned destination is now uninhabited, no path
121        // remains whose definitions are known to be free of safety invariants.
122        let dst = match Dfa::from_tree(dst) {
123            Ok(dst) => dst,
124            Err(layout::Uninhabited) => return Answer::No(Reason::DstMayHaveSafetyInvariants),
125        };
126
127        MaybeTransmutableQuery { src, dst, assume, context }.answer()
128    }
129}
130
131impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Region, <C as QueryContext>::Type>, C>
132where
133    C: QueryContext,
134{
135    /// Answers whether a `Dfa` is transmutable into another `Dfa`.
136    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
137        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:137",
                        "rustc_transmute::maybe_transmutable",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(137u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("src")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("src");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.src)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(src = ?self.src);
138        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:138",
                        "rustc_transmute::maybe_transmutable",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(138u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("dst")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("dst");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.dst)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(dst = ?self.dst);
139        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:139",
                        "rustc_transmute::maybe_transmutable",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(139u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("src_transitions_len")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("src_transitions_len");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("dst_transitions_len")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("dst_transitions_len");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&self.src.transitions.len()
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&self.dst.transitions.len()
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
140            src_transitions_len = self.src.transitions.len(),
141            dst_transitions_len = self.dst.transitions.len()
142        );
143        self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
144    }
145
146    #[inline(always)]
147    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("answer_memo",
                                    "rustc_transmute::maybe_transmutable",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(147u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("src_state")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("src_state");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("dst_state")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("dst_state");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&src_state)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&dst_state)
                                                            as &dyn ::tracing::field::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:
                    Answer<<C as QueryContext>::Region,
                    <C as QueryContext>::Type> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(answer) = cache.get(&(src_state, dst_state)) {
                answer.clone()
            } else {
                let answer = self.answer_impl(cache, src_state, dst_state);
                if let Some(..) =
                        cache.insert((src_state, dst_state), answer.clone()) {
                    {
                        ::core::panicking::panic_fmt(format_args!("failed to correctly cache transmutability"));
                    }
                }
                answer
            }
        }
    }
}#[instrument(level = "debug", skip(self, cache))]
148    fn answer_memo(
149        &self,
150        cache: &mut Map<
151            (dfa::State, dfa::State),
152            Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>,
153        >,
154        src_state: dfa::State,
155        dst_state: dfa::State,
156    ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
157        if let Some(answer) = cache.get(&(src_state, dst_state)) {
158            answer.clone()
159        } else {
160            let answer = self.answer_impl(cache, src_state, dst_state);
161            if let Some(..) = cache.insert((src_state, dst_state), answer.clone()) {
162                panic!("failed to correctly cache transmutability")
163            }
164            answer
165        }
166    }
167
168    fn answer_impl(
169        &self,
170        cache: &mut Map<
171            (dfa::State, dfa::State),
172            Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>,
173        >,
174        src_state: dfa::State,
175        dst_state: dfa::State,
176    ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
177        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:177",
                        "rustc_transmute::maybe_transmutable",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(177u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("src_state")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("src_state");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("dst_state")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("dst_state");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&src_state)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&dst_state)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?src_state, ?dst_state);
178        if dst_state == self.dst.accept {
179            // The destination needs no more input. Union transmutation permits
180            // truncating the remaining source bytes: for example, `u8` to `()`.
181            // Compatibility of the consumed prefix is checked by the preceding
182            // transitions, including any conditions they generate for references.
183            Answer::Yes
184        } else if src_state == self.src.accept {
185            // extension: `size_of(Src) <= size_of(Dst)`
186            if let Some(dst_state_prime) = self.dst.get_uninit_edge_dst(dst_state) {
187                self.answer_memo(cache, src_state, dst_state_prime)
188            } else {
189                Answer::No(Reason::DstIsTooBig)
190            }
191        } else {
192            let src_quantifier = if self.assume.validity {
193                // The caller checks validity (for example, `src <= 1u8` for a
194                // `u8`-to-`bool` transmutation), so at least one source transition
195                // must admit a compatible continuation.
196                Quantifier::ThereExists
197            } else {
198                // Every source transition must admit a compatible continuation
199                // in the destination when the caller does not assume validity.
200                Quantifier::ForAll
201            };
202
203            let bytes_answer = src_quantifier.apply(
204                union(self.src.bytes_from(src_state), self.dst.bytes_from(dst_state)).filter_map(
205                    |(_range, (src_state_prime, dst_state_prime))| {
206                        match (src_state_prime, dst_state_prime) {
207                            // No matching transitions in `src`. Skip.
208                            (None, _) => None,
209                            // No matching transitions in `dst`. Fail.
210                            (Some(_), None) => Some(Answer::No(Reason::DstIsBitIncompatible)),
211                            // Matching transitions. Continue with successor states.
212                            (Some(src_state_prime), Some(dst_state_prime)) => {
213                                Some(self.answer_memo(cache, src_state_prime, dst_state_prime))
214                            }
215                        }
216                    },
217                ),
218            );
219
220            // The below early returns reflect how this code would behave:
221            //   if self.assume.validity {
222            //       or(bytes_answer, refs_answer)
223            //   } else {
224            //       and(bytes_answer, refs_answer)
225            //   }
226            // ...if `refs_answer` was computed lazily. The below early
227            // returns can be deleted without impacting the correctness of
228            // the algorithm; only its performance.
229            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs:229",
                        "rustc_transmute::maybe_transmutable",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_transmute/src/maybe_transmutable/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(229u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_transmute::maybe_transmutable"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("bytes_answer")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("bytes_answer");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&bytes_answer)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?bytes_answer);
230            match bytes_answer {
231                Answer::No(_) if !self.assume.validity => return bytes_answer,
232                Answer::Yes if self.assume.validity => return bytes_answer,
233                _ => {}
234            };
235
236            let refs_answer = src_quantifier.apply(
237                // for each reference transition out of `src_state`...
238                self.src.refs_from(src_state).map(|(src_ref, src_state_prime)| {
239                    // ...there exists a reference transition out of `dst_state`...
240                    Quantifier::ThereExists.apply(self.dst.refs_from(dst_state).map(
241                        |(dst_ref, dst_state_prime)| {
242                            if !src_ref.is_mut && dst_ref.is_mut {
243                                Answer::No(Reason::DstIsMoreUnique)
244                            } else if !self.assume.alignment
245                                && src_ref.referent_align < dst_ref.referent_align
246                            {
247                                Answer::No(Reason::DstHasStricterAlignment {
248                                    src_min_align: src_ref.referent_align,
249                                    dst_min_align: dst_ref.referent_align,
250                                })
251                            } else if dst_ref.referent_size > src_ref.referent_size {
252                                Answer::No(Reason::DstRefIsTooBig {
253                                    src: src_ref.referent,
254                                    src_size: src_ref.referent_size,
255                                    dst: dst_ref.referent,
256                                    dst_size: dst_ref.referent_size,
257                                })
258                            } else {
259                                let mut conditions = Vec::with_capacity(4);
260                                let mut is_transmutable =
261                                    |src: Reference<_, _>, dst: Reference<_, _>| {
262                                        conditions.push(Condition::Transmutable {
263                                            src: src.referent,
264                                            dst: dst.referent,
265                                        });
266                                        if !self.assume.lifetimes {
267                                            conditions.push(Condition::Outlives {
268                                                long: src.region,
269                                                short: dst.region,
270                                            });
271                                        }
272                                    };
273
274                                is_transmutable(src_ref, dst_ref);
275
276                                if dst_ref.is_mut {
277                                    is_transmutable(dst_ref, src_ref);
278                                } else {
279                                    conditions.push(Condition::Immutable { ty: dst_ref.referent });
280                                }
281
282                                Answer::If(Condition::IfAll(conditions)).and(self.answer_memo(
283                                    cache,
284                                    src_state_prime,
285                                    dst_state_prime,
286                                ))
287                            }
288                        },
289                    ))
290                }),
291            );
292
293            if self.assume.validity {
294                bytes_answer.or(refs_answer)
295            } else {
296                bytes_answer.and(refs_answer)
297            }
298        }
299    }
300}
301
302impl<R, T> Answer<R, T> {
303    /// Requires both answers, combining their conditions into a conjunction.
304    fn and(self, rhs: Answer<R, T>) -> Answer<R, T> {
305        let lhs = self;
306        match (lhs, rhs) {
307            // Prefer a specific reason over generic bit incompatibility;
308            // otherwise, retain the left-hand reason.
309            (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
310            | (Answer::No(reason), Answer::No(_))
311            // If either is an error, return it
312            | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason),
313            // If only one side has a condition, pass it along
314            (Answer::Yes, other) | (other, Answer::Yes) => other,
315            // If both sides have IfAll conditions, merge them
316            (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => {
317                lhs.append(rhs);
318                Answer::If(Condition::IfAll(lhs))
319            }
320            // If only one side is an IfAll, add the other Condition to it
321            (Answer::If(cond), Answer::If(Condition::IfAll(mut conds)))
322            | (Answer::If(Condition::IfAll(mut conds)), Answer::If(cond)) => {
323                conds.push(cond);
324                Answer::If(Condition::IfAll(conds))
325            }
326            // Otherwise, both lhs and rhs conditions can be combined in a parent IfAll
327            (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAll(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [lhs, rhs]))vec![lhs, rhs])),
328        }
329    }
330
331    /// Combines alternative answers and collects their conditions in an `IfAny`.
332    ///
333    /// Currently, combining `Yes` with `If` retains the condition. This differs
334    /// from Boolean disjunction, where unconditional success would suffice.
335    fn or(self, rhs: Answer<R, T>) -> Answer<R, T> {
336        let lhs = self;
337        match (lhs, rhs) {
338            // Prefer a specific reason over generic bit incompatibility;
339            // otherwise, retain the left-hand reason.
340            (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
341            | (Answer::No(reason), Answer::No(_)) => Answer::No(reason),
342            // Otherwise, errors can be ignored for the rest of the pattern matching
343            (Answer::No(_), other) | (other, Answer::No(_)) => other.or(Answer::Yes),
344            // If only one side has a condition, pass it along
345            (Answer::Yes, other) | (other, Answer::Yes) => other,
346            // If both sides have IfAny conditions, merge them
347            (Answer::If(Condition::IfAny(mut lhs)), Answer::If(Condition::IfAny(ref mut rhs))) => {
348                lhs.append(rhs);
349                Answer::If(Condition::IfAny(lhs))
350            }
351            // If only one side is an IfAny, add the other Condition to it
352            (Answer::If(cond), Answer::If(Condition::IfAny(mut conds)))
353            | (Answer::If(Condition::IfAny(mut conds)), Answer::If(cond)) => {
354                conds.push(cond);
355                Answer::If(Condition::IfAny(conds))
356            }
357            // Otherwise, both lhs and rhs conditions can be combined in a parent IfAny
358            (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAny(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [lhs, rhs]))vec![lhs, rhs])),
359        }
360    }
361}
362
363enum Quantifier {
364    ThereExists,
365    ForAll,
366}
367
368impl Quantifier {
369    /// Folds answers with `or` or `and`, stopping on `Yes` or `No`, respectively.
370    /// An empty iterator yields bit incompatibility for `ThereExists` and `Yes`
371    /// for `ForAll`.
372    fn apply<R, T, I>(&self, iter: I) -> Answer<R, T>
373    where
374        R: layout::Region,
375        T: layout::Type,
376        I: IntoIterator<Item = Answer<R, T>>,
377    {
378        use std::ops::ControlFlow::{Break, Continue};
379
380        let (init, try_fold_f): (_, fn(_, _) -> _) = match self {
381            Self::ThereExists => {
382                (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R, T>, next| match accum
383                    .or(next)
384                {
385                    Answer::Yes => Break(Answer::Yes),
386                    maybe => Continue(maybe),
387                })
388            }
389            Self::ForAll => (Answer::Yes, |accum: Answer<R, T>, next| {
390                let answer = accum.and(next);
391                match answer {
392                    Answer::No(_) => Break(answer),
393                    maybe => Continue(maybe),
394                }
395            }),
396        };
397
398        let (Continue(result) | Break(result)) = iter.into_iter().try_fold(init, try_fold_f);
399        result
400    }
401}