diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 74e6ce37e971a..b775739fed2ae 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -55,7 +55,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
         // contain dangling references.
         PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) |
-        PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
+        PlaceContext::NonUse(NonUseContext::AscribeUserTy(_)) |
 
         PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index dcabeb792be3e..33b24b68f7cfc 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -777,7 +777,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow
                 | AddressOf | Projection,
             ) => ty::Covariant,
-            PlaceContext::NonUse(AscribeUserTy) => ty::Covariant,
+            PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index c4d4e0d6d78bc..5187e63f8e3a1 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -31,6 +31,7 @@ use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
 
 use std::ops::ControlFlow;
@@ -222,7 +223,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
     if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
         return;
     }
-    check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
+    check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
 }
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -391,7 +392,6 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 fn check_opaque_meets_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
-    substs: SubstsRef<'tcx>,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
@@ -406,6 +406,8 @@ fn check_opaque_meets_bounds<'tcx>(
         .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
         .build();
     let ocx = ObligationCtxt::new(&infcx);
+
+    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
     let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
 
     // `ReErased` regions appear in the "parent_substs" of closures/generators.
@@ -448,9 +450,18 @@ fn check_opaque_meets_bounds<'tcx>(
     match origin {
         // Checked when type checking the function containing them.
         hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+        // Nested opaque types occur only in associated types:
+        // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
+        // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
+        // We don't have to check them here because their well-formedness follows from the WF of
+        // the projection input types in the defining- and use-sites.
+        hir::OpaqueTyOrigin::TyAlias
+            if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias => {
-            let outlives_env = OutlivesEnvironment::new(param_env);
+            let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
+            let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
+            let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
             let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
         }
     }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 79253cbc8b43c..3fe600ce0468c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -10,6 +10,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_middle::ty;
+use rustc_session::config::CrateType;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{BytePos, Span};
@@ -366,7 +367,11 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
                 })
         };
 
-        if let Some(ident) = &crate_ident {
+        if let Some(ident) = &crate_ident
+            && cx.tcx.sess.crate_types().iter().all(|&crate_type| {
+                crate_type != CrateType::Executable
+            })
+        {
             self.check_snake_case(cx, "crate", ident);
         }
     }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 6718605ed0bc4..4b7014e31090b 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -64,7 +64,7 @@
 
 use crate::mir::*;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{CanonicalUserTypeAnnotation, Ty};
+use crate::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc_span::Span;
 
 macro_rules! make_mir_visitor {
@@ -782,12 +782,12 @@ macro_rules! make_mir_visitor {
 
             fn super_ascribe_user_ty(&mut self,
                                      place: & $($mutability)? Place<'tcx>,
-                                     _variance: $(& $mutability)? ty::Variance,
+                                     variance: $(& $mutability)? ty::Variance,
                                      user_ty: & $($mutability)? UserTypeProjection,
                                      location: Location) {
                 self.visit_place(
                     place,
-                    PlaceContext::NonUse(NonUseContext::AscribeUserTy),
+                    PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)),
                     location
                 );
                 self.visit_user_type_projection(user_ty);
@@ -1320,7 +1320,7 @@ pub enum NonUseContext {
     /// Ending a storage live range.
     StorageDead,
     /// User type annotation assertions for NLL.
-    AscribeUserTy,
+    AscribeUserTy(ty::Variance),
     /// The data of a user variable, for debug info.
     VarDebugInfo,
 }
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index dafd2ae23a635..d1bc9ee91538e 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -85,7 +85,9 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let ssa = SsaLocals::new(body);
 
     let mut replacer = compute_replacement(tcx, body, &ssa);
-    debug!(?replacer.targets, ?replacer.allowed_replacements, ?replacer.storage_to_remove);
+    debug!(?replacer.targets);
+    debug!(?replacer.allowed_replacements);
+    debug!(?replacer.storage_to_remove);
 
     replacer.visit_body_preserves_cfg(body);
 
@@ -190,8 +192,11 @@ fn compute_replacement<'tcx>(
             continue;
         }
 
+        // Whether the current local is subject to the uniqueness rule.
+        let needs_unique = ty.is_mutable_ptr();
+
         // If this a mutable reference that we cannot fully replace, mark it as unknown.
