rustc_transmute/
lib.rs
1#![allow(unused_variables)]
3#![feature(alloc_layout_extra)]
4#![feature(never_type)]
5#![warn(unreachable_pub)]
6pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
9
10pub mod layout;
11mod maybe_transmutable;
12
13#[derive(Copy, Clone, Debug, Default)]
14pub struct Assume {
15 pub alignment: bool,
16 pub lifetimes: bool,
17 pub safety: bool,
18 pub validity: bool,
19}
20
21#[derive(Debug, Hash, Eq, PartialEq, Clone)]
24pub enum Answer<R> {
25 Yes,
26 No(Reason<R>),
27 If(Condition<R>),
28}
29
30#[derive(Debug, Hash, Eq, PartialEq, Clone)]
32pub enum Condition<R> {
33 IfTransmutable { src: R, dst: R },
35
36 IfAll(Vec<Condition<R>>),
38
39 IfAny(Vec<Condition<R>>),
41}
42
43#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
45pub enum Reason<T> {
46 SrcIsNotYetSupported,
48 DstIsNotYetSupported,
50 DstIsBitIncompatible,
52 DstUninhabited,
54 DstMayHaveSafetyInvariants,
56 DstIsTooBig,
58 DstRefIsTooBig {
60 src: T,
62 dst: T,
64 },
65 DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
67 DstIsMoreUnique,
69 TypeError,
71 SrcLayoutUnknown,
73 DstLayoutUnknown,
75 SrcSizeOverflow,
77 DstSizeOverflow,
79}
80
81#[cfg(feature = "rustc")]
82mod rustc {
83 use rustc_hir::lang_items::LangItem;
84 use rustc_infer::infer::InferCtxt;
85 use rustc_macros::TypeVisitable;
86 use rustc_middle::traits::ObligationCause;
87 use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt};
88
89 use super::*;
90
91 #[derive(TypeVisitable, Debug, Clone, Copy)]
93 pub struct Types<'tcx> {
94 pub src: Ty<'tcx>,
96 pub dst: Ty<'tcx>,
98 }
99
100 pub struct TransmuteTypeEnv<'cx, 'tcx> {
101 infcx: &'cx InferCtxt<'tcx>,
102 }
103
104 impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
105 pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
106 Self { infcx }
107 }
108
109 #[allow(unused)]
110 pub fn is_transmutable(
111 &mut self,
112 cause: ObligationCause<'tcx>,
113 types: Types<'tcx>,
114 assume: crate::Assume,
115 ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
116 crate::maybe_transmutable::MaybeTransmutableQuery::new(
117 types.src,
118 types.dst,
119 assume,
120 self.infcx.tcx,
121 )
122 .answer()
123 }
124 }
125
126 impl Assume {
127 pub fn from_const<'tcx>(
129 tcx: TyCtxt<'tcx>,
130 param_env: ParamEnv<'tcx>,
131 ct: Const<'tcx>,
132 ) -> Option<Self> {
133 use rustc_middle::ty::ScalarInt;
134 use rustc_span::sym;
135
136 let Some(cv) = ct.try_to_value() else {
137 return None;
138 };
139
140 let adt_def = cv.ty.ty_adt_def()?;
141
142 if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) {
143 tcx.dcx().delayed_bug(format!(
144 "The given `const` was not marked with the `{}` lang item.",
145 LangItem::TransmuteOpts.name()
146 ));
147 return Some(Self {
148 alignment: true,
149 lifetimes: true,
150 safety: true,
151 validity: true,
152 });
153 }
154
155 let variant = adt_def.non_enum_variant();
156 let fields = cv.valtree.unwrap_branch();
157
158 let get_field = |name| {
159 let (field_idx, _) = variant
160 .fields
161 .iter()
162 .enumerate()
163 .find(|(_, field_def)| name == field_def.name)
164 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
165 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
166 };
167
168 Some(Self {
169 alignment: get_field(sym::alignment),
170 lifetimes: get_field(sym::lifetimes),
171 safety: get_field(sym::safety),
172 validity: get_field(sym::validity),
173 })
174 }
175 }
176}
177
178#[cfg(feature = "rustc")]
179pub use rustc::*;