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 pub struct TransmuteTypeEnv<'tcx> {
97 tcx: TyCtxt<'tcx>,
98 }
99
100 impl<'tcx> TransmuteTypeEnv<'tcx> {
101 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
102 Self { tcx }
103 }
104
105 pub fn is_transmutable(
106 &mut self,
107 src: Ty<'tcx>,
108 dst: Ty<'tcx>,
109 assume: crate::Assume,
110 ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
111 crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx)
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 cv = ct.try_to_value()?;
123 let adt_def = cv.ty.ty_adt_def()?;
124
125 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
126 tcx.dcx().delayed_bug(format!(
127 "The given `const` was not marked with the `{}` lang item.",
128 LangItem::TransmuteOpts.name()
129 ));
130 return Some(Self {
131 alignment: true,
132 lifetimes: true,
133 safety: true,
134 validity: true,
135 });
136 }
137
138 let variant = adt_def.non_enum_variant();
139 let fields = cv.to_branch();
140
141 let get_field = |name| {
142 let (field_idx, _) = variant
143 .fields
144 .iter()
145 .enumerate()
146 .find(|(_, field_def)| name == field_def.name)
147 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
148 fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE)
149 };
150
151 Some(Self {
152 alignment: get_field(sym::alignment)?,
153 lifetimes: get_field(sym::lifetimes)?,
154 safety: get_field(sym::safety)?,
155 validity: get_field(sym::validity)?,
156 })
157 }
158 }
159}
160
161#[cfg(feature = "rustc")]
162pub use rustc::*;