about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-02 21:17:31 +0000
committerbors <bors@rust-lang.org>2022-08-02 21:17:31 +0000
commite4417cf020fbcd6182c11637bc6b8694434bd81a (patch)
tree0e57100d6b7d73ba497ea478b1aeb94739b85776 /compiler/rustc_trait_selection/src
parent4493a0f4724c0bae1436242d76cccc9c0a287b80 (diff)
parent965ffb0b5cf3372900ce473f244ec33270058888 (diff)
downloadrust-e4417cf020fbcd6182c11637bc6b8694434bd81a.tar.gz
rust-e4417cf020fbcd6182c11637bc6b8694434bd81a.zip
Auto merge of #92268 - jswrenn:transmute, r=oli-obk
Initial implementation of transmutability trait.

*T'was the night before Christmas and all through the codebase, not a miri was stirring — no hint of `unsafe`!*

This PR provides an initial, **incomplete** implementation of *[MCP 411: Lang Item for Transmutability](https://github.com/rust-lang/compiler-team/issues/411)*. The `core::mem::BikeshedIntrinsicFrom` trait provided by this PR is implemented on-the-fly by the compiler for types `Src` and `Dst` when the bits of all possible values of type `Src` are safely reinterpretable as a value of type `Dst`.

What this PR provides is:
- [x] [support for transmutations involving primitives](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/primitives)
- [x] [support for transmutations involving arrays](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/arrays)
- [x] [support for transmutations involving structs](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/structs)
- [x] [support for transmutations involving enums](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/enums)
- [x] [support for transmutations involving unions](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/unions)
- [x] [support for weaker validity checks](https://github.com/jswrenn/rust/blob/transmute/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs) (i.e., `Assume::VALIDITY`)
- [x] visibility checking

What isn't yet implemented:
- [ ] transmutability options passed using the `Assume` struct
- [ ] [support for references](https://github.com/jswrenn/rust/blob/transmute/src/test/ui/transmutability/references.rs)
- [ ] smarter error messages

These features will be implemented in future PRs.
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs52
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs3
3 files changed, 77 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 6e8581128dd..a60ce0f3437 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_for_unsizing(obligation, &mut candidates);
             } else if lang_items.destruct_trait() == Some(def_id) {
                 self.assemble_const_destruct_candidates(obligation, &mut candidates);
+            } else if lang_items.transmute_trait() == Some(def_id) {
+                // User-defined transmutability impls are permitted.
+                self.assemble_candidates_from_impls(obligation, &mut candidates);
+                self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
                     // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -874,6 +878,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+    fn assemble_candidates_for_transmutability(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        if obligation.has_param_types_or_consts() {
+            return;
+        }
+
+        if obligation.has_infer_types_or_consts() {
+            candidates.ambiguous = true;
+            return;
+        }
+
+        candidates.vec.push(TransmutabilityCandidate);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_trait_alias(
         &mut self,
         obligation: &TraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index d4c9fd1c5f9..672c9b7b088 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Builtin(data)
             }
 
+            TransmutabilityCandidate => {
+                let data = self.confirm_transmutability_candidate(obligation)?;
+                ImplSource::Builtin(data)
+            }
+
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
@@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ImplSourceBuiltinData { nested: obligations }
     }
 
+    fn confirm_transmutability_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        debug!(?obligation, "confirm_transmutability_candidate");
+
+        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 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),
+        });
+
+        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 cause = obligation.cause.clone();
+
+        let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
+
+        let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
+
+        use rustc_transmute::Answer;
+
+        match maybe_transmutable {
+            Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+            _ => Err(Unimplemented),
+        }
+    }
+
     /// This handles the case where an `auto trait Foo` impl is being used.
     /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
     ///
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 17f34012d1d..9ca23228b98 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
             }
 
+            // FIXME(@jswrenn): this should probably be more sophisticated
+            (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+
             // (*)
             (
                 BuiltinCandidate { has_nested: false }