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 cv = ct.try_to_value()?;
133 let adt_def = cv.ty.ty_adt_def()?;
134
135 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
136 tcx.dcx().delayed_bug(format!(
137 "The given `const` was not marked with the `{}` lang item.",
138 LangItem::TransmuteOpts.name()
139 ));
140 return Some(Self {
141 alignment: true,
142 lifetimes: true,
143 safety: true,
144 validity: true,
145 });
146 }
147
148 let variant = adt_def.non_enum_variant();
149 let fields = cv.to_branch();
150
151 let get_field = |name| {
152 let (field_idx, _) = variant
153 .fields
154 .iter()
155 .enumerate()
156 .find(|(_, field_def)| name == field_def.name)
157 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
158 fields[field_idx].to_leaf() == ScalarInt::TRUE
159 };
160
161 Some(Self {
162 alignment: get_field(sym::alignment),
163 lifetimes: get_field(sym::lifetimes),
164 safety: get_field(sym::safety),
165 validity: get_field(sym::validity),
166 })
167 }
168 }
169}
170
171#[cfg(feature = "rustc")]
172pub use rustc::*;