diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 0425c53d9dc3c..8317206c69adb 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -289,6 +289,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
             | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, operand)
             }
+            Rvalue::VirtualRef(ref place) => {
+                let op = &Operand::Copy(*place);
+                self.consume_operand(location, op);
+            }
 
             Rvalue::Len(place) | Rvalue::Discriminant(place) => {
                 let af = match *rvalue {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 8ef2974c37232..9d8c5fe6d41d2 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1224,6 +1224,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, (operand, span), flow_state)
             }
+            Rvalue::VirtualRef(place) => {
+                self.access_place(
+                    location,
+                    (place, span),
+                    (Deep, Read(ReadKind::Copy)),
+                    LocalMutationIsAllowed::No,
+                    flow_state,
+                );
+
+                // Finally, check if path was already moved.
+                self.check_if_path_or_subpath_is_moved(
+                    location,
+                    InitializationRequiringAction::Use,
+                    (place.as_ref(), span),
+                    flow_state,
+                );
+            }
 
             Rvalue::Len(place) | Rvalue::Discriminant(place) => {
                 let af = match *rvalue {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 355254fe9429b..ed72f17740d3c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2278,6 +2278,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
                 self.check_operand(operand, location);
             }
+            Rvalue::VirtualRef(place) => {
+                let op = &Operand::Copy(*place);
+                self.check_operand(op, location);
+            }
 
             Rvalue::BinaryOp(_, box (left, right))
             | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
@@ -2308,6 +2312,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | Rvalue::BinaryOp(..)
             | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
+            | Rvalue::VirtualRef(..)
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..) => None,
 
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index cad301812123b..9e50d33486cf2 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -1,11 +1,10 @@
-use crate::assert::expr_if_not;
 use rustc_ast::{
     attr,
     ptr::P,
     token,
     tokenstream::{DelimSpan, TokenStream, TokenTree},
-    BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path,
-    PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID,
+    BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability,
+    Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -16,11 +15,19 @@ use rustc_span::{
 };
 
 pub(super) struct Context<'cx, 'a> {
+    // An optimization.
+    //
+    // Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the
+    // `assert!` expression fails rather than copied on-the-fly.
+    best_case_captures: Vec<Stmt>,
     // Top-level `let captureN = Capture::new()` statements
     capture_decls: Vec<Capture>,
     cx: &'cx ExtCtxt<'a>,
     // Formatting string used for debugging
     fmt_string: String,
+    // If the current expression being visited consumes itself. Used to construct
+    // `best_case_captures`.
+    is_consumed: bool,
     // Top-level `let __local_bindN = &expr` statements
     local_bind_decls: Vec<Stmt>,
     // Used to avoid capturing duplicated paths
@@ -36,9 +43,11 @@ pub(super) struct Context<'cx, 'a> {
 impl<'cx, 'a> Context<'cx, 'a> {
     pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
         Self {
+            best_case_captures: <_>::default(),
             capture_decls: <_>::default(),
             cx,
             fmt_string: <_>::default(),
+            is_consumed: true,
             local_bind_decls: <_>::default(),
             paths: <_>::default(),
             span,
@@ -69,14 +78,22 @@ impl<'cx, 'a> Context<'cx, 'a> {
         self.manage_cond_expr(&mut cond_expr);
         let initial_imports = self.build_initial_imports();
         let panic = self.build_panic(&expr_str, panic_path);
+        let cond_expr_with_unlikely = self.build_unlikely(cond_expr);
+
+        let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self;
 
-        let Self { capture_decls, cx, local_bind_decls, span, .. } = self;
+        let mut assert_then_stmts = Vec::with_capacity(2);
+        assert_then_stmts.extend(best_case_captures);
+        assert_then_stmts.push(self.cx.stmt_expr(panic));
+        let assert_then = self.cx.block(span, assert_then_stmts);
 
         let mut stmts = Vec::with_capacity(4);
         stmts.push(initial_imports);
         stmts.extend(capture_decls.into_iter().map(|c| c.decl));
         stmts.extend(local_bind_decls);
-        stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None)));
+        stmts.push(
+            cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))),
+        );
         cx.expr_block(cx.block(span, stmts))
     }
 
@@ -115,6 +132,16 @@ impl<'cx, 'a> Context<'cx, 'a> {
         )
     }
 
