about summary refs log tree commit diff
diff options
context:
space:
mode:
authorouz-a <ouz.agz@gmail.com>2023-08-28 11:19:19 +0300
committerMark Rousskov <mark.simulacrum@gmail.com>2023-12-04 09:55:14 -0500
commitcaab4b7d945532fc543db99a26e20ee9907ea412 (patch)
tree2cb85a9532223faaebd800f3bb6990ef5e686434
parentfa7a3184b49946e6bc6e77c0d79ed231ea29c69a (diff)
downloadrust-caab4b7d945532fc543db99a26e20ee9907ea412.tar.gz
rust-caab4b7d945532fc543db99a26e20ee9907ea412.zip
Add docs, remove code, change subtyper code
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs5
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs5
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs43
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs7
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs9
-rw-r--r--compiler/rustc_mir_transform/src/add_subtyping_projections.rs20
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs1
-rw-r--r--tabula.rs14
-rw-r--r--tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff1
-rw-r--r--tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff3
-rw-r--r--tests/mir-opt/mir_subtyping.main.Subtyper.diff262
-rw-r--r--tests/mir-opt/mir_subtyping.rs43
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir5
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir5
24 files changed, 106 insertions, 363 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 745949d3ff0..8d4028de90d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -318,13 +318,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
                 ProjectionElem::Deref
                 | ProjectionElem::Index(..)
-                | ProjectionElem::Subtype(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
                     PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
                 }
                 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
-                ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
+                ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
+                    PlaceTy::from_ty(*ty)
+                }
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index fcf45179b9d..777ebf0d438 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -243,13 +243,13 @@ fn place_components_conflict<'tcx>(
                 }
 
                 (ProjectionElem::Deref, _, Deep)
-                | (ProjectionElem::Subtype(_), _, _)
                 | (ProjectionElem::Deref, _, AccessDepth::Drop)
                 | (ProjectionElem::Field { .. }, _, _)
                 | (ProjectionElem::Index { .. }, _, _)
                 | (ProjectionElem::ConstantIndex { .. }, _, _)
                 | (ProjectionElem::Subslice { .. }, _, _)
                 | (ProjectionElem::OpaqueCast { .. }, _, _)
+                | (ProjectionElem::Subtype(_), _, _)
                 | (ProjectionElem::Downcast { .. }, _, _) => {
                     // Recursive case. This can still be disjoint on a
                     // further iteration if this a shallow access and
@@ -360,7 +360,6 @@ fn place_projection_conflict<'tcx>(
         (
             ProjectionElem::Index(..),
             ProjectionElem::Index(..)
-            | ProjectionElem::Subtype(..)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. },
         )
@@ -505,12 +504,12 @@ fn place_projection_conflict<'tcx>(
             debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
             Overlap::EqualOrDisjoint
         }
-        (ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint,
         (
             ProjectionElem::Deref
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subtype(_)
             | ProjectionElem::OpaqueCast { .. }
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Downcast(..),
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 72c22d217b4..e9c9709bd1f 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -89,7 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                             cursor = cursor_base;
                             continue 'cursor;
                         }
-                        ProjectionElem::Subtype(..) => continue 'cursor,
+                        ProjectionElem::Subtype(..) => {
+                            panic!("Subtype projection is not allowed before borrow check")
+                        }
                         ProjectionElem::Deref => {
                             // (handled below)
                         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 33687792701..a3724c391d2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -621,7 +621,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
                 }))
             }
-            ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty),
             ProjectionElem::Index(i) => {
                 let index_ty = Place::from(i).ty(self.body(), tcx).ty;
                 if index_ty != tcx.types.usize {
@@ -717,6 +716,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 }
                 PlaceTy::from_ty(fty)
             }
