about summary refs log tree commit diff
path: root/compiler
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
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')
-rw-r--r--compiler/rustc_hir/src/lang_items.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs20
-rw-r--r--compiler/rustc_transmute/Cargo.toml2
-rw-r--r--compiler/rustc_transmute/src/lib.rs59
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs2
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs4
7 files changed, 74 insertions, 21 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index c337be12ae4..ccbc225b9ec 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -192,7 +192,8 @@ language_item_table! {
     DispatchFromDyn,         sym::dispatch_from_dyn,   dispatch_from_dyn_trait,    Target::Trait,          GenericRequirement::Minimum(1);
 
     // language items relating to transmutability
-    TransmuteTrait,          sym::transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(6);
+    TransmuteOpts,           sym::transmute_opts,      transmute_opts,             Target::Struct,         GenericRequirement::Exact(0);
+    TransmuteTrait,          sym::transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(3);
 
     Add(Op),                 sym::add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
     Sub(Op),                 sym::sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 156f53ac486..130cc9a854a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -334,6 +334,7 @@ symbols! {
         alias,
         align,
         align_offset,
+        alignment,
         alignstack,
         all,
         alloc,
@@ -859,6 +860,7 @@ symbols! {
         lib,
         libc,
         lifetime,
+        lifetimes,
         likely,
         line,
         line_macro,
@@ -1284,6 +1286,7 @@ symbols! {
         rustfmt,
         rvalue_static_promotion,
         s,
+        safety,
         sanitize,
         sanitizer_runtime,
         saturating_add,
@@ -1466,6 +1469,7 @@ symbols! {
         trait_alias,
         trait_upcasting,
         transmute,
+        transmute_opts,
         transmute_trait,
         transparent,
         transparent_enums,
@@ -1560,6 +1564,7 @@ symbols! {
         va_list,
         va_start,
         val,
+        validity,
         values,
         var,
         variant_count,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2a1099fc82a..e44f6665795 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -279,29 +279,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let predicate = obligation.predicate;
 
         let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
-        let bool_at = |i| {
-            predicate
-                .skip_binder()
-                .trait_ref
-                .substs
-                .const_at(i)
-                .try_eval_bool(self.tcx(), obligation.param_env)
-                .unwrap_or(true)
-        };
+        let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
 
         let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
-            src: p.trait_ref.substs.type_at(1),
             dst: p.trait_ref.substs.type_at(0),
+            src: p.trait_ref.substs.type_at(1),
         });
 
         let scope = type_at(2).skip_binder();
 
-        let assume = rustc_transmute::Assume {
-            alignment: bool_at(3),
-            lifetimes: bool_at(4),
-            validity: bool_at(5),
-            visibility: bool_at(6),
-        };
+        let assume =
+            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3));
 
         let cause = obligation.cause.clone();
 
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
index 9dc96e08a8e..fa3f45fa235 100644
--- a/compiler/rustc_transmute/Cargo.toml
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
 [dependencies]
 tracing = "0.1"
 rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_hir = { path = "../rustc_hir", optional = true}
 rustc_infer = { path = "../rustc_infer", optional = true}
 rustc_macros = { path = "../rustc_macros", optional = true}
 rustc_middle = { path = "../rustc_middle", optional = true}
@@ -18,6 +19,7 @@ rustc_target = { path = "../rustc_target", optional = true}
 rustc = [
     "rustc_middle",
     "rustc_data_structures",
+    "rustc_hir",
     "rustc_infer",
     "rustc_macros",
     "rustc_span",
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")]
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 076d922d1b7..b6b6de38f66 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -105,7 +105,7 @@ where
     #[inline(always)]
     #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
     pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
-        let assume_visibility = self.assume.visibility;
+        let assume_visibility = self.assume.safety;
         let query_or_answer = self.map_layouts(|src, dst, scope, context| {
             // Remove all `Def` nodes from `src`, without checking their visibility.
             let src = src.prune(&|def| true);
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
index d9d125687f6..4d5772a4f2e 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -13,7 +13,7 @@ mod bool {
             layout::Tree::<Def, !>::bool(),
             layout::Tree::<Def, !>::bool(),
             (),
-            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
             UltraMinimal,
         )
         .answer();
@@ -26,7 +26,7 @@ mod bool {
             layout::Dfa::<!>::bool(),
             layout::Dfa::<!>::bool(),
             (),
-            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
             UltraMinimal,
         )
         .answer();