about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs329
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs5
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr13
-rw-r--r--src/test/rustdoc/intra-doc/extern-type.rs24
-rw-r--r--src/test/rustdoc/intra-doc/generic-trait-impl.rs20
-rw-r--r--src/test/rustdoc/intra-doc/prim-self.rs (renamed from src/test/rustdoc/intra-link-prim-self.rs)11
-rw-r--r--src/test/rustdoc/intra-doc/self-cache.rs (renamed from src/test/rustdoc/intra-link-self-cache.rs)0
-rw-r--r--src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr80
-rw-r--r--src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr20
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs (renamed from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs)56
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr128
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs (renamed from src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs)28
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr38
-rw-r--r--src/test/ui/generic-associated-types/issue-92096.migrate.stderr18
-rw-r--r--src/test/ui/generic-associated-types/issue-92096.rs29
-rw-r--r--src/test/ui/generic-associated-types/issue-92280.rs26
-rw-r--r--src/test/ui/macros/stringify.rs2
-rw-r--r--src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs4
-rw-r--r--src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-84148-1.rs5
-rw-r--r--src/test/ui/parser/issues/issue-84148-1.stderr18
-rw-r--r--src/test/ui/parser/issues/issue-84148-2.rs3
-rw-r--r--src/test/ui/parser/issues/issue-84148-2.stderr24
-rw-r--r--src/test/ui/parser/trailing-question-in-type.fixed10
-rw-r--r--src/test/ui/parser/trailing-question-in-type.rs10
-rw-r--r--src/test/ui/parser/trailing-question-in-type.stderr24
26 files changed, 623 insertions, 306 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index af62232e792..1544fae962c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -6,13 +6,12 @@ use rustc_ast as ast;
 use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtensionKind;
-use rustc_hir as hir;
 use rustc_hir::def::{
     DefKind,
     Namespace::{self, *},
     PerNS,
 };
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::ParentScope;
@@ -109,6 +108,45 @@ impl Res {
             Res::Primitive(_) => None,
         }
     }
+
+    /// Used for error reporting.
+    fn disambiguator_suggestion(self) -> Suggestion {
+        let kind = match self {
+            Res::Primitive(_) => return Suggestion::Prefix("prim"),
+            Res::Def(kind, _) => kind,
+        };
+        if kind == DefKind::Macro(MacroKind::Bang) {
+            return Suggestion::Macro;
+        } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
+            return Suggestion::Function;
+        } else if kind == DefKind::Field {
+            return Suggestion::RemoveDisambiguator;
+        }
+
+        let prefix = match kind {
+            DefKind::Struct => "struct",
+            DefKind::Enum => "enum",
+            DefKind::Trait => "trait",
+            DefKind::Union => "union",
+            DefKind::Mod => "mod",
+            DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
+                "const"
+            }
+            DefKind::Static => "static",
+            DefKind::Macro(MacroKind::Derive) => "derive",
+            // Now handle things that don't have a specific disambiguator
+            _ => match kind
+                .ns()
+                .expect("tried to calculate a disambiguator for a def without a namespace?")
+            {
+                Namespace::TypeNS => "type",
+                Namespace::ValueNS => "value",
+                Namespace::MacroNS => "macro",
+            },
+        };
+
+        Suggestion::Prefix(prefix)
+    }
 }
 
 impl TryFrom<ResolveRes> for Res {
@@ -346,7 +384,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     /// In particular, this will return an error whenever there aren't three
     /// full path segments left in the link.
     ///
-    /// [enum struct variant]: hir::VariantData::Struct
+    /// [enum struct variant]: rustc_hir::VariantData::Struct
     fn variant_field<'path>(
         &self,
         path_str: &'path str,
@@ -667,10 +705,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         }))
     }
 
-    /// Returns:
-    /// - None if no associated item was found
-    /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
-    /// - Some((_, _, None)) otherwise
+    /// Resolve an associated item, returning its containing page's `Res`
+    /// and the fragment targeting the associated item on its page.
     fn resolve_associated_item(
         &mut self,
         root_res: Res,
@@ -903,7 +939,18 @@ fn traits_implemented_by<'a>(
                 ty
             );
             // Fast path: if this is a primitive simple `==` will work
-            let saw_impl = impl_type == ty;
+            // NOTE: the `match` is necessary; see #92662.
+            // this allows us to ignore generics because the user input
+            // may not include the generic placeholders
+            // e.g. this allows us to match Foo (user comment) with Foo<T> (actual type)
+            let saw_impl = impl_type == ty
+                || match (impl_type.kind(), ty.kind()) {
+                    (ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => {
+                        debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did, ty_def.did);
+                        impl_def.did == ty_def.did
+                    }
+                    _ => false,
+                };
 
             if saw_impl { Some(trait_) } else { None }
         })