+    /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely`
+    fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> {
+        let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]);
+        self.cx.expr_call(
+            self.span,
+            self.cx.expr_path(self.cx.path(self.span, unlikely_path)),
+            vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))],
+        )
+    }
+
     /// The necessary custom `panic!(...)` expression.
     ///
     /// panic!(
@@ -167,17 +194,39 @@ impl<'cx, 'a> Context<'cx, 'a> {
     /// See [Self::manage_initial_capture] and [Self::manage_try_capture]
     fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
         match (*expr).kind {
-            ExprKind::AddrOf(_, _, ref mut local_expr) => {
-                self.manage_cond_expr(local_expr);
+            ExprKind::AddrOf(_, mutability, ref mut local_expr) => {
+                self.with_is_consumed_management(
+                    matches!(mutability, Mutability::Mut),
+                    |this| this.manage_cond_expr(local_expr)
+                );
             }
             ExprKind::Array(ref mut local_exprs) => {
                 for local_expr in local_exprs {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Binary(_, ref mut lhs, ref mut rhs) => {
-                self.manage_cond_expr(lhs);
-                self.manage_cond_expr(rhs);
+            ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => {
+                self.with_is_consumed_management(
+                    matches!(
+                        op.node,
+                        BinOpKind::Add
+                            | BinOpKind::And
+                            | BinOpKind::BitAnd
+                            | BinOpKind::BitOr
+                            | BinOpKind::BitXor
+                            | BinOpKind::Div
+                            | BinOpKind::Mul
+                            | BinOpKind::Or
+                            | BinOpKind::Rem
+                            | BinOpKind::Shl
+                            | BinOpKind::Shr
+                            | BinOpKind::Sub
+                    ),
+                    |this| {
+                        this.manage_cond_expr(lhs);
+                        this.manage_cond_expr(rhs);
+                    }
+                );
             }
             ExprKind::Call(_, ref mut local_exprs) => {
                 for local_expr in local_exprs {
@@ -228,8 +277,11 @@ impl<'cx, 'a> Context<'cx, 'a> {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Unary(_, ref mut local_expr) => {
-                self.manage_cond_expr(local_expr);
+            ExprKind::Unary(un_op, ref mut local_expr) => {
+                self.with_is_consumed_management(
+                    matches!(un_op, UnOp::Neg | UnOp::Not),
+                    |this| this.manage_cond_expr(local_expr)
+                );
             }
             // Expressions that are not worth or can not be captured.
             //
@@ -337,9 +389,23 @@ impl<'cx, 'a> Context<'cx, 'a> {
             ))
             .add_trailing_semicolon();
         let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind));
-        let ret = self.cx.stmt_expr(local_bind_path);
-        let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]));
-        *expr = self.cx.expr_deref(self.span, block);
+        let rslt = if self.is_consumed {
+            let ret = self.cx.stmt_expr(local_bind_path);
+            self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]))
+        } else {
+            self.best_case_captures.push(try_capture_call);
+            local_bind_path
+        };
+        *expr = self.cx.expr_deref(self.span, rslt);
+    }
+
+    // Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then
+    // sets the internal `is_consumed` back to its original value.
+    fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) {
+        let prev_is_consumed = self.is_consumed;
+        self.is_consumed = curr_is_consumed;
+        f(self);
+        self.is_consumed = prev_is_consumed;
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index fbe830b2b1030..9f40b5264576c 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -503,6 +503,11 @@ fn codegen_stmt<'tcx>(
                     let val = codegen_operand(fx, operand);
                     lval.write_cvalue(fx, val);
                 }
+                Rvalue::VirtualRef(place) => {
+                    let cplace = codegen_place(fx, place);
+                    let val = cplace.to_cvalue(fx);
+                    lval.write_cvalue(fx, val)
+                }
                 Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
                     let place = codegen_place(fx, place);
                     let ref_ = place.place_ref(fx, lval.layout());
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 81c1897694ce6..30fc4db6e89bf 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -8,6 +8,7 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_middle::mir;
+use rustc_middle::mir::Operand;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
@@ -401,6 +402,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_place_to_pointer(bx, place, mk_ref)
             }
 
+            mir::Rvalue::VirtualRef(place) => {
+                let operand = self.codegen_operand(&mut bx, &Operand::Copy(place));
+                (bx, operand)
+            }
             mir::Rvalue::AddressOf(mutability, place) => {
                 let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
                     tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability })
@@ -755,6 +760,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
         match *rvalue {
             mir::Rvalue::Ref(..) |
+            mir::Rvalue::VirtualRef(..) |
             mir::Rvalue::AddressOf(..) |
             mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 98f69456e49aa..06a2f40daef4f 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -172,6 +172,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.copy_op(&op, &dest)?;
             }
 
+            VirtualRef(ref place) => {
+                let op = self.eval_place_to_op(*place, Some(dest.layout))?;
+                self.copy_op(&op, &dest)?;
+            }
+
             BinaryOp(bin_op, box (ref left, ref right)) => {
                 let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                 let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 069fbed36ee3a..d216cde9d2886 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -445,6 +445,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
 
             Rvalue::Use(_)
+            | Rvalue::VirtualRef(..)
             | Rvalue::Repeat(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(_)
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 6e5a0c813ac20..84eddbb355cfa 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -260,6 +260,8 @@ where
             in_place::<Q, _>(cx, in_local, place.as_ref())
         }
 
+        Rvalue::VirtualRef(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
+
         Rvalue::Use(operand)
         | Rvalue::Repeat(operand, _)
         | Rvalue::UnaryOp(_, operand)
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index fd7febc17a3a7..e6c9f57e0d8c8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -199,6 +199,7 @@ where
             mir::Rvalue::Cast(..)
             | mir::Rvalue::ShallowInitBox(..)
             | mir::Rvalue::Use(..)
+            | mir::Rvalue::VirtualRef(..)
             | mir::Rvalue::ThreadLocalRef(..)
             | mir::Rvalue::Repeat(..)
             | mir::Rvalue::Len(..)
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 3595a488d0c5b..2b4bdf5b5f28a 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -494,6 +494,10 @@ impl<'tcx> Validator<'_, 'tcx> {
             Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
                 self.validate_operand(operand)?;
             }
+            Rvalue::VirtualRef(place) => {
+                let op = &Operand::Copy(*place);
+                self.validate_operand(op)?
+            }
 
             Rvalue::Discriminant(place) | Rvalue::Len(place) => {
                 self.validate_place(place.as_ref())?
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index d830000b65f69..1f3cb401314d6 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -92,7 +92,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
                     .borrow_mut()
                     .unwrap_region_constraints()
                     .opportunistic_resolve_var(rid);
-                self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
+                TypeFolder::tcx(self).reuse_or_mk_region(r, ty::ReVar(resolved))
             }
             _ => r,
         }
@@ -179,15 +179,13 @@ struct FullTypeResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
     type Error = FixupError<'tcx>;
 
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
-}
 
-impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
     fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.needs_infer() {
             Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 3f5b16d5ea5f7..6684745c8cfa2 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -159,6 +159,8 @@ pub enum MirPhase {
     /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
     /// query.
     ConstsPromoted = 2,
+    /// After this projections may only contain deref projections as the first element.
+    Derefered = 3,
     /// Beginning with this phase, the following variants are disallowed:
     /// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace)
     /// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind)
@@ -173,9 +175,7 @@ pub enum MirPhase {
     /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
     /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
     /// are allowed for non-`Copy` types.
-    DropsLowered = 3,
-    /// After this projections may only contain deref projections as the first element.
-    Derefered = 4,
+    DropsLowered = 4,
     /// Beginning with this phase, the following variant is disallowed:
     /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
     ///
@@ -1174,6 +1174,15 @@ impl<'tcx> LocalDecl<'tcx> {
         }
     }
 
+    /// Returns `true` if this is a DerefTemp
+    pub fn is_deref_temp(&self) -> bool {
+        match self.local_info {
+            Some(box LocalInfo::DerefTemp) => return true,
+            _ => (),
+        }
+        return false;
+    }
+
     /// Returns `true` is the local is from a compiler desugaring, e.g.,
     /// `__next` from a `for` loop.
     #[inline]
@@ -2616,6 +2625,15 @@ pub enum Rvalue<'tcx> {
     /// initialized but its content as uninitialized. Like other pointer casts, this in general
     /// affects alias analysis.
     ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
+
+    /// A virtual ref is equivalent to a read from a reference/pointer at the
+    /// codegen level, but is treated specially by drop elaboration. When such a read happens, it
+    /// is guaranteed that the only use of the returned value is a deref operation, immediately
+    /// followed by one or more projections. Drop elaboration treats this virtual ref as if the
+    /// read never happened and just projects further. This allows simplifying various MIR
+    /// optimizations and codegen backends that previously had to handle deref operations anywhere
+    /// in a place.
+    VirtualRef(Place<'tcx>),
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -2632,6 +2650,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
 
             Rvalue::Use(_)
+            | Rvalue::VirtualRef(_)
             | Rvalue::Repeat(_, _)
             | Rvalue::Ref(_, _, _)
             | Rvalue::ThreadLocalRef(_)
@@ -2809,6 +2828,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 };
                 write!(fmt, "&{}{}{:?}", region, kind_str, place)
             }
+            VirtualRef(ref place) => write!(fmt, "virt {:#?}", place),
 
             AddressOf(mutability, ref place) => {
                 let kind_str = match mutability {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index c93b7a9550229..8ec04e61a2e0b 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -211,6 +211,7 @@ impl<'tcx> Rvalue<'tcx> {
                 }
             },
             Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
+            Rvalue::VirtualRef(ref place) => place.ty(local_decls, tcx).ty,
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 4201b2d11ce2a..f20c0101d9fd5 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -184,6 +184,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             Ref(region, bk, place) => {
                 Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
             }
+            VirtualRef(place) => VirtualRef(place.try_fold_with(folder)?),
             AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
             Len(place) => Len(place.try_fold_with(folder)?),
             Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
@@ -235,6 +236,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
                 region.visit_with(visitor)?;
                 place.visit_with(visitor)
             }
+            VirtualRef(ref place) => place.visit_with(visitor),
             AddressOf(_, ref place) => place.visit_with(visitor),
             Len(ref place) => place.visit_with(visitor),
             Cast(_, ref op, ty) => {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 5ce92d127f3db..9aea4ae61d44a 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -670,6 +670,13 @@ macro_rules! make_mir_visitor {
                         };
                         self.visit_place(path, ctx, location);
                     }
+                    Rvalue::VirtualRef(place) => {
+                        self.visit_place(
+                            place,
+                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
+                            location
+                        );
+                    }
 
                     Rvalue::AddressOf(m, path) => {
                         let ctx = match m {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 31b8fa1ce956f..b1b8bc13e2f13 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -86,7 +86,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     /// A convenient alternative to `try_fold_with` for use with infallible
     /// folders. Do not override this method, to ensure coherence with
     /// `try_fold_with`.
-    fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         self.try_fold_with(folder).into_ok()
     }
 
@@ -216,7 +216,7 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
     /// A convenient alternative to `try_super_fold_with` for use with
     /// infallible folders. Do not override this method, to ensure coherence
     /// with `try_super_fold_with`.
-    fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         self.try_super_fold_with(folder).into_ok()
     }
 
@@ -229,70 +229,46 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
 }
 
-/// This trait is implemented for every folding traversal. There is a fold
-/// method defined for every type of interest. Each such method has a default
-/// that does an "identity" fold. Implementations of these methods often fall
-/// back to a `super_fold_with` method if the primary argument doesn't
-/// satisfy a particular condition.
+/// This trait is implemented for every infallible folding traversal. There is
+/// a fold method defined for every type of interest. Each such method has a
+/// default that does an "identity" fold. Implementations of these methods
+/// often fall back to a `super_fold_with` method if the primary argument
+/// doesn't satisfy a particular condition.
 ///
-/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
-/// associated type is something other than the default `!`) then
-/// [`FallibleTypeFolder`] should be implemented manually. Otherwise,
-/// a blanket implementation of [`FallibleTypeFolder`] will defer to
+/// A blanket implementation of [`FallibleTypeFolder`] will defer to
 /// the infallible methods of this trait to ensure that the two APIs
 /// are coherent.
-pub trait TypeFolder<'tcx>: Sized {
-    type Error = !;
-
+pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
     fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
     where
         T: TypeFoldable<'tcx>,
-        Self: TypeFolder<'tcx, Error = !>,
     {
         t.super_fold_with(self)
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         t.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r.super_fold_with(self)
     }
 
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         c.super_fold_with(self)
     }
 
-    fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> {
         uv.super_fold_with(self)
     }
 
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
         p.super_fold_with(self)
     }
 
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx>
-    where
-        Self: TypeFolder<'tcx, Error = !>,
-    {
+    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
         bug!("most type folders should not be folding MIR datastructures: {:?}", c)
     }
 }
@@ -304,7 +280,11 @@ pub trait TypeFolder<'tcx>: Sized {
 /// A blanket implementation of this trait (that defers to the relevant
 /// method of [`TypeFolder`]) is provided for all infallible folders in
 /// order to ensure the two APIs are coherent.
-pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
+pub trait FallibleTypeFolder<'tcx>: Sized {
+    type Error;
+
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+
     fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
     where
         T: TypeFoldable<'tcx>,
@@ -350,45 +330,48 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
 // delegates to infallible methods to ensure coherence.
 impl<'tcx, F> FallibleTypeFolder<'tcx> for F
 where
-    F: TypeFolder<'tcx, Error = !>,
+    F: TypeFolder<'tcx>,
 {
-    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+    type Error = !;
+
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        TypeFolder::tcx(self)
+    }
+
+    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
     where
         T: TypeFoldable<'tcx>,
     {
         Ok(self.fold_binder(t))
     }
 
-    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
         Ok(self.fold_ty(t))
     }
 
-    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
         Ok(self.fold_region(r))
     }
 
-    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
         Ok(self.fold_const(c))
     }
 
     fn try_fold_unevaluated(
         &mut self,
         c: ty::Unevaluated<'tcx>,
-    ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
+    ) -> Result<ty::Unevaluated<'tcx>, !> {
         Ok(self.fold_unevaluated(c))
     }
 
-    fn try_fold_predicate(
-        &mut self,
-        p: ty::Predicate<'tcx>,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+    fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
         Ok(self.fold_predicate(p))
     }
 
     fn try_fold_mir_const(
         &mut self,
         c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+    ) -> Result<mir::ConstantKind<'tcx>, !> {
         Ok(self.fold_mir_const(c))
     }
 }
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 9bbbd7e2f7c5e..66a0a192a87c1 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -228,15 +228,13 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
     type Error = NormalizationError<'tcx>;
 
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
-}
 
-impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
             Ok(t) => Ok(t.expect_ty()),
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index ad2898ccd67ba..1417c8a511c24 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -705,7 +705,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
             return val;
         }
 
-        let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed);
+        let result = ty::fold::shift_vars(TypeFolder::tcx(self), val, self.binders_passed);
         debug!("shift_vars: shifted result = {:?}", result);
 
         result
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 627fe3f7f576b..4681f942f92ff 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -102,7 +102,8 @@ where
             | mir::Rvalue::NullaryOp(..)
             | mir::Rvalue::UnaryOp(..)
             | mir::Rvalue::Discriminant(..)
-            | mir::Rvalue::Aggregate(..) => {}
+            | mir::Rvalue::Aggregate(..)
+            | mir::Rvalue::VirtualRef(..) => {}
         }
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index e4c130f0807dd..5793a286bd03d 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -38,6 +38,7 @@ pub mod impls;
 pub mod move_paths;
 pub mod rustc_peek;
 pub mod storage;
+pub mod un_derefer;
 
 pub(crate) mod indexes {
     pub(crate) use super::move_paths::MovePathIndex;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index b08cb50f77aed..75b0a68e65802 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,3 +1,4 @@
+use crate::un_derefer::UnDerefer;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::tcx::RvalueInitializationState;
 use rustc_middle::mir::*;
@@ -19,6 +20,7 @@ struct MoveDataBuilder<'a, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     data: MoveData<'tcx>,
     errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
+    un_derefer: UnDerefer<'tcx>,
 }
 
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -32,6 +34,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             tcx,
             param_env,
             errors: Vec::new(),
+            un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() },
             data: MoveData {
                 moves: IndexVec::new(),
                 loc_map: LocationMap::new(body),
@@ -94,6 +97,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     ///
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
+        if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) {
+            return self.move_path_for(new_place);
+        }
+
         debug!("lookup({:?})", place);
         let mut base = self.builder.data.rev_lookup.locals[place.local];
 
@@ -224,6 +231,8 @@ pub(super) fn gather_moves<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
 ) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
     let mut builder = MoveDataBuilder::new(body, tcx, param_env);
+    let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() };
+    un_derefer.ref_finder(body);
 
     builder.gather_args();
 
@@ -276,6 +285,10 @@ struct Gatherer<'b, 'a, 'tcx> {
 impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
         match &stmt.kind {
+            StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => {
+                assert!(place.projection.is_empty());
+                self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed);
+            }
             StatementKind::Assign(box (place, rval)) => {
                 self.create_move_path(*place);
                 if let RvalueInitializationState::Shallow = rval.initialization_state() {
@@ -294,7 +307,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             }
             StatementKind::StorageLive(_) => {}
             StatementKind::StorageDead(local) => {
-                self.gather_move(Place::from(*local));
+                // DerefTemp locals (results of VirtualRef) don't actually move anything.
+                if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) {
+                    self.gather_move(Place::from(*local));
+                }
             }
             StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => {
                 span_bug!(
@@ -328,6 +344,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                     self.gather_operand(operand);
                 }
             }
+            Rvalue::VirtualRef(..) => unreachable!(),
             Rvalue::Ref(..)
             | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
@@ -439,6 +456,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
 
     fn gather_move(&mut self, place: Place<'tcx>) {
         debug!("gather_move({:?}, {:?})", self.loc, place);
+        if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) {
+            self.gather_move(new_place);
+            return;
+        }
 
         if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
             **place.projection
@@ -494,6 +515,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
         debug!("gather_init({:?}, {:?})", self.loc, place);
 
+        if let Some(new_place) = self.builder.un_derefer.derefer(place) {
+            self.gather_init(new_place.as_ref(), kind);
+            return;
+        }
+
         let mut place = place;
 
         // Check if we are assigning into a field of a union, if so, lookup the place
diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs
new file mode 100644
index 0000000000000..4c45d385707b1
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs
@@ -0,0 +1,31 @@
+use rustc_data_structures::stable_map::FxHashMap;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+/// Used for reverting changes made by `DerefSeparator`
+pub struct UnDerefer<'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+    pub derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
+}
+
+impl<'tcx> UnDerefer<'tcx> {
+    pub fn derefer(&self, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> {
+        let reffed = self.derefer_sidetable.get(&place.local)?;
+
+        let new_place = reffed.project_deeper(place.projection, self.tcx);
+        Some(new_place)
+    }
+
+    pub fn ref_finder(&mut self, body: &Body<'tcx>) {
+        for (_bb, data) in body.basic_blocks().iter_enumerated() {
+            for stmt in data.statements.iter() {
+                match stmt.kind {
+                    StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => {
+                        self.derefer_sidetable.insert(place.local, reffed);
+                    }
+                    _ => (),
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 0495439385bee..000abbee51e38 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -57,17 +57,6 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
     }
 }
 
-/// Determines whether or not this LocalDecl is temp, if not it needs retagging.
-fn is_not_temp<'tcx>(local_decl: &LocalDecl<'tcx>) -> bool {
-    if let Some(local_info) = &local_decl.local_info {
-        match local_info.as_ref() {
-            LocalInfo::DerefTemp => return false,
-            _ => (),
-        };
-    }
-    return true;
-}
-
 impl<'tcx> MirPass<'tcx> for AddRetag {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.opts.debugging_opts.mir_emit_retag
@@ -84,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
             // a temporary and retag on that.
             is_stable(place.as_ref())
                 && may_be_reference(place.ty(&*local_decls, tcx).ty)
-                && is_not_temp(&local_decls[place.local])
+                && !local_decls[place.local].is_deref_temp()
         };
         let place_base_raw = |place: &Place<'tcx>| {
             // If this is a `Deref`, get the type of what we are deref'ing.
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 412a5b4fc9104..8b17b70e196f8 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -616,6 +616,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // There's no other checking to do at this time.
             Rvalue::Aggregate(..)
             | Rvalue::Use(..)
+            | Rvalue::VirtualRef(..)
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 15ad13009e59a..b29440f17e45f 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -683,6 +683,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // There's no other checking to do at this time.
             Rvalue::Aggregate(..)
             | Rvalue::Use(..)
+            | Rvalue::VirtualRef(..)
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index bfb3ad1be2734..badb092fb25db 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -35,6 +35,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
                     last_deref_idx = idx;
                 }
             }
+
             for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
                 if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref {
                     let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
@@ -54,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
                     self.patcher.add_assign(
                         loc,
                         Place::from(temp),
-                        Rvalue::Use(Operand::Move(deref_place)),
+                        Rvalue::VirtualRef(deref_place),
                     );
                     place_local = temp;
                     last_len = p_ref.projection.len();
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index e0e27c53f1822..d11f514ee1ae2 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,3 +1,4 @@
+use crate::deref_separator::deref_finder;
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
@@ -9,6 +10,7 @@ use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyl
 use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 use rustc_mir_dataflow::on_lookup_result_bits;
+use rustc_mir_dataflow::un_derefer::UnDerefer;
 use rustc_mir_dataflow::MoveDataParamEnv;
 use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -26,6 +28,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
 
+        let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() };
+        un_derefer.ref_finder(body);
         let def_id = body.source.def_id();
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
         let move_data = match MoveData::gather_moves(body, tcx, param_env) {
@@ -41,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
         let elaborate_patch = {
             let body = &*body;
             let env = MoveDataParamEnv { move_data, param_env };
-            let dead_unwinds = find_dead_unwinds(tcx, body, &env);
+            let dead_unwinds = find_dead_unwinds(tcx, body, &env, &un_derefer);
 
             let inits = MaybeInitializedPlaces::new(tcx, body, &env)
                 .into_engine(tcx, body)
@@ -65,10 +69,12 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
                 init_data: InitializationData { inits, uninits },
                 drop_flags: Default::default(),
                 patch: MirPatch::new(body),
+                un_derefer: un_derefer,
             }
             .elaborate()
         };
         elaborate_patch.apply(body);
+        deref_finder(tcx, body);
     }
 }
 
@@ -79,6 +85,7 @@ fn find_dead_unwinds<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     env: &MoveDataParamEnv<'tcx>,
+    und: &UnDerefer<'tcx>,
 ) -> BitSet<BasicBlock> {
     debug!("find_dead_unwinds({:?})", body.span);
     // We only need to do this pass once, because unwind edges can only
@@ -92,7 +99,9 @@ fn find_dead_unwinds<'tcx>(
     for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
         let place = match bb_data.terminator().kind {
             TerminatorKind::Drop { ref place, unwind: Some(_), .. }
-            | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place,
+            | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => {
+                und.derefer(place.as_ref()).unwrap_or(*place)
+            }
             _ => continue,
         };
 
@@ -256,6 +265,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
     init_data: InitializationData<'a, 'tcx>,
     drop_flags: FxHashMap<MovePathIndex, Local>,
     patch: MirPatch<'tcx>,
+    un_derefer: UnDerefer<'tcx>,
 }
 
 impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
@@ -298,7 +308,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             let terminator = data.terminator();
             let place = match terminator.kind {
                 TerminatorKind::Drop { ref place, .. }
-                | TerminatorKind::DropAndReplace { ref place, .. } => place,
+                | TerminatorKind::DropAndReplace { ref place, .. } => {
+                    self.un_derefer.derefer(place.as_ref()).unwrap_or(*place)
+                }
                 _ => continue,
             };
 
@@ -312,12 +324,17 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 LookupResult::Parent(None) => continue,
                 LookupResult::Parent(Some(parent)) => {
                     let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
+
+                    if self.body.local_decls[place.local].is_deref_temp() {
+                        continue;
+                    }
+
                     if maybe_dead {
                         self.tcx.sess.delay_span_bug(
                             terminator.source_info.span,
                             &format!(
                                 "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
-                                bb, place, path,
+                                bb, place, path
                             ),
                         );
                     }
@@ -348,7 +365,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
             let resume_block = self.patch.resume_block();
             match terminator.kind {
-                TerminatorKind::Drop { place, target, unwind } => {
+                TerminatorKind::Drop { mut place, target, unwind } => {
+                    if let Some(new_place) = self.un_derefer.derefer(place.as_ref()) {
+                        place = new_place;
+                    }
+
                     self.init_data.seek_before(loc);
                     match self.move_data().rev_lookup.find(place.as_ref()) {
                         LookupResult::Exact(path) => elaborate_drop(
@@ -372,9 +393,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                         }
                     }
                 }
-                TerminatorKind::DropAndReplace { place, ref value, target, unwind } => {
+                TerminatorKind::DropAndReplace { mut place, ref value, target, unwind } => {
                     assert!(!data.is_cleanup);
 
+                    if let Some(new_place) = self.un_derefer.derefer(place.as_ref()) {
+                        place = new_place;
+                    }
                     self.elaborate_replace(loc, place, value, target, unwind);
                 }
                 _ => continue,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b7caa61ef07a7..37014497c6887 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -415,6 +415,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &cleanup_post_borrowck::CleanupNonCodegenStatements,
         &simplify::SimplifyCfg::new("early-opt"),
+        &deref_separator::Derefer,
         // These next passes must be executed together
         &add_call_guards::CriticalCallEdges,
         &elaborate_drops::ElaborateDrops,
@@ -427,7 +428,6 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
-        &deref_separator::Derefer,
         &elaborate_box_derefs::ElaborateBoxDerefs,
         &add_retag::AddRetag,
         &lower_intrinsics::LowerIntrinsics,
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 33ea1c4ba2f59..ec4bff30f95cd 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -218,6 +218,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
                         // These rvalues move the place to track
                         Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _)
                         | Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
+                        | Rvalue::VirtualRef(place)
                         | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place))
                         | Rvalue::Discriminant(place) => tracked_place = place,
                     }
@@ -279,6 +280,7 @@ fn find_determining_place<'tcx>(
                     // that may be const in the predecessor
                     Rvalue::Use(Operand::Move(new) | Operand::Copy(new))
                     | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new))
+                    | Rvalue::VirtualRef(new)
                     | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _)
                     | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _)
                     | Rvalue::Discriminant(new)
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index f1087db09d132..1b94c59b55f09 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -1,5 +1,5 @@
 use super::{cvs, wasm_base};
-use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions};
+use super::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut options = wasm_base::options();
@@ -26,6 +26,7 @@ pub fn target() -> Target {
         // functionality, and a .wasm file.
         exe_suffix: ".js".into(),
         linker: None,
+        relocation_model: RelocModel::Pic,
         panic_strategy: PanicStrategy::Unwind,
         no_default_libraries: false,
         post_link_args,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index b80a27eb07d06..7f15b683fda3e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
 use rustc_middle::mir;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 
@@ -162,15 +162,13 @@ struct QueryNormalizer<'cx, 'tcx> {
     universes: Vec<Option<ty::UniverseIndex>>,
 }
 
-impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
     type Error = NoSolution;
 
     fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
-}
 
-impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
     fn try_fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index f46997b807ab2..cd43e1cadae9a 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -184,6 +184,11 @@ pub struct DirEntry(fs_imp::DirEntry);
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OpenOptions(fs_imp::OpenOptions);
 
+/// Representation of the various timestamps on a file.
+#[derive(Copy, Clone, Debug, Default)]
+#[unstable(feature = "file_set_times", issue = "98245")]
+pub struct FileTimes(fs_imp::FileTimes);
+
 /// Representation of the various permissions on a file.
 ///
 /// This module only currently provides one bit of information,
@@ -590,6 +595,58 @@ impl File {
     pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
         self.inner.set_permissions(perm.0)
     }
+
+    /// Changes the timestamps of the underlying file.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `futimens` function on Unix (falling back to
+    /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the user lacks permission to change timestamps on the
+    /// underlying file. It may also return an error in other os-specific unspecified cases.
+    ///
+    /// This function may return an error if the operating system lacks support to change one or
+    /// more of the timestamps set in the `FileTimes` structure.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_set_times)]
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     use std::fs::{self, File, FileTimes};
+    ///
+    ///     let src = fs::metadata("src")?;
+    ///     let dest = File::options().write(true).open("dest")?;
+    ///     let times = FileTimes::new()
+    ///         .set_accessed(src.accessed()?)
+    ///         .set_modified(src.modified()?);
+    ///     dest.set_times(times)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_set_times", issue = "98245")]
+    #[doc(alias = "futimens")]
+    #[doc(alias = "futimes")]
+    #[doc(alias = "SetFileTime")]
+    pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+        self.inner.set_times(times.0)
+    }
+
+    /// Changes the modification time of the underlying file.
+    ///
+    /// This is an alias for `set_times(FileTimes::new().set_modified(time))`.
+    #[unstable(feature = "file_set_times", issue = "98245")]
+    #[inline]
+    pub fn set_modified(&self, time: SystemTime) -> io::Result<()> {
+        self.set_times(FileTimes::new().set_modified(time))
+    }
 }
 
 // In addition to the `impl`s here, `File` also has `impl`s for
@@ -1246,6 +1303,30 @@ impl FromInner<fs_imp::FileAttr> for Metadata {
     }
 }
 
+impl FileTimes {
+    /// Create a new `FileTimes` with no times set.
+    ///
+    /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps.
+    #[unstable(feature = "file_set_times", issue = "98245")]
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Set the last access time of a file.
+    #[unstable(feature = "file_set_times", issue = "98245")]
+    pub fn set_accessed(mut self, t: SystemTime) -> Self {
+        self.0.set_accessed(t.into_inner());
+        self
+    }
+
+    /// Set the last modified time of a file.
+    #[unstable(feature = "file_set_times", issue = "98245")]
+    pub fn set_modified(mut self, t: SystemTime) -> Self {
+        self.0.set_modified(t.into_inner());
+        self
+    }
+}
+
 impl Permissions {
     /// Returns `true` if these permissions describe a readonly (unwritable) file.
     ///
diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs
index f99ee4fa897ea..5eb14bb7e534b 100644
--- a/library/std/src/sys/itron/abi.rs
+++ b/library/std/src/sys/itron/abi.rs
@@ -30,15 +30,32 @@ pub type ER = int_t;
 /// Error code type, `ID` on success
 pub type ER_ID = int_t;
 
+/// Service call operational mode
+pub type MODE = uint_t;
+
+/// OR waiting condition for an eventflag
+pub const TWF_ORW: MODE = 0x01;
+
+/// Object attributes
+pub type ATR = uint_t;
+
+/// FIFO wait order
+pub const TA_FIFO: ATR = 0;
+/// Only one task is allowed to be in the waiting state for the eventflag
+pub const TA_WSGL: ATR = 0;
+/// The eventflag’s bit pattern is cleared when a task is released from the
+/// waiting state for that eventflag.
+pub const TA_CLR: ATR = 0x04;
+
+/// Bit pattern of an eventflag
+pub type FLGPTN = uint_t;
+
 /// Task or interrupt priority
 pub type PRI = int_t;
 
 /// The special value of `PRI` representing the current task's priority.
 pub const TPRI_SELF: PRI = 0;
 
-/// Object attributes
-pub type ATR = uint_t;
-
 /// Use the priority inheritance protocol
 #[cfg(target_os = "solid_asp3")]
 pub const TA_INHERIT: ATR = 0x02;
@@ -90,6 +107,13 @@ pub struct T_CSEM {
     pub maxsem: uint_t,
 }
 
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CFLG {
+    pub flgatr: ATR,
+    pub iflgptn: FLGPTN,
+}
+
 #[derive(Clone, Copy)]
 #[repr(C)]
 pub struct T_CMTX {
@@ -139,6 +163,24 @@ extern "C" {
     pub fn sns_dsp() -> bool_t;
     #[link_name = "__asp3_get_tim"]
     pub fn get_tim(p_systim: *mut SYSTIM) -> ER;
+    #[link_name = "__asp3_acre_flg"]
+    pub fn acre_flg(pk_cflg: *const T_CFLG) -> ER_ID;
+    #[link_name = "__asp3_del_flg"]
+    pub fn del_flg(flgid: ID) -> ER;
+    #[link_name = "__asp3_set_flg"]
+    pub fn set_flg(flgid: ID, setptn: FLGPTN) -> ER;
+    #[link_name = "__asp3_clr_flg"]
+    pub fn clr_flg(flgid: ID, clrptn: FLGPTN) -> ER;
+    #[link_name = "__asp3_wai_flg"]
+    pub fn wai_flg(flgid: ID, waiptn: FLGPTN, wfmode: MODE, p_flgptn: *mut FLGPTN) -> ER;
+    #[link_name = "__asp3_twai_flg"]
+    pub fn twai_flg(
+        flgid: ID,
+        waiptn: FLGPTN,
+        wfmode: MODE,
+        p_flgptn: *mut FLGPTN,
+        tmout: TMO,
+    ) -> ER;
     #[link_name = "__asp3_acre_mtx"]
     pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID;
     #[link_name = "__asp3_del_mtx"]
diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs
new file mode 100644
index 0000000000000..e432edd207754
--- /dev/null
+++ b/library/std/src/sys/itron/wait_flag.rs
@@ -0,0 +1,72 @@
+use crate::mem::MaybeUninit;
+use crate::time::Duration;
+
+use super::{
+    abi,
+    error::{expect_success, fail},
+    time::with_tmos,
+};
+
+const CLEAR: abi::FLGPTN = 0;
+const RAISED: abi::FLGPTN = 1;
+
+/// A thread parking primitive that is not susceptible to race conditions,
+/// but provides no atomic ordering guarantees and allows only one `raise` per wait.
+pub struct WaitFlag {
+    flag: abi::ID,
+}
+
+impl WaitFlag {
+    /// Creates a new wait flag.
+    pub fn new() -> WaitFlag {
+        let flag = expect_success(
+            unsafe {
+                abi::acre_flg(&abi::T_CFLG {
+                    flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR,
+                    iflgptn: CLEAR,
+                })
+            },
+            &"acre_flg",
+        );
+
+        WaitFlag { flag }
+    }
+
+    /// Wait for the wait flag to be raised.
+    pub fn wait(&self) {
+        let mut token = MaybeUninit::uninit();
+        expect_success(
+            unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) },
+            &"wai_flg",
+        );
+    }
+
+    /// Wait for the wait flag to be raised or the timeout to occur.
+    ///
+    /// Returns whether the flag was raised (`true`) or the operation timed out (`false`).
+    pub fn wait_timeout(&self, dur: Duration) -> bool {
+        let mut token = MaybeUninit::uninit();
+        let res = with_tmos(dur, |tmout| unsafe {
+            abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout)
+        });
+
+        match res {
+            abi::E_OK => true,
+            abi::E_TMOUT => false,
+            error => fail(error, &"twai_flg"),
+        }
+    }
+
+    /// Raise the wait flag.
+    ///
+    /// Calls to this function should be balanced with the number of successful waits.
+    pub fn raise(&self) {
+        expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg");
+    }
+}
+
+impl Drop for WaitFlag {
+    fn drop(&mut self) {
+        expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg");
+    }
+}
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index 3792a3820a534..ea24fedd0eb3d 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -1,13 +1,16 @@
 #![allow(unused)]
 
+use crate::arch::asm;
 use crate::cell::UnsafeCell;
+use crate::cmp;
+use crate::convert::TryInto;
 use crate::mem;
 use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
 use crate::ptr::{self, NonNull};
 use crate::slice;
 use crate::slice::SliceIndex;
 
-use super::super::mem::is_user_range;
+use super::super::mem::{is_enclave_range, is_user_range};
 use fortanix_sgx_abi::*;
 
 /// A type that can be safely read from or written to userspace.
@@ -210,7 +213,9 @@ where
         unsafe {
             // Mustn't call alloc with size 0.
             let ptr = if size > 0 {
-                rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
+                // `copy_to_userspace` is more efficient when data is 8-byte aligned
+                let alignment = cmp::max(T::align_of(), 8);
+                rtunwrap!(Ok, super::alloc(size, alignment)) as _
             } else {
                 T::align_of() as _ // dangling pointer ok for size 0
             };
@@ -225,13 +230,9 @@ where
     /// Copies `val` into freshly allocated space in user memory.
     pub fn new_from_enclave(val: &T) -> Self {
         unsafe {
-            let ret = Self::new_uninit_bytes(mem::size_of_val(val));
-            ptr::copy(
-                val as *const T as *const u8,
-                ret.0.as_ptr() as *mut u8,
-                mem::size_of_val(val),
-            );
-            ret
+            let mut user = Self::new_uninit_bytes(mem::size_of_val(val));
+            user.copy_from_enclave(val);
+            user
         }
     }
 
@@ -304,6 +305,105 @@ where
     }
 }
 
+/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst`
+///
+/// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either:
+///  - preceded by the VERW instruction and followed by the MFENCE; LFENCE instruction sequence
+///  - or are in multiples of 8 bytes, aligned to an 8-byte boundary
+///
+/// # Panics
+/// This function panics if:
+///
+/// * The `src` pointer is null
+/// * The `dst` pointer is null
+/// * The `src` memory range is not in enclave memory
+/// * The `dst` memory range is not in user memory
+///
+/// # References
+///  - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
+///  - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html#inpage-nav-3-2-2
+pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
+    unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
+        unsafe {
+            let mut seg_sel: u16 = 0;
+            for off in 0..len {
+                asm!("
+                    mov %ds, ({seg_sel})
+                    verw ({seg_sel})
+                    movb {val}, ({dst})
+                    mfence
+                    lfence
+                    ",
+                    val = in(reg_byte) *src.offset(off as isize),
+                    dst = in(reg) dst.offset(off as isize),
+                    seg_sel = in(reg) &mut seg_sel,
+                    options(nostack, att_syntax)
+                );
+            }
+        }
+    }
+
+    unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
+        unsafe {
+            asm!(
+                "rep movsq (%rsi), (%rdi)",
+                inout("rcx") len / 8 => _,
+                inout("rdi") dst => _,
+                inout("rsi") src => _,
+                options(att_syntax, nostack, preserves_flags)
+            );
+        }
+    }
+    assert!(!src.is_null());
+    assert!(!dst.is_null());
+    assert!(is_enclave_range(src, len));
+    assert!(is_user_range(dst, len));
+    assert!(len < isize::MAX as usize);
+    assert!(!(src as usize).overflowing_add(len).1);
+    assert!(!(dst as usize).overflowing_add(len).1);
+
+    if len < 8 {
+        // Can't align on 8 byte boundary: copy safely byte per byte
+        unsafe {
+            copy_bytewise_to_userspace(src, dst, len);
+        }
+    } else if len % 8 == 0 && dst as usize % 8 == 0 {
+        // Copying 8-byte aligned quadwords: copy quad word per quad word
+        unsafe {
+            copy_aligned_quadwords_to_userspace(src, dst, len);
+        }
+    } else {
+        // Split copies into three parts:
+        //   +--------+
+        //   | small0 | Chunk smaller than 8 bytes
+        //   +--------+
+        //   |   big  | Chunk 8-byte aligned, and size a multiple of 8 bytes
+        //   +--------+
+        //   | small1 | Chunk smaller than 8 bytes
+        //   +--------+
+
+        unsafe {
+            // Copy small0
+            let small0_size = (8 - dst as usize % 8) as u8;
+            let small0_src = src;
+            let small0_dst = dst;
+            copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _);
+
+            // Copy big
+            let small1_size = ((len - small0_size as usize) % 8) as u8;
+            let big_size = len - small0_size as usize - small1_size as usize;
+            let big_src = src.offset(small0_size as _);
+            let big_dst = dst.offset(small0_size as _);
+            copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size);
+
+            // Copy small1
+            let small1_src = src.offset(big_size as isize + small0_size as isize);
+            let small1_dst = dst.offset(big_size as isize + small0_size as isize);
+            copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _);
+        }
+    }
+}
+
 #[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> UserRef<T>
 where
