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 [`rustc_middle::ty::transmute::Answer`]; reference transitions can leave
7//! [`rustc_middle::ty::transmute::Condition`]s for the trait solver to discharge.
8
9// tidy-alphabetical-start
10#![cfg_attr(test, feature(test))]
11#![feature(option_into_flat_iter)]
12// tidy-alphabetical-end
13
14pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
15
16pub mod layout;
17mod maybe_transmutable;
18
19/// Proof obligations supplied by the caller rather than checked by the analysis.
20///
21/// This mirrors `core::mem::Assume`. A `true` field transfers the corresponding
22/// obligation to the caller; the default leaves all four obligations to the compiler.
23#[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) -> Self {
        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() -> Self {
        Assume {
            alignment: ::core::default::Default::default(),
            lifetimes: ::core::default::Default::default(),
            safety: ::core::default::Default::default(),
            validity: ::core::default::Default::default(),
        }
    }
}Default)]
24pub struct Assume {
25    pub alignment: bool,
26    pub lifetimes: bool,
27    pub safety: bool,
28    pub validity: bool,
29}
30
31#[cfg(feature = "rustc")]
32mod rustc {
33    use rustc_attr_ir::lang_items::LangItem;
34    use rustc_middle::ty::transmute::Answer;
35    use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
36
37    use super::*;
38
39    pub struct TransmuteTypeEnv<'tcx> {
40        tcx: TyCtxt<'tcx>,
41    }
42
43    impl<'tcx> TransmuteTypeEnv<'tcx> {
44        pub fn new(tcx: TyCtxt<'tcx>) -> Self {
45            Self { tcx }
46        }
47
48        pub fn is_transmutable(
49            &mut self,
50            src: Ty<'tcx>,
51            dst: Ty<'tcx>,
52            assume: crate::Assume,
53        ) -> Answer<Region<'tcx>, Ty<'tcx>> {
54            crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx)
55                .answer()
56        }
57    }
58
59    impl Assume {
60        /// Constructs an `Assume` from a given const-`Assume`.
61        pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
62            use rustc_middle::ty::ScalarInt;
63            use rustc_span::sym;
64
65            let cv = ct.try_to_value()?;
66            let adt_def = cv.ty.ty_adt_def()?;
67
68            if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
69                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!(
70                    "The given `const` was not marked with the `{}` lang item.",
71                    LangItem::TransmuteOpts.name()
72                ));
73                return Some(Self {
74                    alignment: true,
75                    lifetimes: true,
76                    safety: true,
77                    validity: true,
78                });
79            }
80
81            let variant = adt_def.non_enum_variant();
82            let fields = cv.to_branch();
83
84            let get_field = |name| {
85                let (field_idx, _) = variant
86                    .fields
87                    .iter()
88                    .enumerate()
89                    .find(|(_, field_def)| name == field_def.name)
90                    .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("There were no fields named `{0}`.",
            name));
}panic!("There were no fields named `{name}`."));
91                fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE)
92            };
93
94            Some(Self {
95                alignment: get_field(sym::alignment)?,
96                lifetimes: get_field(sym::lifetimes)?,
97                safety: get_field(sym::safety)?,
98                validity: get_field(sym::validity)?,
99            })
100        }
101    }
102}
103
104#[cfg(feature = "rustc")]
105pub use rustc::*;