@@ -958,17 +1005,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
             {
                 self.cx.tcx.parent(did)
             }
-            Some(did) => match self.cx.tcx.parent(did) {
-                // HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
-                // Fixing this breaks `fn render_deref_methods`.
-                // As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
-                // regardless of what rustdoc wants to call it.
-                Some(parent) => {
-                    let parent_kind = self.cx.tcx.def_kind(parent);
-                    Some(if parent_kind == DefKind::Impl { parent } else { did })
-                }
-                None => Some(did),
-            },
+            Some(did) => Some(did),
         };
 
         // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
@@ -1277,79 +1314,9 @@ impl LinkCollector<'_, '_> {
             }
         }
 
-        let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
-            // The resolved item did not match the disambiguator; give a better error than 'not found'
-            let msg = format!("incompatible link kind for `{}`", path_str);
-            let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
-                let note = format!(
-                    "this link resolved to {} {}, which is not {} {}",
-                    resolved.article(),
-                    resolved.descr(),
-                    specified.article(),
-                    specified.descr()
-                );
-                if let Some(sp) = sp {
-                    diag.span_label(sp, &note);
-                } else {
-                    diag.note(&note);
-                }
-                suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
-            };
-            report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
-        };
-
-        let verify = |kind: DefKind, id: DefId| {
-            let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
-                (self.cx.tcx.def_kind(id), id)
-            } else {
-                (kind, id)
-            };
-            debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
-
-            // Disallow e.g. linking to enums with `struct@`
-            debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
-            match (kind, disambiguator) {
-                | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
-                // NOTE: this allows 'method' to mean both normal functions and associated functions
-                // This can't cause ambiguity because both are in the same namespace.
-                | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
-                // These are namespaces; allow anything in the namespace to match
-                | (_, Some(Disambiguator::Namespace(_)))
-                // If no disambiguator given, allow anything
-                | (_, None)
-                // All of these are valid, so do nothing
-                => {}
-                (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
-                (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
-                    report_mismatch(specified, Disambiguator::Kind(kind));
-                    return None;
-                }
-            }
-
-            // item can be non-local e.g. when using #[doc(primitive = "pointer")]
-            if let Some((src_id, dst_id)) = id
-                .as_local()
-                // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-                // would presumably panic if a fake `DefIndex` were passed.
-                .and_then(|dst_id| {
-                    item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
-                })
-            {
-                if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
-                    && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
-                {
-                    privacy_error(self.cx, &diag_info, path_str);
-                }
-            }
-
-            Some(())
-        };
-
         match res {
             Res::Primitive(prim) => {
                 if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
-                    let kind = self.cx.tcx.def_kind(id);
-
                     // We're actually resolving an associated item of a primitive, so we need to
                     // verify the disambiguator (if any) matches the type of the associated item.
                     // This case should really follow the same flow as the `Res::Def` branch below,
@@ -1358,7 +1325,16 @@ impl LinkCollector<'_, '_> {
                     // doesn't allow statements like `use str::trim;`, making this a (hopefully)
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
-                    verify(kind, id)?;
+                    let kind = self.cx.tcx.def_kind(id);
+                    self.verify_disambiguator(
+                        path_str,
+                        &ori_link,
+                        kind,
+                        id,
+                        disambiguator,
+                        item,
+                        &diag_info,
+                    )?;
 
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
@@ -1372,7 +1348,9 @@ impl LinkCollector<'_, '_> {
                     match disambiguator {
                         Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
                         Some(other) => {
-                            report_mismatch(other, Disambiguator::Primitive);
+                            self.report_disambiguator_mismatch(
+                                path_str, &ori_link, other, res, &diag_info,
+                            );
                             return None;
                         }
                     }
@@ -1386,13 +1364,106 @@ impl LinkCollector<'_, '_> {
                 })
             }
             Res::Def(kind, id) => {
-                verify(kind, id)?;
+                let (kind_for_dis, id_for_dis) =
+                    if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+                        (self.cx.tcx.def_kind(id), id)
+                    } else {
+                        (kind, id)
+                    };
+                self.verify_disambiguator(
+                    path_str,
+                    &ori_link,
+                    kind_for_dis,
+                    id_for_dis,
+                    disambiguator,
+                    item,
+                    &diag_info,
+                )?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
                 Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
             }
         }
     }
 