+            ProjectionElem::Subtype(_) => {
+                let guard = span_mirbug_and_err!(
+                    self,
+                    place,
+                    "ProjectionElem::Subtype shouldn't exist in borrowck"
+                );
+                PlaceTy::from_ty(Ty::new_error(tcx, guard))
+            }
             ProjectionElem::OpaqueCast(ty) => {
                 let ty = self.sanitize_type(place, ty);
                 let ty = self.cx.normalize(ty, location);
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 06780567fb8..a13d3a0e115 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -872,13 +872,11 @@ pub(crate) fn codegen_place<'tcx>(
 
     for elem in place.projection {
         match elem {
-            PlaceElem::Subtype(_) => {
-                continue;
-            }
             PlaceElem::Deref => {
                 cplace = cplace.place_deref(fx);
             }
             PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
+            PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty),
             PlaceElem::Field(field, _ty) => {
                 cplace = cplace.place_field(fx, field);
             }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index d4273c0b593..34cde0a0e78 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -674,6 +674,14 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
+    pub(crate) fn place_transmute_type(
+        self,
+        fx: &mut FunctionCx<'_, '_, 'tcx>,
+        ty: Ty<'tcx>,
+    ) -> CPlace<'tcx> {
+        CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) }
+    }
+
     pub(crate) fn place_field(
         self,
         fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 9ff73aab907..eb590a45a63 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -466,6 +466,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 mir::ProjectionElem::OpaqueCast(ty) => {
                     bug!("encountered OpaqueCast({ty}) in codegen")
                 }
+                mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
                 mir::ProjectionElem::Index(index) => {
                     let index = &mir::Operand::Copy(mir::Place::from(index));
                     let index = self.codegen_operand(bx, index);
@@ -499,7 +500,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     subslice
                 }
                 mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
-                mir::ProjectionElem::Subtype(_) => continue,
             };
         }
         debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index b33396de33b..a32ea204f98 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -665,9 +665,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?;
         // Using `try_fold` turned out to be bad for performance, hence the loop.
         for elem in mir_place.projection.iter() {
-            if elem.is_subtype() {
-                continue;
-            }
             op = self.project(&op, elem)?
         }
 
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 3c24381f93d..70df3d8fd78 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -319,6 +319,8 @@ where
             OpaqueCast(ty) => {
                 span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
             }
+            // We don't want anything happening here, this is here as a dummy.
+            Subtype(_) => base.transmute(base.layout(), self)?,
             Field(field, _) => self.project_field(base, field.index())?,
             Downcast(_, variant) => self.project_downcast(base, variant)?,
             Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
@@ -332,7 +334,6 @@ where
                 self.project_constant_index(base, offset, min_length, from_end)?
             }
             Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?,
-            Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?,
         })
     }
 }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index ecedfc74450..a8e5254d860 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -16,6 +16,8 @@ use rustc_target::spec::abi::Abi;
 
 use crate::util::is_within_packed;
 
+use crate::util::is_subtype;
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum EdgeKind {
     Unwind,
@@ -602,35 +604,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
-        crate::util::is_subtype(self.tcx, self.param_env, src, dest)
+        return crate::util::is_subtype(self.tcx, self.param_env, src, dest);
     }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        match operand {
-            Operand::Copy(place) | Operand::Move(place) => {
-                if let Some(stmt) = self.body.stmt_at(location).left() {
-                    match &stmt.kind {
-                        StatementKind::Assign(box (lval, rvalue)) => {
-                            let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                            let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty;
-
-                            if !place.is_subtype()
-                                && place_ty != lval_ty
-                                && rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty
-                                && (rvalue.ty(&self.body.local_decls, self.tcx).is_closure()
-                                    != lval_ty.is_closure())
-                            {
-                                self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}"))
-                            }
-                        }
-                        _ => (),
-                    }
-                }
-            }
-            _ => (),
-        }
         // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
         if self.tcx.sess.opts.unstable_opts.validate_mir
             && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
@@ -776,6 +755,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                 }
             }
