]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_transmute/src/lib.rs
b3b9a67b26e3d23fcfa2ab9153847dc787145560
[rustc.git] / compiler / rustc_transmute / src / lib.rs
1 #![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)]
2 #![allow(dead_code, unused_variables)]
3 #![deny(rustc::untranslatable_diagnostic)]
4 #![deny(rustc::diagnostic_outside_of_impl)]
5
6 #[macro_use]
7 extern crate tracing;
8
9 pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
10
11 pub(crate) mod layout;
12 pub(crate) mod maybe_transmutable;
13
14 #[derive(Default)]
15 pub struct Assume {
16 pub alignment: bool,
17 pub lifetimes: bool,
18 pub safety: bool,
19 pub validity: bool,
20 }
21
22 /// The type encodes answers to the question: "Are these types transmutable?"
23 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
24 pub enum Answer<R>
25 where
26 R: layout::Ref,
27 {
28 /// `Src` is transmutable into `Dst`.
29 Yes,
30
31 /// `Src` is NOT transmutable into `Dst`.
32 No(Reason),
33
34 /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
35 IfTransmutable { src: R, dst: R },
36
37 /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
38 IfAll(Vec<Answer<R>>),
39
40 /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
41 IfAny(Vec<Answer<R>>),
42 }
43
44 /// Answers: Why wasn't the source type transmutable into the destination type?
45 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
46 pub enum Reason {
47 /// The layout of the source type is unspecified.
48 SrcIsUnspecified,
49 /// The layout of the destination type is unspecified.
50 DstIsUnspecified,
51 /// The layout of the destination type is bit-incompatible with the source type.
52 DstIsBitIncompatible,
53 /// There aren't any public constructors for `Dst`.
54 DstIsPrivate,
55 /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
56 DstIsTooBig,
57 }
58
59 #[cfg(feature = "rustc")]
60 mod rustc {
61 use super::*;
62
63 use rustc_hir::lang_items::LangItem;
64 use rustc_infer::infer::InferCtxt;
65 use rustc_macros::{TypeFoldable, TypeVisitable};
66 use rustc_middle::traits::ObligationCause;
67 use rustc_middle::ty::Binder;
68 use rustc_middle::ty::Const;
69 use rustc_middle::ty::ParamEnv;
70 use rustc_middle::ty::Ty;
71 use rustc_middle::ty::TyCtxt;
72
73 /// The source and destination types of a transmutation.
74 #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
75 pub struct Types<'tcx> {
76 /// The source type.
77 pub src: Ty<'tcx>,
78 /// The destination type.
79 pub dst: Ty<'tcx>,
80 }
81
82 pub struct TransmuteTypeEnv<'cx, 'tcx> {
83 infcx: &'cx InferCtxt<'tcx>,
84 }
85
86 impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
87 pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
88 Self { infcx }
89 }
90
91 #[allow(unused)]
92 pub fn is_transmutable(
93 &mut self,
94 cause: ObligationCause<'tcx>,
95 src_and_dst: Binder<'tcx, Types<'tcx>>,
96 scope: Ty<'tcx>,
97 assume: crate::Assume,
98 ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
99 let src = src_and_dst.map_bound(|types| types.src).skip_binder();
100 let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
101 crate::maybe_transmutable::MaybeTransmutableQuery::new(
102 src,
103 dst,
104 scope,
105 assume,
106 self.infcx.tcx,
107 )
108 .answer()
109 }
110 }
111
112 impl Assume {
113 /// Constructs an `Assume` from a given const-`Assume`.
114 pub fn from_const<'tcx>(
115 tcx: TyCtxt<'tcx>,
116 param_env: ParamEnv<'tcx>,
117 c: Const<'tcx>,
118 ) -> Option<Self> {
119 use rustc_middle::ty::ScalarInt;
120 use rustc_middle::ty::TypeVisitable;
121 use rustc_span::symbol::sym;
122
123 let c = c.eval(tcx, param_env);
124
125 if let Err(err) = c.error_reported() {
126 return Some(Self {
127 alignment: true,
128 lifetimes: true,
129 safety: true,
130 validity: true,
131 });
132 }
133
134 let adt_def = c.ty().ty_adt_def()?;
135
136 assert_eq!(
137 tcx.require_lang_item(LangItem::TransmuteOpts, None),
138 adt_def.did(),
139 "The given `Const` was not marked with the `{}` lang item.",
140 LangItem::TransmuteOpts.name(),
141 );
142
143 let variant = adt_def.non_enum_variant();
144 let fields = c.to_valtree().unwrap_branch();
145
146 let get_field = |name| {
147 let (field_idx, _) = variant
148 .fields
149 .iter()
150 .enumerate()
151 .find(|(_, field_def)| name == field_def.name)
152 .expect(&format!("There were no fields named `{name}`."));
153 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
154 };
155
156 Some(Self {
157 alignment: get_field(sym::alignment),
158 lifetimes: get_field(sym::lifetimes),
159 safety: get_field(sym::safety),
160 validity: get_field(sym::validity),
161 })
162 }
163 }
164 }
165
166 #[cfg(feature = "rustc")]
167 pub use rustc::*;