1 #![feature(alloc_layout_extra, control_flow_enum, 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)]
9 pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
11 pub(crate) mod layout;
12 pub(crate) mod maybe_transmutable;
22 /// The type encodes answers to the question: "Are these types transmutable?"
23 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
28 /// `Src` is transmutable into `Dst`.
31 /// `Src` is NOT transmutable into `Dst`.
34 /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
35 IfTransmutable { src: R, dst: R },
37 /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
38 IfAll(Vec<Answer<R>>),
40 /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
41 IfAny(Vec<Answer<R>>),
44 /// Answers: Why wasn't the source type transmutable into the destination type?
45 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
47 /// The layout of the source type is unspecified.
49 /// The layout of the destination type is unspecified.
51 /// The layout of the destination type is bit-incompatible with the source type.
53 /// There aren't any public constructors for `Dst`.
55 /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
59 #[cfg(feature = "rustc")]
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;
73 /// The source and destination types of a transmutation.
74 #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
75 pub struct Types<'tcx> {
78 /// The destination type.
82 pub struct TransmuteTypeEnv<'cx, 'tcx> {
83 infcx: &'cx InferCtxt<'cx, 'tcx>,
86 impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
87 pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
92 pub fn is_transmutable(
94 cause: ObligationCause<'tcx>,
95 src_and_dst: Binder<'tcx, Types<'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(
113 /// Constructs an `Assume` from a given const-`Assume`.
114 pub fn from_const<'tcx>(
116 param_env: ParamEnv<'tcx>,
119 use rustc_middle::ty::ScalarInt;
120 use rustc_middle::ty::TypeVisitable;
121 use rustc_span::symbol::sym;
123 let c = c.eval(tcx, param_env);
125 if let Some(err) = c.error_reported() {
134 let adt_def = c.ty().ty_adt_def()?;
137 tcx.require_lang_item(LangItem::TransmuteOpts, None),
139 "The given `Const` was not marked with the `{}` lang item.",
140 LangItem::TransmuteOpts.name(),
143 let variant = adt_def.non_enum_variant();
144 let fields = c.to_valtree().unwrap_branch();
146 let get_field = |name| {
147 let (field_idx, _) = variant
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
157 alignment: get_field(sym::alignment),
158 lifetimes: get_field(sym::lifetimes),
159 safety: get_field(sym::safety),
160 validity: get_field(sym::validity),
166 #[cfg(feature = "rustc")]