+            ProjectionElem::Subtype(ty) => {
+                if !is_subtype(
+                    self.tcx,
+                    self.param_env,
+                    ty,
+                    place_ref.ty(&self.body.local_decls, self.tcx).ty,
+                ) {
+                    self.fail(
+                        location,
+                        format!(
+                            "Failed subtyping {ty:#?} and {:#?}",
+                            place_ref.ty(&self.body.local_decls, self.tcx).ty
+                        ),
+                    )
+                }
+            }
             _ => {}
         }
         self.super_projection_elem(place_ref, elem, context, location);
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 27105eae665..0a72289f1bb 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1103,6 +1103,7 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
     for &elem in projection.iter().rev() {
         match elem {
             ProjectionElem::OpaqueCast(_)
+            | ProjectionElem::Subtype(_)
             | ProjectionElem::Downcast(_, _)
             | ProjectionElem::Field(_, _) => {
                 write!(fmt, "(").unwrap();
@@ -1125,6 +1126,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
             ProjectionElem::OpaqueCast(ty) => {
                 write!(fmt, " as {ty})")?;
             }
+            ProjectionElem::Subtype(ty) => {
+                write!(fmt, "as {ty})")?;
+            }
             ProjectionElem::Downcast(Some(name), _index) => {
                 write!(fmt, " as {name})")?;
             }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index b308fb51993..3471d620ee6 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -57,6 +57,7 @@ impl<V, T> ProjectionElem<V, T> {
             Self::Field(_, _)
             | Self::Index(_)
             | Self::OpaqueCast(_)
+            | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
             | Self::Downcast(_, _) => false,
@@ -70,6 +71,7 @@ impl<V, T> ProjectionElem<V, T> {
             Self::Deref | Self::Index(_) => false,
             Self::Field(_, _)
             | Self::OpaqueCast(_)
+            | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
             | Self::Downcast(_, _) => true,
@@ -95,6 +97,7 @@ impl<V, T> ProjectionElem<V, T> {
             | Self::Field(_, _) => true,
             Self::ConstantIndex { from_end: true, .. }
             | Self::Index(_)
+            | Self::Subtype(_)
             | Self::OpaqueCast(_)
             | Self::Subslice { .. } => false,
         }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index e405de90ee5..fea7819d545 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1076,6 +1076,13 @@ pub enum ProjectionElem<V, T> {
     /// requiring an intermediate variable.
     OpaqueCast(T),
 
+    /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
+    /// type of lvalue doesn't match type of rvalue, primary goal being making subtyping
+    /// explicit during optimizations and codegen.
+    ///
+    /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
+    /// borrowchecker, as we only care about subtyping that can affect trait selection and
+    /// `TypeId`.
     Subtype(T),
 }
 
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 5ea8325412b..f2745b32cf9 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1109,8 +1109,12 @@ macro_rules! visit_place_fns {
                     self.visit_ty(&mut new_ty, TyContext::Location(location));
                     if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
                 }
+                PlaceElem::Subtype(ty) => {
+                    let mut new_ty = ty;
+                    self.visit_ty(&mut new_ty, TyContext::Location(location));
+                    if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
+                }
                 PlaceElem::Deref
-                | PlaceElem::Subtype { .. }
                 | PlaceElem::ConstantIndex { .. }
                 | PlaceElem::Subslice { .. }
                 | PlaceElem::Downcast(..) => None,
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 0e4fc2447e1..4447ff0798c 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -112,9 +112,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
         let mut union_path = None;
 
         for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
-            if elem.is_subtype() {
-                continue;
-            }
+            // We don't care creating `MovePath` for `ProjectionElem::Subtype(T)` because it's for debugging/validating
+            // purposes it's movement doesn't affect anything.
             let body = self.builder.body;
             let tcx = self.builder.tcx;
             let place_ty = place_ref.ty(body, tcx).ty;
@@ -233,7 +232,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                 // `OpaqueCast` only transmutes the type, so no moves there and
                 // `Downcast` only changes information about a `Place` without moving
                 // So it's safe to skip these.
-                ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (),
+                ProjectionElem::OpaqueCast(_)
+                | ProjectionElem::Subtype(_)
+                | ProjectionElem::Downcast(_, _) => (),
             }
             if union_path.is_none() {
                 // inlined from add_move_path because of a borrowck conflict with the iterator
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index e51f4a2ff21..594bb9bf142 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -7,13 +7,13 @@ use rustc_middle::ty::TyCtxt;
 
 pub struct Subtyper;
 
-pub struct SubTypeCheker<'a, 'tcx> {
+pub struct SubTypeChecker<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     patcher: MirPatch<'tcx>,
     local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
 }
 
-impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
+impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -25,28 +25,30 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
         location: Location,
     ) {
         let place_ty = place.ty(self.local_decls, self.tcx);
-        let rval_ty = rvalue.ty(self.local_decls, self.tcx);
+        let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
         if place_ty.ty != rval_ty {
+            // Not erasing this causes `Free Regions` errors in validator,
+            // when rval is `ReStatic`.
+            rval_ty = self.tcx.erase_regions_ty(rval_ty);
             let temp = self
                 .patcher
                 .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
-            let new_place =
-                Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
+            let new_place = Place::from(temp);
             self.patcher.add_assign(location, new_place, rvalue.clone());
-            let new_rval = Rvalue::Use(Operand::Move(new_place));
-            *rvalue = new_rval;
+            let subtyped =
+                new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
+            *rvalue = Rvalue::Use(Operand::Move(subtyped));
         }
     }
 }
 
 pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let patch = MirPatch::new(body);
-    let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls };
+    let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
 
     for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
         checker.visit_basic_block_data(bb, data);
     }
-
     checker.patcher.apply(body);
 }
 
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 449bade3322..56bdc5a171a 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -306,6 +306,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 }
                 ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
                 ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
