1#![cfg_attr(doc, recursion_limit = "256")] #![feature(never_type)]
4pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
7
8pub mod layout;
9mod maybe_transmutable;
10
11#[derive(Copy, Clone, Debug, Default)]
12pub struct Assume {
13 pub alignment: bool,
14 pub lifetimes: bool,
15 pub safety: bool,
16 pub validity: bool,
17}
18
19#[derive(Debug, Hash, Eq, PartialEq, Clone)]
22pub enum Answer<R> {
23 Yes,
24 No(Reason<R>),
25 If(Condition<R>),
26}
27
28#[derive(Debug, Hash, Eq, PartialEq, Clone)]
30pub enum Condition<R> {
31 IfTransmutable { src: R, dst: R },
33
34 IfAll(Vec<Condition<R>>),
36
37 IfAny(Vec<Condition<R>>),
39}
40
41#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
43pub enum Reason<T> {
44 SrcIsNotYetSupported,
46 DstIsNotYetSupported,
48 DstIsBitIncompatible,
50 DstUninhabited,
52 DstMayHaveSafetyInvariants,
54 DstIsTooBig,
56 DstRefIsTooBig {
58 src: T,
60 dst: T,
62 },
63 DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
65 DstIsMoreUnique,
67 TypeError,
69 SrcLayoutUnknown,
71 DstLayoutUnknown,
73 SrcSizeOverflow,
75 DstSizeOverflow,
77}
78
79#[cfg(feature = "rustc")]
80mod rustc {
81 use rustc_hir::lang_items::LangItem;
82 use rustc_middle::ty::{Const, Ty, TyCtxt};
83
84 use super::*;
85
86 #[derive(Debug, Clone, Copy)]
88 pub struct Types<'tcx> {
89 pub src: Ty<'tcx>,
91 pub dst: Ty<'tcx>,
93 }
94
95 pub struct TransmuteTypeEnv<'tcx> {
96 tcx: TyCtxt<'tcx>,
97 }
98
99 impl<'tcx> TransmuteTypeEnv<'tcx> {
100 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
101 Self { tcx }
102 }
103
104 pub fn is_transmutable(
105 &mut self,
106 types: Types<'tcx>,
107 assume: crate::Assume,
108 ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
109 crate::maybe_transmutable::MaybeTransmutableQuery::new(
110 types.src, types.dst, assume, self.tcx,
111 )
112 .answer()
113 }
114 }
115
116 impl Assume {
117 pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
119 use rustc_middle::ty::ScalarInt;
120 use rustc_span::sym;
121
122 let Some(cv) = ct.try_to_value() else {
123 return None;
124 };
125
126 let adt_def = cv.ty.ty_adt_def()?;
127
128 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
129 tcx.dcx().delayed_bug(format!(
130 "The given `const` was not marked with the `{}` lang item.",
131 LangItem::TransmuteOpts.name()
132 ));
133 return Some(Self {
134 alignment: true,
135 lifetimes: true,
136 safety: true,
137 validity: true,
138 });
139 }
140
141 let variant = adt_def.non_enum_variant();
142 let fields = cv.valtree.unwrap_branch();
143
144 let get_field = |name| {
145 let (field_idx, _) = variant
146 .fields
147 .iter()
148 .enumerate()
149 .find(|(_, field_def)| name == field_def.name)
150 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
151 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
152 };
153
154 Some(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}
163
164#[cfg(feature = "rustc")]
165pub use rustc::*;