@@ -352,7 +452,7 @@ where
     pub fn copy_from_enclave(&mut self, val: &T) {
         unsafe {
             assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get()));
-            ptr::copy(
+            copy_to_userspace(
                 val as *const T as *const u8,
                 self.0.get() as *mut T as *mut u8,
                 mem::size_of_val(val),
diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs
index 2f99abba77667..79d1db5e1c50d 100644
--- a/library/std/src/sys/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs
@@ -6,6 +6,8 @@ use crate::time::{Duration, Instant};
 pub(crate) mod alloc;
 #[macro_use]
 pub(crate) mod raw;
+#[cfg(test)]
+mod tests;
 
 use self::raw::*;
 
diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs
new file mode 100644
index 0000000000000..cbf7d7d54f7a2
--- /dev/null
+++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs
@@ -0,0 +1,30 @@
+use super::alloc::copy_to_userspace;
+use super::alloc::User;
+
+#[test]
+fn test_copy_function() {
+    let mut src = [0u8; 100];
+    let mut dst = User::<[u8]>::uninitialized(100);
+
+    for i in 0..src.len() {
+        src[i] = i as _;
+    }
+
+    for size in 0..48 {
+        // For all possible alignment
+        for offset in 0..8 {
+            // overwrite complete dst
+            dst.copy_from_enclave(&[0u8; 100]);
+
+            // Copy src[0..size] to dst + offset
+            unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().offset(offset), size) };
+
+            // Verify copy
+            for byte in 0..size {
+                unsafe {
+                    assert_eq!(*dst.as_ptr().offset(offset + byte as isize), src[byte as usize]);
+                }
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 5ffa381f2e50f..2d21e4764fc21 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -15,6 +15,7 @@ mod itron {
     pub mod thread;
     pub(super) mod time;
     use super::unsupported;
+    pub mod wait_flag;
 }
 
 pub mod alloc;
@@ -43,6 +44,7 @@ pub mod memchr;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
+pub use self::itron::wait_flag;
 
 mod rwlock;
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 8b0bbd6a55c6b..f33ab3a3e14b2 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -311,6 +311,9 @@ pub struct FilePermissions {
     mode: mode_t,
 }
 
+#[derive(Copy, Clone)]
+pub struct FileTimes([libc::timespec; 2]);
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct FileType {
     mode: mode_t,
@@ -503,6 +506,43 @@ impl FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, t: SystemTime) {
+        self.0[0] = t.t.to_timespec().expect("Invalid system time");
+    }
+
+    pub fn set_modified(&mut self, t: SystemTime) {
+        self.0[1] = t.t.to_timespec().expect("Invalid system time");
+    }
+}
+
+struct TimespecDebugAdapter<'a>(&'a libc::timespec);
+
+impl fmt::Debug for TimespecDebugAdapter<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("timespec")
+            .field("tv_sec", &self.0.tv_sec)
+            .field("tv_nsec", &self.0.tv_nsec)
+            .finish()
+    }
+}
+
+impl fmt::Debug for FileTimes {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("FileTimes")
+            .field("accessed", &TimespecDebugAdapter(&self.0[0]))
+            .field("modified", &TimespecDebugAdapter(&self.0[1]))
+            .finish()
+    }
+}
+
+impl Default for FileTimes {
+    fn default() -> Self {
+        let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT };
+        Self([omit; 2])
+    }
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.is(libc::S_IFDIR)
@@ -1021,6 +1061,30 @@ impl File {
         cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?;
         Ok(())
     }