-        if ty.is_mutable_ptr() && !fully_replacable_locals.contains(local) {
+        if needs_unique && !fully_replacable_locals.contains(local) {
             debug!("not fully replaceable");
             continue;
         }
@@ -203,13 +208,14 @@ fn compute_replacement<'tcx>(
             // have been visited before.
             Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
             | Rvalue::CopyForDeref(place) => {
-                if let Some(rhs) = place.as_local() {
+                if let Some(rhs) = place.as_local() && ssa.is_ssa(rhs) {
                     let target = targets[rhs];
-                    if matches!(target, Value::Pointer(..)) {
+                    // Only see through immutable reference and pointers, as we do not know yet if
+                    // mutable references are fully replaced.
+                    if !needs_unique && matches!(target, Value::Pointer(..)) {
                         targets[local] = target;
-                    } else if ssa.is_ssa(rhs) {
-                        let refmut = body.local_decls[rhs].ty.is_mutable_ptr();
-                        targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), refmut);
+                    } else {
+                        targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), needs_unique);
                     }
                 }
             }
@@ -217,10 +223,10 @@ fn compute_replacement<'tcx>(
                 let mut place = *place;
                 // Try to see through `place` in order to collapse reborrow chains.
                 if place.projection.first() == Some(&PlaceElem::Deref)
-                    && let Value::Pointer(target, refmut) = targets[place.local]
+                    && let Value::Pointer(target, inner_needs_unique) = targets[place.local]
                     // Only see through immutable reference and pointers, as we do not know yet if
                     // mutable references are fully replaced.
-                    && !refmut
+                    && !inner_needs_unique
                     // Only collapse chain if the pointee is definitely live.
                     && can_perform_opt(target, location)
                 {
@@ -228,7 +234,7 @@ fn compute_replacement<'tcx>(
                 }
                 assert_ne!(place.local, local);
                 if is_constant_place(place) {
-                    targets[local] = Value::Pointer(place, ty.is_mutable_ptr());
+                    targets[local] = Value::Pointer(place, needs_unique);
                 }
             }
             // We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +282,35 @@ fn compute_replacement<'tcx>(
                 return;
             }
 
-            if let Value::Pointer(target, refmut) = self.targets[place.local]
-                && place.projection.first() == Some(&PlaceElem::Deref)
-            {
-                let perform_opt = (self.can_perform_opt)(target, loc);
-                if perform_opt {
-                    self.allowed_replacements.insert((target.local, loc));
-                } else if refmut {
-                    // This mutable reference is not fully replacable, so drop it.
-                    self.targets[place.local] = Value::Unknown;
+            if place.projection.first() != Some(&PlaceElem::Deref) {
+                // This is not a dereference, nothing to do.
+                return;
+            }
+
+            let mut place = place.as_ref();
+            loop {
+                if let Value::Pointer(target, needs_unique) = self.targets[place.local] {
+                    let perform_opt = (self.can_perform_opt)(target, loc);
+                    debug!(?place, ?target, ?needs_unique, ?perform_opt);
+
+                    // This a reborrow chain, recursively allow the replacement.
+                    //
+                    // This also allows to detect cases where `target.local` is not replacable,
+                    // and mark it as such.
+                    if let &[PlaceElem::Deref] = &target.projection[..] {
+                        assert!(perform_opt);
+                        self.allowed_replacements.insert((target.local, loc));
+                        place.local = target.local;
+                        continue;
+                    } else if perform_opt {
+                        self.allowed_replacements.insert((target.local, loc));
+                    } else if needs_unique {
+                        // This mutable reference is not fully replacable, so drop it.
+                        self.targets[place.local] = Value::Unknown;
+                    }
                 }
+
+                break;
             }
         }
     }
