summary refs log tree commit diff
path: root/compiler/rustc_transmute/src/lib.rs
diff options
context:
space:
mode:
authorJack Wrenn <jack@wrenn.fyi>2022-08-18 19:39:14 +0000
committerJack Wrenn <jack@wrenn.fyi>2022-08-22 18:37:54 +0000
commitf46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a (patch)
tree5a5d0e994f5cf930365f2d03343e64d54e12f308 /compiler/rustc_transmute/src/lib.rs
parente0dc8d78019ca924203fe153ff0af7f64f68cb5d (diff)
downloadrust-f46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a.tar.gz
rust-f46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a.zip
safe transmute: use `Assume` struct to provide analysis options
This was left as a TODO in #92268, and brings the trait more in
line with what was defined in MCP411.

`Assume::visibility` has been renamed to `Assume::safety`, as
library safety is what's actually being assumed; visibility is
just the mechanism by which it is currently checked (this may
change).

ref: https://github.com/rust-lang/compiler-team/issues/411
ref: https://github.com/rust-lang/rust/issues/99571
Diffstat (limited to 'compiler/rustc_transmute/src/lib.rs')
-rw-r--r--compiler/rustc_transmute/src/lib.rs59
1 files changed, 58 insertions, 1 deletions
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 32e6cb9c64f..d7c2119a1c4 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -26,8 +26,8 @@ pub(crate) mod maybe_transmutable;
 pub struct Assume {
     pub alignment: bool,
     pub lifetimes: bool,
+    pub safety: bool,
     pub validity: bool,
-    pub visibility: bool,
 }
 
 /// The type encodes answers to the question: "Are these types transmutable?"
@@ -69,11 +69,17 @@ pub enum Reason {
 
 #[cfg(feature = "rustc")]
 mod rustc {
+    use super::*;
+
+    use rustc_hir::lang_items::LangItem;
     use rustc_infer::infer::InferCtxt;
     use rustc_macros::{TypeFoldable, TypeVisitable};
     use rustc_middle::traits::ObligationCause;
     use rustc_middle::ty::Binder;
+    use rustc_middle::ty::Const;
+    use rustc_middle::ty::ParamEnv;
     use rustc_middle::ty::Ty;
+    use rustc_middle::ty::TyCtxt;
 
     /// The source and destination types of a transmutation.
     #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
@@ -113,6 +119,57 @@ mod rustc {
             .answer()
         }
     }
+
+    impl Assume {
+        /// Constructs an `Assume` from a given const-`Assume`.
+        pub fn from_const<'tcx>(
+            tcx: TyCtxt<'tcx>,
+            param_env: ParamEnv<'tcx>,
+            c: Const<'tcx>,
+        ) -> Self {
+            use rustc_middle::ty::DestructuredConst;
+            use rustc_middle::ty::TypeVisitable;
+            use rustc_span::symbol::sym;
+
+            let c = c.eval(tcx, param_env);
+
+            if let Some(err) = c.error_reported() {
+                return Self { alignment: true, lifetimes: true, safety: true, validity: true };
+            }
+
+            let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT.");
+
+            assert_eq!(
+                tcx.require_lang_item(LangItem::TransmuteOpts, None),
+                adt_def.did(),
+                "The given `Const` was not marked with the `{}` lang item.",
+                LangItem::TransmuteOpts.name(),
+            );
+
+            let DestructuredConst { variant, fields } = tcx.destructure_const(c);
+            let variant_idx = variant.expect("The given `Const` must be an ADT.");
+            let variant = adt_def.variant(variant_idx);
+
+            let get_field = |name| {
+                let (field_idx, _) = variant
+                    .fields
+                    .iter()
+                    .enumerate()
+                    .find(|(_, field_def)| name == field_def.name)
+                    .expect(&format!("There were no fields named `{name}`."));
+                fields[field_idx].try_eval_bool(tcx, param_env).expect(&format!(
+                    "The field named `{name}` lang item could not be evaluated to a bool."
+                ))
+            };
+
+            Self {
+                alignment: get_field(sym::alignment),
+                lifetimes: get_field(sym::lifetimes),
+                safety: get_field(sym::safety),
+                validity: get_field(sym::validity),
+            }
+        }
+    }
 }
 
 #[cfg(feature = "rustc")]