+    fn verify_disambiguator(
+        &self,
+        path_str: &str,
+        ori_link: &MarkdownLink,
+        kind: DefKind,
+        id: DefId,
+        disambiguator: Option<Disambiguator>,
+        item: &Item,
+        diag_info: &DiagnosticInfo<'_>,
+    ) -> Option<()> {
+        debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id));
+
+        // Disallow e.g. linking to enums with `struct@`
+        debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+        match (kind, disambiguator) {
+                | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+                // NOTE: this allows 'method' to mean both normal functions and associated functions
+                // This can't cause ambiguity because both are in the same namespace.
+                | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+                // These are namespaces; allow anything in the namespace to match
+                | (_, Some(Disambiguator::Namespace(_)))
+                // If no disambiguator given, allow anything
+                | (_, None)
+                // All of these are valid, so do nothing
+                => {}
+                (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+                (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
+                    self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info);
+                    return None;
+                }
+            }
+
+        // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+        if let Some((src_id, dst_id)) = id
+            .as_local()
+            // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
+            // would presumably panic if a fake `DefIndex` were passed.
+            .and_then(|dst_id| {
+                item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
+            })
+        {
+            if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
+                && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
+            {
+                privacy_error(self.cx, diag_info, path_str);
+            }
+        }
+
+        Some(())
+    }
+
+    fn report_disambiguator_mismatch(
+        &self,
+        path_str: &str,
+        ori_link: &MarkdownLink,
+        specified: Disambiguator,
+        resolved: Res,
+        diag_info: &DiagnosticInfo<'_>,
+    ) {
+        // The resolved item did not match the disambiguator; give a better error than 'not found'
+        let msg = format!("incompatible link kind for `{}`", path_str);
+        let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
+            let note = format!(
+                "this link resolved to {} {}, which is not {} {}",
+                resolved.article(),
+                resolved.descr(),
+                specified.article(),
+                specified.descr(),
+            );
+            if let Some(sp) = sp {
+                diag.span_label(sp, &note);
+            } else {
+                diag.note(&note);
+            }
+            suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
+        };
+        report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
+    }
+
     fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) {
         let span =
             super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
@@ -1413,7 +1484,6 @@ impl LinkCollector<'_, '_> {
         diag: DiagnosticInfo<'_>,
         cache_resolution_failure: bool,
     ) -> Option<(Res, Option<UrlFragment>)> {
-        // Try to look up both the result and the corresponding side channel value
         if let Some(ref cached) = self.visited_links.get(&key) {
             match cached {
                 Some(cached) => {
@@ -1686,53 +1756,6 @@ impl Disambiguator {
         }
     }
 
-    fn from_res(res: Res) -> Self {
-        match res {
-            Res::Def(kind, _) => Disambiguator::Kind(kind),
-            Res::Primitive(_) => Disambiguator::Primitive,
-        }
-    }
-
-    /// Used for error reporting.
-    fn suggestion(self) -> Suggestion {
-        let kind = match self {
-            Disambiguator::Primitive => return Suggestion::Prefix("prim"),
-            Disambiguator::Kind(kind) => kind,
-            Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"),
-        };
-        if kind == DefKind::Macro(MacroKind::Bang) {
-            return Suggestion::Macro;
-        } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
-            return Suggestion::Function;
-        } else if kind == DefKind::Field {
-            return Suggestion::RemoveDisambiguator;
-        }
-
-        let prefix = match kind {
-            DefKind::Struct => "struct",
-            DefKind::Enum => "enum",
-            DefKind::Trait => "trait",
-            DefKind::Union => "union",
-            DefKind::Mod => "mod",
-            DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
-                "const"
-            }
-            DefKind::Static => "static",
-            DefKind::Macro(MacroKind::Derive) => "derive",
-            // Now handle things that don't have a specific disambiguator
-            _ => match kind
-                .ns()
-                .expect("tried to calculate a disambiguator for a def without a namespace?")
-            {
-                Namespace::TypeNS => "type",
-                Namespace::ValueNS => "value",
-                Namespace::MacroNS => "macro",
-            },
-        };
-
-        Suggestion::Prefix(prefix)
-    }
-
     fn ns(self) -> Namespace {
         match self {
             Self::Namespace(n) => n,
@@ -1754,9 +1777,9 @@ impl Disambiguator {
     fn descr(self) -> &'static str {
         match self {
             Self::Namespace(n) => n.descr(),
-            // HACK(jynelson): by looking at the source I saw the DefId we pass
-            // for `expected.descr()` doesn't matter, since it's not a crate
-            Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))),
+            // HACK(jynelson): the source of `DefKind::descr` only uses the DefId for
+            // printing "module" vs "crate" so using the wrong ID is not a huge problem
+            Self::Kind(k) => k.descr(CRATE_DEF_ID.to_def_id()),
             Self::Primitive => "builtin type",
         }
     }
@@ -2080,16 +2103,7 @@ fn resolution_failure(
                     ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
                     ResolutionFailure::Dummy => continue,
                     ResolutionFailure::WrongNamespace { res, expected_ns } => {
-                        if let Res::Def(kind, _) = res {
-                            let disambiguator = Disambiguator::Kind(kind);
-                            suggest_disambiguator(
-                                disambiguator,
-                                diag,
-                                path_str,
-                                diag_info.ori_link,
-                                sp,
-                            )
-                        }
+                        suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
 
                         format!(
                             "this link resolves to {}, which is not in the {} namespace",
@@ -2224,8 +2238,7 @@ fn ambiguity_error(
         }
 
         for res in candidates {
-            let disambiguator = Disambiguator::from_res(res);
-            suggest_disambiguator(disambiguator, diag, path_str, diag_info.ori_link, sp);
+            suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
         }
     });
 }
@@ -2233,14 +2246,14 @@ fn ambiguity_error(
 /// In case of an ambiguity or mismatched disambiguator, suggest the correct
 /// disambiguator.
 fn suggest_disambiguator(
-    disambiguator: Disambiguator,
+    res: Res,
     diag: &mut DiagnosticBuilder<'_>,
     path_str: &str,
     ori_link: &str,
     sp: Option<rustc_span::Span>,
 ) {
-    let suggestion = disambiguator.suggestion();
-    let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr());
+    let suggestion = res.disambiguator_suggestion();
+    let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
 
     if let Some(sp) = sp {
         let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
index 142008cf765..2d66566119b 100644
--- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
@@ -73,4 +73,9 @@ trait T {}
 //~^ ERROR incompatible link kind for `f`
 //~| NOTE this link resolved
 //~| HELP add parentheses
+
+/// Link to [fn@std]
+//~^ ERROR unresolved link to `std`
+//~| NOTE this link resolves to the crate `std`
+//~| HELP to link to the crate, prefix with `mod@`
 pub fn f() {}
diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
index 12122f5fa86..ad9102c506f 100644
--- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
@@ -138,5 +138,16 @@ LL - /// Link to [const@f]
 LL + /// Link to [f()]
    | 
 
-error: aborting due to 12 previous errors
+error: unresolved link to `std`
+  --> $DIR/disambiguator-mismatch.rs:77:14
+   |
+LL | /// Link to [fn@std]
+   |              ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
+   |
+help: to link to the crate, prefix with `mod@`
+   |
+LL | /// Link to [mod@std]
+   |              ~~~~
+
+error: aborting due to 13 previous errors
 
diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs
index f37ae62dde1..ab088ab789d 100644
--- a/src/test/rustdoc/intra-doc/extern-type.rs
+++ b/src/test/rustdoc/intra-doc/extern-type.rs
@@ -4,14 +4,34 @@ extern {
     pub type ExternType;
 }
 
+pub trait T {
+    fn test(&self) {}
+}
+
+pub trait G<N> {
+    fn g(&self, n: N) {}
+}
+
 impl ExternType {
-    pub fn f(&self) {
+    pub fn f(&self) {}
+}
 
-    }
+impl T for ExternType {
+    fn test(&self) {}
+}
+
+impl G<usize> for ExternType {
+    fn g(&self, n: usize) {}
 }
 
 // @has 'extern_type/foreigntype.ExternType.html'
 // @has 'extern_type/fn.links_to_extern_type.html' \
 // 'href="foreigntype.ExternType.html#method.f"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.test"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.g"'
 /// See also [ExternType::f]
+/// See also [ExternType::test]
+/// See also [ExternType::g]
 pub fn links_to_extern_type() {}
diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
new file mode 100644
index 00000000000..ba8595abfa9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
@@ -0,0 +1,20 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// Test intra-doc links on trait implementations with generics
+// regression test for issue #92662
+
+use std::marker::PhantomData;
+
+pub trait Bar<T> {
+    fn bar(&self);
+}
+
+pub struct Foo<U>(PhantomData<U>);
+
+impl<T, U> Bar<T> for Foo<U> {
+    fn bar(&self) {}
+}
+
+// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar'
+/// link to [`Foo::bar`]
+pub fn main() {}
diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs
index 8a564acf2ca..7a65723d77b 100644
--- a/src/test/rustdoc/intra-link-prim-self.rs
+++ b/src/test/rustdoc/intra-doc/prim-self.rs
@@ -1,13 +1,15 @@
 #![deny(rustdoc::broken_intra_doc_links)]
+#![allow(incomplete_features)] // inherent_associated_types
 #![feature(lang_items)]
 #![feature(no_core)]
 #![feature(rustdoc_internals)]
+#![feature(inherent_associated_types)]
 #![no_core]
 
 #[lang = "usize"]
 /// [Self::f]
 /// [Self::MAX]
-// @has intra_link_prim_self/primitive.usize.html
+// @has prim_self/primitive.usize.html
 // @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
 // @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
 impl usize {
@@ -17,10 +19,9 @@ impl usize {
     /// 10 and 2^32 are basically the same.
     pub const MAX: usize = 10;
 
-    // FIXME(#8995) uncomment this when associated types in inherent impls are supported
-    // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
-    // / [Self::ME]
-    //pub type ME = usize;
+    // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+    /// [Self::ME]
+    pub type ME = usize;
 }
 
 #[doc(primitive = "usize")]
diff --git a/src/test/rustdoc/intra-link-self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs
index 63bf7fa5768..63bf7fa5768 100644
--- a/src/test/rustdoc/intra-link-self-cache.rs
+++ b/src/test/rustdoc/intra-doc/self-cache.rs
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr
deleted file mode 100644
index 2751a37f741..00000000000
--- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr
+++ /dev/null
@@ -1,80 +0,0 @@
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:13:13
-   |
-LL |     ty_ref: &Ty<'_>,
-   |             ^^^^^^^ help: try passing by value: `Ty<'_>`
-   |
-note: the lint level is defined here
-  --> $DIR/pass_ty_by_ref.rs:4:9
-   |
-LL | #![deny(rustc::ty_pass_by_reference)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:15:18
-   |
-LL |     ty_ctxt_ref: &TyCtxt<'_>,
-   |                  ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:19:28
-   |
-LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                            ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:19:55
-   |
-LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                                       ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:26:17
-   |
-LL |         ty_ref: &Ty<'_>,
-   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:28:22
-   |
-LL |         ty_ctxt_ref: &TyCtxt<'_>,
-   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:31:41
-   |
-LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
-   |                                         ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:31:68
-   |
-LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
-   |                                                                    ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:53:17
-   |
-LL |         ty_ref: &Ty<'_>,
-   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:55:22
-   |
-LL |         ty_ctxt_ref: &TyCtxt<'_>,
-   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:59:38
-   |
-LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                      ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:59:65
-   |
-LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                                                 ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: aborting due to 12 previous errors
-
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr
deleted file mode 100644
index 15a06e721dd..00000000000
--- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: passing `TyCtxt<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:18:15
-   |
-LL |     fn by_ref(&self) {}
-   |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
-   |
-note: the lint level is defined here
-  --> $DIR/pass_ty_by_ref_self.rs:8:9
-   |
-LL | #![deny(rustc::ty_pass_by_reference)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: passing `Ty<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:31:21
-   |
-LL |     fn by_ref(self: &Ty<'tcx>) {}
-   |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
index e0fdbaeac30..402c41f3766 100644
--- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
@@ -1,7 +1,8 @@
 // compile-flags: -Z unstable-options
 
+#![feature(rustc_attrs)]
 #![feature(rustc_private)]
-#![deny(rustc::ty_pass_by_reference)]
+#![deny(rustc::pass_by_value)]
 #![allow(unused)]
 
 extern crate rustc_middle;
@@ -61,4 +62,57 @@ impl Foo {
     //~^^ ERROR passing `TyCtxt<'_>` by reference
 }
 
+#[rustc_pass_by_value]
+enum CustomEnum {
+    A,
+    B,
+}
+
+impl CustomEnum {
+    fn test(
+        value: CustomEnum,
+        reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference
+    ) {
+    }
+}
+
+#[rustc_pass_by_value]
+struct CustomStruct {
+    s: u8,
+}
+
+#[rustc_pass_by_value]
+type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference
+
+impl CustomStruct {
+    fn test(
+        value: CustomStruct,
+        reference: &CustomStruct, //~ ERROR passing `CustomStruct` by reference
+    ) {
+    }
+
+    fn test_alias(
+        value: CustomAlias,
+        reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference
+    ) {
+    }
+}
+
+#[rustc_pass_by_value]
+struct WithParameters<T, const N: usize, M = u32> {
+    slice: [T; N],
+    m: M,
+}
+
+impl<T> WithParameters<T, 1> {
+    fn test<'a>(
+        value: WithParameters<T, 1>,
+        reference: &'a WithParameters<T, 1>, //~ ERROR passing `WithParameters<T, 1>` by reference
+        reference_with_m: &WithParameters<T, 1, u32>, //~ ERROR passing `WithParameters<T, 1, u32>` by reference
+    ) -> &'a WithParameters<T, 1> {
+        //~^ ERROR passing `WithParameters<T, 1>` by reference
+        reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference
+    }
+}
+
 fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
new file mode 100644
index 00000000000..7f6e57b38f3
--- /dev/null
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
@@ -0,0 +1,128 @@
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:14:13
+   |
+LL |     ty_ref: &Ty<'_>,
+   |             ^^^^^^^ help: try passing by value: `Ty<'_>`
+   |
+note: the lint level is defined here
+  --> $DIR/rustc_pass_by_value.rs:5:9
+   |
+LL | #![deny(rustc::pass_by_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:16:18
+   |
+LL |     ty_ctxt_ref: &TyCtxt<'_>,
+   |                  ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:20:28
+   |
+LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                            ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:20:55
+   |
+LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                                       ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:27:17
+   |
+LL |         ty_ref: &Ty<'_>,
+   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:29:22
+   |
+LL |         ty_ctxt_ref: &TyCtxt<'_>,
+   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:32:41
+   |
+LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
+   |                                         ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:32:68
+   |
+LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
+   |                                                                    ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:54:17
+   |
+LL |         ty_ref: &Ty<'_>,
+   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:56:22
+   |
+LL |         ty_ctxt_ref: &TyCtxt<'_>,
+   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:60:38
+   |
+LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                      ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:60:65
+   |
+LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                                                 ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `CustomEnum` by reference
+  --> $DIR/rustc_pass_by_value.rs:74:20
+   |
+LL |         reference: &CustomEnum,
+   |                    ^^^^^^^^^^^ help: try passing by value: `CustomEnum`
+
+error: passing `CustomStruct` by reference
+  --> $DIR/rustc_pass_by_value.rs:85:24
+   |
+LL | type CustomAlias<'a> = &'a CustomStruct;
+   |                        ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
+
+error: passing `CustomStruct` by reference
+  --> $DIR/rustc_pass_by_value.rs:90:20
+   |
+LL |         reference: &CustomStruct,
+   |                    ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
+
+error: passing `CustomAlias<>` by reference
+  --> $DIR/rustc_pass_by_value.rs:96:20
+   |
+LL |         reference: &CustomAlias,
+   |                    ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>`
+
+error: passing `WithParameters<T, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:110:20
+   |
+LL |         reference: &'a WithParameters<T, 1>,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
+
+error: passing `WithParameters<T, 1, u32>` by reference
+  --> $DIR/rustc_pass_by_value.rs:111:27
+   |
+LL |         reference_with_m: &WithParameters<T, 1, u32>,
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1, u32>`
+
+error: passing `WithParameters<T, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:112:10
+   |
+LL |     ) -> &'a WithParameters<T, 1> {
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
+
+error: passing `WithParameters<_, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:114:22
+   |
+LL |         reference as &WithParameters<_, 1>
+   |                      ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<_, 1>`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
index 48b140d9174..2868517774d 100644
--- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
@@ -5,10 +5,10 @@
 // Considering that all other `internal-lints` are tested here
 // this seems like the cleaner solution though.
 #![feature(rustc_attrs)]
-#![deny(rustc::ty_pass_by_reference)]
+#![deny(rustc::pass_by_value)]
 #![allow(unused)]
 
-#[rustc_diagnostic_item = "TyCtxt"]
+#[rustc_pass_by_value]
 struct TyCtxt<'tcx> {
     inner: &'tcx (),
 }
@@ -18,12 +18,11 @@ impl<'tcx> TyCtxt<'tcx> {
     fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
 }
 
-
 struct TyS<'tcx> {
     inner: &'tcx (),
 }
 
