about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-04 07:55:44 +0000
committerbors <bors@rust-lang.org>2022-09-04 07:55:44 +0000
commit8521a8c92da6c0c845d4f6394e903651a227946a (patch)
tree18fff039f86b368a19865a2c5a563987ef4185d3 /compiler
parentc2d140bd36e7fcdc894b7c342fd81a63fdd66373 (diff)
parentfbcc038a224e58f7d3aca25c7f2321f11ce5513d (diff)
downloadrust-8521a8c92da6c0c845d4f6394e903651a227946a.tar.gz
rust-8521a8c92da6c0c845d4f6394e903651a227946a.zip
Auto merge of #100726 - jswrenn:transmute, r=oli-obk
safe transmute: use `Assume` struct to provide analysis options

This task was left as a TODO in #92268; resolving it brings [`BikeshedIntrinsicFrom`](https://doc.rust-lang.org/nightly/core/mem/trait.BikeshedIntrinsicFrom.html) more in line with the API defined in [MCP411](https://github.com/rust-lang/compiler-team/issues/411).

**Before:**
```rust
pub unsafe trait BikeshedIntrinsicFrom<
    Src,
    Context,
    const ASSUME_ALIGNMENT: bool,
    const ASSUME_LIFETIMES: bool,
    const ASSUME_VALIDITY: bool,
    const ASSUME_VISIBILITY: bool,
> where
    Src: ?Sized,
{}
```
**After:**
```rust
pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
where
    Src: ?Sized,
{}
```

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

r? `@oli-obk`

---

Related:
- https://github.com/rust-lang/compiler-team/issues/411
- 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.toml5
-rw-r--r--compiler/rustc_transmute/src/layout/dfa.rs1
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs6
-rw-r--r--compiler/rustc_transmute/src/lib.rs62
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs2
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs4
9 files changed, 73 insertions, 35 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 0c01326d003..f19d07d98dc 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -193,7 +193,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 64b919587e8..c501fba21c6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -339,6 +339,7 @@ symbols! {
         alias,
         align,
         align_offset,
+        alignment,
         alignstack,
         all,
         alloc,
@@ -866,6 +867,7 @@ symbols! {
         lib,
         libc,
         lifetime,
+        lifetimes,
         likely,
         line,
         line_macro,
@@ -1294,6 +1296,7 @@ symbols! {
         rustfmt,
         rvalue_static_promotion,
         s,
+        safety,
         sanitize,
         sanitizer_runtime,
         saturating_add,
@@ -1478,6 +1481,7 @@ symbols! {
         trait_alias,
         trait_upcasting,
         transmute,
+        transmute_opts,
         transmute_trait,
         transparent,
         transparent_enums,
@@ -1573,6 +1577,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..aa6fe7d2419 100644
--- a/compiler/rustc_transmute/Cargo.toml
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -7,7 +7,8 @@ edition = "2021"
 
 [dependencies]
 tracing = "0.1"
-rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_data_structures = { path = "../rustc_data_structures"}
+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}
@@ -17,7 +18,7 @@ rustc_target = { path = "../rustc_target", optional = true}
 [features]
 rustc = [
     "rustc_middle",
-    "rustc_data_structures",
+    "rustc_hir",
     "rustc_infer",
     "rustc_macros",
     "rustc_span",
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index b60ea6e7a24..b8922696e30 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -104,7 +104,6 @@ where
     }
 
     #[instrument(level = "debug")]
-    #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
     pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
         let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
 
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index f25e3c1fd8a..c2bc47bc043 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -119,8 +119,6 @@ where
 
         let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
 
-        // the iteration order doesn't matter
-        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
         for (source, transition) in other.transitions {
             let fix_state = |state| if state == other.start { self.accepting } else { state };
             let entry = transitions.entry(fix_state(source)).or_default();
@@ -142,8 +140,6 @@ where
 
         let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
 
-        // the iteration order doesn't matter
-        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
         for (&(mut source), transition) in other.transitions.iter() {
             // if source is starting state of `other`, replace with starting state of `self`
             if source == other.start {
@@ -152,8 +148,6 @@ where
             let entry = transitions.entry(source).or_default();
             for (edge, destinations) in transition {
                 let entry = entry.entry(edge.clone()).or_default();
-                // the iteration order doesn't matter
-                #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
                 for &(mut destination) in destinations {
                     // if dest is accepting state of `other`, replace with accepting state of `self`
                     if destination == other.accepting {
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 89b1ce5abe9..64cd70d3678 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -6,11 +6,7 @@
 #[macro_use]
 extern crate tracing;
 
-#[cfg(feature = "rustc")]
-pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
-
-#[cfg(not(feature = "rustc"))]
-pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
+pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
 
 pub(crate) mod layout;
 pub(crate) mod maybe_transmutable;
@@ -19,8 +15,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?"
@@ -62,11 +58,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)]
@@ -106,6 +108,54 @@ 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::ScalarInt;
+            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 variant = adt_def.non_enum_variant();
+            let fields = c.to_valtree().unwrap_branch();
+
+            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].unwrap_leaf() == ScalarInt::TRUE
+            };
+
+            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 248ff1ec241..1186eac37ab 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();