]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_transmute/src/lib.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / compiler / rustc_transmute / src / lib.rs
1 #![feature(alloc_layout_extra)]
2 #![feature(never_type)]
3 #![allow(unused_variables)]
4
5 pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
6
7 pub mod layout;
8 mod maybe_transmutable;
9
10 #[derive(Default)]
11 pub struct Assume {
12 pub alignment: bool,
13 pub lifetimes: bool,
14 pub safety: bool,
15 pub validity: bool,
16 }
17
18 /// Either transmutation is allowed, we have an error, or we have an optional
19 /// Condition that must hold.
20 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
21 pub enum Answer<R> {
22 Yes,
23 No(Reason<R>),
24 If(Condition<R>),
25 }
26
27 /// A condition which must hold for safe transmutation to be possible.
28 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
29 pub enum Condition<R> {
30 /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
31 IfTransmutable { src: R, dst: R },
32
33 /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
34 IfAll(Vec<Condition<R>>),
35
36 /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
37 IfAny(Vec<Condition<R>>),
38 }
39
40 /// Answers "why wasn't the source type transmutable into the destination type?"
41 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
42 pub enum Reason<T> {
43 /// The layout of the source type is not yet supported.
44 SrcIsNotYetSupported,
45 /// The layout of the destination type is not yet supported.
46 DstIsNotYetSupported,
47 /// The layout of the destination type is bit-incompatible with the source type.
48 DstIsBitIncompatible,
49 /// The destination type is uninhabited.
50 DstUninhabited,
51 /// The destination type may carry safety invariants.
52 DstMayHaveSafetyInvariants,
53 /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
54 DstIsTooBig,
55 /// A referent of `Dst` is larger than a referent in `Src`.
56 DstRefIsTooBig {
57 /// The referent of the source type.
58 src: T,
59 /// The too-large referent of the destination type.
60 dst: T,
61 },
62 /// Src should have a stricter alignment than Dst, but it does not.
63 DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
64 /// Can't go from shared pointer to unique pointer
65 DstIsMoreUnique,
66 /// Encountered a type error
67 TypeError,
68 /// The layout of src is unknown
69 SrcLayoutUnknown,
70 /// The layout of dst is unknown
71 DstLayoutUnknown,
72 /// The size of src is overflow
73 SrcSizeOverflow,
74 /// The size of dst is overflow
75 DstSizeOverflow,
76 }
77
78 #[cfg(feature = "rustc")]
79 mod rustc {
80 use super::*;
81
82 use rustc_hir::lang_items::LangItem;
83 use rustc_infer::infer::InferCtxt;
84 use rustc_macros::TypeVisitable;
85 use rustc_middle::traits::ObligationCause;
86 use rustc_middle::ty::Const;
87 use rustc_middle::ty::ParamEnv;
88 use rustc_middle::ty::Ty;
89 use rustc_middle::ty::TyCtxt;
90 use rustc_middle::ty::ValTree;
91 use rustc_span::DUMMY_SP;
92
93 /// The source and destination types of a transmutation.
94 #[derive(TypeVisitable, Debug, Clone, Copy)]
95 pub struct Types<'tcx> {
96 /// The source type.
97 pub src: Ty<'tcx>,
98 /// The destination type.
99 pub dst: Ty<'tcx>,
100 }
101
102 pub struct TransmuteTypeEnv<'cx, 'tcx> {
103 infcx: &'cx InferCtxt<'tcx>,
104 }
105
106 impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
107 pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
108 Self { infcx }
109 }
110
111 #[allow(unused)]
112 pub fn is_transmutable(
113 &mut self,
114 cause: ObligationCause<'tcx>,
115 types: Types<'tcx>,
116 assume: crate::Assume,
117 ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
118 crate::maybe_transmutable::MaybeTransmutableQuery::new(
119 types.src,
120 types.dst,
121 assume,
122 self.infcx.tcx,
123 )
124 .answer()
125 }
126 }
127
128 impl Assume {
129 /// Constructs an `Assume` from a given const-`Assume`.
130 pub fn from_const<'tcx>(
131 tcx: TyCtxt<'tcx>,
132 param_env: ParamEnv<'tcx>,
133 c: Const<'tcx>,
134 ) -> Option<Self> {
135 use rustc_middle::ty::ScalarInt;
136 use rustc_span::symbol::sym;
137
138 let Ok((ty, cv)) = c.eval(tcx, param_env, DUMMY_SP) else {
139 return Some(Self {
140 alignment: true,
141 lifetimes: true,
142 safety: true,
143 validity: true,
144 });
145 };
146
147 let adt_def = ty.ty_adt_def()?;
148
149 assert_eq!(
150 tcx.require_lang_item(LangItem::TransmuteOpts, None),
151 adt_def.did(),
152 "The given `Const` was not marked with the `{}` lang item.",
153 LangItem::TransmuteOpts.name(),
154 );
155
156 let variant = adt_def.non_enum_variant();
157 let fields = match cv {
158 ValTree::Branch(branch) => branch,
159 _ => {
160 return Some(Self {
161 alignment: true,
162 lifetimes: true,
163 safety: true,
164 validity: true,
165 });
166 }
167 };
168
169 let get_field = |name| {
170 let (field_idx, _) = variant
171 .fields
172 .iter()
173 .enumerate()
174 .find(|(_, field_def)| name == field_def.name)
175 .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
176 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
177 };
178
179 Some(Self {
180 alignment: get_field(sym::alignment),
181 lifetimes: get_field(sym::lifetimes),
182 safety: get_field(sym::safety),
183 validity: get_field(sym::validity),
184 })
185 }
186 }
187 }
188
189 #[cfg(feature = "rustc")]
190 pub use rustc::*;