1#![cfg_attr(test, feature(test))]
3#![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, T> {
23 Yes,
24 No(Reason<T>),
25 If(Condition<R, T>),
26}
27
28#[derive(Debug, Hash, Eq, PartialEq, Clone)]
30pub enum Condition<R, T> {
31 Transmutable { src: T, dst: T },
33
34 Outlives { long: R, short: R },
36
37 Immutable { ty: T },
39
40 IfAll(Vec<Condition<R, T>>),
42
43 IfAny(Vec<Condition<R, T>>),
45}
46
47#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
49pub enum Reason<T> {
50 SrcIsNotYetSupported,
52 DstIsNotYetSupported,
54 DstIsBitIncompatible,
56 DstUninhabited,
58 DstMayHaveSafetyInvariants,
60 DstIsTooBig,
62 DstRefIsTooBig {
64 src: T,
66 src_size: usize,
68 dst: T,
70 dst_size: usize,
72 },
73 DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
75 DstIsMoreUnique,
77 TypeError,
79 SrcLayoutUnknown,
81 DstLayoutUnknown,
83 SrcSizeOverflow,
85 DstSizeOverflow,
87}
88
89#[cfg(feature = "rustc")]
90mod rustc {
91 use rustc_hir::lang_items::LangItem;
92 use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
93
94 use super::*;
95
96 #[derive(Debug, Clone, Copy)]
98 pub struct Types<'tcx> {
99 pub src: Ty<'tcx>,
101 pub dst: Ty<'tcx>,
103 }
104
105 pub struct TransmuteTypeEnv<'tcx> {
106 tcx: TyCtxt<'tcx>,
107 }
108
109 impl<'tcx> TransmuteTypeEnv<'tcx> {
110 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
111 Self { tcx }
112 }
113
114 pub fn is_transmutable(
115 &mut self,
116 types: Types<'tcx>,
117 assume: crate::Assume,
118 ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
119 crate::maybe_transmutable::MaybeTransmutableQuery::new(
120 types.src, types.dst, assume, self.tcx,
121 )
122 .answer()
123 }
124 }
125
126 impl Assume {
127 pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
129 use rustc_middle::ty::ScalarInt;
130 use rustc_span::sym;
131
132 let Some(cv) = ct.try_to_value() else {
133 return None;
134 };
135
136 let adt_def = cv.ty.ty_adt_def()?;
137
138 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
139 tcx.dcx().delayed_bug(format!(
140 "The given `const` was not marked with the `{}` lang item.",
141 LangItem::TransmuteOpts.name()
142 ));
143 return Some(Self {
144 alignment: true,
145 lifetimes: true,
146 safety: true,
147 validity: true,
148 });
149 }
150
151 let variant = adt_def.non_enum_variant();
152 let fields = cv.valtree.unwrap_branch();
153
154 let get_field = |name| {
155 let (field_idx, _) = variant
156 .fields
157 .iter()
158 .enumerate()
159 .find(|(_, field_def)| name == field_def.name)
160 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
161 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
162 };
163
164 Some(Self {
165 alignment: get_field(sym::alignment),
166 lifetimes: get_field(sym::lifetimes),
167 safety: get_field(sym::safety),
168 validity: get_field(sym::validity),
169 })
170 }
171 }
172}
173
174#[cfg(feature = "rustc")]
175pub use rustc::*;