+
+    pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+        cfg_if::cfg_if! {
+            // futimens requires macOS 10.13
+            if #[cfg(target_os = "macos")] {
+                fn ts_to_tv(ts: &libc::timespec) -> libc::timeval {
+                    libc::timeval { tv_sec: ts.tv_sec, tv_usec: (ts.tv_nsec / 1000) as _ }
+                }
+                cvt(unsafe {
+                    weak!(fn futimens(c_int, *const libc::timespec) -> c_int);
+                    futimens.get()
+                        .map(|futimens| futimens(self.as_raw_fd(), times.0.as_ptr()))
+                        .unwrap_or_else(|| {
+                            let timevals = [ts_to_tv(&times.0[0]), ts_to_tv(&times.0[1])];
+                            libc::futimes(self.as_raw_fd(), timevals.as_ptr())
+                        })
+                })?;
+            } else {
+                cvt(unsafe { libc::futimens(self.as_raw_fd(), times.0.as_ptr()) })?;
+            }
+        }
+
+        Ok(())
+    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs
index d1d2847cd33be..0e1a6257ed763 100644
--- a/library/std/src/sys/unsupported/fs.rs
+++ b/library/std/src/sys/unsupported/fs.rs
@@ -17,6 +17,9 @@ pub struct DirEntry(!);
 #[derive(Clone, Debug)]
 pub struct OpenOptions {}
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 pub struct FilePermissions(!);
 
 pub struct FileType(!);