-#[rustc_diagnostic_item = "Ty"]
+#[rustc_pass_by_value]
 type Ty<'tcx> = &'tcx TyS<'tcx>;
 
 impl<'tcx> TyS<'tcx> {
@@ -31,4 +30,25 @@ impl<'tcx> TyS<'tcx> {
     fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
 }
 
+#[rustc_pass_by_value]
+struct Foo;
+
+impl Foo {
+    fn with_ref(&self) {} //~ ERROR passing `Foo` by reference
+}
+
+#[rustc_pass_by_value]
+struct WithParameters<T, const N: usize, M = u32> {
+    slice: [T; N],
+    m: M,
+}
+
+impl<T> WithParameters<T, 1> {
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference
+}
+
+impl<T> WithParameters<T, 1, u8> {
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference
+}
+
 fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
new file mode 100644
index 00000000000..54a7cf7cab7
--- /dev/null
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
@@ -0,0 +1,38 @@
+error: passing `TyCtxt<'tcx>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:18:15
+   |
+LL |     fn by_ref(&self) {}
+   |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
+   |
+note: the lint level is defined here
+  --> $DIR/rustc_pass_by_value_self.rs:8:9
+   |
+LL | #![deny(rustc::pass_by_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: passing `Ty<'tcx>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:30:21
+   |
+LL |     fn by_ref(self: &Ty<'tcx>) {}
+   |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
+
+error: passing `Foo` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:37:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `Foo`
+
+error: passing `WithParameters<T, 1_usize>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:47:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>`
+
+error: passing `WithParameters<T, 1_usize, u8>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:51:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
new file mode 100644
index 00000000000..72ade5774d7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
@@ -0,0 +1,18 @@
+error[E0311]: the parameter type `C` may not live long enough
+  --> $DIR/issue-92096.rs:20:33
+   |
+LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |                 |
+   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+
+error[E0311]: the parameter type `C` may not live long enough
+  --> $DIR/issue-92096.rs:20:33
+   |
+LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |                 |
+   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs
new file mode 100644
index 00000000000..066132a5d98
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-92096.rs
@@ -0,0 +1,29 @@
+// edition:2018
+// [nll] check-pass
+// revisions: migrate nll
+// Explicitly testing nll with revision, so ignore compare-mode=nll
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+#![feature(generic_associated_types)]
+
+use std::future::Future;
+
+trait Client {
+    type Connecting<'a>: Future + Send
+    where
+        Self: 'a;
+
+    fn connect(&'_ self) -> Self::Connecting<'_>;
+}
+
+fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+//[migrate]~^ ERROR the parameter
+//[migrate]~| ERROR the parameter
+where
+    C: Client + Send + Sync,
+{
+    async move { c.connect().await }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs
new file mode 100644
index 00000000000..db26493ecad
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-92280.rs
@@ -0,0 +1,26 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+#![allow(non_camel_case_types)]
+
+trait HasAssoc {
+    type Assoc;
+}
+
+trait Iterate<S: HasAssoc> {
+    type Iter<'a>
+    where
+        Self: 'a;
+}
+
+struct KeySegment_Broken<T> {
+    key: T,
+}
+impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> {
+    type Iter<'a>
+    where
+        Self: 'a,
+    = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index 820dcdb9394..004ab386b3f 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -589,7 +589,7 @@ fn test_item() {
         stringify_item!(
             pub trait Trait<T> = Sized where T: 'a;
         ),
-        "", // FIXME
+        "pub trait Trait<T> = Sized where T: 'a;",
     );
 
     // ItemKind::Impl
diff --git a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs
index e725aa5d73d..23f245a5168 100644
--- a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs
+++ b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs
@@ -117,9 +117,9 @@ static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]);
 
 pub fn cast_then_try() -> Result<u64,u64> {
     Err(0u64) as Result<u64,u64>?;
-    //~^ ERROR: casts cannot be followed by ?
+    //~^ ERROR: casts cannot be followed by `?`
     Err(0u64): Result<u64,u64>?;
-    //~^ ERROR: casts cannot be followed by ?
+    //~^ ERROR: casts cannot be followed by `?`
     Ok(1)
 }
 
diff --git a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 19b68556d79..e96b67da336 100644
--- a/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -265,7 +265,7 @@ help: try surrounding the expression in parentheses
 LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]);
    |                         +                      +
 
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
   --> $DIR/issue-35813-postfix-after-cast.rs:119:5
    |
 LL |     Err(0u64) as Result<u64,u64>?;
@@ -276,7 +276,7 @@ help: try surrounding the expression in parentheses
 LL |     (Err(0u64) as Result<u64,u64>)?;
    |     +                            +
 
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
   --> $DIR/issue-35813-postfix-after-cast.rs:121:5
    |
 LL |     Err(0u64): Result<u64,u64>?;
diff --git a/src/test/ui/parser/issues/issue-84148-1.rs b/src/test/ui/parser/issues/issue-84148-1.rs
index 25f7ba4d1f8..9fa8086c2c9 100644
--- a/src/test/ui/parser/issues/issue-84148-1.rs
+++ b/src/test/ui/parser/issues/issue-84148-1.rs
@@ -1,4 +1,3 @@
 fn f(t:for<>t?)
-//~^ ERROR: expected parameter name
-//~| ERROR: expected one of
-//~| ERROR: expected one of
+//~^ ERROR: expected one of
+//~| ERROR: invalid `?` in type
diff --git a/src/test/ui/parser/issues/issue-84148-1.stderr b/src/test/ui/parser/issues/issue-84148-1.stderr
index 77f0896e9c1..9261067c221 100644
--- a/src/test/ui/parser/issues/issue-84148-1.stderr
+++ b/src/test/ui/parser/issues/issue-84148-1.stderr
@@ -1,17 +1,13 @@
-error: expected parameter name, found `?`
+error: invalid `?` in type
   --> $DIR/issue-84148-1.rs:1:14
    |
 LL | fn f(t:for<>t?)
-   |              ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
-  --> $DIR/issue-84148-1.rs:1:14
+   |              ^ `?` is only allowed on expressions, not types
    |
-LL | fn f(t:for<>t?)
-   |              ^
-   |              |
-   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
-   |              help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn f(t:Option<for<>t>)
+   |        +++++++      ~
 
 error: expected one of `->`, `where`, or `{`, found `<eof>`
   --> $DIR/issue-84148-1.rs:1:15
@@ -19,5 +15,5 @@ error: expected one of `->`, `where`, or `{`, found `<eof>`
 LL | fn f(t:for<>t?)
    |               ^ expected one of `->`, `where`, or `{`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/issues/issue-84148-2.rs b/src/test/ui/parser/issues/issue-84148-2.rs
index 257a3fd6720..2f6a7facfb2 100644
--- a/src/test/ui/parser/issues/issue-84148-2.rs
+++ b/src/test/ui/parser/issues/issue-84148-2.rs
@@ -1,4 +1,3 @@
 // error-pattern: this file contains an unclosed delimiter
-// error-pattern: expected parameter name
-// error-pattern: expected one of
+// error-pattern: invalid `?` in type
 fn f(t:for<>t?
diff --git a/src/test/ui/parser/issues/issue-84148-2.stderr b/src/test/ui/parser/issues/issue-84148-2.stderr
index 396208316df..71d543f9b73 100644
--- a/src/test/ui/parser/issues/issue-84148-2.stderr
+++ b/src/test/ui/parser/issues/issue-84148-2.stderr
@@ -1,31 +1,27 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-84148-2.rs:4:16
+  --> $DIR/issue-84148-2.rs:3:16
    |
 LL | fn f(t:for<>t?
    |     -          ^
    |     |
    |     unclosed delimiter
 
-error: expected parameter name, found `?`
-  --> $DIR/issue-84148-2.rs:4:14
+error: invalid `?` in type
+  --> $DIR/issue-84148-2.rs:3:14
    |
 LL | fn f(t:for<>t?
-   |              ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
-  --> $DIR/issue-84148-2.rs:4:14
+   |              ^ `?` is only allowed on expressions, not types
    |
-LL | fn f(t:for<>t?
-   |              ^
-   |              |
-   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
-   |              help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn f(t:Option<for<>t>
+   |        +++++++      ~
 
 error: expected one of `->`, `where`, or `{`, found `<eof>`
-  --> $DIR/issue-84148-2.rs:4:16
+  --> $DIR/issue-84148-2.rs:3:16
    |
 LL | fn f(t:for<>t?
    |                ^ expected one of `->`, `where`, or `{`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/trailing-question-in-type.fixed b/src/test/ui/parser/trailing-question-in-type.fixed
new file mode 100644
index 00000000000..6ea24484e03
--- /dev/null
+++ b/src/test/ui/parser/trailing-question-in-type.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn foo() -> Option<i32> { //~ ERROR invalid `?` in type
+    let x: Option<i32> = Some(1); //~ ERROR invalid `?` in type
+    x
+}
+
+fn main() {
+    let _: Option<i32> = foo();
+}
diff --git a/src/test/ui/parser/trailing-question-in-type.rs b/src/test/ui/parser/trailing-question-in-type.rs
new file mode 100644
index 00000000000..b1c508365cf
--- /dev/null
+++ b/src/test/ui/parser/trailing-question-in-type.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn foo() -> i32? { //~ ERROR invalid `?` in type
+    let x: i32? = Some(1); //~ ERROR invalid `?` in type
+    x
+}
+
+fn main() {
+    let _: Option<i32> = foo();
+}
diff --git a/src/test/ui/parser/trailing-question-in-type.stderr b/src/test/ui/parser/trailing-question-in-type.stderr
new file mode 100644
index 00000000000..a3cd419c0c7
--- /dev/null
+++ b/src/test/ui/parser/trailing-question-in-type.stderr
@@ -0,0 +1,24 @@
+error: invalid `?` in type
+  --> $DIR/trailing-question-in-type.rs:3:16
+   |
+LL | fn foo() -> i32? {
+   |                ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn foo() -> Option<i32> {
+   |             +++++++   ~
+
+error: invalid `?` in type
+  --> $DIR/trailing-question-in-type.rs:4:15
+   |
+LL |     let x: i32? = Some(1);
+   |               ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL |     let x: Option<i32> = Some(1);
+   |            +++++++   ~
+
+error: aborting due to 2 previous errors
+