@@ -326,18 +351,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
-        if let Value::Pointer(target, _) = self.targets[place.local]
-            && place.projection.first() == Some(&PlaceElem::Deref)
-        {
-            let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
-                || self.allowed_replacements.contains(&(target.local, loc));
-
-            if perform_opt {
-                *place = target.project_deeper(&place.projection[1..], self.tcx);
-                self.any_replacement = true;
+        if place.projection.first() != Some(&PlaceElem::Deref) {
+            return;
+        }
+
+        loop {
+            if let Value::Pointer(target, _) = self.targets[place.local] {
+                let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
+                    || self.allowed_replacements.contains(&(target.local, loc));
+
+                if perform_opt {
+                    *place = target.project_deeper(&place.projection[1..], self.tcx);
+                    self.any_replacement = true;
+                    continue;
+                }
             }
-        } else {
-            self.super_place(place, ctxt, loc);
+
+            break;
         }
     }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2a8287d5554f8..d7509cbf10e33 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1482,7 +1482,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
                 self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
 
-                if let LifetimeRes::Param { param, .. } = res {
+                if let LifetimeRes::Param { param, binder } = res {
                     match self.lifetime_uses.entry(param) {
                         Entry::Vacant(v) => {
                             debug!("First use of {:?} at {:?}", res, ident.span);
@@ -1496,10 +1496,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                                     LifetimeRibKind::Item
                                     | LifetimeRibKind::AnonymousReportError
                                     | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
-                                    // An anonymous lifetime is legal here, go ahead.
-                                    LifetimeRibKind::AnonymousCreateParameter { .. } => {
-                                        Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
-                                    }
+                                    // An anonymous lifetime is legal here, and bound to the right
+                                    // place, go ahead.
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder: anon_binder,
+                                        ..
+                                    } => Some(if binder == anon_binder {
+                                        LifetimeUseSet::One { use_span: ident.span, use_ctxt }
+                                    } else {
+                                        LifetimeUseSet::Many
+                                    }),
                                     // Only report if eliding the lifetime would have the same
                                     // semantics.
                                     LifetimeRibKind::Elided(r) => Some(if res == r {
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 56d6cc28bc83f..5ca5d14337cf0 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -31,6 +31,18 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
             }
         }
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+        DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
+            DefKind::TyAlias => ty::List::empty(),
+            DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+            // Nested opaque types only occur in associated types:
+            // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
+            // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
+            // and `&'static T`.
+            DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
+            def_kind @ _ => {
+                bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
+            }
+        },
         DefKind::Mod
         | DefKind::Struct
         | DefKind::Union
@@ -51,7 +63,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
         | DefKind::ForeignMod
         | DefKind::AnonConst
         | DefKind::InlineConst
-        | DefKind::OpaqueTy
         | DefKind::ImplTraitPlaceholder
         | DefKind::Field
         | DefKind::LifetimeParam
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 7e5a4d1c73532..f6b44bdf27ef9 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -643,7 +643,7 @@ impl UnifyKey for FloatVid {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
diff --git a/src/tools/cargo b/src/tools/cargo
index 26b73d15a68fb..13413c64ff88d 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 26b73d15a68fb94579f6d3590585ec0e9d81d3d5
+Subproject commit 13413c64ff88dd6c2824e9eb9374fc5f10895d28
diff --git a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
new file mode 100644
index 0000000000000..af8ee2411d36d
--- /dev/null
+++ b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
@@ -0,0 +1,74 @@
+- // MIR for `mut_raw_then_mut_shr` before ReferencePropagation
++ // MIR for `mut_raw_then_mut_shr` after ReferencePropagation
+  
+  fn mut_raw_then_mut_shr() -> (i32, i32) {
+      let mut _0: (i32, i32);              // return place in scope 0 at $DIR/reference_prop.rs:+0:30: +0:40
+      let mut _1: i32;                     // in scope 0 at $DIR/reference_prop.rs:+1:9: +1:14
+      let mut _4: *mut i32;                // in scope 0 at $DIR/reference_prop.rs:+3:16: +3:36
+      let mut _5: &mut i32;                // in scope 0 at $DIR/reference_prop.rs:+3:16: +3:26
+      let _8: ();                          // in scope 0 at $DIR/reference_prop.rs:+7:5: +7:26
+      let mut _9: i32;                     // in scope 0 at $DIR/reference_prop.rs:+8:6: +8:7
+      let mut _10: i32;                    // in scope 0 at $DIR/reference_prop.rs:+8:9: +8:10
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:14
+          let _2: &mut i32;                // in scope 1 at $DIR/reference_prop.rs:+2:9: +2:13
+          scope 2 {
+              debug xref => _2;            // in scope 2 at $DIR/reference_prop.rs:+2:9: +2:13
+              let _3: *mut i32;            // in scope 2 at $DIR/reference_prop.rs:+3:9: +3:13
+              scope 3 {
+                  debug xraw => _3;        // in scope 3 at $DIR/reference_prop.rs:+3:9: +3:13
+                  let _6: &i32;            // in scope 3 at $DIR/reference_prop.rs:+4:9: +4:13
+                  scope 4 {
+                      debug xshr => _6;    // in scope 4 at $DIR/reference_prop.rs:+4:9: +4:13
+                      let _7: i32;         // in scope 4 at $DIR/reference_prop.rs:+6:9: +6:10
+                      scope 5 {
+                          debug a => _7;   // in scope 5 at $DIR/reference_prop.rs:+6:9: +6:10
+                          scope 6 {
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/reference_prop.rs:+1:9: +1:14
+          _1 = const 2_i32;                // scope 0 at $DIR/reference_prop.rs:+1:17: +1:18
+-         StorageLive(_2);                 // scope 1 at $DIR/reference_prop.rs:+2:9: +2:13
+          _2 = &mut _1;                    // scope 1 at $DIR/reference_prop.rs:+2:16: +2:22
+          StorageLive(_3);                 // scope 2 at $DIR/reference_prop.rs:+3:9: +3:13
+-         StorageLive(_4);                 // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36
+-         StorageLive(_5);                 // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
+-         _5 = &mut (*_2);                 // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
+-         _4 = &raw mut (*_5);             // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
++         _4 = &raw mut _1;                // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
+          _3 = _4;                         // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36
+-         StorageDead(_5);                 // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37
+-         StorageDead(_4);                 // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37
+          StorageLive(_6);                 // scope 3 at $DIR/reference_prop.rs:+4:9: +4:13
+-         _6 = &(*_2);                     // scope 3 at $DIR/reference_prop.rs:+4:16: +4:22
++         _6 = &_1;                        // scope 3 at $DIR/reference_prop.rs:+4:16: +4:22
+          StorageLive(_7);                 // scope 4 at $DIR/reference_prop.rs:+6:9: +6:10
+-         _7 = (*_6);                      // scope 4 at $DIR/reference_prop.rs:+6:13: +6:18
+-         StorageLive(_8);                 // scope 5 at $DIR/reference_prop.rs:+7:5: +7:26
+-         (*_3) = const 4_i32;             // scope 6 at $DIR/reference_prop.rs:+7:14: +7:23
+-         _8 = const ();                   // scope 6 at $DIR/reference_prop.rs:+7:5: +7:26
+-         StorageDead(_8);                 // scope 5 at $DIR/reference_prop.rs:+7:25: +7:26
++         _7 = _1;                         // scope 4 at $DIR/reference_prop.rs:+6:13: +6:18
++         _1 = const 4_i32;                // scope 6 at $DIR/reference_prop.rs:+7:14: +7:23
+          StorageLive(_9);                 // scope 5 at $DIR/reference_prop.rs:+8:6: +8:7
+          _9 = _7;                         // scope 5 at $DIR/reference_prop.rs:+8:6: +8:7
+          StorageLive(_10);                // scope 5 at $DIR/reference_prop.rs:+8:9: +8:10
+          _10 = _1;                        // scope 5 at $DIR/reference_prop.rs:+8:9: +8:10
+          _0 = (move _9, move _10);        // scope 5 at $DIR/reference_prop.rs:+8:5: +8:11
+          StorageDead(_10);                // scope 5 at $DIR/reference_prop.rs:+8:10: +8:11
+          StorageDead(_9);                 // scope 5 at $DIR/reference_prop.rs:+8:10: +8:11
+          StorageDead(_7);                 // scope 4 at $DIR/reference_prop.rs:+9:1: +9:2
+          StorageDead(_6);                 // scope 3 at $DIR/reference_prop.rs:+9:1: +9:2
+          StorageDead(_3);                 // scope 2 at $DIR/reference_prop.rs:+9:1: +9:2
+-         StorageDead(_2);                 // scope 1 at $DIR/reference_prop.rs:+9:1: +9:2
+          StorageDead(_1);                 // scope 0 at $DIR/reference_prop.rs:+9:1: +9:2
+          return;                          // scope 0 at $DIR/reference_prop.rs:+9:2: +9:2
+      }
+  }
+  
diff --git a/tests/mir-opt/reference_prop.read_through_raw.ReferencePropagation.diff b/tests/mir-opt/reference_prop.read_through_raw.ReferencePropagation.diff
index a7d505c69066b..75c1f8f57ccae 100644
--- a/tests/mir-opt/reference_prop.read_through_raw.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.read_through_raw.ReferencePropagation.diff
@@ -9,15 +9,14 @@
       let mut _5: *mut usize;              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
   
       bb0: {
-          _2 = &mut (*_1);                 // scope 0 at $DIR/reference_prop.rs:+10:13: +10:25
+-         _2 = &mut (*_1);                 // scope 0 at $DIR/reference_prop.rs:+10:13: +10:25
 -         _3 = &mut (*_2);                 // scope 0 at $DIR/reference_prop.rs:+11:13: +11:26
 -         _4 = &raw mut (*_2);             // scope 0 at $DIR/reference_prop.rs:+12:13: +12:30
 -         _5 = &raw mut (*_3);             // scope 0 at $DIR/reference_prop.rs:+13:13: +13:30
 -         _0 = (*_4);                      // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
 -         _0 = (*_5);                      // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
-+         _3 = &mut (*_1);                 // scope 0 at $DIR/reference_prop.rs:+11:13: +11:26
-+         _0 = (*_2);                      // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
-+         _0 = (*_3);                      // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
++         _0 = (*_1);                      // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
++         _0 = (*_1);                      // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
           return;                          // scope 0 at $DIR/reference_prop.rs:+17:13: +17:21
       }
   }
diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs
index e3e5d791464eb..93f8d1df8e85a 100644
--- a/tests/mir-opt/reference_prop.rs
+++ b/tests/mir-opt/reference_prop.rs
@@ -433,6 +433,29 @@ fn maybe_dead(m: bool) {
     )
 }
 
+fn mut_raw_then_mut_shr() -> (i32, i32) {
+    let mut x = 2;
+    let xref = &mut x;
+    let xraw = &mut *xref as *mut _;
+    let xshr = &*xref;
+    // Verify that we completely replace with `x` in both cases.
+    let a = *xshr;
+    unsafe { *xraw = 4; }
+    (a, x)
+}
+
+fn unique_with_copies() {
+    let y = {
+        let mut a = 0;
+        let x = &raw mut a;
+        // `*y` is not replacable below, so we must not replace `*x`.
+        unsafe { opaque(*x) };
+        x
+    };
+    // But rewriting as `*x` is ok.
+    unsafe { opaque(*y) };
+}
+
 fn main() {
     let mut x = 5_usize;
     let mut y = 7_usize;
@@ -444,6 +467,8 @@ fn main() {
     multiple_storage();
     dominate_storage();
     maybe_dead(true);
+    mut_raw_then_mut_shr();
+    unique_with_copies();
 }
 
 // EMIT_MIR reference_prop.reference_propagation.ReferencePropagation.diff
@@ -454,3 +479,5 @@ fn main() {
 // EMIT_MIR reference_prop.multiple_storage.ReferencePropagation.diff
 // EMIT_MIR reference_prop.dominate_storage.ReferencePropagation.diff
 // EMIT_MIR reference_prop.maybe_dead.ReferencePropagation.diff
+// EMIT_MIR reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
+// EMIT_MIR reference_prop.unique_with_copies.ReferencePropagation.diff
diff --git a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
new file mode 100644
index 0000000000000..2cda2409e8093
--- /dev/null
+++ b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
@@ -0,0 +1,66 @@
+- // MIR for `unique_with_copies` before ReferencePropagation
++ // MIR for `unique_with_copies` after ReferencePropagation
+  
+  fn unique_with_copies() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/reference_prop.rs:+0:25: +0:25
+      let _1: *mut i32;                    // in scope 0 at $DIR/reference_prop.rs:+1:9: +1:10
+      let mut _2: i32;                     // in scope 0 at $DIR/reference_prop.rs:+2:13: +2:18
+      let _4: ();                          // in scope 0 at $DIR/reference_prop.rs:+5:18: +5:28
+      let mut _5: i32;                     // in scope 0 at $DIR/reference_prop.rs:+5:25: +5:27
+      let _6: ();                          // in scope 0 at $DIR/reference_prop.rs:+9:14: +9:24
+      let mut _7: i32;                     // in scope 0 at $DIR/reference_prop.rs:+9:21: +9:23
+      scope 1 {
+          debug y => _1;                   // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:10
+          scope 5 {
+          }
+      }
+      scope 2 {
+          debug a => _2;                   // in scope 2 at $DIR/reference_prop.rs:+2:13: +2:18
+          let _3: *mut i32;                // in scope 2 at $DIR/reference_prop.rs:+3:13: +3:14
+          scope 3 {
+              debug x => _3;               // in scope 3 at $DIR/reference_prop.rs:+3:13: +3:14
+              scope 4 {
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/reference_prop.rs:+1:9: +1:10
+          StorageLive(_2);                 // scope 0 at $DIR/reference_prop.rs:+2:13: +2:18
+          _2 = const 0_i32;                // scope 0 at $DIR/reference_prop.rs:+2:21: +2:22
+-         StorageLive(_3);                 // scope 2 at $DIR/reference_prop.rs:+3:13: +3:14
+          _3 = &raw mut _2;                // scope 2 at $DIR/reference_prop.rs:+3:17: +3:27
+          StorageLive(_4);                 // scope 3 at $DIR/reference_prop.rs:+5:9: +5:30
+          StorageLive(_5);                 // scope 4 at $DIR/reference_prop.rs:+5:25: +5:27
+          _5 = (*_3);                      // scope 4 at $DIR/reference_prop.rs:+5:25: +5:27
+          _4 = opaque::<i32>(move _5) -> bb1; // scope 4 at $DIR/reference_prop.rs:+5:18: +5:28
+                                           // mir::Constant
+                                           // + span: $DIR/reference_prop.rs:452:18: 452:24
+                                           // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_5);                 // scope 4 at $DIR/reference_prop.rs:+5:27: +5:28
+          StorageDead(_4);                 // scope 3 at $DIR/reference_prop.rs:+5:30: +5:31
+          _1 = _3;                         // scope 3 at $DIR/reference_prop.rs:+6:9: +6:10
+-         StorageDead(_3);                 // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6
+          StorageDead(_2);                 // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6
+          StorageLive(_6);                 // scope 1 at $DIR/reference_prop.rs:+9:5: +9:26
+          StorageLive(_7);                 // scope 5 at $DIR/reference_prop.rs:+9:21: +9:23
+-         _7 = (*_1);                      // scope 5 at $DIR/reference_prop.rs:+9:21: +9:23
++         _7 = (*_3);                      // scope 5 at $DIR/reference_prop.rs:+9:21: +9:23
+          _6 = opaque::<i32>(move _7) -> bb2; // scope 5 at $DIR/reference_prop.rs:+9:14: +9:24
+                                           // mir::Constant
+                                           // + span: $DIR/reference_prop.rs:456:14: 456:20
+                                           // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_7);                 // scope 5 at $DIR/reference_prop.rs:+9:23: +9:24
+          StorageDead(_6);                 // scope 1 at $DIR/reference_prop.rs:+9:26: +9:27
+          _0 = const ();                   // scope 0 at $DIR/reference_prop.rs:+0:25: +10:2
+          StorageDead(_1);                 // scope 0 at $DIR/reference_prop.rs:+10:1: +10:2
+          return;                          // scope 0 at $DIR/reference_prop.rs:+10:2: +10:2
+      }
+  }
+  
diff --git a/tests/ui/associated-inherent-types/issue-109790.rs b/tests/ui/associated-inherent-types/issue-109790.rs
index b2be19a28f442..88327f864237a 100644
--- a/tests/ui/associated-inherent-types/issue-109790.rs
+++ b/tests/ui/associated-inherent-types/issue-109790.rs
@@ -2,6 +2,7 @@
 
 #![feature(inherent_associated_types)]
 #![allow(incomplete_features)]
+#![deny(single_use_lifetimes)]
 
 struct Foo<T>(T);
 
diff --git a/tests/ui/lint/lint-non-snake-case-crate-2.stderr b/tests/ui/lint/lint-non-snake-case-crate-2.stderr
deleted file mode 100644
index 4b42145bbed8b..0000000000000
--- a/tests/ui/lint/lint-non-snake-case-crate-2.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: crate `NonSnakeCase` should have a snake case name
-   |
-   = help: convert the identifier to snake case: `non_snake_case`
-note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate-2.rs:4:9
-   |
-LL | #![deny(non_snake_case)]
-   |         ^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin.rs b/tests/ui/lint/lint-non-snake-case-crate-bin.rs
new file mode 100644
index 0000000000000..ef4ec35d2b927
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-bin.rs
@@ -0,0 +1,6 @@
+// check-pass
+#![crate_name = "NonSnakeCase"]
+
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-2.rs b/tests/ui/lint/lint-non-snake-case-crate-bin2.rs
similarity index 54%
rename from tests/ui/lint/lint-non-snake-case-crate-2.rs
rename to tests/ui/lint/lint-non-snake-case-crate-bin2.rs
index 1b763a9d868d9..fc80142aec83d 100644
--- a/tests/ui/lint/lint-non-snake-case-crate-2.rs
+++ b/tests/ui/lint/lint-non-snake-case-crate-bin2.rs
@@ -1,5 +1,5 @@
+// check-pass
 // compile-flags: --crate-name NonSnakeCase
-// error-pattern: crate `NonSnakeCase` should have a snake case name
 
 #![deny(non_snake_case)]
 
diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin3.rs b/tests/ui/lint/lint-non-snake-case-crate-bin3.rs
new file mode 100644
index 0000000000000..0327dbb07f7d5
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-bin3.rs
@@ -0,0 +1,7 @@
+// check-pass
+#![crate_type = "bin"]
+#![crate_name = "NonSnakeCase"]
+
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs b/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs
new file mode 100644
index 0000000000000..d2cd62fd68a8d
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs
@@ -0,0 +1,6 @@
+#![crate_type = "cdylib"]
+#![crate_name = "NonSnakeCase"]
+//~^ ERROR crate `NonSnakeCase` should have a snake case name
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr b/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr
new file mode 100644
index 0000000000000..e98747f9aadc1
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr
@@ -0,0 +1,14 @@
+error: crate `NonSnakeCase` should have a snake case name
+  --> $DIR/lint-non-snake-case-crate-cdylib.rs:2:18
+   |
+LL | #![crate_name = "NonSnakeCase"]
+   |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-non-snake-case-crate-cdylib.rs:4:9
+   |
+LL | #![deny(non_snake_case)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.rs b/tests/ui/lint/lint-non-snake-case-crate-dylib.rs
new file mode 100644
index 0000000000000..1ab974c54f6e3
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-dylib.rs
@@ -0,0 +1,6 @@
+#![crate_type = "dylib"]
+#![crate_name = "NonSnakeCase"]
+//~^ ERROR crate `NonSnakeCase` should have a snake case name
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr b/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr
new file mode 100644
index 0000000000000..162373819aed9
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr
@@ -0,0 +1,14 @@
+error: crate `NonSnakeCase` should have a snake case name
+  --> $DIR/lint-non-snake-case-crate-dylib.rs:2:18
+   |
+LL | #![crate_name = "NonSnakeCase"]
+   |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-non-snake-case-crate-dylib.rs:4:9
+   |
+LL | #![deny(non_snake_case)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-non-snake-case-crate.rs b/tests/ui/lint/lint-non-snake-case-crate-lib.rs
similarity index 85%
rename from tests/ui/lint/lint-non-snake-case-crate.rs
rename to tests/ui/lint/lint-non-snake-case-crate-lib.rs
index e4e84261a4ee9..79e020f07ba2a 100644
--- a/tests/ui/lint/lint-non-snake-case-crate.rs
+++ b/tests/ui/lint/lint-non-snake-case-crate-lib.rs
@@ -1,3 +1,4 @@
+#![crate_type = "lib"]
 #![crate_name = "NonSnakeCase"]
 //~^ ERROR crate `NonSnakeCase` should have a snake case name
 #![deny(non_snake_case)]
diff --git a/tests/ui/lint/lint-non-snake-case-crate.stderr b/tests/ui/lint/lint-non-snake-case-crate-lib.stderr
similarity index 77%
rename from tests/ui/lint/lint-non-snake-case-crate.stderr
rename to tests/ui/lint/lint-non-snake-case-crate-lib.stderr
index da6b89c1e0499..4030925b16e4a 100644
--- a/tests/ui/lint/lint-non-snake-case-crate.stderr
+++ b/tests/ui/lint/lint-non-snake-case-crate-lib.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:1:18
+  --> $DIR/lint-non-snake-case-crate-lib.rs:2:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:3:9
+  --> $DIR/lint-non-snake-case-crate-lib.rs:4:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs
new file mode 100644
index 0000000000000..949abe5573c79
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs
@@ -0,0 +1,6 @@
+#![crate_type = "proc-macro"]
+#![crate_name = "NonSnakeCase"]
+//~^ ERROR crate `NonSnakeCase` should have a snake case name
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr
new file mode 100644
index 0000000000000..4848c4abf8207
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr
@@ -0,0 +1,14 @@
+error: crate `NonSnakeCase` should have a snake case name
+  --> $DIR/lint-non-snake-case-crate-proc-macro.rs:2:18
+   |
+LL | #![crate_name = "NonSnakeCase"]
+   |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-non-snake-case-crate-proc-macro.rs:4:9
+   |
+LL | #![deny(non_snake_case)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.rs b/tests/ui/lint/lint-non-snake-case-crate-rlib.rs
new file mode 100644
index 0000000000000..1d5334d81f303
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-rlib.rs
@@ -0,0 +1,6 @@
+#![crate_type = "rlib"]
+#![crate_name = "NonSnakeCase"]
+//~^ ERROR crate `NonSnakeCase` should have a snake case name
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr b/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr
new file mode 100644
index 0000000000000..4d47c13f7d6d8
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr
@@ -0,0 +1,14 @@
+error: crate `NonSnakeCase` should have a snake case name
+  --> $DIR/lint-non-snake-case-crate-rlib.rs:2:18
+   |
+LL | #![crate_name = "NonSnakeCase"]
+   |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-non-snake-case-crate-rlib.rs:4:9
+   |
+LL | #![deny(non_snake_case)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs b/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs
new file mode 100644
index 0000000000000..d28fc9118aca8
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs
@@ -0,0 +1,6 @@
+#![crate_type = "staticlib"]
+#![crate_name = "NonSnakeCase"]
+//~^ ERROR crate `NonSnakeCase` should have a snake case name
+#![deny(non_snake_case)]
+
+fn main() {}
diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr b/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr
new file mode 100644
index 0000000000000..adc4b77d8beaa
--- /dev/null
+++ b/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr
@@ -0,0 +1,14 @@
+error: crate `NonSnakeCase` should have a snake case name
+  --> $DIR/lint-non-snake-case-crate-staticlib.rs:2:18
+   |
+LL | #![crate_name = "NonSnakeCase"]
+   |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-non-snake-case-crate-staticlib.rs:4:9
+   |
+LL | #![deny(non_snake_case)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
new file mode 100644
index 0000000000000..9e96323ab54bb
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
@@ -0,0 +1,25 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/wf-in-associated-type.rs:36:23
+   |
+LL |         type Opaque = impl Sized + 'a;
+   |                       ^^^^^^^^^^^^^^^ ...so that the type `&'a T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     impl<'a, T: 'a> Trait<'a, T> for () {
+   |               ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/wf-in-associated-type.rs:36:23
+   |
+LL |         type Opaque = impl Sized + 'a;
+   |                       ^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     impl<'a, T: 'a> Trait<'a, T> for () {
+   |               ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
new file mode 100644
index 0000000000000..31fbef9f78f83
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
@@ -0,0 +1,45 @@
+// WF check for impl Trait in associated type position.
+//
+// revisions: pass fail
+// [pass] check-pass
+// [fail] check-fail
+
+#![feature(impl_trait_in_assoc_type)]
+
+// The hidden type here (`&'a T`) requires proving `T: 'a`.
+// We know it holds because of implied bounds from the impl header.
+#[cfg(pass)]
+mod pass {
+    trait Trait<Req> {
+        type Opaque1;
+        fn constrain_opaque1(req: Req) -> Self::Opaque1;
+    }
+
+    impl<'a, T> Trait<&'a T> for () {
+        type Opaque1 = impl IntoIterator<Item = impl Sized + 'a>;
+        fn constrain_opaque1(req: &'a T) -> Self::Opaque1 {
+            [req]
+        }
+    }
+}
+
+// The hidden type here (`&'a T`) requires proving `T: 'a`,
+// but that is not known to hold in the impl.
+#[cfg(fail)]
+mod fail {
+    trait Trait<'a, T> {
+        type Opaque;
+        fn constrain_opaque(req: &'a T) -> Self::Opaque;
+    }
+
+    impl<'a, T> Trait<'a, T> for () {
+        type Opaque = impl Sized + 'a;
+        //[fail]~^ ERROR the parameter type `T` may not live long enough
+        //[fail]~| ERROR the parameter type `T` may not live long enough
+        fn constrain_opaque(req: &'a T) -> Self::Opaque {
+            req
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
new file mode 100644
index 0000000000000..753a46e882eda
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
@@ -0,0 +1,19 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/wf-nested.rs:55:27
+   |
+LL |     type InnerOpaque<T> = impl Sized;
+   |                           ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/wf-nested.rs:12:20
+   |
+LL | struct IsStatic<T: 'static>(T);
+   |                    ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     type InnerOpaque<T: 'static> = impl Sized;
+   |                       +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
new file mode 100644
index 0000000000000..9ab6685a7f73f
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/wf-nested.rs:46:17
+   |
+LL |         let _ = outer.get();
+   |                 ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn test<T: 'static>() {
+   |              +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/type-alias-impl-trait/wf-nested.rs b/tests/ui/type-alias-impl-trait/wf-nested.rs
new file mode 100644
index 0000000000000..de38832948918
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/wf-nested.rs
@@ -0,0 +1,60 @@
+// Well-formedness of nested opaque types, i.e. `impl Sized` in
+// `type Outer = impl Trait<Assoc = impl Sized>`.
+// See the comments below.
+//
+// revisions: pass pass_sound fail
+// [pass] check-pass
+// [pass_sound] check-fail
+// [fail] check-fail
+
+#![feature(type_alias_impl_trait)]
+
+struct IsStatic<T: 'static>(T);
+
+trait Trait<In> {
+    type Out;
+
+    fn get(&self) -> Result<Self::Out, ()> {
+        Err(())
+    }
+}
+
+impl<T> Trait<&'static T> for () {
+    type Out = IsStatic<T>;
+}
+
+// The hidden type for `impl Sized` is `IsStatic<T>`, which requires `T: 'static`.
+// We know it is well-formed because it can *only* be referenced as a projection:
+// <OuterOpaque<T> as Trait<&'static T>>::Out`.
+// So any instantiation of the type already requires proving `T: 'static`.
+#[cfg(pass)]
+mod pass {
+    use super::*;
+    type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
+    fn define<T>() -> OuterOpaque<T> {}
+}
+
+// Test the soundness of `pass` - We should require `T: 'static` at the use site.
+#[cfg(pass_sound)]
+mod pass_sound {
+    use super::*;
+    type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
+    fn define<T>() -> OuterOpaque<T> {}
+
+    fn test<T>() {
+        let outer = define::<T>();
+        let _ = outer.get(); //[pass_sound]~ ERROR `T` may not live long enough
+    }
+}
+
+// Similar to `pass` but here `impl Sized` can be referenced directly as
+// InnerOpaque<T>, so we require an explicit bound `T: 'static`.
+#[cfg(fail)]
+mod fail {
+    use super::*;
+    type InnerOpaque<T> = impl Sized; //[fail]~ ERROR `T` may not live long enough
+    type OuterOpaque<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
+    fn define<T>() -> OuterOpaque<T> {}
+}
+
+fn main() {}