about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs27
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs28
-rw-r--r--compiler/rustc_ast/src/visit.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs59
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs91
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs38
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs5
-rw-r--r--compiler/rustc_lint/src/context.rs10
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs34
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/item.rs82
-rw-r--r--compiler/rustc_target/src/spec/aarch64_linux_android.rs3
-rw-r--r--compiler/rustc_target/src/spec/arm_linux_androideabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/armv7_linux_androideabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_linux_android.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_android.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs217
-rw-r--r--src/test/rustdoc/intra-doc/associated-items.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-generic_associated_types.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr2
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87735.rs4
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87748.rs2
-rw-r--r--src/test/ui/generic-associated-types/collections-project-default.rs2
-rw-r--r--src/test/ui/generic-associated-types/collections.rs2
-rw-r--r--src/test/ui/generic-associated-types/construct_with_other_type.rs4
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path.rs2
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-types-where.rs2
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-types-where.stderr2
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds.rs6
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds.stderr18
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds_ok.rs6
-rw-r--r--src/test/ui/generic-associated-types/issue-47206-where-clause.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-47206-where-clause.stderr2
-rw-r--r--src/test/ui/generic-associated-types/issue-76826.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-84931.stderr6
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.rs9
-rw-r--r--src/test/ui/generic-associated-types/issue-88287.rs5
-rw-r--r--src/test/ui/generic-associated-types/issue-90014.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.rs5
-rw-r--r--src/test/ui/generic-associated-types/issue-92033.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-92280.rs5
-rw-r--r--src/test/ui/generic-associated-types/iterable.rs8
-rw-r--r--src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs2
-rw-r--r--src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr2
-rw-r--r--src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs2
-rw-r--r--src/test/ui/generic-associated-types/projection-bound-cycle.rs2
-rw-r--r--src/test/ui/generic-associated-types/streaming_iterator.rs4
-rw-r--r--src/test/ui/parser/bounds-lifetime-where.rs2
-rw-r--r--src/test/ui/parser/bounds-lifetime-where.stderr4
-rw-r--r--src/test/ui/parser/removed-syntax-ptr-lifetime.rs2
-rw-r--r--src/test/ui/parser/removed-syntax-ptr-lifetime.stderr4
-rw-r--r--src/test/ui/parser/type-alias-where-fixable.fixed30
-rw-r--r--src/test/ui/parser/type-alias-where-fixable.rs30
-rw-r--r--src/test/ui/parser/type-alias-where-fixable.stderr42
-rw-r--r--src/test/ui/parser/type-alias-where.rs28
-rw-r--r--src/test/ui/parser/type-alias-where.stderr36
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs48
m---------src/tools/miri17
-rw-r--r--src/tools/rustfmt/src/items.rs108
60 files changed, 705 insertions, 389 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 725499e5c78..ed5a282ec06 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2662,10 +2662,37 @@ pub struct Trait {
     pub items: Vec<P<AssocItem>>,
 }
 
+/// The location of a where clause on a `TyAlias` (`Span`) and whether there was
+/// a `where` keyword (`bool`). This is split out from `WhereClause`, since there
+/// are two locations for where clause on type aliases, but their predicates
+/// are concatenated together.
+///
+/// Take this example:
+/// ```ignore (only-for-syntax-highlight)
+/// trait Foo {
+///   type Assoc<'a, 'b> where Self: 'a, Self: 'b;
+/// }
+/// impl Foo for () {
+///   type Assoc<'a, 'b> where Self: 'a = () where Self: 'b;
+///   //                 ^^^^^^^^^^^^^^ first where clause
+///   //                                     ^^^^^^^^^^^^^^ second where clause
+/// }
+/// ```
+///
+/// If there is no where clause, then this is `false` with `DUMMY_SP`.
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
+pub struct TyAliasWhereClause(pub bool, pub Span);
+
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct TyAlias {
     pub defaultness: Defaultness,
     pub generics: Generics,
+    /// The span information for the two where clauses (before equals, after equals)
+    pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+    /// The index in `generics.where_clause.predicates` that would split into
+    /// predicates from the where clause before the equals and the predicates
+    /// from the where clause after the equals
+    pub where_predicates_split: usize,
     pub bounds: GenericBounds,
     pub ty: Option<P<Ty>>,
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index a81a2276295..c60c77e6987 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1018,9 +1018,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
         }
         ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
         ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
-        ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+        ItemKind::TyAlias(box TyAlias {
+            defaultness, generics, where_clauses, bounds, ty, ..
+        }) => {
             visit_defaultness(defaultness, vis);
             vis.visit_generics(generics);
+            vis.visit_span(&mut where_clauses.0.1);
+            vis.visit_span(&mut where_clauses.1.1);
             visit_bounds(bounds, vis);
             visit_opt(ty, |ty| vis.visit_ty(ty));
         }
@@ -1087,9 +1091,18 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
             visit_fn_sig(sig, visitor);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+        AssocItemKind::TyAlias(box TyAlias {
+            defaultness,
+            generics,
+            where_clauses,
+            bounds,
+            ty,
+            ..
+        }) => {
             visit_defaultness(defaultness, visitor);
             visitor.visit_generics(generics);
+            visitor.visit_span(&mut where_clauses.0.1);
+            visitor.visit_span(&mut where_clauses.1.1);
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
@@ -1152,9 +1165,18 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
             visit_fn_sig(sig, visitor);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+        ForeignItemKind::TyAlias(box TyAlias {
+            defaultness,
+            generics,
+            where_clauses,
+            bounds,
+            ty,
+            ..
+        }) => {
             visit_defaultness(defaultness, visitor);
             visitor.visit_generics(generics);
+            visitor.visit_span(&mut where_clauses.0.1);
+            visitor.visit_span(&mut where_clauses.1.1);
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 73e9297549c..ed16c25d921 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -303,7 +303,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
         ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
-        ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
+        ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, ty);
@@ -559,7 +559,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
             let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
-        ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
+        ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, ty);
@@ -665,7 +665,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
             let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
-        AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
+        AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, ty);
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index e8fca6f04ba..b452290dff4 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -25,6 +25,26 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
     pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
 }
 
+/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
+/// to the where clause that is prefered, if it exists. Otherwise, it sets the span to the other where
+/// clause if it exists.
+fn add_ty_alias_where_clause(
+    generics: &mut ast::Generics,
+    mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+    prefer_first: bool,
+) {
+    if !prefer_first {
+        where_clauses = (where_clauses.1, where_clauses.0);
+    }
+    if where_clauses.0.0 || !where_clauses.1.0 {
+        generics.where_clause.has_where_token = where_clauses.0.0;
+        generics.where_clause.span = where_clauses.0.1;
+    } else {
+        generics.where_clause.has_where_token = where_clauses.1.0;
+        generics.where_clause.span = where_clauses.1.1;
+    }
+}
+
 impl ItemLowerer<'_, '_, '_> {
     fn with_trait_impl_ref<T>(
         &mut self,
@@ -277,7 +297,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ItemKind::GlobalAsm(ref asm) => {
                 hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
             }
-            ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
+            ItemKind::TyAlias(box TyAlias {
+                ref generics,
+                where_clauses,
+                ty: Some(ref ty),
+                ..
+            }) => {
                 // We lower
                 //
                 // type Foo = impl Trait
@@ -292,16 +317,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         capturable_lifetimes: &mut FxHashSet::default(),
                     },
                 );