@@ -86,6 +89,11 @@ impl fmt::Debug for FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.0
@@ -237,6 +245,10 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         self.0
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        self.0
+    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index cd6815bfc2136..b0cc748037862 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -63,6 +63,12 @@ pub struct FilePermissions {
     readonly: bool,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {
+    accessed: Option<wasi::Timestamp>,
+    modified: Option<wasi::Timestamp>,
+}
+
 #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
 pub struct FileType {
     bits: wasi::Filetype,
@@ -112,6 +118,16 @@ impl FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, t: SystemTime) {
+        self.accessed = t.to_wasi_timestamp_or_panic();
+    }
+
+    pub fn set_modified(&mut self, t: SystemTime) {
+        self.modified = t.to_wasi_timestamp_or_panic();
+    }
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.bits == wasi::FILETYPE_DIRECTORY
@@ -459,6 +475,15 @@ impl File {
         unsupported()
     }
 
+    pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+        self.fd.filestat_set_times(
+            times.accessed.unwrap_or(0),
+            times.modified.unwrap_or(0),
+            times.accessed.map_or(0, || wasi::FSTFLAGS_ATIM)
+                | times.modified.map_or(0, || wasi::FSTFLAGS_MTIM),
+        )
+    }
+
     pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
         read_link(&self.fd, file)
     }
diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs
index 088585654b948..3d326e49106ca 100644
--- a/library/std/src/sys/wasi/time.rs
+++ b/library/std/src/sys/wasi/time.rs
@@ -47,6 +47,10 @@ impl SystemTime {
         SystemTime(Duration::from_nanos(ts))
     }
 
+    pub fn to_wasi_timestamp_or_panic(&self) -> wasi::Timestamp {
+        self.0.as_nanos().try_into().expect("time does not fit in WASI timestamp")
+    }
+
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 5469487df1eed..abb471213d251 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -607,7 +607,7 @@ pub struct SOCKADDR {
 }
 
 #[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Default)]
 pub struct FILETIME {
     pub dwLowDateTime: DWORD,
     pub dwHighDateTime: DWORD,
@@ -875,6 +875,12 @@ extern "system" {
     pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
     pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
     pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL;
+    pub fn SetFileTime(
+        hFile: BorrowedHandle<'_>,
+        lpCreationTime: Option<&FILETIME>,
+        lpLastAccessTime: Option<&FILETIME>,
+        lpLastWriteTime: Option<&FILETIME>,
+    ) -> BOOL;
     pub fn SetLastError(dwErrCode: DWORD);
     pub fn GetCommandLineW() -> LPWSTR;
     pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD;
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 157d8a044d3cd..e3809f3579dfd 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -82,6 +82,12 @@ pub struct FilePermissions {
     attrs: c::DWORD,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {
+    accessed: c::FILETIME,
+    modified: c::FILETIME,
+}
+
 #[derive(Debug)]
 pub struct DirBuilder;
 
@@ -550,6 +556,14 @@ impl File {
         })?;
         Ok(())
     }
+
+    pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+        cvt(unsafe {
+            c::SetFileTime(self.as_handle(), None, Some(&times.accessed), Some(&times.modified))
+        })?;
+        Ok(())
+    }
+
     /// Get only basic file information such as attributes and file times.
     fn basic_info(&self) -> io::Result<c::FILE_BASIC_INFO> {
         unsafe {
@@ -895,6 +909,16 @@ impl FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, t: SystemTime) {
+        self.accessed = t.into_inner();
+    }
+
+    pub fn set_modified(&mut self, t: SystemTime) {
+        self.modified = t.into_inner();
+    }
+}
+
 impl FileType {
     fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
         FileType { attributes: attrs, reparse_tag }
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 8f46781c75340..b8209a8544585 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -2,6 +2,7 @@ use crate::cmp::Ordering;
 use crate::fmt;
 use crate::mem;
 use crate::sys::c;
+use crate::sys_common::IntoInner;
 use crate::time::Duration;
 
 use core::hash::{Hash, Hasher};
@@ -136,6 +137,12 @@ impl From<c::FILETIME> for SystemTime {
     }
 }
 
+impl IntoInner<c::FILETIME> for SystemTime {
+    fn into_inner(self) -> c::FILETIME {
+        self.t
+    }
+}
+
 impl Hash for SystemTime {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.intervals().hash(state)
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index 7e8bfb2565e45..cbd7832eb7a4c 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -10,9 +10,10 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::Parker;
-    } else if #[cfg(windows)] {
-        pub use crate::sys::thread_parker::Parker;
-    } else if #[cfg(target_family = "unix")] {
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod wait_flag;
+        pub use wait_flag::Parker;
+    } else if #[cfg(any(windows, target_family = "unix"))] {
         pub use crate::sys::thread_parker::Parker;
     } else {
         mod generic;
diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parker/wait_flag.rs
new file mode 100644
index 0000000000000..6561c186655a5
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/wait_flag.rs
@@ -0,0 +1,102 @@
+//! A wait-flag-based thread parker.
+//!
+//! Some operating systems provide low-level parking primitives like wait counts,
+//! event flags or semaphores which are not susceptible to race conditions (meaning
+//! the wakeup can occur before the wait operation). To implement the `std` thread
+//! parker on top of these primitives, we only have to ensure that parking is fast
+//! when the thread token is available, the atomic ordering guarantees are maintained
+//! and spurious wakeups are minimized.
+//!
+//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
+//! `PARKED` and `NOTIFIED`:
+//! * `EMPTY` means the token has not been made available, but the thread is not
+//!    currently waiting on it.
+//! * `PARKED` means the token is not available and the thread is parked.
+//! * `NOTIFIED` means the token is available.
+//!
+//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
+//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
+//! execution can continue without calling into the OS. If the state was `EMPTY`,
+//! the token is not available and the thread waits on the primitive (here called
+//! "wait flag").
+//!
+//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
+//! is or will be sleeping on the wait flag, so we raise it.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicI8;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sys::wait_flag::WaitFlag;
+use crate::time::Duration;
+
+const EMPTY: i8 = 0;
+const PARKED: i8 = -1;
+const NOTIFIED: i8 = 1;
+
+pub struct Parker {
+    state: AtomicI8,
+    wait_flag: WaitFlag,
+}
+
+impl Parker {
+    /// Construct a parker for the current thread. The UNIX parker
+    /// implementation requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        match self.state.fetch_sub(1, Acquire) {
+            // NOTIFIED => EMPTY
+            NOTIFIED => return,
+            // EMPTY => PARKED
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        // Avoid waking up from spurious wakeups (these are quite likely, see below).
+        loop {
+            self.wait_flag.wait();
+
+            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
+                Ok(_) => return,
+                Err(PARKED) => (),
+                Err(_) => panic!("inconsistent park state"),
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        match self.state.fetch_sub(1, Acquire) {
+            NOTIFIED => return,
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        self.wait_flag.wait_timeout(dur);
+
+        // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
+        // a race condition when `unpark` is performed between receiving the timeout and
+        // resetting the state, resulting in the eventflag being set unnecessarily. `park`
+        // is protected against this by looping until the token is actually given, but
+        // here we cannot easily tell.
+
+        // Use `swap` to provide acquire ordering.
+        match self.state.swap(EMPTY, Acquire) {
+            NOTIFIED => (),
+            PARKED => (),
+            _ => panic!("inconsistent park state"),
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+
+        if state == PARKED {
+            self.wait_flag.raise();
+        }
+    }
+}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index b2014f462bd34..759a59e1f98d2 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -38,7 +38,7 @@ use crate::error::Error;
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::time;
-use crate::sys_common::FromInner;
+use crate::sys_common::{FromInner, IntoInner};
 
 #[stable(feature = "time", since = "1.3.0")]
 pub use core::time::Duration;
@@ -686,3 +686,9 @@ impl FromInner<time::SystemTime> for SystemTime {
         SystemTime(time)
     }
 }
+
+impl IntoInner<time::SystemTime> for SystemTime {
+    fn into_inner(self) -> time::SystemTime {
+        self.0
+    }
+}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index b4b7790eebba1..5d0756d30fb53 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -983,42 +983,51 @@ table,
 	font-weight: normal;
 }
 
-body.blur > :not(#help) {
-	filter: blur(8px);
-	-webkit-filter: blur(8px);
-	opacity: .7;
+.popover {
+	font-size: 1rem;
+	position: absolute;
+	right: 0;
+	z-index: 2;
+	display: block;
+	margin-top: 7px;
+	border-radius: 3px;
+	border: 1px solid;
+	font-size: 1rem;
 }
 
-#help {
-	width: 100%;
-	height: 100vh;
-	position: fixed;
-	top: 0;
-	left: 0;
-	display: flex;
-	justify-content: center;
-	align-items: center;
+/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
+.popover::before {
+	content: '';
+	position: absolute;
+	right: 11px;
+	border: solid;
+	border-width: 1px 1px 0 0;
+	display: inline-block;
+	padding: 4px;
+	transform: rotate(-45deg);
+	top: -5px;
 }
-#help > div {
-	flex: 0 0 auto;
-	box-shadow: 0 0 6px rgba(0,0,0,.2);
-	width: 550px;
-	height: auto;
-	border: 1px solid;
+
+#help-button .popover {
+	max-width: 600px;
 }
-#help dt {
+
+#help-button .popover::before {
+	right: 48px;
+}
+
+#help-button dt {
 	float: left;
 	clear: left;
 	display: block;
 	margin-right: 0.5rem;
 }