+                ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
             };
             value = self.insert(Value::Projection(value, proj));
         }
diff --git a/tabula.rs b/tabula.rs
new file mode 100644
index 00000000000..19400a870e7
--- /dev/null
+++ b/tabula.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![deny(drop_bounds)]
+// As a special exemption, `impl Drop` in the return position raises no error.
+// This allows a convenient way to return an unnamed drop guard.
+fn voldemort_type() -> impl Drop {
+    struct Voldemort;
+    impl Drop for Voldemort {
+        fn drop(&mut self) {}
+    }
+    Voldemort
+}
+fn main() {
+    let _ = voldemort_type();
+}
diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff
index 6779003b693..23e0ab67121 100644
--- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff
@@ -12,6 +12,7 @@
           debug _r => _1;
       }
 +     scope 2 (inlined g) {
++         let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
 +     }
 +     scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
 +         debug pointer => _3;
diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
index 31744be99ec..a5488f6fb28 100644
--- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
@@ -12,6 +12,7 @@
           debug _r => _1;
       }
 +     scope 2 (inlined g) {
++         let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
 +     }
 +     scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
 +         debug pointer => _3;
@@ -55,7 +56,7 @@
   
 -     bb3: {
 +     bb1: {
-+         StorageDead(_5);
++         StorageDead(_6);
           StorageDead(_2);
 -         drop(_4) -> [return: bb4, unwind: bb6];
 +         drop(_4) -> [return: bb2, unwind: bb4];
diff --git a/tests/mir-opt/mir_subtyping.main.Subtyper.diff b/tests/mir-opt/mir_subtyping.main.Subtyper.diff
deleted file mode 100644
index 233915d48d7..00000000000
--- a/tests/mir-opt/mir_subtyping.main.Subtyper.diff
+++ /dev/null
@@ -1,262 +0,0 @@
-- // MIR for `main` before Subtyper
-+ // MIR for `main` after Subtyper
-  
-  | User Type Annotations
-  | 0: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:18, inferred_ty: fn(Foo<fn(&u8)>) -> std::boxed::Box<Foo<fn(&u8)>> {std::boxed::Box::<Foo<fn(&u8)>>::new}
-  | 1: user_ty: Canonical { value: Ty(fn(&'static u8)), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:34:23: 34:48, inferred_ty: fn(&u8)
-  | 2: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = std::string::String>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:87, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>
-  | 3: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:18, inferred_ty: fn(Foo<for<'a> fn(&'a u8)>) -> std::boxed::Box<Foo<for<'a> fn(&'a u8)>> {std::boxed::Box::<Foo<for<'a> fn(&'a u8)>>::new}
-  | 4: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:83, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>
-  | 5: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:37:20: 37:28, inferred_ty: fn(Foo<for<'a> fn(&'a u8)>) -> std::boxed::Box<Foo<for<'a> fn(&'a u8)>> {std::boxed::Box::<Foo<for<'a> fn(&'a u8)>>::new}
-  | 6: user_ty: Canonical { value: Ty(std::boxed::Box<Foo<fn(&'static u8)>>), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:38:20: 38:57, inferred_ty: std::boxed::Box<Foo<fn(&u8)>>
-  | 7: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = std::string::String>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:39:19: 39:64, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>
-  |
-  fn main() -> () {
-      let mut _0: ();
-      let _1: Wrapper;
-      let mut _2: for<'a> fn(&'a u8);
-      let _3: ();
-      let mut _4: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
-      let mut _5: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
-      let mut _6: std::boxed::Box<Foo<fn(&u8)>>;
-      let mut _7: Foo<fn(&u8)>;
-      let mut _8: fn(&u8);
-      let mut _9: fn(&u8);
-      let _10: ();
-      let mut _11: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>;
-      let mut _12: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>;
-      let mut _13: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
-      let mut _14: Foo<for<'a> fn(&'a u8)>;
-      let mut _15: for<'a> fn(&'a u8);
-      let mut _17: Foo<for<'a> fn(&'a u8)>;
-      let mut _18: for<'b> fn(&'b u8);
-      let mut _20: std::boxed::Box<Foo<fn(&u8)>>;
-      let mut _22: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
-      let mut _23: std::boxed::Box<Foo<fn(&u8)>>;
-      let mut _25: &mut dyn GetInner<Assoc = std::string::String>;
-      let _26: ();
-      let mut _27: std::string::String;
-+     let mut _28: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
-      scope 1 {
-          debug wrapper => _1;
-          let _16: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
-          scope 2 {
-              debug hr_fnptr => _16;
-              let _19: std::boxed::Box<Foo<fn(&u8)>>;
-              scope 3 {
-                  debug lr_fnptr => _19;
-                  let mut _21: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
-                  scope 4 {
-                      debug any => _21;
-                      let _24: std::string::String;
-                      scope 5 {
-                          debug evil_string => _24;
-                      }
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
-          _1 = Wrapper(move _2);
-          StorageDead(_2);
-          FakeRead(ForLet(None), _1);
-          StorageLive(_3);
-          StorageLive(_4);
-          StorageLive(_5);
-          StorageLive(_6);
-          StorageLive(_7);
-          StorageLive(_8);
-          StorageLive(_9);
-          _9 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
-          AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] });
-          _8 = _9;
-          _7 = Foo::<fn(&u8)>(move _8);
-          StorageDead(_8);
-          _6 = Box::<Foo<fn(&u8)>>::new(move _7) -> [return: bb1, unwind: bb28];
-      }
-  
-      bb1: {
-          _5 = move _6 as std::boxed::Box<dyn GetInner<Assoc = std::string::String>> (PointerCoercion(Unsize));
-          drop(_6) -> [return: bb2, unwind: bb28];
-      }
-  
-      bb2: {
-          StorageDead(_7);
-          StorageDead(_6);
-          AscribeUserType(_5, o, UserTypeProjection { base: UserType(2), projs: [] });
-          _4 = move _5;
-          _3 = std::mem::drop::<Box<dyn GetInner<Assoc = String>>>(move _4) -> [return: bb3, unwind: bb26];
-      }
-  
-      bb3: {
-          StorageDead(_4);
-          drop(_5) -> [return: bb4, unwind: bb28];
-      }
-  
-      bb4: {
-          StorageDead(_9);
-          StorageDead(_5);
-          StorageDead(_3);
-          StorageLive(_10);
-          StorageLive(_11);
-          StorageLive(_12);
-          StorageLive(_13);
-          StorageLive(_14);
-          StorageLive(_15);
-          _15 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
-          _14 = Foo::<for<'a> fn(&'a u8)>(move _15);
-          StorageDead(_15);
-          _13 = Box::<Foo<for<'a> fn(&'a u8)>>::new(move _14) -> [return: bb5, unwind: bb28];
-      }
-  
-      bb5: {
-          _12 = move _13 as std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>> (PointerCoercion(Unsize));
-          drop(_13) -> [return: bb6, unwind: bb28];
-      }
-  
-      bb6: {
-          StorageDead(_14);
-          StorageDead(_13);
-          AscribeUserType(_12, o, UserTypeProjection { base: UserType(4), projs: [] });
-          _11 = move _12;
-          _10 = std::mem::drop::<Box<dyn GetInner<Assoc = [usize; 3]>>>(move _11) -> [return: bb7, unwind: bb24];
-      }
-  
-      bb7: {
-          StorageDead(_11);
-          drop(_12) -> [return: bb8, unwind: bb28];
-      }
-  
-      bb8: {
-          StorageDead(_12);
-          StorageDead(_10);
-          StorageLive(_16);
-          StorageLive(_17);
-          StorageLive(_18);
-          _18 = (_1.0: for<'b> fn(&'b u8));
-          _17 = Foo::<for<'a> fn(&'a u8)>(move _18);
-          StorageDead(_18);
-          _16 = Box::<Foo<for<'a> fn(&'a u8)>>::new(move _17) -> [return: bb9, unwind: bb28];
-      }
-  
-      bb9: {
-          StorageDead(_17);
-          FakeRead(ForLet(None), _16);
-          StorageLive(_19);
-          StorageLive(_20);
--         _20 = move _16;
-+         _20 = move (_16 Subtyped as Box<Foo<fn(&u8)>>;
-          AscribeUserType(_20, o, UserTypeProjection { base: UserType(6), projs: [] });
-          _19 = move _20;
-          FakeRead(ForLet(None), _19);
-          drop(_20) -> [return: bb10, unwind: bb22];
-      }
-  
-      bb10: {
-          StorageDead(_20);
-          StorageLive(_21);
-          StorageLive(_22);
-          StorageLive(_23);
-          _23 = move _19;
-          _22 = move _23 as std::boxed::Box<dyn GetInner<Assoc = std::string::String>> (PointerCoercion(Unsize));
-          drop(_23) -> [return: bb11, unwind: bb22];
-      }
-  
-      bb11: {
-          StorageDead(_23);
-          AscribeUserType(_22, o, UserTypeProjection { base: UserType(7), projs: [] });
-          _21 = move _22;
-          FakeRead(ForLet(None), _21);
-          drop(_22) -> [return: bb12, unwind: bb21];
-      }
-  
-      bb12: {
-          StorageDead(_22);
-          StorageLive(_24);
-          StorageLive(_25);
-          _25 = &mut (*_21);
-          _24 = <dyn GetInner<Assoc = String> as GetInner>::muahaha(move _25) -> [return: bb13, unwind: bb21];
-      }
-  
-      bb13: {
-          StorageDead(_25);
-          FakeRead(ForLet(None), _24);
-          StorageLive(_26);
-          StorageLive(_27);
-          _27 = move _24;
-          _26 = std::mem::drop::<String>(move _27) -> [return: bb14, unwind: bb19];
-      }
-  
-      bb14: {
-          StorageDead(_27);
-          StorageDead(_26);
-          _0 = const ();
-          drop(_24) -> [return: bb15, unwind: bb21];
-      }
-  
-      bb15: {
-          StorageDead(_24);
-          drop(_21) -> [return: bb16, unwind: bb22];
-      }
-  
-      bb16: {
-          StorageDead(_21);
-          drop(_19) -> [return: bb17, unwind: bb23];
-      }
-  
-      bb17: {
-          StorageDead(_19);
-          drop(_16) -> [return: bb18, unwind: bb28];
-      }
-  
-      bb18: {
-          StorageDead(_16);
-          StorageDead(_1);
-          return;
-      }
-  
-      bb19 (cleanup): {
-          drop(_27) -> [return: bb20, unwind terminate];
-      }
-  
-      bb20 (cleanup): {
-          drop(_24) -> [return: bb21, unwind terminate];
-      }
-  
-      bb21 (cleanup): {
-          drop(_21) -> [return: bb22, unwind terminate];
-      }
-  
-      bb22 (cleanup): {
-          drop(_19) -> [return: bb23, unwind terminate];
-      }
-  
-      bb23 (cleanup): {
-          drop(_16) -> [return: bb28, unwind terminate];
-      }
-  
-      bb24 (cleanup): {
-          drop(_11) -> [return: bb25, unwind terminate];
-      }
-  
-      bb25 (cleanup): {
-          drop(_12) -> [return: bb28, unwind terminate];
-      }
-  
-      bb26 (cleanup): {
-          drop(_4) -> [return: bb27, unwind terminate];
-      }
-  
-      bb27 (cleanup): {
-          drop(_5) -> [return: bb28, unwind terminate];
-      }
-  
-      bb28 (cleanup): {
-          resume;
-      }
-  }
-  
diff --git a/tests/mir-opt/mir_subtyping.rs b/tests/mir-opt/mir_subtyping.rs
deleted file mode 100644
index 558ccaca9f3..00000000000
--- a/tests/mir-opt/mir_subtyping.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// compile-flags: -Z mir-opt-level=0
-
-// EMIT_MIR mir_subtyping.main.Subtyper.diff
-#![allow(coherence_leak_check)]
-
-struct Foo<T: 'static>(T);
-
-fn useful<'a>(_: &'a u8) {}
-
-pub struct Wrapper(for<'b> fn(&'b u8));
-
-trait GetInner {
-    type Assoc;
-    fn muahaha(&mut self) -> Self::Assoc;
-}
-
-impl GetInner for Foo<fn(&'static u8)> {
-    type Assoc = String;
-    fn muahaha(&mut self) -> String {
-        panic!("cant do it boss")
-    }
-}
-
-impl GetInner for Foo<for<'a> fn(&'a u8)> {
-    type Assoc = [usize; 3];
-    fn muahaha(&mut self) -> [usize; 3] {
-        [100; 3]
-    }
-}
-
-fn main() {
-    let wrapper = Wrapper(useful);
-
-    drop(Box::new(Foo(useful as fn(&'static u8))) as Box<dyn GetInner<Assoc = String>>);
-    drop(Box::new(Foo(useful as fn(&u8))) as Box<dyn GetInner<Assoc = [usize; 3]>>);
-
-    let hr_fnptr = Box::new(Foo::<for<'a> fn(&'a u8)>(wrapper.0));
-    let lr_fnptr = hr_fnptr as Box<Foo<fn(&'static u8)>>;
-    let mut any = lr_fnptr as Box<dyn GetInner<Assoc = String>>;
-
-    let evil_string = any.muahaha();
-    drop(evil_string);
-}
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
index 67afa50bd58..8a0eb36701a 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
@@ -22,7 +22,7 @@ fn main() -> () {
     let _24: i32;
     let mut _26: *const i32;
     let _27: ();
-    let mut _29: [closure@main::{closure#0}];
+    let mut _29: for<'a> fn(&'a i32) -> &'a i32;
     scope 1 {
         debug x => _1;
         let _3: &mut i32;
@@ -106,7 +106,8 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
index 467b4493bf3..ac1fe555900 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
@@ -22,7 +22,7 @@ fn main() -> () {
     let _24: i32;
     let mut _26: *const i32;
     let _27: ();
-    let mut _29: [closure@main::{closure#0}];
+    let mut _29: for<'a> fn(&'a i32) -> &'a i32;
     scope 1 {
         debug x => _1;
         let _3: &mut i32;
@@ -106,7 +106,8 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);