+                let mut generics = generics.clone();
+                add_ty_alias_where_clause(&mut generics, where_clauses, true);
                 let generics = self.lower_generics(
-                    generics,
+                    &generics,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
-            ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
+            ItemKind::TyAlias(box TyAlias {
+                ref generics, ref where_clauses, ty: None, ..
+            }) => {
                 let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
+                let mut generics = generics.clone();
+                add_ty_alias_where_clause(&mut generics, *where_clauses, true);
                 let generics = self.lower_generics(
-                    generics,
+                    &generics,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
@@ -832,18 +863,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
             }
-            AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
+            AssocItemKind::TyAlias(box TyAlias {
+                ref generics,
+                where_clauses,
+                ref bounds,
+                ref ty,
+                ..
+            }) => {
                 let ty = ty.as_ref().map(|x| {
                     self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
                 });
+                let mut generics = generics.clone();
+                add_ty_alias_where_clause(&mut generics, where_clauses, false);
                 let generics = self.lower_generics(
-                    generics,
+                    &generics,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                 );
                 let kind = hir::TraitItemKind::Type(
                     self.lower_param_bounds(
                         bounds,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     ),
                     ty,
                 );
@@ -917,9 +956,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                 (generics, hir::ImplItemKind::Fn(sig, body_id))
             }
-            AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
+            AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
+                let mut generics = generics.clone();
+                add_ty_alias_where_clause(&mut generics, *where_clauses, false);
                 let generics = self.lower_generics(
-                    generics,
+                    &generics,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                 );
                 let kind = match ty {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 20caed1b230..0cf73178d67 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -11,11 +11,13 @@ use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast::*;
-use rustc_ast_pretty::pprust;
+use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
 use rustc_parse::validate_attr;
-use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
+use rustc_session::lint::builtin::{
+    DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
+};
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
@@ -122,6 +124,42 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn check_gat_where(
+        &mut self,
+        id: NodeId,
+        before_predicates: &[WherePredicate],
+        where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+    ) {
+        if !before_predicates.is_empty() {
+            let mut state = State::new();
+            if !where_clauses.1.0 {
+                state.space();
+                state.word_space("where");
+            } else {
+                state.word_space(",");
+            }
+            let mut first = true;
+            for p in before_predicates.iter() {
+                if !first {
+                    state.word_space(",");
+                }
+                first = false;
+                state.print_where_predicate(p);
+            }
+            let suggestion = state.s.eof();
+            self.lint_buffer.buffer_lint_with_diagnostic(
+                DEPRECATED_WHERE_CLAUSE_LOCATION,
+                id,
+                where_clauses.0.1,
+                "where clause not allowed here",
+                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
+                    where_clauses.1.1.shrink_to_hi(),
+                    suggestion,
+                ),
+            );
+        }
+    }
+
     fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
         f(self);
@@ -454,7 +492,7 @@ impl<'a> AstValidator<'a> {
             .emit();
     }
 
-    fn check_foreign_ty_genericless(&self, generics: &Generics) {
+    fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
         let cannot_have = |span, descr, remove_descr| {
             self.err_handler()
                 .struct_span_err(
@@ -477,7 +515,7 @@ impl<'a> AstValidator<'a> {
         }
 
         if !generics.where_clause.predicates.is_empty() {
-            cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
+            cannot_have(where_span, "`where` clauses", "`where` clause");
         }
     }
 
@@ -1223,13 +1261,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 let msg = "free static item without body";
                 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
             }
-            ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
+            ItemKind::TyAlias(box TyAlias {
+                defaultness,
+                where_clauses,
+                ref bounds,
+                ref ty,
+                ..
+            }) => {
                 self.check_defaultness(item.span, defaultness);
                 if ty.is_none() {
                     let msg = "free type alias without body";
                     self.error_item_without_body(item.span, "type", msg, " = <type>;");
                 }
                 self.check_type_no_bounds(bounds, "this context");
+                if where_clauses.1.0 {
+                    let mut err = self.err_handler().struct_span_err(
+                        where_clauses.1.1,
+                        "where clauses are not allowed after the type for type aliases",
+                    );
+                    err.note(
+                        "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
+                    );
+                    err.emit();
+                }
             }
             _ => {}
         }
@@ -1245,11 +1299,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
                 self.check_foreign_item_ascii_only(fi.ident);
             }
-            ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
+            ForeignItemKind::TyAlias(box TyAlias {
+                defaultness,
+                generics,
+                where_clauses,
+                bounds,
+                ty,
+                ..
+            }) => {
                 self.check_defaultness(fi.span, *defaultness);
                 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
                 self.check_type_no_bounds(bounds, "`extern` blocks");
-                self.check_foreign_ty_genericless(generics);
+                self.check_foreign_ty_genericless(generics, where_clauses.0.1);
                 self.check_foreign_item_ascii_only(fi.ident);
             }
             ForeignItemKind::Static(_, _, body) => {
@@ -1503,9 +1564,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 AssocItemKind::Fn(box Fn { body, .. }) => {
                     self.check_impl_item_provided(item.span, body, "function", " { <body> }");
                 }
-                AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
+                AssocItemKind::TyAlias(box TyAlias {
+                    generics,
+                    where_clauses,
+                    where_predicates_split,
+                    bounds,
+                    ty,
+                    ..
+                }) => {
                     self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
                     self.check_type_no_bounds(bounds, "`impl`s");
+                    if ty.is_some() {
+                        self.check_gat_where(
+                            item.id,
+                            generics.where_clause.predicates.split_at(*where_predicates_split).0,
+                            *where_clauses,
+                        );
+                    }
                 }
                 _ => {}
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index d7e9ef0e50d..2a35dd1006e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -36,12 +36,16 @@ impl<'a> State<'a> {
             ast::ForeignItemKind::TyAlias(box ast::TyAlias {
                 defaultness,
                 generics,
+                where_clauses,
+                where_predicates_split,
                 bounds,
                 ty,
             }) => {
                 self.print_associated_type(
                     ident,
                     generics,
+                    *where_clauses,
+                    *where_predicates_split,
                     bounds,
                     ty.as_deref(),
                     vis,
@@ -95,11 +99,15 @@ impl<'a> State<'a> {
         &mut self,
         ident: Ident,
         generics: &ast::Generics,
+        where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+        where_predicates_split: usize,
         bounds: &ast::GenericBounds,
         ty: Option<&ast::Ty>,
         vis: &ast::Visibility,
         defaultness: ast::Defaultness,
     ) {
+        let (before_predicates, after_predicates) =
+            generics.where_clause.predicates.split_at(where_predicates_split);
         self.head("");
         self.print_visibility(vis);
         self.print_defaultness(defaultness);
@@ -107,12 +115,13 @@ impl<'a> State<'a> {
         self.print_ident(ident);
         self.print_generic_params(&generics.params);
         self.print_type_bounds(":", bounds);
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause_parts(where_clauses.0.0, before_predicates);
         if let Some(ty) = ty {
             self.space();
             self.word_space("=");
             self.print_type(ty);
         }
+        self.print_where_clause_parts(where_clauses.1.0, after_predicates);
         self.word(";");
         self.end(); // end inner head-block
         self.end(); // end outer head-block
@@ -211,6 +220,8 @@ impl<'a> State<'a> {
             ast::ItemKind::TyAlias(box ast::TyAlias {
                 defaultness,
                 ref generics,
+                where_clauses,
+                where_predicates_split,
                 ref bounds,
                 ref ty,
             }) => {
@@ -218,6 +229,8 @@ impl<'a> State<'a> {
                 self.print_associated_type(
                     item.ident,
                     generics,
+                    where_clauses,
+                    where_predicates_split,
                     bounds,
                     ty,
                     &item.vis,
@@ -496,10 +509,19 @@ impl<'a> State<'a> {
             ast::AssocItemKind::Const(def, ty, body) => {
                 self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
             }
-            ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+            ast::AssocItemKind::TyAlias(box ast::TyAlias {
+                defaultness,
+                generics,
+                where_clauses,
+                where_predicates_split,
+                bounds,
+                ty,
+            }) => {
                 self.print_associated_type(
                     ident,
                     generics,
+                    *where_clauses,
+                    *where_predicates_split,
                     bounds,
                     ty.as_deref(),
                     vis,
@@ -566,14 +588,22 @@ impl<'a> State<'a> {
     }
 
     fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
-        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+        self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates);
+    }
+
+    crate fn print_where_clause_parts(
+        &mut self,
+        has_where_token: bool,
+        predicates: &[ast::WherePredicate],
+    ) {
+        if predicates.is_empty() && !has_where_token {
             return;
         }
 
         self.space();
         self.word_space("where");
 
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+        for (i, predicate) in predicates.iter().enumerate() {
             if i != 0 {
                 self.word_space(",");
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 985c45e2253..f87f4726d1c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -560,6 +560,11 @@ impl<'a> TraitDef<'a> {
                 kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
                     defaultness: ast::Defaultness::Final,
                     generics: Generics::default(),
+                    where_clauses: (
+                        ast::TyAliasWhereClause::default(),
+                        ast::TyAliasWhereClause::default(),
+                    ),
+                    where_predicates_split: 0,
                     bounds: Vec::new(),
                     ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
                 })),
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index c6bbf769b23..b892e520d3b 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -818,6 +818,16 @@ pub trait LintContext: Sized {
                         }
                     }
                 },
+                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => {
+                    db.multipart_suggestion(
+                        "move it to the end of the type declaration",
+                        vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)],
+                        Applicability::MachineApplicable,
+                    );
+                    db.note(
+                        "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
+                    );
+                },
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 272913f3f0e..04a339f3c95 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3127,6 +3127,7 @@ declare_lint_pass! {
         DUPLICATE_MACRO_ATTRIBUTES,
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         UNEXPECTED_CFGS,
+        DEPRECATED_WHERE_CLAUSE_LOCATION,
     ]
 }
 
@@ -3737,3 +3738,36 @@ declare_lint! {
         reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>",
     };
 }
+
+declare_lint! {
+    /// The `deprecated_where_clause_location` lint detects when a where clause in front of the equals
+    /// in an associated type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(generic_associated_types)]
+    ///
+    /// trait Trait {
+    ///   type Assoc<'a> where Self: 'a;
+    /// }
+    ///
+    /// impl Trait for () {
+    ///   type Assoc<'a> where Self: 'a = ();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred location for where clauses on associated types in impls
+    /// is after the type. However, for most of generic associated types development,
+    /// it was only accepted before the equals. To provide a transition period and
+    /// further evaluate this change, both are currently accepted. At some point in
+    /// the future, this may be disallowed at an edition boundary; but, that is
+    /// undecided currently.
+    pub DEPRECATED_WHERE_CLAUSE_LOCATION,
+    Warn,
+    "deprecated where clause location"
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index e7f6dfa67b9..cd328b08735 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -427,6 +427,7 @@ pub enum BuiltinLintDiagnostics {
     NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
     UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+    DeprecatedWhereclauseLocation(Span, String),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 4f91f1fecba..5db1e4e0523 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -13,11 +13,12 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari
 use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, ErrorGuaranteed, PResult, StashKey};
+use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
 use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
 use rustc_span::lev_distance::lev_distance;
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::DUMMY_SP;
 
 use std::convert::TryFrom;
 use std::mem;
@@ -801,44 +802,6 @@ impl<'a> Parser<'a> {
         ))
     }
 
-    /// Emits an error that the where clause at the end of a type alias is not
-    /// allowed and suggests moving it.
-    fn error_ty_alias_where(
-        &self,
-        before_where_clause_present: bool,
-        before_where_clause_span: Span,
-        after_predicates: &[WherePredicate],
-        after_where_clause_span: Span,
-    ) -> ErrorGuaranteed {
-        let mut err =
-            self.struct_span_err(after_where_clause_span, "where clause not allowed here");
-        if !after_predicates.is_empty() {
-            let mut state = crate::pprust::State::new();
-            if !before_where_clause_present {
-                state.space();
-                state.word_space("where");
-            } else {
-                state.word_space(",");
-            }
-            let mut first = true;
-            for p in after_predicates.iter() {
-                if !first {
-                    state.word_space(",");
-                }
-                first = false;
-                state.print_where_predicate(p);
-            }
-            let suggestion = state.s.eof();
-            err.span_suggestion(
-                before_where_clause_span.shrink_to_hi(),
-                "move it here",
-                suggestion,
-                Applicability::MachineApplicable,
-            );
-        }
-        err.emit()
-    }
-
     /// Parses a `type` alias with the following grammar:
     /// ```
     /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
@@ -851,27 +814,40 @@ impl<'a> Parser<'a> {
         // Parse optional colon and param bounds.
         let bounds =
             if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
-
-        generics.where_clause = self.parse_where_clause()?;
+        let before_where_clause = self.parse_where_clause()?;
 
         let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
 
-        if self.token.is_keyword(kw::Where) {
-            let after_where_clause = self.parse_where_clause()?;
-
-            self.error_ty_alias_where(
-                generics.where_clause.has_where_token,
-                generics.where_clause.span,
-                &after_where_clause.predicates,
-                after_where_clause.span,
-            );
+        let after_where_clause = self.parse_where_clause()?;
 
-            generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
-        }
+        let where_clauses = (
+            TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span),
+            TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span),
+        );
+        let where_predicates_split = before_where_clause.predicates.len();
+        let mut predicates = before_where_clause.predicates;
+        predicates.extend(after_where_clause.predicates.into_iter());
+        let where_clause = WhereClause {
+            has_where_token: before_where_clause.has_where_token
+                || after_where_clause.has_where_token,
+            predicates,
+            span: DUMMY_SP,
+        };
+        generics.where_clause = where_clause;
 
         self.expect_semi()?;
 
-        Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
+        Ok((
+            ident,
+            ItemKind::TyAlias(Box::new(TyAlias {
+                defaultness,
+                generics,
+                where_clauses,
+                where_predicates_split,
+                bounds,
+                ty,
+            })),
+        ))
     }
 
     /// Parses a `UseTree`.
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 5692925f63b..87696b3664c 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -16,7 +16,8 @@ pub fn target() -> Target {
             features: "+neon,+fp-armv8".to_string(),
             supported_sanitizers: SanitizerSet::CFI
                 | SanitizerSet::HWADDRESS
-                | SanitizerSet::MEMTAG,
+                | SanitizerSet::MEMTAG
+                | SanitizerSet::ADDRESS,
             ..super::android_base::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
index 9b5366c576e..933b43986c9 100644
--- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -10,6 +10,7 @@ pub fn target() -> Target {
             abi: "eabi".to_string(),
             // https://developer.android.com/ndk/guides/abis.html#armeabi
             features: "+strict-align,+v5te".to_string(),
+            supported_sanitizers: SanitizerSet::ADDRESS,
             max_atomic_width: Some(32),
             ..super::android_base::opts()
         },
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 55956f3bad4..adf831c12eb 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
 
 // This target if is for the baseline of the Android v7a ABI
 // in thumb mode. It's named armv7-* instead of thumbv7-*
@@ -19,6 +19,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             abi: "eabi".to_string(),
             features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string(),
+            supported_sanitizers: SanitizerSet::ADDRESS,
             max_atomic_width: Some(64),
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 640f9e42f4a..e9ddaa37c26 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions};
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
@@ -21,6 +21,6 @@ pub fn target() -> Target {
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        options: base,
+        options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index 9065283b731..657520a8caf 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
@@ -16,6 +16,6 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: "x86_64".to_string(),
-        options: base,
+        options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base },
     }
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 3ebd28e83b1..aa771a06f9c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -26,7 +26,8 @@ use std::fmt::Write;
 use std::mem;
 use std::ops::Range;
 
-use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::{self, utils::find_nearest_parent_module};
+use crate::clean::{Crate, Item, ItemId, ItemLink, PrimitiveType};
 use crate::core::DocContext;
 use crate::html::markdown::{markdown_links, MarkdownLink};
 use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
@@ -177,6 +178,8 @@ enum ResolutionFailure<'a> {
     /// The link failed to resolve. [`resolution_failure`] should look to see if there's
     /// a more helpful error that can be given.
     NotResolved {
+        /// Item on which the link is resolved, used for resolving `Self`.
+        item_id: ItemId,
         /// The scope the link was resolved in.
         module_id: DefId,
         /// If part of the link resolved, this has the `Res`.
@@ -343,6 +346,7 @@ impl ItemFragment {
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 struct ResolutionInfo {
+    item_id: ItemId,
     module_id: DefId,
     dis: Option<Disambiguator>,
     path_str: String,
@@ -384,10 +388,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     fn variant_field<'path>(
         &self,
         path_str: &'path str,
+        item_id: ItemId,
         module_id: DefId,
     ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
+            item_id,
             module_id,
             partial_res: None,
             unresolved: path_str.into(),
@@ -410,13 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             // If there's no third component, we saw `[a::b]` before and it failed to resolve.
             // So there's no partial res.
             .ok_or_else(no_res)?;
-        let ty_res = self
-            .cx
-            .enter_resolver(|resolver| {
-                resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
-            })
-            .and_then(|(_, res)| res.try_into())
-            .map_err(|()| no_res())?;
+        let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
 
         match ty_res {
             Res::Def(DefKind::Enum, did) => {
@@ -437,6 +437,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                             Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
                         } else {
                             Err(ResolutionFailure::NotResolved {
+                                item_id,
                                 module_id,
                                 partial_res: Some(Res::Def(DefKind::Enum, def.did)),
                                 unresolved: variant_field_name.to_string().into(),
@@ -448,6 +449,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 }
             }
             _ => Err(ResolutionFailure::NotResolved {
+                item_id,
                 module_id,
                 partial_res: Some(ty_res),
                 unresolved: variant_name.to_string().into(),
@@ -481,6 +483,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     fn resolve_macro(
         &self,
         path_str: &'a str,
+        item_id: ItemId,
         module_id: DefId,
     ) -> Result<Res, ResolutionFailure<'a>> {
         self.cx.enter_resolver(|resolver| {
@@ -499,6 +502,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 return Ok(res.try_into().unwrap());
             }
             Err(ResolutionFailure::NotResolved {
+                item_id,
                 module_id,
                 partial_res: None,
                 unresolved: path_str.into(),
@@ -506,12 +510,52 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         })
     }
 
+    fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Option<Res> {
+        if ns != TypeNS || path_str != "Self" {
+            return None;
+        }
+
+        let tcx = self.cx.tcx;
+        item_id
+            .as_def_id()
+            .map(|def_id| match tcx.def_kind(def_id) {
+                def_kind @ (DefKind::AssocFn
+                | DefKind::AssocConst
+                | DefKind::AssocTy
+                | DefKind::Variant
+                | DefKind::Field) => {
+                    let parent_def_id = tcx.parent(def_id).expect("nested item has no parent");
+                    if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant
+                    {
+                        tcx.parent(parent_def_id).expect("variant has no parent")
+                    } else {
+                        parent_def_id
+                    }
+                }
+                _ => def_id,
+            })
+            .and_then(|self_id| match tcx.def_kind(self_id) {
+                DefKind::Impl => self.def_id_to_res(self_id),
+                def_kind => Some(Res::Def(def_kind, self_id)),
+            })
+    }
+
     /// Convenience wrapper around `resolve_str_path_error`.
     ///
     /// This also handles resolving `true` and `false` as booleans.
     /// NOTE: `resolve_str_path_error` knows only about paths, not about types.
     /// Associated items will never be resolved by this function.
-    fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
+    fn resolve_path(
+        &self,
+        path_str: &str,
+        ns: Namespace,
+        item_id: ItemId,
+        module_id: DefId,
+    ) -> Option<Res> {
+        if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) {
+            return res;
+        }
+
         let result = self.cx.enter_resolver(|resolver| {
             resolver
                 .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
@@ -532,10 +576,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &mut self,
         path_str: &'path str,
         ns: Namespace,
+        item_id: ItemId,
         module_id: DefId,
         user_fragment: &Option<String>,
     ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
-        let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?;
+        let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, item_id, module_id)?;
         let chosen_fragment = match (user_fragment, rustdoc_fragment) {
             (Some(_), Some(r_frag)) => {
                 let diag_res = match r_frag {
@@ -555,9 +600,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &mut self,
         path_str: &'path str,
         ns: Namespace,
+        item_id: ItemId,
         module_id: DefId,
     ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
-        if let Some(res) = self.resolve_path(path_str, ns, module_id) {
+        if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) {
             match res {
                 // FIXME(#76467): make this fallthrough to lookup the associated
                 // item a separate function.
@@ -585,6 +631,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             .ok_or_else(|| {
                 debug!("found no `::`, assumming {} was correctly not in scope", item_name);
                 ResolutionFailure::NotResolved {
+                    item_id,
                     module_id,
                     partial_res: None,
                     unresolved: item_str.into(),
@@ -596,7 +643,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         // error instead and special case *only* modules with `#[doc(primitive)]`, not all
         // primitives.
         resolve_primitive(&path_root, TypeNS)
-            .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
+            .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
             .and_then(|ty_res| {
                 let (res, fragment) =
                     self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
@@ -605,9 +652,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             })
             .unwrap_or_else(|| {
                 if ns == Namespace::ValueNS {
-                    self.variant_field(path_str, module_id)
+                    self.variant_field(path_str, item_id, module_id)
                 } else {
                     Err(ResolutionFailure::NotResolved {
+                        item_id,
                         module_id,
                         partial_res: None,
                         unresolved: path_root.into(),
@@ -723,10 +771,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 self.resolve_associated_item(res, item_name, ns, module_id)
             }
             Res::Def(
-                DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy,
+                def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
                 did,
             ) => {
                 debug!("looking for associated item named {} for item {:?}", item_name, did);
+                // Checks if item_name is a variant of the `SomeItem` enum
+                if ns == TypeNS && def_kind == DefKind::Enum {
+                    match tcx.type_of(did).kind() {
+                        ty::Adt(adt_def, _) => {
+                            for variant in &adt_def.variants {
+                                if variant.name == item_name {
+                                    return Some((
+                                        root_res,
+                                        ItemFragment(FragmentKind::Variant, variant.def_id),
+                                    ));
+                                }
+                            }
+                        }
+                        _ => unreachable!(),
+                    }
+                }
+
                 // Checks if item_name belongs to `impl SomeItem`
                 let assoc_item = tcx
                     .inherent_impls(did)
@@ -813,17 +878,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &mut self,
         ns: Namespace,
         path_str: &str,
+        item_id: ItemId,
         module_id: DefId,
         extra_fragment: &Option<String>,
     ) -> Option<Res> {
         // resolve() can't be used for macro namespace
         let result = match ns {
             Namespace::MacroNS => self
-                .resolve_macro(path_str, module_id)
+                .resolve_macro(path_str, item_id, module_id)
                 .map(|res| (res, None))
                 .map_err(ErrorKind::from),
             Namespace::TypeNS | Namespace::ValueNS => {
-                self.resolve(path_str, ns, module_id, extra_fragment)
+                self.resolve(path_str, ns, item_id, module_id, extra_fragment)
             }
         };
 
@@ -970,53 +1036,6 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
             trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
         }
 
-        // find item's parent to resolve `Self` in item's docs below
-        debug!("looking for the `Self` type");
-        let self_id = match item.def_id.as_def_id() {
-            None => None,
-            Some(did)
-                if (matches!(self.cx.tcx.def_kind(did), DefKind::Field)
-                    && matches!(
-                        self.cx.tcx.def_kind(self.cx.tcx.parent(did).unwrap()),
-                        DefKind::Variant
-                    )) =>
-            {
-                self.cx.tcx.parent(did).and_then(|item_id| self.cx.tcx.parent(item_id))
-            }
-            Some(did)
-                if matches!(
-                    self.cx.tcx.def_kind(did),
-                    DefKind::AssocConst
-                        | DefKind::AssocFn
-                        | DefKind::AssocTy
-                        | DefKind::Variant
-                        | DefKind::Field
-                ) =>
-            {
-                self.cx.tcx.parent(did)
-            }
-            Some(did) => Some(did),
-        };
-
-        // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
-        let self_name = self_id.and_then(|self_id| {
-            if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) {
-                // using `ty.to_string()` (or any variant) has issues with raw idents
-                let ty = self.cx.tcx.type_of(self_id);
-                let name = match ty.kind() {
-                    ty::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
-                    other if other.is_primitive() => Some(ty.to_string()),
-                    _ => None,
-                };
-                debug!("using type_of(): {:?}", name);
-                name
-            } else {
-                let name = self.cx.tcx.opt_item_name(self_id).map(|sym| sym.to_string());
-                debug!("using item_name(): {:?}", name);
-                name
-            }
-        });
-
         let inner_docs = item.inner_docs(self.cx.tcx);
 
         if item.is_mod() && inner_docs {
@@ -1038,7 +1057,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
             for md_link in markdown_links(&doc) {
-                let link = self.resolve_link(&item, &doc, &self_name, parent_node, krate, md_link);
+                let link = self.resolve_link(&item, &doc, parent_node, krate, md_link);
                 if let Some(link) = link {
                     self.cx.cache.intra_doc_links.entry(item.def_id).or_default().push(link);
                 }
@@ -1172,7 +1191,6 @@ impl LinkCollector<'_, '_> {
         &mut self,
         item: &Item,
         dox: &str,
-        self_name: &Option<String>,
         parent_node: Option<DefId>,
         krate: CrateNum,
         ori_link: MarkdownLink,
@@ -1240,19 +1258,8 @@ impl LinkCollector<'_, '_> {
         };
 
         let resolved_self;
-        // replace `Self` with suitable item's parent name
-        let is_lone_self = path_str == "Self";
         let is_lone_crate = path_str == "crate";
-        if path_str.starts_with("Self::") || is_lone_self {
-            if let Some(ref name) = self_name {
-                if is_lone_self {
-                    path_str = name;
-                } else {
-                    resolved_self = format!("{}::{}", name, &path_str[6..]);
-                    path_str = &resolved_self;
-                }
-            }
-        } else if path_str.starts_with("crate::") || is_lone_crate {
+        if path_str.starts_with("crate::") || is_lone_crate {
             use rustc_span::def_id::CRATE_DEF_INDEX;
 
             // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
@@ -1272,6 +1279,7 @@ impl LinkCollector<'_, '_> {
 
         let (mut res, fragment) = self.resolve_with_disambiguator_cached(
             ResolutionInfo {
+                item_id: item.def_id,
                 module_id,
                 dis: disambiguator,
                 path_str: path_str.to_owned(),
@@ -1514,12 +1522,13 @@ impl LinkCollector<'_, '_> {
     ) -> Option<(Res, Option<UrlFragment>)> {
         let disambiguator = key.dis;
         let path_str = &key.path_str;
+        let item_id = key.item_id;
         let base_node = key.module_id;
         let extra_fragment = &key.extra_fragment;
 
         match disambiguator.map(Disambiguator::ns) {
             Some(expected_ns @ (ValueNS | TypeNS)) => {
-                match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
+                match self.resolve(path_str, expected_ns, item_id, base_node, extra_fragment) {
                     Ok(res) => Some(res),
                     Err(ErrorKind::Resolve(box mut kind)) => {
                         // We only looked in one namespace. Try to give a better error if possible.
@@ -1528,9 +1537,13 @@ impl LinkCollector<'_, '_> {
                             // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
                             // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
                             for new_ns in [other_ns, MacroNS] {
-                                if let Some(res) =
-                                    self.check_full_res(new_ns, path_str, base_node, extra_fragment)
-                                {
+                                if let Some(res) = self.check_full_res(
+                                    new_ns,
+                                    path_str,
+                                    item_id,
+                                    base_node,
+                                    extra_fragment,
+                                ) {
                                     kind = ResolutionFailure::WrongNamespace { res, expected_ns };
                                     break;
                                 }
@@ -1552,9 +1565,15 @@ impl LinkCollector<'_, '_> {
                 // Try everything!
                 let mut candidates = PerNS {
                     macro_ns: self
-                        .resolve_macro(path_str, base_node)
+                        .resolve_macro(path_str, item_id, base_node)
                         .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
-                    type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
+                    type_ns: match self.resolve(
+                        path_str,
+                        TypeNS,
+                        item_id,
+                        base_node,
+                        extra_fragment,
+                    ) {
                         Ok(res) => {
                             debug!("got res in TypeNS: {:?}", res);
                             Ok(res)
@@ -1565,7 +1584,13 @@ impl LinkCollector<'_, '_> {
                         }
                         Err(ErrorKind::Resolve(box kind)) => Err(kind),
                     },
-                    value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) {
+                    value_ns: match self.resolve(
+                        path_str,
+                        ValueNS,
+                        item_id,
+                        base_node,
+                        extra_fragment,
+                    ) {
                         Ok(res) => Ok(res),
                         Err(ErrorKind::AnchorFailure(msg)) => {
                             anchor_failure(self.cx, diag, msg);
@@ -1624,14 +1649,18 @@ impl LinkCollector<'_, '_> {
                 }
             }
             Some(MacroNS) => {
-                match self.resolve_macro(path_str, base_node) {
+                match self.resolve_macro(path_str, item_id, base_node) {
                     Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
                     Err(mut kind) => {
                         // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
                         for ns in [TypeNS, ValueNS] {
-                            if let Some(res) =
-                                self.check_full_res(ns, path_str, base_node, extra_fragment)
-                            {
+                            if let Some(res) = self.check_full_res(
+                                ns,
+                                path_str,
+                                item_id,
+                                base_node,
+                                extra_fragment,
+                            ) {
                                 kind =
                                     ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
                                 break;
@@ -1958,11 +1987,16 @@ fn resolution_failure(
                 }
                 variants_seen.push(variant);
 
-                if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } =
-                    &mut failure
+                if let ResolutionFailure::NotResolved {
+                    item_id,
+                    module_id,
+                    partial_res,
+                    unresolved,
+                } = &mut failure
                 {
                     use DefKind::*;
 
+                    let item_id = *item_id;
                     let module_id = *module_id;
                     // FIXME(jynelson): this might conflict with my `Self` fix in #76467
                     // FIXME: maybe use itertools `collect_tuple` instead?
@@ -1984,7 +2018,8 @@ fn resolution_failure(
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
+                            if let Some(res) =
+                                collector.check_full_res(ns, start, item_id, module_id, &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs
index 9b70ea054ad..0b958eb8eac 100644
--- a/src/test/rustdoc/intra-doc/associated-items.rs
+++ b/src/test/rustdoc/intra-doc/associated-items.rs
@@ -57,4 +57,12 @@ impl T2 for S {
     fn ambiguous_method() {}
 }
 
+// @has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant'
+/// Link to [MyEnumAlias::MyVariant]
+pub enum MyEnum {
+    MyVariant,
+}
+
+pub type MyEnumAlias = MyEnum;
+
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
index 1d2be3657ff..c5c13451488 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
@@ -24,7 +24,7 @@ trait Bar {
 }
 
 impl Bar for Foo {
-    type Assoc where Self: Sized = Foo;
+    type Assoc = Foo where Self: Sized;
     //~^ ERROR where clauses on associated types are unstable
 }
 
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
index 6c2c3ed9c36..12a40ff0a12 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
@@ -55,7 +55,7 @@ LL |     type Assoc where Self: Sized;
 error[E0658]: where clauses on associated types are unstable
   --> $DIR/feature-gate-generic_associated_types.rs:27:5
    |
-LL |     type Assoc where Self: Sized = Foo;
+LL |     type Assoc = Foo where Self: Sized;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
index 6d6063f8085..53e3ad7fe69 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-87735.rs
+++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
@@ -12,7 +12,7 @@ pub trait AsRef2 {
 }
 
 impl<T> AsRef2 for Vec<T> {
-  type Output<'a> where Self: 'a = &'a [T];
+  type Output<'a> = &'a [T] where Self: 'a;
 
   fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
     &self[..]
@@ -33,7 +33,7 @@ where
     T: AsRef2<Output<'b> = &'b [U]>,
     U: 'b
 {
-  type Output<'a> where Self: 'a = FooRef<'a, U>;
+  type Output<'a> = FooRef<'a, U> where Self: 'a;
 
   fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
     FooRef(self.0.as_ref2())
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
index ffcfd62cbb3..6e7cd45bdb1 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-87748.rs
+++ b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
@@ -13,7 +13,7 @@ trait MyTrait {
 struct Foo;
 
 impl MyTrait for Foo {
-    type Assoc<'a, 'b> where 'b: 'a = u32;
+    type Assoc<'a, 'b> = u32 where 'b: 'a;
 
     fn do_sth(_: u32) {}
     // fn do_sth(_: Self::Assoc<'static, 'static>) {}
diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs
index 5b94cdee7c9..157e1b1d295 100644
--- a/src/test/ui/generic-associated-types/collections-project-default.rs
+++ b/src/test/ui/generic-associated-types/collections-project-default.rs
@@ -32,7 +32,7 @@ impl CollectionFamily for VecFamily {
 }
 
 impl<T> Collection<T> for Vec<T> {
-    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+    type Iter<'iter> = std::slice::Iter<'iter, T> where T: 'iter;
     type Family = VecFamily;
 
     fn empty() -> Self {
diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs
index b0f2fb3f567..1c00aa73feb 100644
--- a/src/test/ui/generic-associated-types/collections.rs
+++ b/src/test/ui/generic-associated-types/collections.rs
@@ -32,7 +32,7 @@ impl CollectionFamily for VecFamily {
 }
 
 impl<T> Collection<T> for Vec<T> {
-    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+    type Iter<'iter> = std::slice::Iter<'iter, T> where T: 'iter;
     type Family = VecFamily;
 
     fn empty() -> Self {
diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs
index 9ae328cc48b..060804269aa 100644
--- a/src/test/ui/generic-associated-types/construct_with_other_type.rs
+++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs
@@ -16,9 +16,9 @@ trait Baz {
 }
 
 impl<T> Baz for T where T: Foo {
-    type Quux<'a> where T: 'a = T;
+    type Quux<'a> = T where T: 'a;
 
-    type Baa<'a> where T: 'a = &'a <T as Foo>::Bar<'a, 'static>;
+    type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static> where T: 'a;
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
index fb03a86e169..7bbcf950ae1 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
@@ -15,7 +15,7 @@ impl Foo for Fooy {
 struct Fooer<T>(T);
 
 impl<T> Foo for Fooer<T> {
-    type A<'x> where T: 'x = &'x ();
+    type A<'x> = &'x () where T: 'x;
 }
 
 fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
index 592ff939923..2ecbc8c5912 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
@@ -19,7 +19,7 @@ impl Foo for Bar {
     type Assoc = usize;
     type Assoc2<T> = Vec<T>;
     //~^ ERROR `T` doesn't implement `std::fmt::Display`
-    type Assoc3<T> where T: Iterator = Vec<T>;
+    type Assoc3<T> = Vec<T> where T: Iterator;
     //~^ ERROR impl has stricter requirements than trait
     type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
     type NoGenerics = ::std::cell::Cell<i32>;
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
index 544f2bcbbd7..68594bba486 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
@@ -16,7 +16,7 @@ error[E0276]: impl has stricter requirements than trait
 LL |     type Assoc3<T>;
    |     --------------- definition of `Assoc3` from trait
 ...
-LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+LL |     type Assoc3<T> = Vec<T> where T: Iterator;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs
index ff2ffec22c4..bb5992c88f0 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.rs
+++ b/src/test/ui/generic-associated-types/impl_bounds.rs
@@ -12,12 +12,12 @@ trait Foo {
 struct Fooy<T>(T);
 
 impl<T> Foo for Fooy<T> {
-    type A<'a> where Self: 'static = (&'a ());
+    type A<'a> = (&'a ()) where Self: 'static;
     //~^ ERROR `impl` associated type
-    type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+    type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
     //~^ ERROR `impl` associated type
     //~| ERROR lifetime bound not satisfied
-    type C where Self: Copy = String;
+    type C = String where Self: Copy;
     //~^ ERROR the trait bound `T: Copy` is not satisfied
     fn d() where Self: Copy {}
     //~^ ERROR the trait bound `T: Copy` is not satisfied
diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr
index bd0dea37219..3d90471e398 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.stderr
+++ b/src/test/ui/generic-associated-types/impl_bounds.stderr
@@ -4,7 +4,7 @@ error: `impl` associated type signature for `A` doesn't match `trait` associated
 LL |     type A<'a> where Self: 'a;
    |     -------------------------- expected
 ...
-LL |     type A<'a> where Self: 'static = (&'a ());
+LL |     type A<'a> = (&'a ()) where Self: 'static;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
 
 error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
@@ -13,35 +13,33 @@ error: `impl` associated type signature for `B` doesn't match `trait` associated
 LL |     type B<'a, 'b> where 'a: 'b;
    |     ---------------------------- expected
 ...
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/impl_bounds.rs:17:35
+  --> $DIR/impl_bounds.rs:17:22
    |
 LL |     type B<'a, 'b> where 'a: 'b;
    |     ---------------------------- definition of `B` from trait
 ...
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-   |                                -  ^^^^^^^^^^^^^^^
-   |                                |
-   |                                help: try copying this clause from the trait: `, 'a: 'b`
+LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
+   |                      ^^^^^^^^^^^^^^^             - help: try copying this clause from the trait: `, 'a: 'b`
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
   --> $DIR/impl_bounds.rs:17:12
    |
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
    |            ^^
 note: but lifetime parameter must outlive the lifetime `'b` as defined here
   --> $DIR/impl_bounds.rs:17:16
    |
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
    |                ^^
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/impl_bounds.rs:20:5
    |
-LL |     type C where Self: Copy = String;
+LL |     type C = String where Self: Copy;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
    |
 note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
diff --git a/src/test/ui/generic-associated-types/impl_bounds_ok.rs b/src/test/ui/generic-associated-types/impl_bounds_ok.rs
index 08120b9670f..4df8235d95f 100644
--- a/src/test/ui/generic-associated-types/impl_bounds_ok.rs
+++ b/src/test/ui/generic-associated-types/impl_bounds_ok.rs
@@ -22,9 +22,9 @@ impl Foo for Fooy {
 struct Fooer<T>(T);
 
 impl<T> Foo for Fooer<T> {
-    type A<'x> where T: 'x = (&'x ());
-    type B<'u, 'v> where 'u: 'v = (&'v &'u ());
-    type C where Self: Clone + ToOwned = String;
+    type A<'x> = (&'x ()) where T: 'x;
+    type B<'u, 'v> = (&'v &'u ()) where 'u: 'v;
+    type C = String where Self: Clone + ToOwned;
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
index da5fca2a656..d352c1948f2 100644
--- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
+++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
@@ -9,7 +9,7 @@ trait Foo {
 struct Bar;
 
 impl Foo for Bar {
-    type Assoc3<T> where T: Iterator = Vec<T>;
+    type Assoc3<T> = Vec<T> where T: Iterator;
     //~^ ERROR impl has stricter requirements than trait
 }
 
diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
index 56677457726..39beac38c0b 100644
--- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
+++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
@@ -4,7 +4,7 @@ error[E0276]: impl has stricter requirements than trait
 LL |     type Assoc3<T>;
    |     --------------- definition of `Assoc3` from trait
 ...
-LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+LL |     type Assoc3<T> = Vec<T> where T: Iterator;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
 
 error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/issue-76826.rs b/src/test/ui/generic-associated-types/issue-76826.rs
index d3201a156a1..28eb3b0e750 100644
--- a/src/test/ui/generic-associated-types/issue-76826.rs
+++ b/src/test/ui/generic-associated-types/issue-76826.rs
@@ -29,7 +29,7 @@ impl<T> Windows<T> {
 }
 
 impl<T> Iter for Windows<T> {
-    type Item<'a> where T: 'a = &'a mut [T];
+    type Item<'a> = &'a mut [T] where T: 'a;
 
     fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
         let slice = self.items.get_mut(self.start..self.start + self.len)?;
diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs
index 47ef38ff45d..b9a3c583f7c 100644
--- a/src/test/ui/generic-associated-types/issue-79422.rs
+++ b/src/test/ui/generic-associated-types/issue-79422.rs
@@ -22,7 +22,7 @@ trait MapLike<K, V> {
 }
 
 impl<K: Ord, V: 'static> MapLike<K, V> for std::collections::BTreeMap<K, V> {
-    type VRefCont<'a> where Self: 'a = &'a V;
+    type VRefCont<'a> = &'a V where Self: 'a;
     fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
         std::collections::BTreeMap::get(self, key)
     }
diff --git a/src/test/ui/generic-associated-types/issue-84931.stderr b/src/test/ui/generic-associated-types/issue-84931.stderr
index 47decb70ae7..11c3dffde4b 100644
--- a/src/test/ui/generic-associated-types/issue-84931.stderr
+++ b/src/test/ui/generic-associated-types/issue-84931.stderr
@@ -2,9 +2,9 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-84931.rs:15:21
    |
 LL |     type Item<'a> = &'a mut T;
-   |                  -  ^^^^^^^^^ ...so that the reference type `&'a mut T` does not outlive the data it points at
-   |                  |
-   |                  help: consider adding a where clause: `where T: 'a`
+   |                     ^^^^^^^^^- help: consider adding a where clause: `where T: 'a`
+   |                     |
+   |                     ...so that the reference type `&'a mut T` does not outlive the data it points at
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs
index 5863bac2f9d..0f8096c8a7c 100644
--- a/src/test/ui/generic-associated-types/issue-86787.rs
+++ b/src/test/ui/generic-associated-types/issue-86787.rs
@@ -21,13 +21,10 @@ where
     Right: HasChildrenOf,
 {
     type T = Either<Left::T, Right::T>;
-    // We used to error below because the where clause doesn't match the trait.
-    // Now, we error early on the trait itself.
-    type TRef<'a>
+    type TRef<'a> = Either<&'a Left::T, &'a Right::T>
     where
-    <Left as HasChildrenOf>::T: 'a,
-    <Right as HasChildrenOf>::T: 'a
-    = Either<&'a Left::T, &'a Right::T>;
+        <Left as HasChildrenOf>::T: 'a,
+        <Right as HasChildrenOf>::T: 'a;
 
     fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>> {
         todo!()
diff --git a/src/test/ui/generic-associated-types/issue-88287.rs b/src/test/ui/generic-associated-types/issue-88287.rs
index df5586ed422..6b10edf073f 100644
--- a/src/test/ui/generic-associated-types/issue-88287.rs
+++ b/src/test/ui/generic-associated-types/issue-88287.rs
@@ -27,11 +27,10 @@ impl<T, Criteria> SearchableResourceExt<Criteria> for T
 where
     T: SearchableResource<Criteria>,
 {
-    type Future<'f, A, B: 'f>
+    type Future<'f, A, B: 'f> = SearchFutureTy<'f, A, B>
     where
         A: SearchableResource<B> + ?Sized + 'f,
-        Self: 'f,
-    = SearchFutureTy<'f, A, B>;
+        Self: 'f;
 
     fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> {
         async move { todo!() }
diff --git a/src/test/ui/generic-associated-types/issue-90014.stderr b/src/test/ui/generic-associated-types/issue-90014.stderr
index f8fb71bbddb..51fe3360c7e 100644
--- a/src/test/ui/generic-associated-types/issue-90014.stderr
+++ b/src/test/ui/generic-associated-types/issue-90014.stderr
@@ -5,9 +5,7 @@ LL |     type Fut<'a> where Self: 'a;
    |     ---------------------------- definition of `Fut` from trait
 ...
 LL |     type Fut<'a> = impl Future<Output = ()>;
-   |                 -  ^^^^^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 help: try copying this clause from the trait: `where Self: 'a`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
    |
 note: type must outlive the lifetime `'a` as defined here
   --> $DIR/issue-90014.rs:14:14
diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs
index 2b82d2946b3..5c4a7cf6ffc 100644
--- a/src/test/ui/generic-associated-types/issue-91139.rs
+++ b/src/test/ui/generic-associated-types/issue-91139.rs
@@ -9,10 +9,9 @@ trait Foo<T> {
 }
 
 impl<T> Foo<T> for () {
-    type Type<'a>
+    type Type<'a> = ()
     where
-        T: 'a,
-    = ();
+        T: 'a;
 }
 
 fn foo<T>() {
diff --git a/src/test/ui/generic-associated-types/issue-92033.stderr b/src/test/ui/generic-associated-types/issue-92033.stderr
index caa6618f398..5b90199b809 100644
--- a/src/test/ui/generic-associated-types/issue-92033.stderr
+++ b/src/test/ui/generic-associated-types/issue-92033.stderr
@@ -7,9 +7,7 @@ LL | |         Self: 'a;
    | |_________________- definition of `TextureIter` from trait
 ...
 LL |       type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
-   |                           -  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                           |
-   |                           help: try copying this clause from the trait: `where Self: 'a`
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
    |
 note: type must outlive the lifetime `'a` as defined here
   --> $DIR/issue-92033.rs:22:22
diff --git a/src/test/ui/generic-associated-types/issue-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs
index db26493ecad..81d000f1076 100644
--- a/src/test/ui/generic-associated-types/issue-92280.rs
+++ b/src/test/ui/generic-associated-types/issue-92280.rs
@@ -17,10 +17,9 @@ struct KeySegment_Broken<T> {
     key: T,
 }
 impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> {
-    type Iter<'a>
+    type Iter<'a> = ()
     where
-        Self: 'a,
-    = ();
+        Self: 'a;
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs
index 952fca8ab8a..af0049891b6 100644
--- a/src/test/ui/generic-associated-types/iterable.rs
+++ b/src/test/ui/generic-associated-types/iterable.rs
@@ -11,8 +11,8 @@ trait Iterable {
 
 // Impl for struct type
 impl<T> Iterable for Vec<T> {
-    type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
+    type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a;
+    type Iter<'a> = std::slice::Iter<'a, T> where T: 'a;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
         self[..].iter()
@@ -21,8 +21,8 @@ impl<T> Iterable for Vec<T> {
 
 // Impl for a primitive type
 impl<T> Iterable for [T] {
-    type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
+    type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a;
+    type Iter<'a> = std::slice::Iter<'a, T> where T: 'a;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
         self.iter()
diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
index ad9f2e3e4ec..5fb8f7a4773 100644
--- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
+++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
@@ -6,7 +6,7 @@ trait Foo {
     type Assoc<'a, 'b>;
 }
 impl Foo for () {
-    type Assoc<'a, 'b> where 'a: 'b = ();
+    type Assoc<'a, 'b> = () where 'a: 'b;
     //~^ `impl` associated type
 }
 
diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
index 0e183c8d69a..9e0896127a8 100644
--- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
+++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
@@ -4,7 +4,7 @@ error: `impl` associated type signature for `Assoc` doesn't match `trait` associ
 LL |     type Assoc<'a, 'b>;
    |     ------------------- expected
 ...
-LL |     type Assoc<'a, 'b> where 'a: 'b = ();
+LL |     type Assoc<'a, 'b> = () where 'a: 'b;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
 
 error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
index 7517e1fa9d0..794d677c8b6 100644
--- a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
@@ -22,7 +22,7 @@ impl<T> Foo for Number<T> {
     // }
     // ```
     // which it is :)
-    type Item where [T]: Sized = [T];
+    type Item = [T] where [T]: Sized;
 }
 
 struct OnlySized<T> where T: Sized { f: T }
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle.rs b/src/test/ui/generic-associated-types/projection-bound-cycle.rs
index 8f8cb679e9c..6564a3608ec 100644
--- a/src/test/ui/generic-associated-types/projection-bound-cycle.rs
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle.rs
@@ -24,7 +24,7 @@ impl Foo for Number {
     // }
     // ```
     // which it is :)
-    type Item where str: Sized = str;
+    type Item = str where str: Sized;
 }
 
 struct OnlySized<T> where T: Sized { f: T }
diff --git a/src/test/ui/generic-associated-types/streaming_iterator.rs b/src/test/ui/generic-associated-types/streaming_iterator.rs
index f83d4d7b68e..e71b6805ad4 100644
--- a/src/test/ui/generic-associated-types/streaming_iterator.rs
+++ b/src/test/ui/generic-associated-types/streaming_iterator.rs
@@ -30,7 +30,7 @@ struct StreamEnumerate<I> {
 }
 
 impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
-    type Item<'a> where Self: 'a = (usize, I::Item<'a>);
+    type Item<'a> = (usize, I::Item<'a>) where Self: 'a;
     fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
         match self.iter.next() {
             None => None,
@@ -44,7 +44,7 @@ impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
 }
 
 impl<I: Iterator> StreamingIterator for I {
-    type Item<'a> where Self: 'a = <I as Iterator>::Item;
+    type Item<'a> = <I as Iterator>::Item where Self: 'a;
     fn next(&mut self) -> Option<<I as StreamingIterator>::Item<'_>> {
         Iterator::next(self)
     }
diff --git a/src/test/ui/parser/bounds-lifetime-where.rs b/src/test/ui/parser/bounds-lifetime-where.rs
index e60cc153e67..7ff75233d3a 100644
--- a/src/test/ui/parser/bounds-lifetime-where.rs
+++ b/src/test/ui/parser/bounds-lifetime-where.rs
@@ -5,6 +5,6 @@ type A where 'a:, = u8; // OK
 type A where 'a: 'b + 'c = u8; // OK
 type A where = u8; // OK
 type A where 'a: 'b + = u8; // OK
-type A where , = u8; //~ ERROR expected one of `;`, `=`, lifetime, or type, found `,`
+type A where , = u8; //~ ERROR expected one of `;`, `=`, `where`, lifetime, or type, found `,`
 
 fn main() {}
diff --git a/src/test/ui/parser/bounds-lifetime-where.stderr b/src/test/ui/parser/bounds-lifetime-where.stderr
index 950fa46c66b..785a1fb6793 100644
--- a/src/test/ui/parser/bounds-lifetime-where.stderr
+++ b/src/test/ui/parser/bounds-lifetime-where.stderr
@@ -1,8 +1,8 @@
-error: expected one of `;`, `=`, lifetime, or type, found `,`
+error: expected one of `;`, `=`, `where`, lifetime, or type, found `,`
   --> $DIR/bounds-lifetime-where.rs:8:14
    |
 LL | type A where , = u8;
-   |              ^ expected one of `;`, `=`, lifetime, or type
+   |              ^ expected one of `;`, `=`, `where`, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/removed-syntax-ptr-lifetime.rs b/src/test/ui/parser/removed-syntax-ptr-lifetime.rs
index 5b551addbc8..cc69af44a13 100644
--- a/src/test/ui/parser/removed-syntax-ptr-lifetime.rs
+++ b/src/test/ui/parser/removed-syntax-ptr-lifetime.rs
@@ -1 +1 @@
-type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/`
+type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, `<`, or `where`, found `/`
diff --git a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr
index 5b388ff4ce0..914de43e62d 100644
--- a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr
+++ b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr
@@ -1,8 +1,8 @@
-error: expected one of `!`, `(`, `::`, `;`, or `<`, found `/`
+error: expected one of `!`, `(`, `::`, `;`, `<`, or `where`, found `/`
   --> $DIR/removed-syntax-ptr-lifetime.rs:1:22
    |
 LL | type bptr = &lifetime/isize;
-   |                      ^ expected one of `!`, `(`, `::`, `;`, or `<`
+   |                      ^ expected one of `!`, `(`, `::`, `;`, `<`, or `where`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/type-alias-where-fixable.fixed b/src/test/ui/parser/type-alias-where-fixable.fixed
new file mode 100644
index 00000000000..41dd10676d5
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where-fixable.fixed
@@ -0,0 +1,30 @@
+// check-pass
+// run-rustfix
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+    // Fine.
+    type Assoc where u32: Copy;
+    // Fine.
+    type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+    // Not fine, suggests moving.
+    type Assoc  = () where u32: Copy;
+    //~^ WARNING where clause not allowed here
+    // Not fine, suggests moving `u32: Copy`
+    type Assoc2  = () where i32: Copy, u32: Copy;
+    //~^ WARNING where clause not allowed here
+}
+
+impl Trait for i32 {
+    // Fine.
+    type Assoc = () where u32: Copy;
+    // Not fine, suggests moving both.
+    type Assoc2  = () where u32: Copy, i32: Copy;
+    //~^ WARNING where clause not allowed here
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/type-alias-where-fixable.rs b/src/test/ui/parser/type-alias-where-fixable.rs
new file mode 100644
index 00000000000..562a530a7f3
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where-fixable.rs
@@ -0,0 +1,30 @@
+// check-pass
+// run-rustfix
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+    // Fine.
+    type Assoc where u32: Copy;
+    // Fine.
+    type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+    // Not fine, suggests moving.
+    type Assoc where u32: Copy = ();
+    //~^ WARNING where clause not allowed here
+    // Not fine, suggests moving `u32: Copy`
+    type Assoc2 where u32: Copy = () where i32: Copy;
+    //~^ WARNING where clause not allowed here
+}
+
+impl Trait for i32 {
+    // Fine.
+    type Assoc = () where u32: Copy;
+    // Not fine, suggests moving both.
+    type Assoc2 where u32: Copy, i32: Copy = ();
+    //~^ WARNING where clause not allowed here
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/type-alias-where-fixable.stderr b/src/test/ui/parser/type-alias-where-fixable.stderr
new file mode 100644
index 00000000000..7ec1a965bae
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where-fixable.stderr
@@ -0,0 +1,42 @@
+warning: where clause not allowed here
+  --> $DIR/type-alias-where-fixable.rs:15:16
+   |
+LL |     type Assoc where u32: Copy = ();
+   |                ^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(deprecated_where_clause_location)]` on by default
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL -     type Assoc where u32: Copy = ();
+LL +     type Assoc  = () where u32: Copy;
+   | 
+
+warning: where clause not allowed here
+  --> $DIR/type-alias-where-fixable.rs:18:17
+   |
+LL |     type Assoc2 where u32: Copy = () where i32: Copy;
+   |                 ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL -     type Assoc2 where u32: Copy = () where i32: Copy;
+LL +     type Assoc2  = () where i32: Copy, u32: Copy;
+   | 
+
+warning: where clause not allowed here
+  --> $DIR/type-alias-where-fixable.rs:26:17
+   |
+LL |     type Assoc2 where u32: Copy, i32: Copy = ();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL -     type Assoc2 where u32: Copy, i32: Copy = ();
+LL +     type Assoc2  = () where u32: Copy, i32: Copy;
+   | 
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs
index a9fa23dd95e..f6e7dfb7b7b 100644
--- a/src/test/ui/parser/type-alias-where.rs
+++ b/src/test/ui/parser/type-alias-where.rs
@@ -6,32 +6,8 @@
 type Foo where u32: Copy = ();
 // Not fine.
 type Bar = () where u32: Copy;
-//~^ ERROR where clause not allowed here
+//~^ ERROR where clauses are not allowed
 type Baz = () where;
-//~^ ERROR where clause not allowed here
-
-trait Trait {
-    // Fine.
-    type Assoc where u32: Copy;
-    // Fine.
-    type Assoc2 where u32: Copy, i32: Copy;
-}
-
-impl Trait for u32 {
-    // Fine.
-    type Assoc where u32: Copy = ();
-    // Not fine, suggests moving `i32: Copy`
-    type Assoc2 where u32: Copy = () where i32: Copy;
-    //~^ ERROR where clause not allowed here
-}
-
-impl Trait for i32 {
-    // Not fine, suggests moving `u32: Copy`
-    type Assoc = () where u32: Copy;
-    //~^ ERROR where clause not allowed here
-    // Not fine, suggests moving both.
-    type Assoc2 = () where u32: Copy, i32: Copy;
-    //~^ ERROR where clause not allowed here
-}
+//~^ ERROR where clauses are not allowed
 
 fn main() {}
diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr
index 7ab0b28c864..8789d2665ad 100644
--- a/src/test/ui/parser/type-alias-where.stderr
+++ b/src/test/ui/parser/type-alias-where.stderr
@@ -1,40 +1,18 @@
-error: where clause not allowed here
+error: where clauses are not allowed after the type for type aliases
   --> $DIR/type-alias-where.rs:8:15
    |
 LL | type Bar = () where u32: Copy;
-   |         -     ^^^^^^^^^^^^^^^
-   |         |
-   |         help: move it here: `where u32: Copy`
+   |               ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
 
-error: where clause not allowed here
+error: where clauses are not allowed after the type for type aliases
   --> $DIR/type-alias-where.rs:10:15
    |
 LL | type Baz = () where;
    |               ^^^^^
-
-error: where clause not allowed here
-  --> $DIR/type-alias-where.rs:24:38
-   |
-LL |     type Assoc2 where u32: Copy = () where i32: Copy;
-   |                                -     ^^^^^^^^^^^^^^^
-   |                                |
-   |                                help: move it here: `, i32: Copy`
-
-error: where clause not allowed here
-  --> $DIR/type-alias-where.rs:30:21
-   |
-LL |     type Assoc = () where u32: Copy;
-   |               -     ^^^^^^^^^^^^^^^
-   |               |
-   |               help: move it here: `where u32: Copy`
-
-error: where clause not allowed here
-  --> $DIR/type-alias-where.rs:33:22
    |
-LL |     type Assoc2 = () where u32: Copy, i32: Copy;
-   |                -     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                |
-   |                help: move it here: `where u32: Copy, i32: Copy`
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 3f4043ad052..3a47845ec82 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -279,20 +279,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         (ForeignMod(l), ForeignMod(r)) => {
             both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
         },
-        (
-            TyAlias(box ast::TyAlias {
-                defaultness: ld,
-                generics: lg,
-                bounds: lb,
-                ty: lt,
-            }),
-            TyAlias(box ast::TyAlias {
-                defaultness: rd,
-                generics: rg,
-                bounds: rb,
-                ty: rt,
-            }),
-        ) => {
+        (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }),
+         TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
@@ -382,20 +370,8 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
         ) => {
             eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
         },
-        (
-            TyAlias(box ast::TyAlias {
-                defaultness: ld,
-                generics: lg,
-                bounds: lb,
-                ty: lt,
-            }),
-            TyAlias(box ast::TyAlias {
-                defaultness: rd,
-                generics: rg,
-                bounds: rb,
-                ty: rt,
-            }),
-        ) => {
+        (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }),
+         TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
@@ -426,20 +402,8 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
         ) => {
             eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
         },
-        (
-            TyAlias(box ast::TyAlias {
-                defaultness: ld,
-                generics: lg,
-                bounds: lb,
-                ty: lt,
-            }),
-            TyAlias(box ast::TyAlias {
-                defaultness: rd,
-                generics: rg,
-                bounds: rb,
-                ty: rt,
-            }),
-        ) => {
+        (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }),
+         TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
diff --git a/src/tools/miri b/src/tools/miri
-Subproject c6b3f687d5d9917b626f80a730552a185052ff2
+Subproject 54b14b7f0110133477e7459a327a0a5cbd18fd4
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index babc56f86ed..8498cb6adda 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -694,7 +694,8 @@ pub(crate) fn format_impl(
     let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
     let where_clause_str = rewrite_where_clause(
         context,
-        &generics.where_clause,
+        &generics.where_clause.predicates,
+        generics.where_clause.span,
         context.config.brace_style(),
         Shape::legacy(where_budget, offset.block_only()),
         false,
@@ -1059,7 +1060,8 @@ pub(crate) fn format_trait(
             let option = WhereClauseOption::snuggled(&generics_str);
             let where_clause_str = rewrite_where_clause(
                 context,
-                &generics.where_clause,
+                &generics.where_clause.predicates,
+                generics.where_clause.span,
                 context.config.brace_style(),
                 Shape::legacy(where_budget, offset.block_only()),
                 where_on_new_line,
@@ -1178,7 +1180,8 @@ impl<'a> Rewrite for TraitAliasBounds<'a> {
 
         let where_str = rewrite_where_clause(
             context,
-            &self.generics.where_clause,
+            &self.generics.where_clause.predicates,
+            self.generics.where_clause.span,
             context.config.brace_style(),
             shape,
             false,
@@ -1437,7 +1440,8 @@ fn format_tuple_struct(
             let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
             rewrite_where_clause(
                 context,
-                &generics.where_clause,
+                &generics.where_clause.predicates,
+                generics.where_clause.span,
                 context.config.brace_style(),
                 Shape::legacy(where_budget, offset.block_only()),
                 false,
@@ -1503,6 +1507,8 @@ struct TyAliasRewriteInfo<'c, 'g>(
     &'c RewriteContext<'c>,
     Indent,
     &'g ast::Generics,
+    (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+    usize,
     symbol::Ident,
     Span,
 );
@@ -1521,6 +1527,8 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
         ref generics,
         ref bounds,
         ref ty,
+        where_clauses,
+        where_predicates_split,
     } = *ty_alias_kind;
     let ty_opt = ty.as_ref();
     let (ident, vis) = match visitor_kind {
@@ -1528,7 +1536,15 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
         AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
         ForeignItem(i) => (i.ident, &i.vis),
     };
-    let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
+    let rw_info = &TyAliasRewriteInfo(
+        context,
+        indent,
+        generics,
+        where_clauses,
+        where_predicates_split,
+        ident,
+        span,
+    );
     let op_ty = opaque_ty(ty);
     // Type Aliases are formatted slightly differently depending on the context
     // in which they appear, whether they are opaque, and whether they are associated.
@@ -1564,7 +1580,22 @@ fn rewrite_ty<R: Rewrite>(
     vis: &ast::Visibility,
 ) -> Option<String> {
     let mut result = String::with_capacity(128);
-    let TyAliasRewriteInfo(context, indent, generics, ident, span) = *rw_info;
+    let TyAliasRewriteInfo(
+        context,
+        indent,
+        generics,
+        where_clauses,
+        where_predicates_split,
+        ident,
+        span,
+    ) = *rw_info;
+    let (before_where_predicates, after_where_predicates) = generics
+        .where_clause
+        .predicates
+        .split_at(where_predicates_split);
+    if !after_where_predicates.is_empty() {
+        return None;
+    }
     result.push_str(&format!("{}type ", format_visibility(context, vis)));
     let ident_str = rewrite_ident(context, ident);
 
@@ -1595,7 +1626,8 @@ fn rewrite_ty<R: Rewrite>(
     }
     let where_clause_str = rewrite_where_clause(
         context,
-        &generics.where_clause,
+        before_where_predicates,
+        where_clauses.0.1,
         context.config.brace_style(),
         Shape::legacy(where_budget, indent),
         false,
@@ -1609,7 +1641,7 @@ fn rewrite_ty<R: Rewrite>(
     if let Some(ty) = rhs {
         // If there's a where clause, add a newline before the assignment. Otherwise just add a
         // space.
-        let has_where = !generics.where_clause.predicates.is_empty();
+        let has_where = !before_where_predicates.is_empty();
         if has_where {
             result.push_str(&indent.to_string_with_newline(context.config));
         } else {
@@ -1619,7 +1651,7 @@ fn rewrite_ty<R: Rewrite>(
         let comment_span = context
             .snippet_provider
             .opt_span_before(span, "=")
-            .map(|op_lo| mk_sp(generics.where_clause.span.hi(), op_lo));
+            .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo));
 
         let lhs = match comment_span {
             Some(comment_span)
@@ -2176,7 +2208,7 @@ fn rewrite_fn_base(
     let generics_str = rewrite_generics(
         context,
         rewrite_ident(context, ident),
-        fn_sig.generics,
+        &fn_sig.generics,
         shape,
     )?;
     result.push_str(&generics_str);
@@ -2416,7 +2448,8 @@ fn rewrite_fn_base(
     }
     let where_clause_str = rewrite_where_clause(
         context,
-        where_clause,
+        &where_clause.predicates,
+        where_clause.span,
         context.config.brace_style(),
         Shape::indented(indent, context.config),
         true,
@@ -2692,7 +2725,8 @@ fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> O
 
 fn rewrite_where_clause_rfc_style(
     context: &RewriteContext<'_>,
-    where_clause: &ast::WhereClause,
+    predicates: &[ast::WherePredicate],
+    where_span: Span,
     shape: Shape,
     terminator: &str,
     span_end: Option<BytePos>,
@@ -2701,7 +2735,8 @@ fn rewrite_where_clause_rfc_style(
 ) -> Option<String> {
     let (where_keyword, allow_single_line) = rewrite_where_keyword(
         context,
-        where_clause,
+        predicates,
+        where_span,
         shape,
         span_end_before_where,
         where_clause_option,
@@ -2714,12 +2749,12 @@ fn rewrite_where_clause_rfc_style(
         .block_left(context.config.tab_spaces())?
         .sub_width(1)?;
     let force_single_line = context.config.where_single_line()
-        && where_clause.predicates.len() == 1
+        && predicates.len() == 1
         && !where_clause_option.veto_single_line;
 
     let preds_str = rewrite_bounds_on_where_clause(
         context,
-        where_clause,
+        predicates,
         clause_shape,
         terminator,
         span_end,
@@ -2743,7 +2778,8 @@ fn rewrite_where_clause_rfc_style(
 /// Rewrite `where` and comment around it.
 fn rewrite_where_keyword(
     context: &RewriteContext<'_>,
-    where_clause: &ast::WhereClause,
+    predicates: &[ast::WherePredicate],
+    where_span: Span,
     shape: Shape,
     span_end_before_where: BytePos,
     where_clause_option: WhereClauseOption,
@@ -2763,7 +2799,7 @@ fn rewrite_where_keyword(
     };
 
     let (span_before, span_after) =
-        missing_span_before_after_where(span_end_before_where, where_clause);
+        missing_span_before_after_where(span_end_before_where, predicates, where_span);
     let (comment_before, comment_after) =
         rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
 
@@ -2789,22 +2825,22 @@ fn rewrite_where_keyword(
 /// Rewrite bounds on a where clause.
 fn rewrite_bounds_on_where_clause(
     context: &RewriteContext<'_>,
-    where_clause: &ast::WhereClause,
+    predicates: &[ast::WherePredicate],
     shape: Shape,
     terminator: &str,
     span_end: Option<BytePos>,
     where_clause_option: WhereClauseOption,
     force_single_line: bool,
 ) -> Option<String> {
-    let span_start = where_clause.predicates[0].span().lo();
+    let span_start = predicates[0].span().lo();
     // If we don't have the start of the next span, then use the end of the
     // predicates, but that means we miss comments.
-    let len = where_clause.predicates.len();
-    let end_of_preds = where_clause.predicates[len - 1].span().hi();
+    let len = predicates.len();
+    let end_of_preds = predicates[len - 1].span().hi();
     let span_end = span_end.unwrap_or(end_of_preds);
     let items = itemize_list(
         context.snippet_provider,
-        where_clause.predicates.iter(),
+        predicates.iter(),
         terminator,
         ",",
         |pred| pred.span().lo(),
@@ -2837,7 +2873,8 @@ fn rewrite_bounds_on_where_clause(
 
 fn rewrite_where_clause(
     context: &RewriteContext<'_>,
-    where_clause: &ast::WhereClause,
+    predicates: &[ast::WherePredicate],
+    where_span: Span,
     brace_style: BraceStyle,
     shape: Shape,
     on_new_line: bool,
@@ -2846,14 +2883,15 @@ fn rewrite_where_clause(
     span_end_before_where: BytePos,
     where_clause_option: WhereClauseOption,
 ) -> Option<String> {
-    if where_clause.predicates.is_empty() {
+    if predicates.is_empty() {
         return Some(String::new());
     }
 
     if context.config.indent_style() == IndentStyle::Block {
         return rewrite_where_clause_rfc_style(
             context,
-            where_clause,
+            predicates,
+            where_span,
             shape,
             terminator,
             span_end,
@@ -2873,15 +2911,15 @@ fn rewrite_where_clause(
     // be out by a char or two.
 
     let budget = context.config.max_width() - offset.width();
-    let span_start = where_clause.predicates[0].span().lo();
+    let span_start = predicates[0].span().lo();
     // If we don't have the start of the next span, then use the end of the
     // predicates, but that means we miss comments.
-    let len = where_clause.predicates.len();
-    let end_of_preds = where_clause.predicates[len - 1].span().hi();
+    let len = predicates.len();
+    let end_of_preds = predicates[len - 1].span().hi();
     let span_end = span_end.unwrap_or(end_of_preds);
     let items = itemize_list(
         context.snippet_provider,
-        where_clause.predicates.iter(),
+        predicates.iter(),
         terminator,
         ",",
         |pred| pred.span().lo(),
@@ -2936,12 +2974,13 @@ fn rewrite_where_clause(
 
 fn missing_span_before_after_where(
     before_item_span_end: BytePos,
-    where_clause: &ast::WhereClause,
+    predicates: &[ast::WherePredicate],
+    where_span: Span,
 ) -> (Span, Span) {
-    let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
+    let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
     // 5 = `where`
-    let pos_after_where = where_clause.span.lo() + BytePos(5);
-    let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
+    let pos_after_where = where_span.lo() + BytePos(5);
+    let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
     (missing_span_before, missing_span_after)
 }
 
@@ -3030,7 +3069,8 @@ fn format_generics(
         }
         let where_clause_str = rewrite_where_clause(
             context,
-            &generics.where_clause,
+            &generics.where_clause.predicates,
+            generics.where_clause.span,
             brace_style,
             Shape::legacy(budget, offset.block_only()),
             true,