-#help span.top, #help span.bottom {
+#help-button span.top, #help-button span.bottom {
 	text-align: center;
 	display: block;
 	font-size: 1.125rem;
-
 }
-#help span.top {
+#help-button span.top {
 	text-align: center;
 	display: block;
 	margin: 10px 0;
@@ -1026,17 +1035,17 @@ body.blur > :not(#help) {
 	padding-bottom: 4px;
 	margin-bottom: 6px;
 }
-#help span.bottom {
+#help-button span.bottom {
 	clear: both;
 	border-top: 1px solid;
 }
-#help dd { margin: 5px 35px; }
-#help .infos { padding-left: 0; }
-#help h1, #help h2 { margin-top: 0; }
-#help > div div {
+.side-by-side {
+	text-align: initial;
+}
+.side-by-side > div {
 	width: 50%;
 	float: left;
-	padding: 0 20px 20px 17px;;
+	padding: 0 20px 20px 17px;
 }
 
 .item-info .stab {
@@ -1391,7 +1400,7 @@ pre.rust {
 #copy-path {
 	height: 34px;
 }
-#settings-menu > a, #help-button, #copy-path {
+#settings-menu > a, #help-button > button, #copy-path {
 	padding: 5px;
 	width: 33px;
 	border: 1px solid;
@@ -1401,9 +1410,8 @@ pre.rust {
 #settings-menu {
 	padding: 0;
 }
-#settings-menu > a {
+#settings-menu > a, #help-button > button {
 	padding: 5px;
-	width: 100%;
 	height: 100%;
 	display: block;
 }
@@ -1420,7 +1428,7 @@ pre.rust {
 	animation: rotating 2s linear infinite;
 }
 
-#help-button {
+#help-button > button {
 	font-family: "Fira Sans", Arial, sans-serif;
 	text-align: center;
 	/* Rare exception to specifying font sizes in rem. Since this is acting
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 1cd8e39e03648..e531e6ce6bbde 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -86,27 +86,6 @@ input:checked + .slider:before {
 	display: block;
 }
 
-div#settings {
-	position: absolute;
-	right: 0;
-	z-index: 1;
-	display: block;
-	margin-top: 7px;
-	border-radius: 3px;
-	border: 1px solid;
-}
 #settings .setting-line {
 	margin: 1.2em 0.6em;
 }
-/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
-div#settings::before {
-	content: '';
-	position: absolute;
-	right: 11px;
-	border: solid;
-	border-width: 1px 1px 0 0;
-	display: inline-block;
-	padding: 4px;
-	transform: rotate(-45deg);
-	top: -5px;
-}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 8e0521d9ad6a1..d27294657192c 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 
 /* General structure and fonts */
 
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: #0f1419;
 	color: #c5c5c5;
 }
@@ -567,7 +567,7 @@ kbd {
 	box-shadow: inset 0 -1px 0 #5c6773;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #5c6773;
 	background-color: #0f1419;
 	color: #fff;
@@ -577,7 +577,8 @@ kbd {
 	filter: invert(100);
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #5c6773;
 }
 
@@ -592,7 +593,7 @@ kbd {
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #e0e0e0;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 071ad006ed350..48079ea2f3041 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -1,4 +1,4 @@
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: #353535;
 	color: #ddd;
 }
@@ -442,18 +442,19 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #e0e0e0;
 	background: #f0f0f0;
 	color: #000;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #ffb900;
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #d2d2d2;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 5c3789bf4630a..f4016be967963 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -1,6 +1,6 @@
 /* General structure and fonts */
 
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: white;
 	color: black;
 }
@@ -427,17 +427,18 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #e0e0e0;
 	background-color: #fff;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #717171;
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #DDDDDD;
 }
 
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index b320db9104612..70dbfd4442540 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -63,6 +63,24 @@ function showMain() {
     removeClass(document.getElementById(MAIN_ID), "hidden");
 }
 
