about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-04-07 05:25:56 +0000
committerMichael Goulet <michael@errs.io>2023-04-16 19:12:34 +0000
commitf6bfb4bf8e62e5f924790e62b4e8321b7658da2b (patch)
tree23764bbd8204bcbc620bdf4650562d5325cbd774
parent8a778ca1e35e4a8df95c00d800100d95e63e7722 (diff)
downloadrust-f6bfb4bf8e62e5f924790e62b4e8321b7658da2b.tar.gz
rust-f6bfb4bf8e62e5f924790e62b4e8321b7658da2b.zip
Erase regions when confirming transmutability candidate
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs48
-rw-r--r--compiler/rustc_transmute/src/lib.rs9
-rw-r--r--tests/ui/transmutability/references.current.stderr4
-rw-r--r--tests/ui/transmutability/references.next.stderr4
-rw-r--r--tests/ui/transmutability/region-infer.rs22
-rw-r--r--tests/ui/transmutability/region-infer.stderr23
8 files changed, 89 insertions, 45 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index c29b5b04e00..bb574954587 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -649,7 +649,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
             ObligationCause::dummy(),
-            ty::Binder::dummy(src_and_dst),
+            src_and_dst,
             scope,
             assume,
         ) {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index cef982fcb41..0352f0f380d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -742,7 +742,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         {
                             // Recompute the safe transmute reason and use that for the error reporting
                             self.get_safe_transmute_error_and_reason(
-                                trait_predicate,
                                 obligation.clone(),
                                 trait_ref,
                                 span,
@@ -1629,7 +1628,6 @@ trait InferCtxtPrivExt<'tcx> {
 
     fn get_safe_transmute_error_and_reason(
         &self,
-        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
         obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
         span: Span,
@@ -2921,18 +2919,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
     fn get_safe_transmute_error_and_reason(
         &self,
-        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
         obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
         span: Span,
     ) -> (String, Option<String>) {
-        let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
-            dst: p.trait_ref.substs.type_at(0),
-            src: p.trait_ref.substs.type_at(1),
-        });
-        let scope = trait_ref.skip_binder().substs.type_at(2);
+        // Erase regions because layout code doesn't particularly care about regions.
+        let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+
+        let src_and_dst = rustc_transmute::Types {
+            dst: trait_ref.substs.type_at(0),
+            src: trait_ref.substs.type_at(1),
+        };
+        let scope = trait_ref.substs.type_at(2);
         let Some(assume) =
-            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
+            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
                 span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
             };
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2942,8 +2942,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             assume,
         ) {
             rustc_transmute::Answer::No(reason) => {
-                let dst = trait_ref.skip_binder().substs.type_at(0);
-                let src = trait_ref.skip_binder().substs.type_at(1);
+                let dst = trait_ref.substs.type_at(0);
+                let src = trait_ref.substs.type_at(1);
                 let custom_err_msg = format!(
                     "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 5e60bc01bb6..3bba11262f5 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -275,33 +275,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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 const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
-
-        let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
-            dst: p.trait_ref.substs.type_at(0),
-            src: p.trait_ref.substs.type_at(1),
-        });
-
-        let scope = type_at(2).skip_binder();
-
-        let Some(assume) =
-            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else {
-                return Err(Unimplemented);
-            };
-
-        let cause = obligation.cause.clone();
+        // We erase regions here because transmutability calls layout queries,
+        // which does not handle inference regions and doesn't particularly
+        // care about other regions. Erasing late-bound regions is equivalent
+        // to instantiating the binder with placeholders then erasing those
+        // placeholder regions.
+        let predicate =
+            self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
+
+        let Some(assume) = rustc_transmute::Assume::from_const(
+            self.infcx.tcx,
+            obligation.param_env,
+            predicate.trait_ref.substs.const_at(3)
+        ) else {
+            return Err(Unimplemented);
+        };
 
         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;
+        let maybe_transmutable = transmute_env.is_transmutable(
+            obligation.cause.clone(),
+            rustc_transmute::Types {
+                dst: predicate.trait_ref.substs.type_at(0),
+                src: predicate.trait_ref.substs.type_at(1),
+            },
+            predicate.trait_ref.substs.type_at(2),
+            assume,
+        );
 
         match maybe_transmutable {
-            Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+            rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
             _ => Err(Unimplemented),
         }
     }
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index a93a42987ed..8be02c1d988 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -64,7 +64,6 @@ mod rustc {
     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;
@@ -92,15 +91,13 @@ mod rustc {
         pub fn is_transmutable(
             &mut self,
             cause: ObligationCause<'tcx>,
-            src_and_dst: Binder<'tcx, Types<'tcx>>,
+            types: Types<'tcx>,
             scope: Ty<'tcx>,
             assume: crate::Assume,
         ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
-            let src = src_and_dst.map_bound(|types| types.src).skip_binder();
-            let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
             crate::maybe_transmutable::MaybeTransmutableQuery::new(
-                src,
-                dst,
+                types.src,
+                types.dst,
                 scope,
                 assume,
                 self.infcx.tcx,
diff --git a/tests/ui/transmutability/references.current.stderr b/tests/ui/transmutability/references.current.stderr
index ecb095354a5..819c9b92bc8 100644
--- a/tests/ui/transmutability/references.current.stderr
+++ b/tests/ui/transmutability/references.current.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`
+error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
   --> $DIR/references.rs:29:52
    |
 LL |     assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
-   |                                                    ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout
+   |                                                    ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/references.rs:16:14
diff --git a/tests/ui/transmutability/references.next.stderr b/tests/ui/transmutability/references.next.stderr
index ecb095354a5..819c9b92bc8 100644
--- a/tests/ui/transmutability/references.next.stderr
+++ b/tests/ui/transmutability/references.next.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`
+error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
   --> $DIR/references.rs:29:52
    |
 LL |     assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
-   |                                                    ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout
+   |                                                    ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/references.rs:16:14
diff --git a/tests/ui/transmutability/region-infer.rs b/tests/ui/transmutability/region-infer.rs
new file mode 100644
index 00000000000..09f60277688
--- /dev/null
+++ b/tests/ui/transmutability/region-infer.rs
@@ -0,0 +1,22 @@
+#![feature(transmutability)]
+
+use std::mem::{Assume, BikeshedIntrinsicFrom};
+pub struct Context;
+
+#[repr(C)]
+struct W<'a>(&'a ());
+
+fn test<'a>()
+where
+    W<'a>: BikeshedIntrinsicFrom<
+            (),
+            Context,
+            { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
+        >,
+{
+}
+
+fn main() {
+    test();
+    //~^ ERROR `()` cannot be safely transmuted into `W<'_>`
+}
diff --git a/tests/ui/transmutability/region-infer.stderr b/tests/ui/transmutability/region-infer.stderr
new file mode 100644
index 00000000000..d6b65e9e4a0
--- /dev/null
+++ b/tests/ui/transmutability/region-infer.stderr
@@ -0,0 +1,23 @@
+error[E0277]: `()` cannot be safely transmuted into `W<'_>` in the defining scope of `Context`
+  --> $DIR/region-infer.rs:20:5
+   |
+LL |     test();
+   |     ^^^^ `W<'_>` does not have a well-specified layout
+   |
+note: required by a bound in `test`
+  --> $DIR/region-infer.rs:11:12
+   |
+LL |   fn test<'a>()
+   |      ---- required by a bound in this function
+LL |   where
+LL |       W<'a>: BikeshedIntrinsicFrom<
+   |  ____________^
+LL | |             (),
+LL | |             Context,
+LL | |             { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
+LL | |         >,
+   | |_________^ required by this bound in `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.