1// tidy-alphabetical-start
2#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
3#![feature(never_type)]
4// tidy-alphabetical-end
56pub(crate) use rustc_data_structures::fx::{FxIndexMapas Map, FxIndexSetas Set};
78pub mod layout;
9mod maybe_transmutable;
1011#[derive(Copy, Clone, Debug, Default)]
12pub struct Assume {
13pub alignment: bool,
14pub lifetimes: bool,
15pub safety: bool,
16pub validity: bool,
17}
1819/// Either transmutation is allowed, we have an error, or we have an optional
20/// Condition that must hold.
21#[derive(Debug, Hash, Eq, PartialEq, Clone)]
22pub enum Answer<R> {
23 Yes,
24 No(Reason<R>),
25 If(Condition<R>),
26}
2728/// A condition which must hold for safe transmutation to be possible.
29#[derive(Debug, Hash, Eq, PartialEq, Clone)]
30pub enum Condition<R> {
31/// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
32IfTransmutable { src: R, dst: R },
3334/// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
35IfAll(Vec<Condition<R>>),
3637/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
38IfAny(Vec<Condition<R>>),
39}
4041/// Answers "why wasn't the source type transmutable into the destination type?"
42#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
43pub enum Reason<T> {
44/// The layout of the source type is not yet supported.
45SrcIsNotYetSupported,
46/// The layout of the destination type is not yet supported.
47DstIsNotYetSupported,
48/// The layout of the destination type is bit-incompatible with the source type.
49DstIsBitIncompatible,
50/// The destination type is uninhabited.
51DstUninhabited,
52/// The destination type may carry safety invariants.
53DstMayHaveSafetyInvariants,
54/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
55DstIsTooBig,
56/// A referent of `Dst` is larger than a referent in `Src`.
57DstRefIsTooBig {
58/// The referent of the source type.
59src: T,
60/// The too-large referent of the destination type.
61dst: T,
62 },
63/// Src should have a stricter alignment than Dst, but it does not.
64DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
65/// Can't go from shared pointer to unique pointer
66DstIsMoreUnique,
67/// Encountered a type error
68TypeError,
69/// The layout of src is unknown
70SrcLayoutUnknown,
71/// The layout of dst is unknown
72DstLayoutUnknown,
73/// The size of src is overflow
74SrcSizeOverflow,
75/// The size of dst is overflow
76DstSizeOverflow,
77}
7879#[cfg(feature = "rustc")]
80mod rustc {
81use rustc_hir::lang_items::LangItem;
82use rustc_middle::ty::{Const, Ty, TyCtxt};
8384use super::*;
8586/// The source and destination types of a transmutation.
87#[derive(Debug, Clone, Copy)]
88pub struct Types<'tcx> {
89/// The source type.
90pub src: Ty<'tcx>,
91/// The destination type.
92pub dst: Ty<'tcx>,
93 }
9495pub struct TransmuteTypeEnv<'tcx> {
96 tcx: TyCtxt<'tcx>,
97 }
9899impl<'tcx> TransmuteTypeEnv<'tcx> {
100pub fn new(tcx: TyCtxt<'tcx>) -> Self {
101Self { tcx }
102 }
103104pub fn is_transmutable(
105&mut self,
106 types: Types<'tcx>,
107 assume: crate::Assume,
108 ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
109crate::maybe_transmutable::MaybeTransmutableQuery::new(
110types.src, types.dst, assume, self.tcx,
111 )
112 .answer()
113 }
114 }
115116impl Assume {
117/// Constructs an `Assume` from a given const-`Assume`.
118pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
119use rustc_middle::ty::ScalarInt;
120use rustc_span::sym;
121122let Some(cv) = ct.try_to_value() else {
123return None;
124 };
125126let adt_def = cv.ty.ty_adt_def()?;
127128if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
129tcx.dcx().delayed_bug(format!(
130"The given `const` was not marked with the `{}` lang item.",
131 LangItem::TransmuteOpts.name()
132 ));
133return Some(Self {
134 alignment: true,
135 lifetimes: true,
136 safety: true,
137 validity: true,
138 });
139 }
140141let variant = adt_def.non_enum_variant();
142let fields = cv.valtree.unwrap_branch();
143144let get_field = |name| {
145let (field_idx, _) = variant146 .fields
147 .iter()
148 .enumerate()
149 .find(|(_, field_def)| name == field_def.name)
150 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
151fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
152 };
153154Some(Self {
155 alignment: get_field(sym::alignment),
156 lifetimes: get_field(sym::lifetimes),
157 safety: get_field(sym::safety),
158 validity: get_field(sym::validity),
159 })
160 }
161 }
162}
163164#[cfg(feature = "rustc")]
165pub use rustc::*;