+function elemIsInParent(elem, parent) {
+    while (elem && elem !== document.body) {
+        if (elem === parent) {
+            return true;
+        }
+        elem = elem.parentElement;
+    }
+    return false;
+}
+
+function blurHandler(event, parentElem, hideCallback) {
+    if (!elemIsInParent(document.activeElement, parentElem) &&
+        !elemIsInParent(event.relatedTarget, parentElem)
+    ) {
+        hideCallback();
+    }
+}
+
 (function() {
     window.rootPath = getVar("root-path");
     window.currentCrate = getVar("current-crate");
@@ -104,20 +122,21 @@ const MAIN_ID = "main-content";
 const SETTINGS_BUTTON_ID = "settings-menu";
 const ALTERNATIVE_DISPLAY_ID = "alternative-display";
 const NOT_DISPLAYED_ID = "not-displayed";
+const HELP_BUTTON_ID = "help-button";
 
 function getSettingsButton() {
     return document.getElementById(SETTINGS_BUTTON_ID);
 }
 
+function getHelpButton() {
+    return document.getElementById(HELP_BUTTON_ID);
+}
+
 // Returns the current URL without any query parameter or hash.
 function getNakedUrl() {
     return window.location.href.split("?")[0].split("#")[0];
 }
 
-window.hideSettings = () => {
-    // Does nothing by default.
-};
-
 /**
  * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
  * doesn't have a parent node.
@@ -381,55 +400,16 @@ function loadCss(cssFileName) {
         openParentDetails(document.getElementById(id));
     }
 
-    function getHelpElement(build) {
-        if (build) {
-            buildHelperPopup();
-        }
-        return document.getElementById("help");
-    }
-
-    /**
-     * Show the help popup.
-     *
-     * @param {boolean} display    - Whether to show or hide the popup
-     * @param {Event}   ev         - The event that triggered this call
-     * @param {Element} [help]     - The help element if it already exists
-     */
-    function displayHelp(display, ev, help) {
-        if (display) {
-            help = help ? help : getHelpElement(true);
-            if (hasClass(help, "hidden")) {
-                ev.preventDefault();
-                removeClass(help, "hidden");
-                addClass(document.body, "blur");
-            }
-        } else {
-            // No need to build the help popup if we want to hide it in case it hasn't been
-            // built yet...
-            help = help ? help : getHelpElement(false);
-            if (help && !hasClass(help, "hidden")) {
-                ev.preventDefault();
-                addClass(help, "hidden");
-                removeClass(document.body, "blur");
-            }
-        }
-    }
-
     function handleEscape(ev) {
         searchState.clearInputTimeout();
-        const help = getHelpElement(false);
-        if (help && !hasClass(help, "hidden")) {
-            displayHelp(false, ev, help);
-        } else {
-            switchDisplayedElement(null);
-            if (browserSupportsHistoryApi()) {
-                history.replaceState(null, window.currentCrate + " - Rust",
-                    getNakedUrl() + window.location.hash);
-            }
-            ev.preventDefault();
+        switchDisplayedElement(null);
+        if (browserSupportsHistoryApi()) {
+            history.replaceState(null, window.currentCrate + " - Rust",
+                getNakedUrl() + window.location.hash);
         }
+        ev.preventDefault();
         searchState.defocus();
-        window.hideSettings();
+        window.hidePopoverMenus();
     }
 
     const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
@@ -453,7 +433,6 @@ function loadCss(cssFileName) {
 
             case "s":
             case "S":
-                displayHelp(false, ev);
                 ev.preventDefault();
                 searchState.focus();
                 break;
@@ -465,7 +444,7 @@ function loadCss(cssFileName) {
                 break;
 
             case "?":
-                displayHelp(true, ev);
+                showHelp();
                 break;
 
             default:
@@ -796,9 +775,6 @@ function loadCss(cssFileName) {
             elem.addEventListener("click", f);
         }
     }
-    handleClick("help-button", ev => {
-        displayHelp(true, ev);
-    });
     handleClick(MAIN_ID, () => {
         hideSidebar();
     });
@@ -842,24 +818,16 @@ function loadCss(cssFileName) {
         });
     }
 
-    let buildHelperPopup = () => {
-        const popup = document.createElement("aside");
-        addClass(popup, "hidden");
-        popup.id = "help";
-
-        popup.addEventListener("click", ev => {
-            if (ev.target === popup) {
-                // Clicked the blurred zone outside the help popup; dismiss help.
-                displayHelp(false, ev);
-            }
-        });
+    function helpBlurHandler(event) {
+        blurHandler(event, getHelpButton(), window.hidePopoverMenus);
+    }
 
+    function buildHelpMenu() {
         const book_info = document.createElement("span");
         book_info.className = "top";
         book_info.innerHTML = "You can find more information in \
             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
 
-        const container = document.createElement("div");
         const shortcuts = [
             ["?", "Show this help dialog"],
             ["S", "Focus the search field"],
@@ -895,24 +863,85 @@ function loadCss(cssFileName) {
         addClass(div_infos, "infos");
         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
 
-        container.appendChild(book_info);
-        container.appendChild(div_shortcuts);
-        container.appendChild(div_infos);
-
         const rustdoc_version = document.createElement("span");
         rustdoc_version.className = "bottom";
         const rustdoc_version_code = document.createElement("code");
         rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
         rustdoc_version.appendChild(rustdoc_version_code);
 
+        const container = document.createElement("div");
+        container.className = "popover";
+        container.style.display = "none";
+
+        const side_by_side = document.createElement("div");
+        side_by_side.className = "side-by-side";
+        side_by_side.appendChild(div_shortcuts);
+        side_by_side.appendChild(div_infos);
+
+        container.appendChild(book_info);
+        container.appendChild(side_by_side);
         container.appendChild(rustdoc_version);
 
-        popup.appendChild(container);
-        insertAfter(popup, document.querySelector("main"));
-        // So that it's only built once and then it'll do nothing when called!
-        buildHelperPopup = () => {};
+        const help_button = getHelpButton();
+        help_button.appendChild(container);
+
+        container.onblur = helpBlurHandler;
+        container.onclick = event => {
+            event.preventDefault();
+        };
+        help_button.onblur = helpBlurHandler;
+        help_button.children[0].onblur = helpBlurHandler;
+
+        return container;
+    }
+
+    /**
+     * Hide all the popover menus.
+     */
+    window.hidePopoverMenus = function() {
+        onEachLazy(document.querySelectorAll(".search-container .popover"), elem => {
+            elem.style.display = "none";
+        });
     };
 
+    /**
+     * Returns the help menu element (not the button).
+     *
+     * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be
+     *                                built if it doesn't exist.
+     *
+     * @return {HTMLElement}
+     */
+    function getHelpMenu(buildNeeded) {
+        let menu = getHelpButton().querySelector(".popover");
+        if (!menu && buildNeeded) {
+            menu = buildHelpMenu();
+        }
+        return menu;
+    }
+
+    /**
+     * Show the help popup menu.
+     */
+    function showHelp() {
+        const menu = getHelpMenu(true);
+        if (menu.style.display === "none") {
+            menu.style.display = "";
+        }
+    }
+
+    document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => {
+        const target = event.target;
+        if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) {
+            return;
+        }
+        const menu = getHelpMenu(true);
+        const shouldShowHelp = menu.style.display === "none";
+        if (shouldShowHelp) {
+            showHelp();
+        }
+    });
+
     setMobileTopbar();
     addSidebarItems();
     addSidebarCrates();
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 41bf0ec895580..797b931afc643 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,6 +1,6 @@
 // Local js definitions:
 /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
-/* global addClass, removeClass, onEach, onEachLazy */
+/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
 /* global MAIN_ID, getVar, getSettingsButton */
 
 "use strict";
@@ -209,6 +209,7 @@
         const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
         const el = document.createElement(elementKind);
         el.id = "settings";
+        el.className = "popover";
         el.innerHTML = innerHTML;
 
         if (isSettingsPage) {
@@ -226,23 +227,8 @@
         settingsMenu.style.display = "";
     }
 
-    function elemIsInParent(elem, parent) {
-        while (elem && elem !== document.body) {
-            if (elem === parent) {
-                return true;
-            }
-            elem = elem.parentElement;
-        }
-        return false;
-    }
-
-    function blurHandler(event) {
-        const settingsButton = getSettingsButton();
-        if (!elemIsInParent(document.activeElement, settingsButton) &&
-            !elemIsInParent(event.relatedTarget, settingsButton)
-        ) {
-            window.hideSettings();
-        }
+    function settingsBlurHandler(event) {
+        blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
     }
 
     if (isSettingsPage) {
@@ -254,26 +240,24 @@
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
         const settingsMenu = document.getElementById("settings");
-        window.hideSettings = function() {
-            settingsMenu.style.display = "none";
-        };
         settingsButton.onclick = function(event) {
             if (elemIsInParent(event.target, settingsMenu)) {
                 return;
             }
             event.preventDefault();
-            if (settingsMenu.style.display !== "none") {
-                window.hideSettings();
-            } else {
+            const shouldDisplaySettings = settingsMenu.style.display === "none";
+
+            window.hidePopoverMenus();
+            if (shouldDisplaySettings) {
                 displaySettings();
             }
         };
-        settingsButton.onblur = blurHandler;
-        settingsButton.querySelector("a").onblur = blurHandler;
+        settingsButton.onblur = settingsBlurHandler;
+        settingsButton.querySelector("a").onblur = settingsBlurHandler;
         onEachLazy(settingsMenu.querySelectorAll("input"), el => {
-            el.onblur = blurHandler;
+            el.onblur = settingsBlurHandler;
         });
-        settingsMenu.onblur = blurHandler;
+        settingsMenu.onblur = settingsBlurHandler;
     }
 
     // We now wait a bit for the web browser to end re-computing the DOM...
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index c4999e2c74fce..dfb3e4e6a2ccd 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -119,7 +119,9 @@ <h2 class="location"></h2>
                                 spellcheck="false" {# -#}
                                 placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
                                 type="search"> {#- -#}
-                            <button type="button" id="help-button" title="help">?</button> {#- -#}
+                            <div id="help-button" title="help" tabindex="-1"> {#- -#}
+                                <button type="button">?</button> {#- -#}
+                            </div> {#- -#}
                             <div id="settings-menu" tabindex="-1">
                                 <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
                                     <img width="22" height="22" alt="Change settings" {# -#}
diff --git a/src/test/debuginfo/no_mangle-info.rs b/src/test/debuginfo/no_mangle-info.rs
new file mode 100644
index 0000000000000..3a261e197aa5d
--- /dev/null
+++ b/src/test/debuginfo/no_mangle-info.rs
@@ -0,0 +1,39 @@
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+// gdb-command:p TEST
+// gdb-check:$1 = 3735928559
+// gdb-command:p no_mangle_info::namespace::OTHER_TEST
+// gdb-check:$2 = 42
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:p TEST
+// lldb-check: (unsigned long) $0 = 3735928559
+// lldb-command:p OTHER_TEST
+// lldb-check: (unsigned long) $1 = 42
+
+// === CDB TESTS ==================================================================================
+// cdb-command: g
+// Note: LLDB and GDB allow referring to items that are in the same namespace of the symbol
+// we currently have a breakpoint on in an unqualified way. CDB does not, and thus we need to
+// refer to it in a fully qualified way.
+// cdb-command: dx a!no_mangle_info::TEST
+// cdb-check: a!no_mangle_info::TEST : 0xdeadbeef [Type: unsigned __int64]
+// cdb-command: dx a!no_mangle_info::namespace::OTHER_TEST
+// cdb-check: a!no_mangle_info::namespace::OTHER_TEST : 0x2a [Type: unsigned __int64]
+
+#[no_mangle]
+pub static TEST: u64 = 0xdeadbeef;
+
+// FIXME(rylev, wesleywiser): uncommenting this item breaks the test, and we're not sure why
+// pub static OTHER_TEST: u64 = 43;
+pub mod namespace {
+    pub static OTHER_TEST: u64 = 42;
+}
+
+pub fn main() {
+    println!("TEST: {}", TEST);
+    println!("OTHER TEST: {}", namespace::OTHER_TEST); // #break
+}
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
index f5eabf8696796..75b301016d76e 100644
--- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
@@ -69,7 +69,7 @@
           StorageLive(_12);                // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
 -         _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
 +         StorageLive(_15);                // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
-+         _15 = move ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
++         _15 = virt ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
 +         _12 = (*_15);                    // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13
 +         StorageDead(_15);                // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
           StorageLive(_13);                // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37
@@ -102,10 +102,10 @@
           StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
           _5 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
           goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
-      }
-  
-      bb8 (cleanup): {
-          resume;                          // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
++     }
++ 
++     bb8 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
index e131adae2b683..b9bf710d3fdf3 100644
--- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
@@ -8,7 +8,6 @@
       let mut _3: usize;                   // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
       let mut _4: *mut u8;                 // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
       let mut _5: std::boxed::Box<std::boxed::Box<u32>>; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
-      let mut _6: ();                      // in scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
       scope 1 {
       }
   
@@ -25,7 +24,7 @@
       bb1: {
           StorageLive(_5);                 // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
           _5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
-          (*_5) = f() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12
+          (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12
                                            // mir::Constant
                                            // + span: $DIR/derefer_inline_test.rs:10:9: 10:10
                                            // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(Scalar(<ZST>)) }
@@ -33,12 +32,12 @@
   
       bb2: {
           _1 = move _5;                    // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12
-          goto -> bb3;                     // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
+          drop(_5) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
       }
   
       bb3: {
           StorageDead(_5);                 // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
-          drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13
+          drop(_1) -> bb4;                 // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13
       }
   
       bb4: {
@@ -48,22 +47,15 @@
       }
   
       bb5 (cleanup): {
-          goto -> bb8;                     // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
+          drop(_1) -> bb7;                 // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13
       }
   
       bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2
+          drop(_5) -> bb7;                 // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
       }
   
       bb7 (cleanup): {
-          _6 = alloc::alloc::box_free::<Box<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::boxed::Box<u32>>), move (_5.1: std::alloc::Global)) -> bb6; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
-                                           // mir::Constant
-                                           // + span: $DIR/derefer_inline_test.rs:10:11: 10:12
-                                           // + literal: Const { ty: unsafe fn(Unique<Box<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Box<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb8 (cleanup): {
-          goto -> bb7;                     // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
+          resume;                          // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
index 8b91a65bf3d7d..cfa3eb3f2d78b 100644
--- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
@@ -56,12 +56,12 @@
           _4 = &_5;                        // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22
 -         switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         StorageLive(_10);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
-+         _10 = move (*_4);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _10 = virt (*_4);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         StorageLive(_11);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
-+         _11 = move (*_10);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _11 = virt (*_10);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         StorageDead(_10);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         StorageLive(_12);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
-+         _12 = move (*_11);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
++         _12 = virt (*_11);               // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         StorageDead(_11);                // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
 +         switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22
       }
@@ -94,10 +94,10 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2
           return;                          // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2
-      }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
++     }
++ 
++     bb6 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff
index 84476aeed7a6c..589fc4210fc24 100644
--- a/src/test/mir-opt/derefer_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_test.main.Derefer.diff
@@ -34,13 +34,13 @@
           StorageLive(_4);                 // scope 2 at $DIR/derefer_test.rs:5:9: 5:10
 -         _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
 +         StorageLive(_6);                 // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
-+         _6 = move (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
++         _6 = virt (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
 +         _4 = &mut ((*_6).0: i32);        // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
 +         StorageDead(_6);                 // scope 3 at $DIR/derefer_test.rs:6:9: 6:10
           StorageLive(_5);                 // scope 3 at $DIR/derefer_test.rs:6:9: 6:10
 -         _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26
 +         StorageLive(_7);                 // scope 3 at $DIR/derefer_test.rs:6:13: 6:26
-+         _7 = move (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26
++         _7 = virt (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26
 +         _5 = &mut ((*_7).1: i32);        // scope 3 at $DIR/derefer_test.rs:6:13: 6:26
 +         StorageDead(_7);                 // scope 0 at $DIR/derefer_test.rs:2:11: 7:2
           _0 = const ();                   // scope 0 at $DIR/derefer_test.rs:2:11: 7:2
@@ -49,10 +49,10 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test.rs:7:1: 7:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test.rs:7:1: 7:2
           return;                          // scope 0 at $DIR/derefer_test.rs:7:2: 7:2
-      }
-  
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
++     }
++ 
++     bb1 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
index b8e5a0c328f4d..79734a45dc476 100644
--- a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
@@ -58,24 +58,24 @@
           StorageLive(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
 -         _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageLive(_10);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+         _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _10 = virt (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageLive(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+         _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _11 = virt ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageDead(_10);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageLive(_12);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
-+         _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _12 = virt ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageDead(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         _8 = &mut ((*_12).1: i32);       // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
 +         StorageDead(_12);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
           StorageLive(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
 -         _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageLive(_13);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+         _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _13 = virt (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageLive(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+         _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _14 = virt ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageDead(_13);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageLive(_15);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
-+         _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _15 = virt ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageDead(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         _9 = &mut ((*_15).1: i32);       // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
 +         StorageDead(_15);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
@@ -87,10 +87,10 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2
-      }
-  
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
++     }
++ 
++     bb1 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
index 67ce0c2aabb1c..9cbc5a4233e93 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
@@ -93,7 +93,7 @@
 -         StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
           StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _34 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -101,7 +101,7 @@
   
       bb1: {
           StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _35 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _7 = discriminant((*_35));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -123,7 +123,7 @@
   
       bb3: {
           StorageLive(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _36 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _8 = discriminant((*_36));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -131,7 +131,7 @@
   
       bb4: {
           StorageLive(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _37 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _9 = discriminant((*_37));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -139,7 +139,7 @@
   
       bb5: {
           StorageLive(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _38 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _10 = discriminant((*_38));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -149,14 +149,14 @@
 -         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           StorageLive(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-          _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          _39 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
 -         _12 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
 +         _15 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           StorageDead(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
 -         StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageLive(_40);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-          _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          _40 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
 -         _13 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
 +         _16 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageDead(_40);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
@@ -195,14 +195,14 @@
 -         StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
           StorageLive(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-          _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          _41 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
 -         _17 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
 +         _20 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
           StorageDead(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
 -         StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageLive(_42);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-          _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          _42 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
 -         _18 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
 +         _21 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageDead(_42);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
@@ -241,14 +241,14 @@
 -         StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
           StorageLive(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-          _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          _43 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
 -         _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
 +         _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
           StorageDead(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
 -         StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageLive(_44);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-          _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          _44 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
 -         _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
 +         _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageDead(_44);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
@@ -287,14 +287,14 @@
 -         StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
           StorageLive(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-          _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          _45 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
 -         _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
 +         _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
           StorageDead(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
 -         StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageLive(_46);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-          _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          _46 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
 -         _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
 +         _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageDead(_46);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index c2b00f915a4eb..e52d2865179e5 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -79,7 +79,7 @@
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
           StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _34 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -87,7 +87,7 @@
   
       bb1: {
           StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _35 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _7 = discriminant((*_35));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -107,7 +107,7 @@
   
       bb3: {
           StorageLive(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _36 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _8 = discriminant((*_36));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_36);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -115,7 +115,7 @@
   
       bb4: {
           StorageLive(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _37 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _9 = discriminant((*_37));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_37);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -123,7 +123,7 @@
   
       bb5: {
           StorageLive(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-          _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+          _38 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           _10 = discriminant((*_38));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_38);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
           switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -132,12 +132,12 @@
       bb6: {
           StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           StorageLive(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-          _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+          _39 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           _12 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           StorageDead(_39);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageLive(_40);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-          _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+          _40 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           _13 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
           StorageDead(_40);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
           StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
@@ -160,12 +160,12 @@
       bb7: {
           StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
           StorageLive(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-          _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+          _41 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
           _17 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
           StorageDead(_41);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageLive(_42);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-          _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+          _42 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           _18 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
           StorageDead(_42);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
           StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
@@ -188,12 +188,12 @@
       bb8: {
           StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
           StorageLive(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-          _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+          _43 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
           _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
           StorageDead(_43);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageLive(_44);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-          _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+          _44 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
           StorageDead(_44);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
           StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
@@ -216,12 +216,12 @@
       bb9: {
           StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
           StorageLive(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-          _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+          _45 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
           _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
           StorageDead(_45);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageLive(_46);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-          _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+          _46 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
           StorageDead(_46);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
           StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
index 982dd7a27bc6b..e40ef981a4e8c 100644
--- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
@@ -17,7 +17,7 @@
   
       bb1: {
           StorageLive(_4);                 // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
-          _4 = move (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          _4 = virt (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
           _2 = discriminant((*_4));        // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
           StorageDead(_4);                 // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
           switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index c6b49b66dc5c0..80d8d3b1c7b96 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -46,12 +46,12 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _9 = move (_7.0: i32);           // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_10);                // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
         StorageLive(_12);                // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
-        _12 = move ((*_6).0: &i32);      // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
+        _12 = virt ((*_6).0: &i32);      // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
         _10 = (*_12);                    // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
         StorageDead(_12);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         StorageLive(_11);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         StorageLive(_13);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
-        _13 = move ((*_6).1: &T);        // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        _13 = virt ((*_6).1: &T);        // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         _11 = (*_13);                    // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         StorageDead(_13);                // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         Deinit(_0);                      // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
index 3e1c4a4670143..51c2688da4709 100644
--- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
@@ -77,7 +77,7 @@
 +         StorageLive(_11);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_12);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         _13 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         _13 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
 +         _12 = discriminant((*_13));      // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
 +         StorageDead(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
 +         switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
@@ -125,7 +125,7 @@
 +         ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant(_1) = 0;            // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         StorageLive(_14);                // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+         _14 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
++         _14 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant((*_14)) = 3;        // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         StorageDead(_14);                // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:11: 15:39
@@ -139,7 +139,7 @@
 +         ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         discriminant(_1) = 1;            // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         StorageLive(_15);                // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         _15 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
++         _15 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         discriminant((*_15)) = 1;        // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         StorageDead(_15);                // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:41: 15:41
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
index 11a205eb41580..a0b23b43ef467 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
@@ -22,7 +22,7 @@ fn b(_1: &mut Box<T>) -> &mut T {
         StorageLive(_5);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         StorageLive(_6);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         StorageLive(_7);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
-        _7 = move (*_4);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
+        _7 = virt (*_4);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         StorageLive(_8);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         _8 = (((_7.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         _6 = &mut (*_8);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
index b04a91d7c9590..91acf2d2c5c4e 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
@@ -16,7 +16,7 @@ fn d(_1: &Box<T>) -> &T {
         StorageLive(_3);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15
         _3 = &(*_1);                     // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15
         StorageLive(_4);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
-        _4 = move (*_3);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
+        _4 = virt (*_3);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         StorageLive(_5);                 // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         _5 = (((_4.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         _2 = &(*_5);                     // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
index 8713bf65c8432..d083b0ae0c931 100644
--- a/src/test/rustdoc-gui/escape-key.goml
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -21,17 +21,6 @@ wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 
-// Now let's check that when the help popup is displayed and we press Escape, it doesn't
-// hide the search results too.
-click: "#help-button"
-assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
-assert-attribute: ("#help", {"class": ""})
-press-key: "Escape"
-wait-for: "#alternative-display #search"
-assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#main-content", {"class": "content hidden"})
-assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
-
 // Check that Escape hides the search results when a search result is focused.
 focus: ".search-input"
 assert: ".search-input:focus"
@@ -39,7 +28,6 @@ press-key: "ArrowDown"
 assert-false: ".search-input:focus"
 assert: "#results a:focus"
 press-key: "Escape"
-assert-attribute: ("#help", {"class": "hidden"})
 wait-for: "#not-displayed #search"
 assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml
new file mode 100644
index 0000000000000..ba2986e969a35
--- /dev/null
+++ b/src/test/rustdoc-gui/pocket-menu.goml
@@ -0,0 +1,72 @@
+// This test ensures that the "pocket menus" are working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First we check that the help menu doesn't exist yet.
+assert-false: "#help-button .popover"
+// Then we display the help menu.
+click: "#help-button"
+assert: "#help-button .popover"
+assert-css: ("#help-button .popover", {"display": "block"})
+
+// Now we click somewhere else on the page to ensure it is handling the blur event
+// correctly.
+click: ".sidebar"
+assert-css: ("#help-button .popover", {"display": "none"})
+
+// Now we will check that we cannot have two "pocket menus" displayed at the same time.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+click: "#settings-menu"
+assert-css: ("#help-button .popover", {"display": "none"})
+assert-css: ("#settings-menu .popover", {"display": "block"})
+
+// Now the other way.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
+// We check the borders color now:
+
+// Ayu theme
+local-storage: {
+    "rustdoc-theme": "ayu",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(92, 103, 115)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Dark theme
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(210, 210, 210)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Light theme
+local-storage: {
+    "rustdoc-theme": "light",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(221, 221, 221)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml
index 37a7c1662949d..1f20a0eaa9982 100644
--- a/src/test/rustdoc-gui/shortcuts.goml
+++ b/src/test/rustdoc-gui/shortcuts.goml
@@ -8,7 +8,6 @@ press-key: "Escape"
 assert-false: "input.search-input:focus"
 // We now check for the help popup.
 press-key: "?"
-assert-css: ("#help", {"display": "flex"})
-assert-false: "#help.hidden"
+assert-css: ("#help-button .popover", {"display": "block"})
 press-key: "Escape"
-assert-css: ("#help.hidden", {"display": "none"})
+assert-css: ("#help-button .popover", {"display": "none"})
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs
deleted file mode 100644
index 1db9d33c72aee..0000000000000
--- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-// compile-flags: -Z unpretty=expanded
-
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
-
-fn main() {
-    let elem = 1i32;
-    assert!(elem == 1);
-}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout
deleted file mode 100644
index a590eb3223254..0000000000000
--- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(prelude_import)]
-#![no_std]
-// check-pass
-// compile-flags: -Z unpretty=expanded
-
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-
-fn main() {
-    let elem = 1i32;
-    {
-        #[allow(unused_imports)]
-        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
-        let mut __capture0 = ::core::asserting::Capture::new();
-        let __local_bind0 = &elem;
-        if !(*{
-                                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                                __local_bind0
-                            } == 1) {
-                {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
-                }
-            }
-    };
-}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
new file mode 100644
index 0000000000000..5ec84b08ff808
--- /dev/null
+++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
@@ -0,0 +1,32 @@
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    assert!(elem as usize);
+}
+
+fn addr_of() {
+    let elem = 1i32;
+    assert!(&elem);
+}
+
+fn binary() {
+    let elem = 1i32;
+    assert!(elem == 1);
+    assert!(elem >= 1);
+    assert!(elem > 0);
+    assert!(elem < 3);
+    assert!(elem <= 3);
+    assert!(elem != 3);
+}
+
+fn unary() {
+    let elem = &1i32;
+    assert!(*elem);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
new file mode 100644
index 0000000000000..90f858f80e6b5
--- /dev/null
+++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -0,0 +1,147 @@
+#![feature(prelude_import)]
+#![no_std]
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*{
+                                    (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                                    __local_bind0
+                                } as usize)) {
+
+
+
+
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn addr_of() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!&*__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn binary() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn unary() {
+    let elem = &1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!**__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn main() {}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 498dcbb89006d..53fa2ccdcc138 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -124,6 +124,7 @@ fn check_rvalue<'tcx>(
         Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
             check_place(tcx, *place, span, body)
         },
+        Rvalue::VirtualRef(place) => check_place(tcx, *place, span, body),
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
         | Rvalue::Cast(