• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 /// Either we have an error, transmutation is allowed, or we have an optional
23 /// Condition that must hold.
24 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
25 pub enum Answer<R> {
26     Yes,
27     No(Reason),
28     If(Condition<R>),
29 }
30 
31 /// A condition which must hold for safe transmutation to be possible.
32 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
33 pub enum Condition<R> {
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<Condition<R>>),
39 
40     /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
41     IfAny(Vec<Condition<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     /// Src should have a stricter alignment than Dst, but it does not.
58     DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
59     /// Can't go from shared pointer to unique pointer
60     DstIsMoreUnique,
61     /// Encountered a type error
62     TypeError,
63     /// The layout of src is unknown
64     SrcLayoutUnknown,
65     /// The layout of dst is unknown
66     DstLayoutUnknown,
67 }
68 
69 #[cfg(feature = "rustc")]
70 mod rustc {
71     use super::*;
72 
73     use rustc_hir::lang_items::LangItem;
74     use rustc_infer::infer::InferCtxt;
75     use rustc_macros::TypeVisitable;
76     use rustc_middle::traits::ObligationCause;
77     use rustc_middle::ty::Const;
78     use rustc_middle::ty::ParamEnv;
79     use rustc_middle::ty::Ty;
80     use rustc_middle::ty::TyCtxt;
81 
82     /// The source and destination types of a transmutation.
83     #[derive(TypeVisitable, Debug, Clone, Copy)]
84     pub struct Types<'tcx> {
85         /// The source type.
86         pub src: Ty<'tcx>,
87         /// The destination type.
88         pub dst: Ty<'tcx>,
89     }
90 
91     pub struct TransmuteTypeEnv<'cx, 'tcx> {
92         infcx: &'cx InferCtxt<'tcx>,
93     }
94 
95     impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
new(infcx: &'cx InferCtxt<'tcx>) -> Self96         pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
97             Self { infcx }
98         }
99 
100         #[allow(unused)]
is_transmutable( &mut self, cause: ObligationCause<'tcx>, types: Types<'tcx>, scope: Ty<'tcx>, assume: crate::Assume, ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>>101         pub fn is_transmutable(
102             &mut self,
103             cause: ObligationCause<'tcx>,
104             types: Types<'tcx>,
105             scope: Ty<'tcx>,
106             assume: crate::Assume,
107         ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
108             crate::maybe_transmutable::MaybeTransmutableQuery::new(
109                 types.src,
110                 types.dst,
111                 scope,
112                 assume,
113                 self.infcx.tcx,
114             )
115             .answer()
116         }
117     }
118 
119     impl Assume {
120         /// Constructs an `Assume` from a given const-`Assume`.
from_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, c: Const<'tcx>, ) -> Option<Self>121         pub fn from_const<'tcx>(
122             tcx: TyCtxt<'tcx>,
123             param_env: ParamEnv<'tcx>,
124             c: Const<'tcx>,
125         ) -> Option<Self> {
126             use rustc_middle::ty::ScalarInt;
127             use rustc_middle::ty::TypeVisitableExt;
128             use rustc_span::symbol::sym;
129 
130             let c = c.eval(tcx, param_env);
131 
132             if let Err(err) = c.error_reported() {
133                 return Some(Self {
134                     alignment: true,
135                     lifetimes: true,
136                     safety: true,
137                     validity: true,
138                 });
139             }
140 
141             let adt_def = c.ty().ty_adt_def()?;
142 
143             assert_eq!(
144                 tcx.require_lang_item(LangItem::TransmuteOpts, None),
145                 adt_def.did(),
146                 "The given `Const` was not marked with the `{}` lang item.",
147                 LangItem::TransmuteOpts.name(),
148             );
149 
150             let variant = adt_def.non_enum_variant();
151             let fields = c.to_valtree().unwrap_branch();
152 
153             let get_field = |name| {
154                 let (field_idx, _) = variant
155                     .fields
156                     .iter()
157                     .enumerate()
158                     .find(|(_, field_def)| name == field_def.name)
159                     .unwrap_or_else(|| panic!("There were no fields named `{name}`."));
160                 fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
161             };
162 
163             Some(Self {
164                 alignment: get_field(sym::alignment),
165                 lifetimes: get_field(sym::lifetimes),
166                 safety: get_field(sym::safety),
167                 validity: get_field(sym::validity),
168             })
169         }
170     }
171 }
172 
173 #[cfg(feature = "rustc")]
174 pub use rustc::*;
175