From c6015851f7e54d1e1e267afb315a2b4b23096d0d Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Thu, 9 Mar 2023 13:18:07 -0700
Subject: [PATCH 01/19] rustdoc: move notable trait tests into their own
 directory

---
 .../doc-notable_trait-mut_t_is_not_an_iterator.rs                 | 0
 .../{ => notable-trait}/doc-notable_trait-mut_t_is_not_ref_t.rs   | 0
 .../doc-notable_trait-slice.bare_fn_matches.html                  | 0
 tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.rs      | 0
 tests/rustdoc/{ => notable-trait}/doc-notable_trait.bare-fn.html  | 0
 tests/rustdoc/{ => notable-trait}/doc-notable_trait.rs            | 0
 .../{ => notable-trait}/doc-notable_trait.some-struct-new.html    | 0
 tests/rustdoc/{ => notable-trait}/doc-notable_trait.wrap-me.html  | 0
 .../doc-notable_trait_box_is_not_an_iterator.rs                   | 0
 .../{ => notable-trait}/spotlight-from-dependency.odd.html        | 0
 tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.rs    | 0
 11 files changed, 0 insertions(+), 0 deletions(-)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-mut_t_is_not_an_iterator.rs (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-mut_t_is_not_ref_t.rs (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.bare_fn_matches.html (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait-slice.rs (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.bare-fn.html (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.rs (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.some-struct-new.html (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait.wrap-me.html (100%)
 rename tests/rustdoc/{ => notable-trait}/doc-notable_trait_box_is_not_an_iterator.rs (100%)
 rename tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.odd.html (100%)
 rename tests/rustdoc/{ => notable-trait}/spotlight-from-dependency.rs (100%)

diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs
similarity index 100%
rename from tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs
rename to tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs
diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs
similarity index 100%
rename from tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
rename to tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs
diff --git a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html
similarity index 100%
rename from tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html
rename to tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html
diff --git a/tests/rustdoc/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
similarity index 100%
rename from tests/rustdoc/doc-notable_trait-slice.rs
rename to tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
diff --git a/tests/rustdoc/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html
similarity index 100%
rename from tests/rustdoc/doc-notable_trait.bare-fn.html
rename to tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html
diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/notable-trait/doc-notable_trait.rs
similarity index 100%
rename from tests/rustdoc/doc-notable_trait.rs
rename to tests/rustdoc/notable-trait/doc-notable_trait.rs
diff --git a/tests/rustdoc/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html
similarity index 100%
rename from tests/rustdoc/doc-notable_trait.some-struct-new.html
rename to tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html
diff --git a/tests/rustdoc/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html
similarity index 100%
rename from tests/rustdoc/doc-notable_trait.wrap-me.html
rename to tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html
diff --git a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs
similarity index 100%
rename from tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs
rename to tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs
diff --git a/tests/rustdoc/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html
similarity index 100%
rename from tests/rustdoc/spotlight-from-dependency.odd.html
rename to tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html
diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs
similarity index 100%
rename from tests/rustdoc/spotlight-from-dependency.rs
rename to tests/rustdoc/notable-trait/spotlight-from-dependency.rs

From ee6b228b6a8b874ca8b6e88cd58d4618cf20fb20 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Thu, 9 Mar 2023 13:41:13 -0700
Subject: [PATCH 02/19] rustdoc: handle generics better when matching notable
 traits

This commit makes the `clean::Type::is_same` non-commutative, so
that a generic `impl` matches a concrete return, but a generic return
does not match a concrete `impl`. It makes slice and vector Write
for `u8` not match on every generic return value.
---
 src/librustdoc/clean/types.rs                 | 46 +++++++++++++++++--
 src/librustdoc/clean/types/tests.rs           | 11 +++++
 src/librustdoc/html/render/mod.rs             |  4 +-
 .../notable-trait/doc-notable_trait-slice.rs  |  6 +++
 .../notable-trait/notable-trait-generics.rs   | 35 ++++++++++++++
 5 files changed, 96 insertions(+), 6 deletions(-)
 create mode 100644 tests/rustdoc/notable-trait/notable-trait-generics.rs

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6d8380c5fcc18..5217de7aa8a4f 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1471,11 +1471,37 @@ impl Type {
         result
     }
 
-    /// Check if two types are "potentially the same".
+    pub(crate) fn is_borrowed_ref(&self) -> bool {
+        matches!(self, Type::BorrowedRef { .. })
+    }
+
+    /// Check if two types are "the same" for documentation purposes.
+    ///
     /// This is different from `Eq`, because it knows that things like
     /// `Placeholder` are possible matches for everything.
+    ///
+    /// This relation is not commutative when generics are involved:
+    ///
+    /// ```ignore(private)
+    /// # // see types/tests.rs:is_same_generic for the real test
+    /// use rustdoc::format::cache::Cache;
+    /// use rustdoc::clean::types::{Type, PrimitiveType};
+    /// let cache = Cache::new(false);
+    /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
+    /// let unit = Type::Primitive(PrimitiveType::Unit);
+    /// assert!(!generic.is_same(&unit, &cache));
+    /// assert!(unit.is_same(&generic, &cache));
+    /// ```
+    ///
+    /// An owned type is also the same as its borrowed variants (this is commutative),
+    /// but `&T` is not the same as `&mut T`.
     pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
-        match (self, other) {
+        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
+            (self.without_borrowed_ref(), other.without_borrowed_ref())
+        } else {
+            (self, other)
+        };
+        match (self_cleared, other_cleared) {
             // Recursive cases.
             (Type::Tuple(a), Type::Tuple(b)) => {
                 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache))
@@ -1489,9 +1515,21 @@ impl Type {
                 Type::BorrowedRef { mutability, type_, .. },
                 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
             ) => mutability == b_mutability && type_.is_same(b_type_, cache),
-            // Placeholders and generics are equal to all other types.
+            // Placeholders are equal to all other types.
             (Type::Infer, _) | (_, Type::Infer) => true,
-            (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+            // Generics match everything on the right, but not on the left.
+            (_, Type::Generic(_)) => true,
+            (Type::Generic(_), _) => false,
+            // Paths account for both the path itself and its generics.
+            (Type::Path { path: a }, Type::Path { path: b }) => {
+                a.def_id() == b.def_id()
+                    && a.generics()
+                        .zip(b.generics())
+                        .map(|(ag, bg)| {
+                            ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_same(bt, cache))
+                        })
+                        .unwrap_or(true)
+            }
             // Other cases, such as primitives, just use recursion.
             (a, b) => a
                 .def_id(cache)
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
index 20627c2cfc164..7df87a9804aa2 100644
--- a/src/librustdoc/clean/types/tests.rs
+++ b/src/librustdoc/clean/types/tests.rs
@@ -69,3 +69,14 @@ fn should_not_trim() {
     run_test("\t    line1  \n\t    line2", "line1  \nline2");
     run_test("    \tline1  \n    \tline2", "line1  \nline2");
 }
+
+#[test]
+fn is_same_generic() {
+    use crate::clean::types::{PrimitiveType, Type};
+    use crate::formats::cache::Cache;
+    let cache = Cache::new(false);
+    let generic = Type::Generic(rustc_span::symbol::sym::Any);
+    let unit = Type::Primitive(PrimitiveType::Unit);
+    assert!(!generic.is_same(&unit, &cache));
+    assert!(unit.is_same(&generic, &cache));
+}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index e6a040d02e565..f8c26dc4706b1 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1291,7 +1291,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
     if let Some(impls) = cx.cache().impls.get(&did) {
         for i in impls {
             let impl_ = i.inner_impl();
-            if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
+            if !ty.is_same(&impl_.for_, cx.cache()) {
                 // Two different types might have the same did,
                 // without actually being the same.
                 continue;
@@ -1327,7 +1327,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
 
     for i in impls {
         let impl_ = i.inner_impl();
-        if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
+        if !ty.is_same(&impl_.for_, cx.cache()) {
             // Two different types might have the same did,
             // without actually being the same.
             continue;
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
index 2411da8cd4549..ef206710b4b08 100644
--- a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
@@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] {
 pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
     &[]
 }
+
+// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html
+// @count - '//script[@id="notable-traits-data"]' 0
+pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] {
+    &mut []
+}
diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs
new file mode 100644
index 0000000000000..7bfe9d43ea986
--- /dev/null
+++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs
@@ -0,0 +1,35 @@
+#![feature(doc_notable_trait)]
+
+// Notable traits SHOULD be shown when the `impl` has a generic type and the
+// return type has a concrete type.
+pub mod generic_return {
+    pub struct Wrapper<T>(T);
+
+    #[doc(notable_trait)]
+    pub trait NotableTrait {}
+
+    impl NotableTrait for Wrapper<u8> {}
+
+    // @has notable_trait_generics/generic_return/fn.returning.html
+    // @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<T>'
+    pub fn returning<T>() -> Wrapper<T> {
+        loop {}
+    }
+}
+
+// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and
+// the return type has a generic type.
+pub mod generic_impl {
+    pub struct Wrapper<T>(T);
+
+    #[doc(notable_trait)]
+    pub trait NotableTrait {}
+
+    impl<T> NotableTrait for Wrapper<T> {}
+
+    // @has notable_trait_generics/generic_impl/fn.returning.html
+    // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<u8>'
+    pub fn returning() -> Wrapper<u8> {
+        loop {}
+    }
+}

From 86179c4549e74acf22fc4da02b64f0bb2ce1f4aa Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Sun, 12 Mar 2023 17:45:15 -0700
Subject: [PATCH 03/19] rustdoc: rename `Type::is_same` to `is_doc_subtype_of`

---
 src/librustdoc/clean/types.rs       | 14 +++++++-------
 src/librustdoc/clean/types/tests.rs |  4 ++--
 src/librustdoc/html/render/mod.rs   |  4 ++--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5217de7aa8a4f..1b8478ee21c68 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1495,7 +1495,7 @@ impl Type {
     ///
     /// An owned type is also the same as its borrowed variants (this is commutative),
     /// but `&T` is not the same as `&mut T`.
-    pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
+    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
         let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
             (self.without_borrowed_ref(), other.without_borrowed_ref())
         } else {
@@ -1504,17 +1504,17 @@ impl Type {
         match (self_cleared, other_cleared) {
             // Recursive cases.
             (Type::Tuple(a), Type::Tuple(b)) => {
-                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache))
+                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
             }
-            (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache),
-            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache),
+            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
+            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
             (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
-                mutability == b_mutability && type_.is_same(b_type_, cache)
+                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
             }
             (
                 Type::BorrowedRef { mutability, type_, .. },
                 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
-            ) => mutability == b_mutability && type_.is_same(b_type_, cache),
+            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
             // Placeholders are equal to all other types.
             (Type::Infer, _) | (_, Type::Infer) => true,
             // Generics match everything on the right, but not on the left.
@@ -1526,7 +1526,7 @@ impl Type {
                     && a.generics()
                         .zip(b.generics())
                         .map(|(ag, bg)| {
-                            ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_same(bt, cache))
+                            ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
                         })
                         .unwrap_or(true)
             }
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
index 7df87a9804aa2..afbee3e5f78ca 100644
--- a/src/librustdoc/clean/types/tests.rs
+++ b/src/librustdoc/clean/types/tests.rs
@@ -77,6 +77,6 @@ fn is_same_generic() {
     let cache = Cache::new(false);
     let generic = Type::Generic(rustc_span::symbol::sym::Any);
     let unit = Type::Primitive(PrimitiveType::Unit);
-    assert!(!generic.is_same(&unit, &cache));
-    assert!(unit.is_same(&generic, &cache));
+    assert!(!generic.is_doc_subtype_of(&unit, &cache));
+    assert!(unit.is_doc_subtype_of(&generic, &cache));
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f8c26dc4706b1..832c4e7cfe77b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1291,7 +1291,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
     if let Some(impls) = cx.cache().impls.get(&did) {
         for i in impls {
             let impl_ = i.inner_impl();
-            if !ty.is_same(&impl_.for_, cx.cache()) {
+            if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
                 // Two different types might have the same did,
                 // without actually being the same.
                 continue;
@@ -1327,7 +1327,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
 
     for i in impls {
         let impl_ = i.inner_impl();
-        if !ty.is_same(&impl_.for_, cx.cache()) {
+        if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
             // Two different types might have the same did,
             // without actually being the same.
             continue;

From bfb66eb4bb4ada8a0b4d48d73a93e8f5df0e54be Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Mon, 13 Mar 2023 23:03:53 -0700
Subject: [PATCH 04/19] rustdoc: fix comments in test

---
 tests/rustdoc/notable-trait/notable-trait-generics.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs
index 7bfe9d43ea986..611902abad65b 100644
--- a/tests/rustdoc/notable-trait/notable-trait-generics.rs
+++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs
@@ -1,7 +1,7 @@
 #![feature(doc_notable_trait)]
 
-// Notable traits SHOULD be shown when the `impl` has a generic type and the
-// return type has a concrete type.
+// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and
+// the return type has a generic type.
 pub mod generic_return {
     pub struct Wrapper<T>(T);
 
@@ -17,8 +17,8 @@ pub mod generic_return {
     }
 }
 
-// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and
-// the return type has a generic type.
+// Notable traits SHOULD be shown when the `impl` has a generic type and the
+// return type has a concrete type.
 pub mod generic_impl {
     pub struct Wrapper<T>(T);
 

From 7f76084933b69ae856bc872c3eecdc2378a21f4b Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Fri, 17 Mar 2023 10:46:38 -0700
Subject: [PATCH 05/19] Add clarifying comments

---
 src/librustdoc/clean/types.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 1b8478ee21c68..7dbb3f76a0a83 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1496,6 +1496,8 @@ impl Type {
     /// An owned type is also the same as its borrowed variants (this is commutative),
     /// but `&T` is not the same as `&mut T`.
     pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
+        // Strip the references so that it can compare the actual types, unless both are references.
+        // If both are references, leave them alone and compare the mutabilities later.
         let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
             (self.without_borrowed_ref(), other.without_borrowed_ref())
         } else {
@@ -1518,6 +1520,7 @@ impl Type {
             // Placeholders are equal to all other types.
             (Type::Infer, _) | (_, Type::Infer) => true,
             // Generics match everything on the right, but not on the left.
+            // If both sides are generic, this returns true.
             (_, Type::Generic(_)) => true,
             (Type::Generic(_), _) => false,
             // Paths account for both the path itself and its generics.

From c9ddb73184290e0698060a80b0b5727d6ee11098 Mon Sep 17 00:00:00 2001
From: Ezra Shaw <ezrasure@outlook.com>
Date: Fri, 17 Mar 2023 21:35:43 +1300
Subject: [PATCH 06/19] refactor: refactor identifier parsing somewhat

---
 compiler/rustc_parse/messages.ftl             |  2 +-
 compiler/rustc_parse/src/errors.rs            |  6 ++---
 .../rustc_parse/src/parser/diagnostics.rs     | 17 +++++++++---
 compiler/rustc_parse/src/parser/item.rs       |  2 +-
 compiler/rustc_parse/src/parser/mod.rs        | 27 +++++++++----------
 5 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index c39ada95a4ec4..96765c296e79b 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re
 parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
 parse_expected_identifier = expected identifier
 
-parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier
+parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
 
 parse_sugg_remove_comma = remove this comma
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index af0c3026c6605..2def5c5b32f17 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem {
 
 #[derive(Subdiagnostic)]
 #[suggestion(
-    parse_sugg_escape_to_use_as_identifier,
+    parse_sugg_escape_identifier,
     style = "verbose",
     applicability = "maybe-incorrect",
     code = "r#"
 )]
-pub(crate) struct SuggEscapeToUseAsIdentifier {
+pub(crate) struct SuggEscapeIdentifier {
     #[primary_span]
     pub span: Span,
     pub ident_name: String,
@@ -937,7 +937,7 @@ impl ExpectedIdentifierFound {
 pub(crate) struct ExpectedIdentifier {
     pub span: Span,
     pub token: Token,
-    pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
+    pub suggest_raw: Option<SuggEscapeIdentifier>,
     pub suggest_remove_comma: Option<SuggRemoveComma>,
     pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
 }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 5b12bcc182222..a9f24ab44ea84 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -6,14 +6,14 @@ use super::{
 use crate::errors::{
     AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
     ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
-    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
-    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
+    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
     GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
     HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
     IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
     PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
     StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
-    StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
+    StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma,
     UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
     UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
 };
@@ -268,7 +268,16 @@ impl<'a> Parser<'a> {
         self.sess.source_map().span_to_snippet(span)
     }
 
+    /// Emits an error with suggestions if an identifier was expected but not found.
     pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        if let TokenKind::DocComment(..) = self.prev_token.kind {
+            return DocCommentDoesNotDocumentAnything {
+                span: self.prev_token.span,
+                missing_comma: None,
+            }
+            .into_diagnostic(&self.sess.span_diagnostic);
+        }
+
         let valid_follow = &[
             TokenKind::Eq,
             TokenKind::Colon,
@@ -286,7 +295,7 @@ impl<'a> Parser<'a> {
                 if ident.is_raw_guess()
                     && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
             {
-                Some(SuggEscapeToUseAsIdentifier {
+                Some(SuggEscapeIdentifier {
                     span: ident.span.shrink_to_lo(),
                     // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
                     // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 85cc8ca02a977..b7415dc8fb84c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> {
     /// Parses a field identifier. Specialized version of `parse_ident_common`
     /// for better diagnostics and suggestions.
     fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
-        let (ident, is_raw) = self.ident_or_err()?;
+        let (ident, is_raw) = self.ident_or_err(true)?;
         if !is_raw && ident.is_reserved() {
             let snapshot = self.create_snapshot_for_diagnostic();
             let err = if self.check_fn_front_matter(false, Case::Sensitive) {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 3251dd6d0c6fb..6991520895ddd 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -42,8 +42,7 @@ use thin_vec::ThinVec;
 use tracing::debug;
 
 use crate::errors::{
-    DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter,
-    NonStringAbiLiteral,
+    IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
 };
 
 bitflags::bitflags! {
@@ -552,19 +551,8 @@ impl<'a> Parser<'a> {
         self.parse_ident_common(true)
     }
 
-    fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> {
-        self.token.ident().ok_or_else(|| match self.prev_token.kind {
-            TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything {
-                span: self.prev_token.span,
-                missing_comma: None,
-            }
-            .into_diagnostic(&self.sess.span_diagnostic),
-            _ => self.expected_ident_found(),
-        })
-    }
-
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {
-        let (ident, is_raw) = self.ident_or_err()?;
+        let (ident, is_raw) = self.ident_or_err(recover)?;
         if !is_raw && ident.is_reserved() {
             let mut err = self.expected_ident_found();
             if recover {
@@ -577,6 +565,17 @@ impl<'a> Parser<'a> {
         Ok(ident)
     }
 
+    fn ident_or_err(&mut self, _recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
+        let result = self.token.ident().ok_or_else(|| self.expected_ident_found());
+
+        let (ident, is_raw) = match result {
+            Ok(ident) => ident,
+            Err(err) => return Err(err),
+        };
+
+        Ok((ident, is_raw))
+    }
+
     /// Checks if the next token is `tok`, and returns `true` if so.
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not

From b4e17a5098f0413b01c90c8505e0f01e8bea50de Mon Sep 17 00:00:00 2001
From: Ezra Shaw <ezrasure@outlook.com>
Date: Fri, 17 Mar 2023 21:41:26 +1300
Subject: [PATCH 07/19] refactor: improve "ident starts with number" error

---
 compiler/rustc_parse/src/errors.rs            |  5 ++-
 .../rustc_parse/src/parser/diagnostics.rs     | 34 +++++++++++++------
 compiler/rustc_parse/src/parser/pat.rs        |  6 +---
 compiler/rustc_span/src/lib.rs                | 12 +++++++
 .../parser/integer-literal-start-ident.stderr |  6 +++-
 tests/ui/parser/issues/issue-104088.stderr    | 18 ++++++++--
 6 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2def5c5b32f17..a9d116012ae5b 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
 
 #[derive(Subdiagnostic)]
 #[help(parse_invalid_identifier_with_leading_number)]
-pub(crate) struct HelpIdentifierStartsWithNumber;
+pub(crate) struct HelpIdentifierStartsWithNumber {
+    #[primary_span]
+    pub num_span: Span,
+}
 
 pub(crate) struct ExpectedSemi {
     pub span: Span,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a9f24ab44ea84..47d1108491530 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -38,7 +38,7 @@ use rustc_errors::{
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
+use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP};
 use std::mem::take;
 use std::ops::{Deref, DerefMut};
 use thin_vec::{thin_vec, ThinVec};
@@ -309,8 +309,11 @@ impl<'a> Parser<'a> {
             && self.look_ahead(1, |t| t.is_ident()))
         .then_some(SuggRemoveComma { span: self.token.span });
 
-        let help_cannot_start_number =
-            self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
+        let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| {
+            let (invalid, _valid) = self.token.span.split_at(len as u32);
+
+            HelpIdentifierStartsWithNumber { num_span: invalid }
+        });
 
         let err = ExpectedIdentifier {
             span: self.token.span,
@@ -378,13 +381,24 @@ impl<'a> Parser<'a> {
 
     /// Checks if the current token is a integer or float literal and looks like
     /// it could be a invalid identifier with digits at the start.
-    pub(super) fn is_lit_bad_ident(&mut self) -> bool {
-        matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. })
-            // ensure that the integer literal is followed by a *invalid*
-            // suffix: this is how we know that it is a identifier with an
-            // invalid beginning.
-            if rustc_ast::MetaItemLit::from_token(&self.token).is_none()
-        )
+    ///
+    /// Returns the number of characters (bytes) composing the invalid portion
+    /// of the identifier and the valid portion of the identifier.
+    pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
+        // ensure that the integer literal is followed by a *invalid*
+        // suffix: this is how we know that it is a identifier with an
+        // invalid beginning.
+        if let token::Literal(Lit {
+            kind: token::LitKind::Integer | token::LitKind::Float,
+            symbol,
+            suffix,
+        }) = self.token.uninterpolate().kind
+            && rustc_ast::MetaItemLit::from_token(&self.token).is_none()
+        {
+            Some((symbol.as_str().len(), suffix.unwrap()))
+        } else {
+            None
+        }
     }
 
     pub(super) fn expected_one_of_not_found(
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index fc9f1d1330a72..d9af241584868 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -348,10 +348,6 @@ impl<'a> Parser<'a> {
             lo = self.token.span;
         }
 
-        if self.is_lit_bad_ident() {
-            return Err(self.expected_ident_found());
-        }
-
         let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
             self.parse_pat_deref(expected)?
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
@@ -395,7 +391,7 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Lit(const_expr)
             }
-        } else if self.can_be_ident_pat() {
+        } else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() {
             // Parse `ident @ pat`
             // This can give false positives and parse nullary enums,
             // they are dealt with later in resolve.
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 873cd33f6a4f2..02cffc762bed3 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -795,6 +795,18 @@ impl Span {
         })
     }
 
+    /// Splits a span into two composite spans around a certain position.
+    pub fn split_at(self, pos: u32) -> (Span, Span) {
+        let len = self.hi().0 - self.lo().0;
+        debug_assert!(pos <= len);
+
+        let split_pos = BytePos(self.lo().0 + pos);
+        (
+            Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
+            Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
+        )
+    }
+
     /// Returns a `Span` that would enclose both `self` and `end`.
     ///
     /// Note that this can also be used to extend the span "backwards":
diff --git a/tests/ui/parser/integer-literal-start-ident.stderr b/tests/ui/parser/integer-literal-start-ident.stderr
index 51c37a0d24c3c..b2c6612965608 100644
--- a/tests/ui/parser/integer-literal-start-ident.stderr
+++ b/tests/ui/parser/integer-literal-start-ident.stderr
@@ -4,7 +4,11 @@ error: expected identifier, found `1main`
 LL | fn 1main() {}
    |    ^^^^^ expected identifier
    |
-   = help: identifiers cannot start with a number
+help: identifiers cannot start with a number
+  --> $DIR/integer-literal-start-ident.rs:1:4
+   |
+LL | fn 1main() {}
+   |    ^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr
index 6511a313149f4..08ea1c891c172 100644
--- a/tests/ui/parser/issues/issue-104088.stderr
+++ b/tests/ui/parser/issues/issue-104088.stderr
@@ -4,7 +4,11 @@ error: expected identifier, found `1x`
 LL |     let 1x = 123;
    |         ^^ expected identifier
    |
-   = help: identifiers cannot start with a number
+help: identifiers cannot start with a number
+  --> $DIR/issue-104088.rs:6:9
+   |
+LL |     let 1x = 123;
+   |         ^
 
 error: expected identifier, found `2x`
   --> $DIR/issue-104088.rs:11:9
@@ -12,7 +16,11 @@ error: expected identifier, found `2x`
 LL |     let 2x: i32 = 123;
    |         ^^ expected identifier
    |
-   = help: identifiers cannot start with a number
+help: identifiers cannot start with a number
+  --> $DIR/issue-104088.rs:11:9
+   |
+LL |     let 2x: i32 = 123;
+   |         ^
 
 error: expected identifier, found `23name`
   --> $DIR/issue-104088.rs:22:9
@@ -20,7 +28,11 @@ error: expected identifier, found `23name`
 LL |     let 23name = 123;
    |         ^^^^^^ expected identifier
    |
-   = help: identifiers cannot start with a number
+help: identifiers cannot start with a number
+  --> $DIR/issue-104088.rs:22:9
+   |
+LL |     let 23name = 123;
+   |         ^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-104088.rs:16:12

From 4da79703b6f2f96e473bdd0317743c433792a29e Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sun, 19 Mar 2023 20:41:22 +0000
Subject: [PATCH 08/19] Update stdarch

Bring the the `#![allow(internal_features)]`
---
 library/stdarch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/stdarch b/library/stdarch
index a0c30f3e3c75a..b655243782c18 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit a0c30f3e3c75adcd6ee7efc94014ebcead61c507
+Subproject commit b655243782c18d3419439daa523782e0818ecf26

From 43008cedafe730c71c071dd9278855e72021ea50 Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sun, 19 Mar 2023 21:08:56 +0000
Subject: [PATCH 09/19] Add `#![feature(generic_arg_infer)]` to core for
 stdarch

---
 library/core/src/lib.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1076d357070ef..a6b9acb576eb4 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -209,6 +209,7 @@
 #![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
+#![feature(generic_arg_infer)]
 #![feature(rustdoc_internals)]
 #![feature(exhaustive_patterns)]
 #![feature(doc_cfg_hide)]

From 20dc53208557db5672a1bcf97b3e582a95913f2c Mon Sep 17 00:00:00 2001
From: Mu42 <mu001999@outlook.com>
Date: Mon, 20 Mar 2023 15:32:21 +0800
Subject: [PATCH 10/19] Remove Ty::is_region_ptr

---
 .../src/diagnostics/mutability_errors.rs            | 13 ++++---------
 compiler/rustc_codegen_cranelift/src/vtable.rs      |  4 +---
 compiler/rustc_codegen_ssa/src/mir/block.rs         |  4 ++--
 compiler/rustc_hir_typeck/src/demand.rs             |  2 +-
 compiler/rustc_hir_typeck/src/method/suggest.rs     |  2 +-
 compiler/rustc_middle/src/ty/sty.rs                 |  7 +------
 compiler/rustc_mir_build/src/thir/cx/expr.rs        |  2 +-
 compiler/rustc_ty_utils/src/abi.rs                  |  2 +-
 8 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index bad08451adf08..a8c216407f931 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     && !self.upvars.is_empty()
                 {
                     item_msg = access_place_desc;
-                    debug_assert!(
-                        self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
-                    );
+                    debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
                             the_place_err.local,
@@ -470,11 +468,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             {
                 let local_decl = &self.body.local_decls[local];
 
-                let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
-                    ("&", "reference")
-                } else {
-                    ("*const", "pointer")
-                };
+                let (pointer_sigil, pointer_desc) =
+                    if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
 
                 match self.local_names[local] {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
@@ -1258,7 +1253,7 @@ fn suggest_ampmut<'tcx>(
     (
         suggestability,
         highlight_span,
-        if local_decl.ty.is_region_ptr() {
+        if local_decl.ty.is_ref() {
             format!("&mut {}", ty_mut.ty)
         } else {
             format!("*mut {}", ty_mut.ty)
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index b7bfd8fd39526..94806e0d798ed 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
 ) -> (Pointer, Value) {
     let (ptr, vtable) = 'block: {
         if let Abi::Scalar(_) = arg.layout().abi {
-            'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr()
-                && !arg.layout().ty.is_region_ptr()
-            {
+            'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
                 for i in 0..arg.layout().fields.count() {
                     let field = arg.value_field(fx, mir::Field::new(i));
                     if !field.layout().is_zst() {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index f9aa2aecf65bc..6bad5c3eb2822 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -917,7 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         //
                         // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
                         'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
-                            && !op.layout.ty.is_region_ptr()
+                            && !op.layout.ty.is_ref()
                         {
                             for i in 0..op.layout.fields.count() {
                                 let field = op.extract_field(bx, i);
@@ -959,7 +959,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     Immediate(_) => {
                         // See comment above explaining why we peel these newtypes
                         'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
-                            && !op.layout.ty.is_region_ptr()
+                            && !op.layout.ty.is_ref()
                         {
                             for i in 0..op.layout.fields.count() {
                                 let field = op.extract_field(bx, i);
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index f65f16e317d49..23845d39a981f 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     {
                         let deref_kind = if checked_ty.is_box() {
                             "unboxing the value"
-                        } else if checked_ty.is_region_ptr() {
+                        } else if checked_ty.is_ref() {
                             "dereferencing the borrow"
                         } else {
                             "dereferencing the type"
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 50f2b71250c01..b219be4ae1992 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1182,7 +1182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 .inputs()
                                 .skip_binder()
                                 .get(0)
-                                .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+                                .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
                                 .copied()
                                 .unwrap_or(rcvr_ty),
                         };
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 4c606b939b25e..2e691ab250d83 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1913,11 +1913,6 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    #[inline]
-    pub fn is_region_ptr(self) -> bool {
-        matches!(self.kind(), Ref(..))
-    }
-
     #[inline]
     pub fn is_mutable_ptr(self) -> bool {
         matches!(
@@ -1944,7 +1939,7 @@ impl<'tcx> Ty<'tcx> {
     /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
     #[inline]
     pub fn is_any_ptr(self) -> bool {
-        self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
+        self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr()
     }
 
     #[inline]
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index cecb8a61aa2f4..6fd9b9dbb5755 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> {
         if self.typeck_results().is_coercion_cast(source.hir_id) {
             // Convert the lexpr to a vexpr.
             ExprKind::Use { source: self.mirror_expr(source) }
-        } else if self.typeck_results().expr_ty(source).is_region_ptr() {
+        } else if self.typeck_results().expr_ty(source).is_ref() {
             // Special cased so that we can type check that the element
             // type of the source matches the pointed to type of the
             // destination.
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 35c9f95eb03b1..ee5a7909ba3dc 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>(
         // get a built-in pointer type
         let mut fat_pointer_layout = layout;
         'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
-            && !fat_pointer_layout.ty.is_region_ptr()
+            && !fat_pointer_layout.ty.is_ref()
         {
             for i in 0..fat_pointer_layout.fields.count() {
                 let field_layout = fat_pointer_layout.field(cx, i);

From 05b5046633e9f594f955e0365a1219d1a96a5b54 Mon Sep 17 00:00:00 2001
From: Ezra Shaw <ezrasure@outlook.com>
Date: Fri, 17 Mar 2023 22:27:17 +1300
Subject: [PATCH 11/19] feat: implement error recovery in
 `expected_ident_found`

---
 .../rustc_parse/src/parser/diagnostics.rs     | 84 +++++++++++++------
 compiler/rustc_parse/src/parser/item.rs       |  8 +-
 compiler/rustc_parse/src/parser/mod.rs        | 13 ++-
 compiler/rustc_parse/src/parser/pat.rs        | 10 ++-
 tests/ui/parser/ident-recovery.rs             | 16 ++++
 tests/ui/parser/ident-recovery.stderr         | 42 ++++++++++
 tests/ui/parser/issues/issue-104088.rs        | 23 ++---
 tests/ui/parser/issues/issue-104088.stderr    | 48 +++++++----
 8 files changed, 175 insertions(+), 69 deletions(-)
 create mode 100644 tests/ui/parser/ident-recovery.rs
 create mode 100644 tests/ui/parser/ident-recovery.stderr

diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 47d1108491530..9544afd3d6df9 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -269,13 +269,18 @@ impl<'a> Parser<'a> {
     }
 
     /// Emits an error with suggestions if an identifier was expected but not found.
-    pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+    ///
+    /// Returns a possibly recovered identifier.
+    pub(super) fn expected_ident_found(
+        &mut self,
+        recover: bool,
+    ) -> PResult<'a, (Ident, /* is_raw */ bool)> {
         if let TokenKind::DocComment(..) = self.prev_token.kind {
-            return DocCommentDoesNotDocumentAnything {
+            return Err(DocCommentDoesNotDocumentAnything {
                 span: self.prev_token.span,
                 missing_comma: None,
             }
-            .into_diagnostic(&self.sess.span_diagnostic);
+            .into_diagnostic(&self.sess.span_diagnostic));
         }
 
         let valid_follow = &[
@@ -290,34 +295,51 @@ impl<'a> Parser<'a> {
             TokenKind::CloseDelim(Delimiter::Parenthesis),
         ];
 
-        let suggest_raw = match self.token.ident() {
-            Some((ident, false))
-                if ident.is_raw_guess()
-                    && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
-            {
-                Some(SuggEscapeIdentifier {
-                    span: ident.span.shrink_to_lo(),
-                    // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
-                    // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
-                    ident_name: ident.name.to_string(),
-                })
-            }
-            _ => None,
-        };
+        let mut recovered_ident = None;
+        // we take this here so that the correct original token is retained in
+        // the diagnostic, regardless of eager recovery.
+        let bad_token = self.token.clone();
+
+        // suggest prepending a keyword in identifier position with `r#`
+        let suggest_raw = if let Some((ident, false)) = self.token.ident()
+            && ident.is_raw_guess()
+            && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
+        {
+            recovered_ident = Some((ident, true));
+
+            // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
+            // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
+            let ident_name = ident.name.to_string();
+
+            Some(SuggEscapeIdentifier {
+                span: ident.span.shrink_to_lo(),
+                ident_name
+            })
+        } else { None };
+
+        let suggest_remove_comma =
+            if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
+                if recover {
+                    self.bump();
+                    recovered_ident = self.ident_or_err(false).ok();
+                };
+
+                Some(SuggRemoveComma { span: bad_token.span })
+            } else {
+                None
+            };
 
-        let suggest_remove_comma = (self.token == token::Comma
-            && self.look_ahead(1, |t| t.is_ident()))
-        .then_some(SuggRemoveComma { span: self.token.span });
+        let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
+            let (invalid, valid) = self.token.span.split_at(len as u32);
 
-        let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| {
-            let (invalid, _valid) = self.token.span.split_at(len as u32);
+            recovered_ident = Some((Ident::new(valid_portion, valid), false));
 
             HelpIdentifierStartsWithNumber { num_span: invalid }
         });
 
         let err = ExpectedIdentifier {
-            span: self.token.span,
-            token: self.token.clone(),
+            span: bad_token.span,
+            token: bad_token,
             suggest_raw,
             suggest_remove_comma,
             help_cannot_start_number,
@@ -326,6 +348,7 @@ impl<'a> Parser<'a> {
 
         // if the token we have is a `<`
         // it *might* be a misplaced generic
+        // FIXME: could we recover with this?
         if self.token == token::Lt {
             // all keywords that could have generic applied
             let valid_prev_keywords =
@@ -376,7 +399,16 @@ impl<'a> Parser<'a> {
             }
         }
 
-        err
+        if let Some(recovered_ident) = recovered_ident && recover {
+            err.emit();
+            Ok(recovered_ident)
+        } else {
+            Err(err)
+        }
+    }
+
+    pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        self.expected_ident_found(false).unwrap_err()
     }
 
     /// Checks if the current token is a integer or float literal and looks like
@@ -392,7 +424,7 @@ impl<'a> Parser<'a> {
             kind: token::LitKind::Integer | token::LitKind::Float,
             symbol,
             suffix,
-        }) = self.token.uninterpolate().kind
+        }) = self.token.kind
             && rustc_ast::MetaItemLit::from_token(&self.token).is_none()
         {
             Some((symbol.as_str().len(), suffix.unwrap()))
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index b7415dc8fb84c..ae8fe90e9d611 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> {
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
         let impl_span = self.token.span;
-        let mut err = self.expected_ident_found();
+        let mut err = self.expected_ident_found_err();
 
         // Only try to recover if this is implementing a trait for a type
         let mut impl_info = match self.parse_item_impl(attrs, defaultness) {
@@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> {
                     Err(err) => {
                         err.cancel();
                         self.restore_snapshot(snapshot);
-                        self.expected_ident_found()
+                        self.expected_ident_found_err()
                     }
                 }
             } else if self.eat_keyword(kw::Struct) {
@@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> {
                     Err(err) => {
                         err.cancel();
                         self.restore_snapshot(snapshot);
-                        self.expected_ident_found()
+                        self.expected_ident_found_err()
                     }
                 }
             } else {
-                let mut err = self.expected_ident_found();
+                let mut err = self.expected_ident_found_err();
                 if self.eat_keyword_noexpect(kw::Let)
                     && let removal_span = self.prev_token.span.until(self.token.span)
                     && let Ok(ident) = self.parse_ident_common(false)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 6991520895ddd..53c25a80c4bf3 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -553,8 +553,9 @@ impl<'a> Parser<'a> {
 
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {
         let (ident, is_raw) = self.ident_or_err(recover)?;
+
         if !is_raw && ident.is_reserved() {
-            let mut err = self.expected_ident_found();
+            let mut err = self.expected_ident_found_err();
             if recover {
                 err.emit();
             } else {
@@ -565,12 +566,16 @@ impl<'a> Parser<'a> {
         Ok(ident)
     }
 
-    fn ident_or_err(&mut self, _recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
-        let result = self.token.ident().ok_or_else(|| self.expected_ident_found());
+    fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
+        let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover));
 
         let (ident, is_raw) = match result {
             Ok(ident) => ident,
-            Err(err) => return Err(err),
+            Err(err) => match err {
+                // we recovered!
+                Ok(ident) => ident,
+                Err(err) => return Err(err),
+            },
         };
 
         Ok((ident, is_raw))
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index d9af241584868..2246002f5d32a 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -391,7 +391,13 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Lit(const_expr)
             }
-        } else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() {
+        // Don't eagerly error on semantically invalid tokens when matching
+        // declarative macros, as the input to those doesn't have to be
+        // semantically valid. For attribute/derive proc macros this is not the
+        // case, so doing the recovery for them is fine.
+        } else if self.can_be_ident_pat()
+            || (self.is_lit_bad_ident().is_some() && self.may_recover())
+        {
             // Parse `ident @ pat`
             // This can give false positives and parse nullary enums,
             // they are dealt with later in resolve.
@@ -590,7 +596,7 @@ impl<'a> Parser<'a> {
         // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
         if let token::Interpolated(nt) = &self.token.kind {
             if let token::NtPat(_) = **nt {
-                self.expected_ident_found().emit();
+                self.expected_ident_found_err().emit();
             }
         }
 
diff --git a/tests/ui/parser/ident-recovery.rs b/tests/ui/parser/ident-recovery.rs
new file mode 100644
index 0000000000000..7575372b940fd
--- /dev/null
+++ b/tests/ui/parser/ident-recovery.rs
@@ -0,0 +1,16 @@
+fn ,comma() {
+    //~^ ERROR expected identifier, found `,`
+    struct Foo {
+        x: i32,,
+        //~^ ERROR expected identifier, found `,`
+        y: u32,
+    }
+}
+
+fn break() {
+//~^ ERROR expected identifier, found keyword `break`
+    let continue = 5;
+    //~^ ERROR expected identifier, found keyword `continue`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr
new file mode 100644
index 0000000000000..e9a55026d1245
--- /dev/null
+++ b/tests/ui/parser/ident-recovery.stderr
@@ -0,0 +1,42 @@
+error: expected identifier, found `,`
+  --> $DIR/ident-recovery.rs:1:4
+   |
+LL | fn ,comma() {
+   |    ^
+   |    |
+   |    expected identifier
+   |    help: remove this comma
+
+error: expected identifier, found `,`
+  --> $DIR/ident-recovery.rs:4:16
+   |
+LL |         x: i32,,
+   |                ^
+   |                |
+   |                expected identifier
+   |                help: remove this comma
+
+error: expected identifier, found keyword `break`
+  --> $DIR/ident-recovery.rs:10:4
+   |
+LL | fn break() {
+   |    ^^^^^ expected identifier, found keyword
+   |
+help: escape `break` to use it as an identifier
+   |
+LL | fn r#break() {
+   |    ++
+
+error: expected identifier, found keyword `continue`
+  --> $DIR/ident-recovery.rs:12:9
+   |
+LL |     let continue = 5;
+   |         ^^^^^^^^ expected identifier, found keyword
+   |
+help: escape `continue` to use it as an identifier
+   |
+LL |     let r#continue = 5;
+   |         ++
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/issues/issue-104088.rs
index 86988c8cd21da..3dc636b6a33bd 100644
--- a/tests/ui/parser/issues/issue-104088.rs
+++ b/tests/ui/parser/issues/issue-104088.rs
@@ -1,26 +1,19 @@
-fn test() {
+fn 1234test() {
+//~^ ERROR expected identifier, found `1234test`
     if let 123 = 123 { println!("yes"); }
-}
-
-fn test_2() {
-    let 1x = 123;
-    //~^ ERROR expected identifier, found `1x`
-}
-
-fn test_3() {
-    let 2x: i32 = 123;
-    //~^ ERROR expected identifier, found `2x`
-}
 
-fn test_4() {
     if let 2e1 = 123 {
         //~^ ERROR mismatched types
     }
-}
 
-fn test_5() {
     let 23name = 123;
     //~^ ERROR expected identifier, found `23name`
+
+    let 2x: i32 = 123;
+    //~^ ERROR expected identifier, found `2x`
+
+    let 1x = 123;
+    //~^ ERROR expected identifier, found `1x`
 }
 
 fn main() {}
diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr
index 08ea1c891c172..8b751759d69a6 100644
--- a/tests/ui/parser/issues/issue-104088.stderr
+++ b/tests/ui/parser/issues/issue-104088.stderr
@@ -1,47 +1,59 @@
-error: expected identifier, found `1x`
-  --> $DIR/issue-104088.rs:6:9
+error: expected identifier, found `1234test`
+  --> $DIR/issue-104088.rs:1:4
    |
-LL |     let 1x = 123;
-   |         ^^ expected identifier
+LL | fn 1234test() {
+   |    ^^^^^^^^ expected identifier
    |
 help: identifiers cannot start with a number
-  --> $DIR/issue-104088.rs:6:9
+  --> $DIR/issue-104088.rs:1:4
    |
-LL |     let 1x = 123;
-   |         ^
+LL | fn 1234test() {
+   |    ^^^^
+
+error: expected identifier, found `23name`
+  --> $DIR/issue-104088.rs:9:9
+   |
+LL |     let 23name = 123;
+   |         ^^^^^^ expected identifier
+   |
+help: identifiers cannot start with a number
+  --> $DIR/issue-104088.rs:9:9
+   |
+LL |     let 23name = 123;
+   |         ^^
 
 error: expected identifier, found `2x`
-  --> $DIR/issue-104088.rs:11:9
+  --> $DIR/issue-104088.rs:12:9
    |
 LL |     let 2x: i32 = 123;
    |         ^^ expected identifier
    |
 help: identifiers cannot start with a number
-  --> $DIR/issue-104088.rs:11:9
+  --> $DIR/issue-104088.rs:12:9
    |
 LL |     let 2x: i32 = 123;
    |         ^
 
-error: expected identifier, found `23name`
-  --> $DIR/issue-104088.rs:22:9
+error: expected identifier, found `1x`
+  --> $DIR/issue-104088.rs:15:9
    |
-LL |     let 23name = 123;
-   |         ^^^^^^ expected identifier
+LL |     let 1x = 123;
+   |         ^^ expected identifier
    |
 help: identifiers cannot start with a number
-  --> $DIR/issue-104088.rs:22:9
+  --> $DIR/issue-104088.rs:15:9
    |
-LL |     let 23name = 123;
-   |         ^^
+LL |     let 1x = 123;
+   |         ^
 
 error[E0308]: mismatched types
-  --> $DIR/issue-104088.rs:16:12
+  --> $DIR/issue-104088.rs:5:12
    |
 LL |     if let 2e1 = 123 {
    |            ^^^   --- this expression has type `{integer}`
    |            |
    |            expected integer, found floating-point number
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.

From 460ecd288a34f73f9178acc723a459cbfe77607a Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Thu, 16 Mar 2023 10:05:09 +0000
Subject: [PATCH 12/19] Eagerly intern and check CrateNum/StableCrateId
 collisions

---
 Cargo.lock                                    |  1 +
 compiler/rustc_metadata/src/creader.rs        | 75 ++++++-------------
 compiler/rustc_metadata/src/rmeta/decoder.rs  |  4 -
 .../src/rmeta/decoder/cstore_impl.rs          |  5 +-
 compiler/rustc_span/Cargo.toml                |  1 +
 compiler/rustc_span/src/def_id.rs             |  6 +-
 tests/run-make-fulldeps/issue-83045/Makefile  |  2 +-
 7 files changed, 33 insertions(+), 61 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0c0b5d6ab3b57..aa4d79ed26117 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5294,6 +5294,7 @@ name = "rustc_span"
 version = "0.0.0"
 dependencies = [
  "cfg-if",
+ "indexmap",
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index f870a1db82d9c..538e61c985104 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob
 
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_ast::{self as ast, *};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
 use rustc_expand::base::SyntaxExtension;
-use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::TyCtxt;
@@ -46,9 +46,8 @@ pub struct CStore {
     /// This crate has a `#[alloc_error_handler]` item.
     has_alloc_error_handler: bool,
 
-    /// This map is used to verify we get no hash conflicts between
-    /// `StableCrateId` values.
-    pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
+    /// The interned [StableCrateId]s.
+    pub(crate) stable_crate_ids: StableCrateIdMap,
 
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
@@ -144,9 +143,21 @@ impl CStore {
         })
     }
 
-    fn alloc_new_crate_num(&mut self) -> CrateNum {
-        self.metas.push(None);
-        CrateNum::new(self.metas.len() - 1)
+    fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> {
+        assert_eq!(self.metas.len(), self.stable_crate_ids.len());
+        let num = CrateNum::new(self.stable_crate_ids.len());
+        if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
+            let crate_name0 = root.name();
+            if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) {
+                Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
+            } else {
+                Err(CrateError::SymbolConflictsCurrent(crate_name0))
+            }
+        } else {
+            self.metas.push(None);
+            self.stable_crate_ids.insert(root.stable_crate_id(), num);
+            Ok(num)
+        }
     }
 
     pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
@@ -247,7 +258,7 @@ impl CStore {
     }
 
     pub fn new(sess: &Session) -> CStore {
-        let mut stable_crate_ids = FxHashMap::default();
+        let mut stable_crate_ids = StableCrateIdMap::default();
         stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
         CStore {
             // We add an empty entry for LOCAL_CRATE (which maps to zero) in
@@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         None
     }
 
-    fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> {
-        // Check for (potential) conflicts with the local crate
-        if self.sess.local_stable_crate_id() == root.stable_crate_id() {
-            return Err(CrateError::SymbolConflictsCurrent(root.name()));
-        }
-
-        // Check for conflicts with any crate loaded so far
-        for (_, other) in self.cstore.iter_crate_data() {
-            // Same stable crate id but different SVH
-            if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
-                bug!(
-                    "Previously returned E0523 here. \
-                     See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
-                     root.name() = {}.",
-                    root.name()
-                );
-            }
-        }
-
-        Ok(())
-    }
-
-    fn verify_no_stable_crate_id_hash_conflicts(
-        &mut self,
-        root: &CrateRoot,
-        cnum: CrateNum,
-    ) -> Result<(), CrateError> {
-        if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) {
-            let crate_name0 = root.name();
-            let crate_name1 = self.cstore.get_crate_data(existing).name();
-            return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1));
-        }
-
-        Ok(())
-    }
-
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
@@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep);
 
         // Claim this crate number and cache it
-        let cnum = self.cstore.alloc_new_crate_num();
+        let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
 
         info!(
             "register crate `{}` (cnum = {}. private_dep = {})",
@@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             None
         };
 
-        // Perform some verification *after* resolve_crate_deps() above is
-        // known to have been successful. It seems that - in error cases - the
-        // cstore can be in a temporarily invalid state between cnum allocation
-        // and dependency resolution and the verification code would produce
-        // ICEs in that case (see #83045).
-        self.verify_no_symbol_conflicts(&crate_root)?;
-        self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?;
-
         let crate_metadata = CrateMetadata::new(
             self.sess,
             &self.cstore,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 0070e46ffdf02..cabc144077fd5 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1709,10 +1709,6 @@ impl CrateMetadata {
         self.root.name
     }
 
-    pub(crate) fn stable_crate_id(&self) -> StableCrateId {
-        self.root.stable_crate_id
-    }
-
     pub(crate) fn hash(&self) -> Svh {
         self.root.hash
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index a98433953367b..e0f1435ccb3ae 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -615,7 +615,10 @@ impl CrateStore for CStore {
     }
 
     fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
-        self.stable_crate_ids[&stable_crate_id]
+        *self
+            .stable_crate_ids
+            .get(&stable_crate_id)
+            .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"))
     }
 
     /// Returns the `DefKey` for a given `DefId`. This indicates the
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index ae81d95e27967..98d6e0ab117a3 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -18,3 +18,4 @@ tracing = "0.1"
 sha1 = "0.10.0"
 sha2 = "0.10.1"
 md5 = { package = "md-5", version = "0.10.0" }
+indexmap = { version = "1.9.1" }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 162c15574b56c..b2c58caff2ec4 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -1,13 +1,17 @@
 use crate::{HashStableContext, Symbol};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::unhash::Unhasher;
 use rustc_data_structures::AtomicRef;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::borrow::Borrow;
 use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::{BuildHasherDefault, Hash, Hasher};
+
+pub type StableCrateIdMap =
+    indexmap::IndexMap<StableCrateId, CrateNum, BuildHasherDefault<Unhasher>>;
 
 rustc_index::newtype_index! {
     #[custom_encodable]
diff --git a/tests/run-make-fulldeps/issue-83045/Makefile b/tests/run-make-fulldeps/issue-83045/Makefile
index 34853cb1d31e5..fc180ccfe28e2 100644
--- a/tests/run-make-fulldeps/issue-83045/Makefile
+++ b/tests/run-make-fulldeps/issue-83045/Makefile
@@ -29,5 +29,5 @@ all:
 				  --crate-type=rlib \
 				  --edition=2018 \
 				  c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
-	$(CGREP) E0463 < $(TMPDIR)/output.txt
+	$(CGREP) E0519 < $(TMPDIR)/output.txt
 	$(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt

From 47f24a881bb05293c4d922218d9dfed7e29511cd Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 21 Mar 2023 16:26:23 +0100
Subject: [PATCH 13/19] new solver cleanup + coherence

---
 compiler/rustc_middle/src/traits/solve.rs     | 11 ++-
 .../src/solve/assembly.rs                     | 69 +++++++++++--------
 .../src/solve/eval_ctxt.rs                    |  9 ++-
 .../rustc_trait_selection/src/solve/mod.rs    | 19 +++--
 .../src/solve/project_goals.rs                |  6 +-
 .../src/solve/search_graph/mod.rs             | 13 +++-
 .../src/solve/trait_goals.rs                  | 27 +++++++-
 .../rustc_trait_selection/src/traits/mod.rs   |  2 +-
 .../new-solver/coherence/issue-102048.rs      | 44 ++++++++++++
 .../new-solver/coherence/issue-102048.stderr  | 12 ++++
 .../coherence-conflict.next.stderr            | 11 +++
 ...t.stderr => coherence-conflict.old.stderr} |  2 +-
 .../reservation-impl/coherence-conflict.rs    |  3 +-
 .../{no-use.stderr => no-use.next.stderr}     |  2 +-
 .../traits/reservation-impl/no-use.old.stderr | 13 ++++
 tests/ui/traits/reservation-impl/no-use.rs    |  3 +-
 .../traits/reservation-impl/non-lattice-ok.rs |  6 ++
 tests/ui/traits/reservation-impl/ok.rs        |  3 +
 18 files changed, 203 insertions(+), 52 deletions(-)
 create mode 100644 tests/ui/traits/new-solver/coherence/issue-102048.rs
 create mode 100644 tests/ui/traits/new-solver/coherence/issue-102048.stderr
 create mode 100644 tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
 rename tests/ui/traits/reservation-impl/{coherence-conflict.stderr => coherence-conflict.old.stderr} (91%)
 rename tests/ui/traits/reservation-impl/{no-use.stderr => no-use.next.stderr} (93%)
 create mode 100644 tests/ui/traits/reservation-impl/no-use.old.stderr

diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 92d3e73e683cd..f47f4cbdb4db7 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -63,14 +63,13 @@ impl Certainty {
             (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
             (Certainty::Yes, Certainty::Maybe(_)) => other,
             (Certainty::Maybe(_), Certainty::Yes) => self,
-            (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
+            (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
                 Certainty::Maybe(MaybeCause::Overflow)
             }
-            // If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal
-            // may still result in failure.
-            (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_))
-            | (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => {
-                Certainty::Maybe(MaybeCause::Ambiguity)
+            (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
+            | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
+            | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
+                Certainty::Maybe(MaybeCause::Overflow)
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 76cde1a669225..8cb09108e83ca 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -2,7 +2,8 @@
 
 #[cfg(doc)]
 use super::trait_goals::structural_traits::*;
-use super::EvalCtxt;
+use super::{EvalCtxt, SolverMode};
+use crate::traits::coherence;
 use itertools::Itertools;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
@@ -87,6 +88,8 @@ pub(super) enum CandidateSource {
 pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
     fn self_ty(self) -> Ty<'tcx>;
 
+    fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
 
     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
@@ -244,15 +247,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         self.assemble_object_bound_candidates(goal, &mut candidates);
 
+        self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
+
         candidates
     }
 
     /// If the self type of a goal is a projection, computing the relevant candidates is difficult.
     ///
     /// To deal with this, we first try to normalize the self type and add the candidates for the normalized
-    /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
-    /// this case as projections as self types add
-    // FIXME complete the unfinished sentence above
+    /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the
+    /// projection as a self type as well
     fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -468,14 +472,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
     }
 
+    fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        match self.solver_mode() {
+            SolverMode::Normal => return,
+            SolverMode::Coherence => {
+                let trait_ref = goal.predicate.trait_ref(self.tcx());
+                match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) {
+                    Ok(()) => {}
+                    Err(_) => match self
+                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                    {
+                        Ok(result) => candidates
+                            .push(Candidate { source: CandidateSource::BuiltinImpl, result }),
+                        // FIXME: This will be reachable at some point if we're in
+                        // `assemble_candidates_after_normalizing_self_ty` and we get a
+                        // universe error. We'll deal with it at this point.
+                        Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"),
+                    },
+                }
+            }
+        }
+    }
+
     #[instrument(level = "debug", skip(self), ret)]
-    pub(super) fn merge_candidates_and_discard_reservation_impls(
+    pub(super) fn merge_candidates(
         &mut self,
         mut candidates: Vec<Candidate<'tcx>>,
     ) -> QueryResult<'tcx> {
         match candidates.len() {
             0 => return Err(NoSolution),
-            1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
+            1 => return Ok(candidates.pop().unwrap().result),
             _ => {}
         }
 
@@ -483,10 +513,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             let mut i = 0;
             'outer: while i < candidates.len() {
                 for j in (0..candidates.len()).filter(|&j| i != j) {
-                    if self.trait_candidate_should_be_dropped_in_favor_of(
-                        &candidates[i],
-                        &candidates[j],
-                    ) {
+                    if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
+                    {
                         debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
                         candidates.swap_remove(i);
                         continue 'outer;
@@ -511,11 +539,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             }
         }
 
-        // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl?
-        Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
+        Ok(candidates.pop().unwrap().result)
     }
 
-    fn trait_candidate_should_be_dropped_in_favor_of(
+    fn candidate_should_be_dropped_in_favor_of(
         &self,
         candidate: &Candidate<'tcx>,
         other: &Candidate<'tcx>,
@@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | (CandidateSource::BuiltinImpl, _) => false,
         }
     }
-
-    fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
-        if let CandidateSource::Impl(def_id) = candidate.source {
-            if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
-                debug!("Selected reservation impl");
-                // We assemble all candidates inside of a probe so by
-                // making a new canonical response here our result will
-                // have no constraints.
-                candidate.result = self
-                    .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-                    .unwrap();
-            }
-        }
-
-        candidate
-    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 9541292235795..4b85be69e61bd 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -17,6 +17,7 @@ use rustc_span::DUMMY_SP;
 use std::ops::ControlFlow;
 
 use super::search_graph::{self, OverflowHandler};
+use super::SolverMode;
 use super::{search_graph::SearchGraph, Goal};
 
 pub struct EvalCtxt<'a, 'tcx> {
@@ -78,7 +79,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
     ) -> Result<(bool, Certainty), NoSolution> {
-        let mut search_graph = search_graph::SearchGraph::new(self.tcx);
+        let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
+
+        let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
 
         let mut ecx = EvalCtxt {
             search_graph: &mut search_graph,
@@ -101,6 +104,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
 }
 
 impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+    pub(super) fn solver_mode(&self) -> SolverMode {
+        self.search_graph.solver_mode()
+    }
+
     /// The entry point of the solver.
     ///
     /// This function deals with (coinductive) cycles, overflow, and caching
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 606c2eaa51051..89f4056a58db4 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -9,10 +9,6 @@
 //! FIXME(@lcnr): Write that section. If you read this before then ask me
 //! about it on zulip.
 
-// FIXME: Instead of using `infcx.canonicalize_query` we have to add a new routine which
-// preserves universes and creates a unique var (in the highest universe) for each
-// appearance of a region.
-
 // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
 
 use rustc_hir::def_id::DefId;
@@ -41,6 +37,19 @@ mod trait_goals;
 pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
 pub use fulfill::FulfillmentCtxt;
 
+#[derive(Debug, Clone, Copy)]
+enum SolverMode {
+    /// Ordinary trait solving, using everywhere except for coherence.
+    Normal,
+    /// Trait solving during coherence. There are a few notable differences
+    /// between coherence and ordinary trait solving.
+    ///
+    /// Most importantly, trait solving during coherence must not be incomplete,
+    /// i.e. return `Err(NoSolution)` for goals for which a solution exists.
+    /// This means that we must not make any guesses or arbitrary choices.
+    Coherence,
+}
+
 trait CanonicalResponseExt {
     fn has_no_inference_or_external_constraints(&self) -> bool;
 }
@@ -255,7 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return Err(NoSolution);
         }
 
-        // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with
+        // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
         // a subset of the constraints that all the other responses have.
         let one = candidates[0];
         if candidates[1..].iter().all(|resp| resp == &one) {
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 93d77c39f9580..998859966528b 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // projection cache in the solver.
         if self.term_is_fully_unconstrained(goal) {
             let candidates = self.assemble_and_evaluate_candidates(goal);
-            self.merge_candidates_and_discard_reservation_impls(candidates)
+            self.merge_candidates(candidates)
         } else {
             let predicate = goal.predicate;
             let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term);
@@ -56,6 +56,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         self.self_ty()
     }
 
+    fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
+        self.projection_ty.trait_ref(tcx)
+    }
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
         self.with_self_ty(tcx, self_ty)
     }
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 83d77a69c0020..b94c44cbdd038 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -1,8 +1,9 @@
 mod cache;
 mod overflow;
 
+pub(super) use overflow::OverflowHandler;
+
 use self::cache::ProvisionalEntry;
-pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
 use cache::ProvisionalCache;
 use overflow::OverflowData;
 use rustc_index::vec::IndexVec;
@@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes
 use rustc_middle::ty::TyCtxt;
 use std::{collections::hash_map::Entry, mem};
 
+use super::SolverMode;
+
 rustc_index::newtype_index! {
     pub struct StackDepth {}
 }
@@ -21,6 +24,7 @@ struct StackElem<'tcx> {
 }
 
 pub(super) struct SearchGraph<'tcx> {
+    mode: SolverMode,
     /// The stack of goals currently being computed.
     ///
     /// An element is *deeper* in the stack if its index is *lower*.
@@ -30,14 +34,19 @@ pub(super) struct SearchGraph<'tcx> {
 }
 
 impl<'tcx> SearchGraph<'tcx> {
-    pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> {
+    pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
         Self {
+            mode,
             stack: Default::default(),
             overflow_data: OverflowData::new(tcx),
             provisional_cache: ProvisionalCache::empty(),
         }
     }
 
+    pub(super) fn solver_mode(&self) -> SolverMode {
+        self.mode
+    }
+
     pub(super) fn is_empty(&self) -> bool {
         self.stack.is_empty() && self.provisional_cache.is_empty()
     }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 8ab55c79fc450..2ebdfc8fe72a1 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -2,7 +2,7 @@
 
 use std::iter;
 
-use super::{assembly, EvalCtxt};
+use super::{assembly, EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::traits::query::NoSolution;
@@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         self.self_ty()
     }
 
+    fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
+        self.trait_ref
+    }
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
         self.with_self_ty(tcx, self_ty)
     }
@@ -43,6 +47,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
+        let impl_polarity = tcx.impl_polarity(impl_def_id);
+        // An upper bound of the certainty of this goal, used to lower the certainty
+        // of reservation impl to ambiguous during coherence.
+        let maximal_certainty = match impl_polarity {
+            ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => {
+                match impl_polarity == goal.predicate.polarity {
+                    true => Certainty::Yes,
+                    false => return Err(NoSolution),
+                }
+            }
+            ty::ImplPolarity::Reservation => match ecx.solver_mode() {
+                SolverMode::Normal => return Err(NoSolution),
+                SolverMode::Coherence => Certainty::AMBIGUOUS,
+            },
+        };
+
         ecx.probe(|ecx| {
             let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
@@ -55,7 +75,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
             ecx.add_goals(where_clause_bounds);
-            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+
+            ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
         })
     }
 
@@ -547,6 +568,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
         let candidates = self.assemble_and_evaluate_candidates(goal);
-        self.merge_candidates_and_discard_reservation_impls(candidates)
+        self.merge_candidates(candidates)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index bfeda88a6d40c..2de420b52940a 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -4,7 +4,7 @@
 
 pub mod auto_trait;
 mod chalk_fulfill;
-mod coherence;
+pub(crate) mod coherence;
 pub mod const_evaluatable;
 mod engine;
 pub mod error_reporting;
diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.rs b/tests/ui/traits/new-solver/coherence/issue-102048.rs
new file mode 100644
index 0000000000000..11636bfeb5509
--- /dev/null
+++ b/tests/ui/traits/new-solver/coherence/issue-102048.rs
@@ -0,0 +1,44 @@
+// This must fail coherence.
+//
+// Getting this to pass was fairly difficult, so here's an explanation
+// of what's happening:
+//
+// Normalizing projections currently tries to replace them with inference variables
+// while emitting a nested `Projection` obligation. This cannot be done if the projection
+// has bound variables which is the case here.
+//
+// So the projections stay until after normalization. When unifying two projections we
+// currently treat them as if they are injective, so we **incorrectly** unify their
+// substs. This means that coherence for the two impls ends up unifying `?T` and `?U`
+// as it tries to unify `<?T as WithAssoc1<'a>>::Assoc` with `<?U as WithAssoc1<'a>>::Assoc`.
+//
+// `impl1` therefore has the projection `<?T as WithAssoc2<'a>>::Assoc` and we have the
+// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize
+// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails,
+// causing coherence to consider these two impls distinct.
+
+// compile-flags: -Ztrait-solver=next
+pub trait Trait<T> {}
+
+pub trait WithAssoc1<'a> {
+    type Assoc;
+}
+pub trait WithAssoc2<'a> {
+    type Assoc;
+}
+
+// impl 1
+impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
+where
+    T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>,
+    U: for<'a> WithAssoc2<'a>,
+{
+}
+
+// impl 2
+impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
+    U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.stderr b/tests/ui/traits/new-solver/coherence/issue-102048.stderr
new file mode 100644
index 0000000000000..17a43838fe275
--- /dev/null
+++ b/tests/ui/traits/new-solver/coherence/issue-102048.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)`
+  --> $DIR/issue-102048.rs:39:1
+   |
+LL | impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
+   | --------------------------------------------------------------------------------------------------- first implementation here
+...
+LL | impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
new file mode 100644
index 0000000000000..e5a3c3f5cc4b7
--- /dev/null
+++ b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`
+  --> $DIR/coherence-conflict.rs:12:1
+   |
+LL | impl OtherTrait for () {}
+   | ---------------------- first implementation here
+LL | impl<T: MyTrait> OtherTrait for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr
similarity index 91%
rename from tests/ui/traits/reservation-impl/coherence-conflict.stderr
rename to tests/ui/traits/reservation-impl/coherence-conflict.old.stderr
index a811d7e32016b..393350ea3f12a 100644
--- a/tests/ui/traits/reservation-impl/coherence-conflict.stderr
+++ b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`
-  --> $DIR/coherence-conflict.rs:11:1
+  --> $DIR/coherence-conflict.rs:12:1
    |
 LL | impl OtherTrait for () {}
    | ---------------------- first implementation here
diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.rs b/tests/ui/traits/reservation-impl/coherence-conflict.rs
index fa4a309315b47..6bbd90f94dc39 100644
--- a/tests/ui/traits/reservation-impl/coherence-conflict.rs
+++ b/tests/ui/traits/reservation-impl/coherence-conflict.rs
@@ -1,5 +1,6 @@
 // check that reservation impls are accounted for in negative reasoning.
-
+// revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
 #![feature(rustc_attrs)]
 
 trait MyTrait {}
diff --git a/tests/ui/traits/reservation-impl/no-use.stderr b/tests/ui/traits/reservation-impl/no-use.next.stderr
similarity index 93%
rename from tests/ui/traits/reservation-impl/no-use.stderr
rename to tests/ui/traits/reservation-impl/no-use.next.stderr
index cefb2a8792f17..542e3a28adf28 100644
--- a/tests/ui/traits/reservation-impl/no-use.stderr
+++ b/tests/ui/traits/reservation-impl/no-use.next.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): MyTrait` is not satisfied
-  --> $DIR/no-use.rs:10:26
+  --> $DIR/no-use.rs:11:26
    |
 LL |     <() as MyTrait>::foo(&());
    |     -------------------- ^^^ the trait `MyTrait` is not implemented for `()`
diff --git a/tests/ui/traits/reservation-impl/no-use.old.stderr b/tests/ui/traits/reservation-impl/no-use.old.stderr
new file mode 100644
index 0000000000000..542e3a28adf28
--- /dev/null
+++ b/tests/ui/traits/reservation-impl/no-use.old.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `(): MyTrait` is not satisfied
+  --> $DIR/no-use.rs:11:26
+   |
+LL |     <() as MyTrait>::foo(&());
+   |     -------------------- ^^^ the trait `MyTrait` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `MyTrait` is implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/reservation-impl/no-use.rs b/tests/ui/traits/reservation-impl/no-use.rs
index 65a55d9e20936..864f1791fd0a7 100644
--- a/tests/ui/traits/reservation-impl/no-use.rs
+++ b/tests/ui/traits/reservation-impl/no-use.rs
@@ -1,5 +1,6 @@
 // check that reservation impls can't be used as normal impls in positive reasoning.
-
+// revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
 #![feature(rustc_attrs)]
 
 trait MyTrait { fn foo(&self); }
diff --git a/tests/ui/traits/reservation-impl/non-lattice-ok.rs b/tests/ui/traits/reservation-impl/non-lattice-ok.rs
index a71051243c893..7787904d9b22d 100644
--- a/tests/ui/traits/reservation-impl/non-lattice-ok.rs
+++ b/tests/ui/traits/reservation-impl/non-lattice-ok.rs
@@ -30,6 +30,12 @@
 //
 // [ii]: https://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/
 
+
+// check that reservation impls can't be used as normal impls in positive reasoning.
+
+// revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
+
 #![feature(rustc_attrs, never_type)]
 
 trait MyTrait {}
diff --git a/tests/ui/traits/reservation-impl/ok.rs b/tests/ui/traits/reservation-impl/ok.rs
index 611c8d8841323..8ff6645a2b3d3 100644
--- a/tests/ui/traits/reservation-impl/ok.rs
+++ b/tests/ui/traits/reservation-impl/ok.rs
@@ -3,6 +3,9 @@
 // rpass test for reservation impls. Not 100% required because `From` uses them,
 // but still.
 
+// revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
+
 #![feature(rustc_attrs)]
 
 use std::mem;

From 938434ab82609c8de83028fa80bde4d6d28c282a Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 21 Mar 2023 16:34:04 +0100
Subject: [PATCH 14/19] enable `intercrate` in the solver `InferCtxt`

---
 compiler/rustc_infer/src/infer/mod.rs              |  4 ++--
 .../rustc_trait_selection/src/solve/eval_ctxt.rs   | 10 ++++++++--
 .../rustc_trait_selection/src/traits/coherence.rs  | 14 ++++++++++----
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index aeb4ddb421259..ed5fd590934f3 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -585,8 +585,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
-    pub fn intercrate(mut self) -> Self {
-        self.intercrate = true;
+    pub fn intercrate(mut self, intercrate: bool) -> Self {
+        self.intercrate = intercrate;
         self
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 4b85be69e61bd..c492c8c0aea05 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -127,8 +127,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         //
         // The actual solver logic happens in `ecx.compute_goal`.
         search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
-            let (ref infcx, goal, var_values) =
-                tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
+            let intercrate = match search_graph.solver_mode() {
+                SolverMode::Normal => false,
+                SolverMode::Coherence => true,
+            };
+            let (ref infcx, goal, var_values) = tcx
+                .infer_ctxt()
+                .intercrate(intercrate)
+                .build_with_canonical(DUMMY_SP, &canonical_goal);
             let mut ecx = EvalCtxt {
                 infcx,
                 var_values,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f4cfe4ec0b0ce..5bb0cdda1af0f 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -95,8 +95,11 @@ pub fn overlapping_impls(
         return None;
     }
 
-    let infcx =
-        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let infcx = tcx
+        .infer_ctxt()
+        .with_opaque_type_inference(DefiningAnchor::Bubble)
+        .intercrate(true)
+        .build();
     let selcx = &mut SelectionContext::new(&infcx);
     let overlaps =
         overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
@@ -107,8 +110,11 @@ pub fn overlapping_impls(
     // In the case where we detect an error, run the check again, but
     // this time tracking intercrate ambiguity causes for better
     // diagnostics. (These take time and can lead to false errors.)
-    let infcx =
-        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let infcx = tcx
+        .infer_ctxt()
+        .with_opaque_type_inference(DefiningAnchor::Bubble)
+        .intercrate(true)
+        .build();
     let selcx = &mut SelectionContext::new(&infcx);
     selcx.enable_tracking_intercrate_ambiguity_causes();
     Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())

From a7ec045be8133fe679c34a7eaba989ca6975d53e Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 21 Mar 2023 16:38:40 +0100
Subject: [PATCH 15/19] disable global caching during coherence

---
 compiler/rustc_trait_selection/src/solve/search_graph/mod.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index b94c44cbdd038..219890b9dc42c 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -254,7 +254,8 @@ impl<'tcx> SearchGraph<'tcx> {
             // dependencies, our non-root goal may no longer appear as child of the root goal.
             //
             // See https://github.com/rust-lang/rust/pull/108071 for some additional context.
-            let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty();
+            let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal)
+                && (!self.overflow_data.did_overflow() || self.stack.is_empty());
             if should_cache_globally {
                 tcx.new_solver_evaluation_cache.insert(
                     current_goal.goal,

From f86b0358f81aa67ff5ca8abf90935226fcab4f40 Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 21 Mar 2023 16:39:24 +0100
Subject: [PATCH 16/19] woops

---
 compiler/rustc_middle/src/traits/solve.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index f47f4cbdb4db7..512d67f34b97d 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -64,7 +64,7 @@ impl Certainty {
             (Certainty::Yes, Certainty::Maybe(_)) => other,
             (Certainty::Maybe(_), Certainty::Yes) => self,
             (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
-                Certainty::Maybe(MaybeCause::Overflow)
+                Certainty::Maybe(MaybeCause::Ambiguity)
             }
             (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
             | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))

From 293f21c876278df7943eea889dacd977155a2f62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 21 Mar 2023 01:09:00 +0100
Subject: [PATCH 17/19] iat selection: erase regions in self type

---
 .../rustc_hir_analysis/src/astconv/mod.rs     | 82 ++++++++++++-------
 .../issue-109299-1.rs                         | 12 +++
 .../issue-109299-1.stderr                     | 15 ++++
 .../associated-inherent-types/issue-109299.rs | 12 +++
 .../issue-109299.stderr                       | 11 +++
 5 files changed, 101 insertions(+), 31 deletions(-)
 create mode 100644 tests/ui/associated-inherent-types/issue-109299-1.rs
 create mode 100644 tests/ui/associated-inherent-types/issue-109299-1.stderr
 create mode 100644 tests/ui/associated-inherent-types/issue-109299.rs
 create mode 100644 tests/ui/associated-inherent-types/issue-109299.stderr

diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 6a27383121d2d..9d3f8c2b3e74f 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::middle::stability::AllowUnstable;
+use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::DynKind;
 use rustc_middle::ty::GenericParamDefKind;
@@ -2226,47 +2227,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let param_env = tcx.param_env(block.owner.to_def_id());
         let cause = ObligationCause::misc(span, block.owner.def_id);
+
         let mut fulfillment_errors = Vec::new();
-        let mut applicable_candidates: Vec<_> = candidates
-            .iter()
-            .filter_map(|&(impl_, (assoc_item, def_scope))| {
-                infcx.probe(|_| {
-                    let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+        let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
+            let universe = infcx.create_next_universe();
+
+            // Regions are not considered during selection.
+            let self_ty = tcx.replace_escaping_bound_vars_uncached(
+                self_ty,
+                FnMutDelegate {
+                    regions: &mut |_| tcx.lifetimes.re_erased,
+                    types: &mut |bv| {
+                        tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind })
+                    },
+                    consts: &mut |bv, ty| {
+                        tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty)
+                    },
+                },
+            );
 
-                    let impl_ty = tcx.type_of(impl_);
-                    let impl_substs = infcx.fresh_item_substs(impl_);
-                    let impl_ty = impl_ty.subst(tcx, impl_substs);
-                    let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
+            candidates
+                .iter()
+                .filter_map(|&(impl_, (assoc_item, def_scope))| {
+                    infcx.probe(|_| {
+                        let ocx = ObligationCtxt::new_in_snapshot(&infcx);
 
-                    // Check that the Self-types can be related.
-                    // FIXME(fmease): Should we use `eq` here?
-                    ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
+                        let impl_ty = tcx.type_of(impl_);
+                        let impl_substs = infcx.fresh_item_substs(impl_);
+                        let impl_ty = impl_ty.subst(tcx, impl_substs);
+                        let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
 
-                    // Check whether the impl imposes obligations we have to worry about.
-                    let impl_bounds = tcx.predicates_of(impl_);
-                    let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
+                        // Check that the Self-types can be related.
+                        // FIXME(fmease): Should we use `eq` here?
+                        ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
 
-                    let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
+                        // Check whether the impl imposes obligations we have to worry about.
+                        let impl_bounds = tcx.predicates_of(impl_);
+                        let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
 
-                    let impl_obligations = traits::predicates_for_generics(
-                        |_, _| cause.clone(),
-                        param_env,
-                        impl_bounds,
-                    );
+                        let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
 
-                    ocx.register_obligations(impl_obligations);
+                        let impl_obligations = traits::predicates_for_generics(
+                            |_, _| cause.clone(),
+                            param_env,
+                            impl_bounds,
+                        );
 
-                    let mut errors = ocx.select_where_possible();
-                    if !errors.is_empty() {
-                        fulfillment_errors.append(&mut errors);
-                        return None;
-                    }
+                        ocx.register_obligations(impl_obligations);
+
+                        let mut errors = ocx.select_where_possible();
+                        if !errors.is_empty() {
+                            fulfillment_errors.append(&mut errors);
+                            return None;
+                        }
 
-                    // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
-                    Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
+                        // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
+                        Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
+                    })
                 })
-            })
-            .collect();
+                .collect()
+        });
 
         if applicable_candidates.len() > 1 {
             return Err(self.complain_about_ambiguous_inherent_assoc_type(
diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs
new file mode 100644
index 0000000000000..6f95273116b78
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109299-1.rs
@@ -0,0 +1,12 @@
+#![feature(inherent_associated_types, non_lifetime_binders, type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+struct Lexer<T>(T);
+
+impl Lexer<i32> {
+    type Cursor = ();
+}
+
+type X = impl for<T> Fn() -> Lexer<T>::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr
new file mode 100644
index 0000000000000..dc59b56ee207d
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr
@@ -0,0 +1,15 @@
+error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope
+  --> $DIR/issue-109299-1.rs:10:40
+   |
+LL | struct Lexer<T>(T);
+   | --------------- associated item `Cursor` not found for this struct
+...
+LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
+   |                                        ^^^^^^ associated item not found in `Lexer<T>`
+   |
+   = note: the associated type was found for
+           - `Lexer<i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/issue-109299.rs b/tests/ui/associated-inherent-types/issue-109299.rs
new file mode 100644
index 0000000000000..84e4f9e72527a
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109299.rs
@@ -0,0 +1,12 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct Lexer<'d>(&'d ());
+
+impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d`
+    type Cursor = ();
+}
+
+fn test(_: Lexer::Cursor) {}
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-109299.stderr b/tests/ui/associated-inherent-types/issue-109299.stderr
new file mode 100644
index 0000000000000..63f50732d3c50
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109299.stderr
@@ -0,0 +1,11 @@
+error[E0261]: use of undeclared lifetime name `'d`
+  --> $DIR/issue-109299.rs:6:12
+   |
+LL | impl Lexer<'d> {
+   |     -      ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'d` here: `<'d>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0261`.

From 67a2c5bec838884a0a45d0bd14b7778af731a97b Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 19 Mar 2023 21:32:34 +0400
Subject: [PATCH 18/19] rustc: Remove unused `Session` argument from some
 attribute functions

---
 compiler/rustc_ast/src/attr/mod.rs            | 22 +++++
 compiler/rustc_ast_lowering/src/lib.rs        |  2 +-
 .../rustc_ast_passes/src/ast_validation.rs    |  8 +-
 compiler/rustc_ast_passes/src/feature_gate.rs |  8 +-
 compiler/rustc_attr/src/builtin.rs            |  8 +-
 .../src/deriving/default.rs                   | 12 +--
 .../src/proc_macro_harness.rs                 |  8 +-
 .../src/standard_library_imports.rs           |  8 +-
 compiler/rustc_builtin_macros/src/test.rs     | 22 +++--
 .../rustc_builtin_macros/src/test_harness.rs  | 26 +++---
 compiler/rustc_builtin_macros/src/util.rs     |  4 +-
 .../rustc_codegen_llvm/src/debuginfo/gdb.rs   |  4 +-
 compiler/rustc_codegen_ssa/src/back/write.rs  |  5 +-
 compiler/rustc_codegen_ssa/src/base.rs        |  2 +-
 compiler/rustc_expand/src/base.rs             | 10 +--
 .../rustc_interface/src/proc_macro_decls.rs   |  3 +-
 compiler/rustc_interface/src/util.rs          |  2 +-
 compiler/rustc_lint/src/builtin.rs            | 27 +++----
 compiler/rustc_lint/src/nonstandard_style.rs  |  5 +-
 compiler/rustc_metadata/src/creader.rs        | 37 ++++-----
 compiler/rustc_metadata/src/rmeta/encoder.rs  | 22 +++--
 compiler/rustc_middle/src/ty/context.rs       |  6 +-
 compiler/rustc_mir_build/src/build/mod.rs     |  3 +-
 compiler/rustc_passes/src/check_attr.rs       |  2 +-
 compiler/rustc_passes/src/entry.rs            |  9 ++-
 .../rustc_resolve/src/build_reduced_graph.rs  | 28 +++----
 compiler/rustc_resolve/src/lib.rs             |  8 +-
 compiler/rustc_resolve/src/macros.rs          |  4 +-
 compiler/rustc_session/src/output.rs          |  4 +-
 compiler/rustc_session/src/session.rs         | 36 +--------
 .../clippy_lints/src/functions/must_use.rs    |  6 +-
 src/tools/clippy/clippy_utils/src/attrs.rs    |  4 +-
 src/tools/rustfmt/src/attr.rs                 | 16 +---
 src/tools/rustfmt/src/parse/parser.rs         |  5 +-
 src/tools/rustfmt/src/reorder.rs              |  4 +-
 .../auxiliary/lint-for-crate-rpass.rs         | 80 -------------------
 tests/ui-fulldeps/auxiliary/lint-for-crate.rs | 12 ++-
 37 files changed, 173 insertions(+), 299 deletions(-)
 delete mode 100644 tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs

diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 2e83b3e623f07..c4771115cacf2 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -180,6 +180,12 @@ impl Attribute {
         self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
     }
 
+    pub fn is_proc_macro_attr(&self) -> bool {
+        [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
+            .iter()
+            .any(|kind| self.has_name(*kind))
+    }
+
     /// Extracts the MetaItem from inside this Attribute.
     pub fn meta(&self) -> Option<MetaItem> {
         match &self.kind {
@@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str(
     mk_attr(g, style, path, args, span)
 }
 
+pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
+    attrs.iter().filter(move |attr| attr.has_name(name))
+}
+
+pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
+    filter_by_name(attrs, name).next()
+}
+
+pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
+    find_by_name(attrs, name).and_then(|attr| attr.value_str())
+}
+
+pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
+    find_by_name(attrs, name).is_some()
+}
+
 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
     items.iter().any(|item| item.has_name(name))
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ea7fa02521e44..0b6b02ba00fb5 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             def_id: self.local_def_id(param.id),
             name,
             span: self.lower_span(param.span()),
-            pure_wrt_drop: self.tcx.sess.contains_name(&param.attrs, sym::may_dangle),
+            pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
             kind,
             colon_span: param.colon_span.map(|s| self.lower_span(s)),
             source,
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 539c822ea0977..93c854cc80942 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_item(&mut self, item: &'a Item) {
-        if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
+        if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
             self.has_proc_macro_decls = true;
         }
 
-        if self.session.contains_name(&item.attrs, sym::no_mangle) {
+        if attr::contains_name(&item.attrs, sym::no_mangle) {
             self.check_nomangle_item_asciionly(item.ident, item.span);
         }
 
@@ -973,7 +973,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
                 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
-                    && !self.session.contains_name(&item.attrs, sym::path)
+                    && !attr::contains_name(&item.attrs, sym::path)
                 {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
@@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
-        if self.session.contains_name(&item.attrs, sym::no_mangle) {
+        if attr::contains_name(&item.attrs, sym::no_mangle) {
             self.check_nomangle_item_asciionly(item.ident, item.span);
         }
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 6a5d5614b1cb9..344a1e7f5e795 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
+use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd};
 use rustc_errors::{Applicability, StashKey};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
@@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Fn(..) => {
-                if self.sess.contains_name(&i.attrs, sym::start) {
+                if attr::contains_name(&i.attrs, sym::start) {
                     gate_feature_post!(
                         &self,
                         start,
@@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Struct(..) => {
-                for attr in self.sess.filter_by_name(&i.attrs, sym::repr) {
+                for attr in attr::filter_by_name(&i.attrs, sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
                         if item.has_name(sym::simd) {
                             gate_feature_post!(
@@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
         match i.kind {
             ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
-                let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
+                let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
                 let links_to_llvm =
                     link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
                 if links_to_llvm {
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 3d240108b4ab1..d6dbdd3975e93 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -1,6 +1,6 @@
 //! Parsing and validation of builtin attributes
 
-use rustc_ast as ast;
+use rustc_ast::{self as ast, attr};
 use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
@@ -556,8 +556,8 @@ where
     (stab, const_stab, body_stab)
 }
 
-pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
-    sess.first_attr_value_str_by_name(attrs, sym::crate_name)
+pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
+    attr::first_attr_value_str_by_name(attrs, sym::crate_name)
 }
 
 #[derive(Clone, Debug)]
@@ -1177,7 +1177,7 @@ fn allow_unstable<'a>(
     attrs: &'a [Attribute],
     symbol: Symbol,
 ) -> impl Iterator<Item = Symbol> + 'a {
-    let attrs = sess.filter_by_name(attrs, symbol);
+    let attrs = attr::filter_by_name(attrs, symbol);
     let list = attrs
         .filter_map(move |attr| {
             attr.meta_item_list().or_else(|| {
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 4d753a2ed805c..cc32739d083c7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -1,7 +1,7 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use rustc_ast as ast;
-use rustc_ast::{walk_list, EnumDef, VariantData};
+use rustc_ast::{attr, walk_list, EnumDef, VariantData};
 use rustc_errors::Applicability;
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use rustc_span::symbol::Ident;
@@ -106,7 +106,7 @@ fn extract_default_variant<'a>(
     let default_variants: SmallVec<[_; 1]> = enum_def
         .variants
         .iter()
-        .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default))
+        .filter(|variant| attr::contains_name(&variant.attrs, kw::Default))
         .collect();
 
     let variant = match default_variants.as_slice() {
@@ -116,7 +116,7 @@ fn extract_default_variant<'a>(
                 .variants
                 .iter()
                 .filter(|variant| matches!(variant.data, VariantData::Unit(..)))
-                .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive));
+                .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));
 
             let mut diag = cx.struct_span_err(trait_span, "no default declared");
             diag.help("make a unit variant default by placing `#[default]` above it");
@@ -146,7 +146,7 @@ fn extract_default_variant<'a>(
                         if v.span == variant.span {
                             None
                         } else {
-                            Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new()))
+                            Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new()))
                         }
                     })
                     .collect();
@@ -174,7 +174,7 @@ fn extract_default_variant<'a>(
         return Err(());
     }
 
-    if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) {
+    if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
         cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
             .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
             .help("consider a manual implementation of `Default`")
@@ -191,7 +191,7 @@ fn validate_default_attribute(
     default_variant: &rustc_ast::Variant,
 ) -> Result<(), ()> {
     let attrs: SmallVec<[_; 1]> =
-        cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect();
+        attr::filter_by_name(&default_variant.attrs, kw::Default).collect();
 
     let attr = match attrs.as_slice() {
         [attr] => attr,
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index bc513607ddd1d..a73fed6ccb222 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -1,6 +1,6 @@
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, NodeId};
+use rustc_ast::{self as ast, attr, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
@@ -34,7 +34,6 @@ enum ProcMacro {
 }
 
 struct CollectProcMacros<'a> {
-    sess: &'a Session,
     macros: Vec<ProcMacro>,
     in_root: bool,
     handler: &'a rustc_errors::Handler,
@@ -56,7 +55,6 @@ pub fn inject(
     let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
     let mut collect = CollectProcMacros {
-        sess,
         macros: Vec::new(),
         in_root: true,
         handler,
@@ -160,7 +158,7 @@ impl<'a> CollectProcMacros<'a> {
 impl<'a> Visitor<'a> for CollectProcMacros<'a> {
     fn visit_item(&mut self, item: &'a ast::Item) {
         if let ast::ItemKind::MacroDef(..) = item.kind {
-            if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) {
+            if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
                 let msg =
                     "cannot export macro_rules! macros from a `proc-macro` crate type currently";
                 self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
@@ -176,7 +174,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         let mut found_attr: Option<&'a ast::Attribute> = None;
 
         for attr in &item.attrs {
-            if self.sess.is_proc_macro_attr(&attr) {
+            if attr.is_proc_macro_attr() {
                 if let Some(prev_attr) = found_attr {
                     let prev_item = prev_attr.get_normal_item();
                     let item = attr.get_normal_item();
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index e67c0dba68597..caed40d9fa81b 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -1,4 +1,4 @@
-use rustc_ast as ast;
+use rustc_ast::{self as ast, attr};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::ExpansionConfig;
 use rustc_session::Session;
@@ -16,10 +16,10 @@ pub fn inject(
     let edition = sess.parse_sess.edition;
 
     // the first name in this list is the crate name of the crate with the prelude
-    let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) {
+    let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
         return krate;
-    } else if sess.contains_name(&krate.attrs, sym::no_std) {
-        if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
+    } else if attr::contains_name(&krate.attrs, sym::no_std) {
+        if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
             &[sym::core]
         } else {
             &[sym::core, sym::compiler_builtins]
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 151afd2d458b0..44b9c4718a75f 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,12 +1,11 @@
 /// The expansion from a test function to the appropriate test struct for libtest
 /// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
 use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
-use rustc_ast as ast;
 use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, attr};
 use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_expand::base::*;
-use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{FileNameDisplayPreference, Span};
 use std::iter;
@@ -291,14 +290,11 @@ pub fn expand_test_or_bench(
                                         ),
                                     ),
                                     // ignore: true | false
-                                    field(
-                                        "ignore",
-                                        cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
-                                    ),
+                                    field("ignore", cx.expr_bool(sp, should_ignore(&item)),),
                                     // ignore_message: Some("...") | None
                                     field(
                                         "ignore_message",
-                                        if let Some(msg) = should_ignore_message(cx, &item) {
+                                        if let Some(msg) = should_ignore_message(&item) {
                                             cx.expr_some(sp, cx.expr_str(sp, msg))
                                         } else {
                                             cx.expr_none(sp)
@@ -425,12 +421,12 @@ enum ShouldPanic {
     Yes(Option<Symbol>),
 }
 
-fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
-    sess.contains_name(&i.attrs, sym::ignore)
+fn should_ignore(i: &ast::Item) -> bool {
+    attr::contains_name(&i.attrs, sym::ignore)
 }
 
-fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
-    match cx.sess.find_by_name(&i.attrs, sym::ignore) {
+fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
+    match attr::find_by_name(&i.attrs, sym::ignore) {
         Some(attr) => {
             match attr.meta_item_list() {
                 // Handle #[ignore(bar = "foo")]
@@ -444,7 +440,7 @@ fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
 }
 
 fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
-    match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
+    match attr::find_by_name(&i.attrs, sym::should_panic) {
         Some(attr) => {
             let sd = &cx.sess.parse_sess.span_diagnostic;
 
@@ -510,7 +506,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
 }
 
 fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
+    let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let sd = &cx.sess.parse_sess.span_diagnostic;
     match &i.kind {
         ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index d8e3db9e8ee09..2d491b2dac8b2 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -47,11 +47,11 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast
     // unconditional, so that the attribute is still marked as used in
     // non-test builds.
     let reexport_test_harness_main =
-        sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
+        attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
 
     // Do this here so that the test_runner crate attribute gets marked as used
     // even in non-test builds
-    let test_runner = get_test_runner(sess, span_diagnostic, &krate);
+    let test_runner = get_test_runner(span_diagnostic, &krate);
 
     if sess.opts.test {
         let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
@@ -123,7 +123,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = i.into_inner();
-        if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
+        if let Some(name) = get_test_name(&item) {
             debug!("this is a test item");
 
             let test = Test { span: item.span, ident: item.ident, name };
@@ -145,12 +145,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
 // Beware, this is duplicated in librustc_passes/entry.rs (with
 // `rustc_hir::Item`), so make sure to keep them in sync.
-fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType {
+fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType {
     match item.kind {
         ast::ItemKind::Fn(..) => {
-            if sess.contains_name(&item.attrs, sym::start) {
+            if attr::contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
-            } else if sess.contains_name(&item.attrs, sym::rustc_main) {
+            } else if attr::contains_name(&item.attrs, sym::rustc_main) {
                 EntryPointType::RustcMainAttr
             } else if item.ident.name == sym::main {
                 if depth == 0 {
@@ -184,7 +184,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
         // Remove any #[rustc_main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
-        let item = match entry_point_type(self.sess, &item, self.depth) {
+        let item = match entry_point_type(&item, self.depth) {
             EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
                 item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
                     let allow_dead_code = attr::mk_attr_nested_word(
@@ -373,16 +373,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     )
 }
 
-fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
-    sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
+fn get_test_name(i: &ast::Item) -> Option<Symbol> {
+    attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
 }
 
-fn get_test_runner(
-    sess: &Session,
-    sd: &rustc_errors::Handler,
-    krate: &ast::Crate,
-) -> Option<ast::Path> {
-    let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?;
+fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
+    let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
     let meta_list = test_attr.meta_item_list()?;
     let span = test_attr.span;
     match &*meta_list {
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 83812631c2ff7..9463a1418ce31 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{AttrStyle, Attribute, MetaItem};
+use rustc_ast::{attr, AttrStyle, Attribute, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_feature::AttributeTemplate;
 use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
@@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
         _ => None,
     };
     if let Some(attrs) = attrs {
-        if let Some(attr) = ecx.sess.find_by_name(attrs, name) {
+        if let Some(attr) = attr::find_by_name(attrs, name) {
             ecx.parse_sess().buffer_lint(
                 DUPLICATE_MACRO_ATTRIBUTES,
                 attr.span,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 80fd9726fc780..ff2b005d75767 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -5,12 +5,12 @@ use crate::llvm;
 use crate::builder::Builder;
 use crate::common::CodegenCx;
 use crate::value::Value;
+use rustc_ast::attr;
 use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_session::config::{CrateType, DebugInfo};
-
 use rustc_span::symbol::sym;
 use rustc_span::DebuggerVisualizerType;
 
@@ -87,7 +87,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
 
 pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
     let omit_gdb_pretty_printer_section =
-        cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+        attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
     // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
     // ODR violations at link time, this section will not be emitted for rlibs since
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 8508ab87532c2..7ce72d2172799 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -8,6 +8,7 @@ use crate::{
     CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
 };
 use jobserver::{Acquired, Client};
+use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -447,8 +448,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let sess = tcx.sess;
 
     let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
-    let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
-    let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
+    let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
+    let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins);
 
     let crate_info = CrateInfo::new(tcx, target_cpu);
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index abc510e360d56..4d34b3da5f501 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -809,7 +809,7 @@ impl CrateInfo {
             .collect();
         let local_crate_name = tcx.crate_name(LOCAL_CRATE);
         let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
-        let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
+        let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
         let windows_subsystem = subsystem.map(|subsystem| {
             if subsystem != sym::windows && subsystem != sym::console {
                 tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 713e4fbbdce23..6eb0d24eb976e 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -776,16 +776,14 @@ impl SyntaxExtension {
         let allow_internal_unstable =
             attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
 
-        let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe);
-        let local_inner_macros = sess
-            .find_by_name(attrs, sym::macro_export)
+        let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
+        let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
             .and_then(|macro_export| macro_export.meta_item_list())
             .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
-        let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo);
+        let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
         tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
 
-        let (builtin_name, helper_attrs) = sess
-            .find_by_name(attrs, sym::rustc_builtin_macro)
+        let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
             .map(|attr| {
                 // Override `helper_attrs` passed above if it's a built-in macro,
                 // marking `proc_macro_derive` macros as built-in is not a realistic use case.
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 9bf7778bfb29c..1c58caa03532e 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -1,3 +1,4 @@
+use rustc_ast::attr;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
 
     for id in tcx.hir().items() {
         let attrs = tcx.hir().attrs(id.hir_id());
-        if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
+        if attr::contains_name(attrs, sym::rustc_proc_macro_decls) {
             decls = Some(id.owner_id.def_id);
         }
     }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 043892410ceaa..8abdcebb7516d 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
                 .opts
                 .crate_name
                 .clone()
-                .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string()))
+                .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
                 .unwrap_or_else(|| sess.io.input.filestem().to_owned());
 
             OutputFilenames::new(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8af1a663ef5e3..29ba480cdd20e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode {
             }
 
             ast::ItemKind::Fn(..) => {
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
                 }
 
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
                 }
 
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
                 }
             }
 
             ast::ItemKind::Static(..) => {
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
                 }
 
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
                 }
 
-                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
+                if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
                     self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
                 }
             }
@@ -391,10 +391,10 @@ impl EarlyLintPass for UnsafeCode {
 
     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         if let ast::AssocItemKind::Fn(..) = it.kind {
-            if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+            if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
                 self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
             }
-            if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+            if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
                 self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
             }
         }
@@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
         };
         match it.kind {
             hir::ItemKind::Fn(.., ref generics, _) => {
-                if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
+                if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
                     check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
                 }
             }
             hir::ItemKind::Const(..) => {
-                if cx.sess().contains_name(attrs, sym::no_mangle) {
+                if attr::contains_name(attrs, sym::no_mangle) {
                     // account for "pub const" (#45562)
                     let start = cx
                         .tcx
@@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
             hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
                 for it in *items {
                     if let hir::AssocItemKind::Fn { .. } = it.kind {
-                        if let Some(no_mangle_attr) = cx
-                            .sess()
-                            .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
+                        if let Some(no_mangle_attr) =
+                            attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
                         {
                             check_no_mangle_on_generic_fn(
                                 no_mangle_attr,
@@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
         }
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
-        if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
+        if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) {
             cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
         }
     }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 0f44dde59485a..9efc14849c76f 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
         let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
             Some(Ident::from_str(name))
         } else {
-            cx.sess()
-                .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
+            attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
                 .and_then(|attr| attr.meta())
                 .and_then(|meta| {
                     meta.name_value_literal().and_then(|lit| {
@@ -489,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         match it.kind {
-            hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => {
+            hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
             }
             hir::ItemKind::Const(..) => {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index f870a1db82d9c..0dea1c52d1f2f 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -720,8 +720,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // compilation mode also comes into play.
         let desired_strategy = self.sess.panic_strategy();
         let mut runtime_found = false;
-        let mut needs_panic_runtime =
-            self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
+        let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
 
         for (cnum, data) in self.cstore.iter_crate_data() {
             needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
@@ -789,7 +788,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         info!("loading profiler");
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
-        if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
+        if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) {
             self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
         }
 
@@ -803,14 +802,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
-        self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
+        self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
             [span1, span2, ..] => {
                 self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
         };
-        self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
+        self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
             [span1, span2, ..] => {
                 self.sess
                     .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
@@ -822,7 +821,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
-        if !self.sess.contains_name(&krate.attrs, sym::needs_allocator)
+        if !attr::contains_name(&krate.attrs, sym::needs_allocator)
             && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
         {
             return;
@@ -881,7 +880,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // allocator. At this point our allocator request is typically fulfilled
             // by the standard library, denoted by the `#![default_lib_allocator]`
             // attribute.
-            if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
+            if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
                 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
                 self.sess.emit_err(errors::GlobalAllocRequired);
@@ -1003,7 +1002,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     }
                     None => item.ident.name,
                 };
-                let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) {
+                let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
                     CrateDepKind::MacrosOnly
                 } else {
                     CrateDepKind::Explicit
@@ -1049,16 +1048,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 }
 
-fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
-    struct Finder<'a> {
-        sess: &'a Session,
+fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
+    struct Finder {
         name: Symbol,
         spans: Vec<Span>,
     }
-    impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+    impl<'ast> visit::Visitor<'ast> for Finder {
         fn visit_item(&mut self, item: &'ast ast::Item) {
             if item.ident.name == self.name
-                && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
             {
                 self.spans.push(item.span);
             }
@@ -1067,21 +1065,20 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
     }
 
     let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
-    let mut f = Finder { sess, name, spans: Vec::new() };
+    let mut f = Finder { name, spans: Vec::new() };
     visit::walk_crate(&mut f, krate);
     f.spans
 }
 
-fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
-    struct Finder<'a> {
-        sess: &'a Session,
+fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
+    struct Finder {
         name: Symbol,
         spans: Vec<Span>,
     }
-    impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+    impl<'ast> visit::Visitor<'ast> for Finder {
         fn visit_item(&mut self, item: &'ast ast::Item) {
             if item.ident.name == self.name
-                && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
             {
                 self.spans.push(item.span);
             }
@@ -1090,7 +1087,7 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
     }
 
     let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
-    let mut f = Finder { sess, name, spans: Vec::new() };
+    let mut f = Finder { name, spans: Vec::new() };
     visit::walk_crate(&mut f, krate);
     f.spans
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ef3eda584e1b8..eb4d9343f1dfb 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
                 has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
                 has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
-                has_default_lib_allocator: tcx
-                    .sess
-                    .contains_name(&attrs, sym::default_lib_allocator),
+                has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator),
                 proc_macro_data,
                 debugger_visualizers,
-                compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
-                needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
-                needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
-                no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
-                panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
-                profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
+                compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
+                needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
+                needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
+                no_builtins: attr::contains_name(&attrs, sym::no_builtins),
+                panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
+                profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
                 symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
 
                 crate_deps,
@@ -1730,11 +1728,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 // Proc-macros may have attributes like `#[allow_internal_unstable]`,
                 // so downstream crates need access to them.
                 let attrs = hir.attrs(proc_macro);
-                let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) {
+                let macro_kind = if attr::contains_name(attrs, sym::proc_macro) {
                     MacroKind::Bang
-                } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) {
+                } else if attr::contains_name(attrs, sym::proc_macro_attribute) {
                     MacroKind::Attr
-                } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) {
+                } else if let Some(attr) = attr::find_by_name(attrs, sym::proc_macro_derive) {
                     // This unwrap chain should have been checked by the proc-macro harness.
                     name = attr.meta_item_list().unwrap()[0]
                         .meta_item()
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 653763353987c..a1c1acc4a2541 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -28,7 +28,7 @@ use crate::ty::{
     TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
 };
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
-use rustc_ast as ast;
+use rustc_ast::{self as ast, attr};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::intern::Interned;
@@ -2520,9 +2520,9 @@ pub fn provide(providers: &mut ty::query::Providers) {
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
     providers.is_panic_runtime =
-        |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
+        |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
     providers.is_compiler_builtins =
-        |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
+        |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
     providers.has_panic_handler = |tcx, LocalCrate| {
         // We want to check if the panic handler was defined in this crate
         tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 80d8b27336c54..1923e10ddb586 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
+use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_errors::ErrorGuaranteed;
@@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
         // the settings for the crate they are codegened in.
-        let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
+        let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
         // Respect -C overflow-checks.
         check_overflow |= tcx.sess.overflow_checks();
         // Constants always need overflow checks.
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 8bed788814209..1c459edabb89e 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Fn => {
                 for attr in attrs {
-                    if self.tcx.sess.is_proc_macro_attr(attr) {
+                    if attr.is_proc_macro_attr() {
                         debug!("Is proc macro attr");
                         return true;
                     }
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index b7e6a11998b1c..f3e683f4b3a0a 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,3 +1,4 @@
+use rustc_ast::attr;
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::error_code;
 use rustc_hir::def::DefKind;
@@ -37,7 +38,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
     }
 
     // If the user wants no main function at all, then stop here.
-    if tcx.sess.contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) {
+    if attr::contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) {
         return None;
     }
 
@@ -57,9 +58,9 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 // An equivalent optimization was not applied to the duplicated code in test_harness.rs.
 fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
     let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-    if ctxt.tcx.sess.contains_name(attrs, sym::start) {
+    if attr::contains_name(attrs, sym::start) {
         EntryPointType::Start
-    } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
+    } else if attr::contains_name(attrs, sym::rustc_main) {
         EntryPointType::RustcMainAttr
     } else {
         if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
@@ -78,7 +79,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
 
 fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
     let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-    ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
+    attr::find_by_name(attrs, sym).map(|attr| attr.span)
 }
 
 fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 362ef693c48d5..f79807fee3957 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -570,7 +570,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             }
             ast::UseTreeKind::Glob => {
                 let kind = ImportKind::Glob {
-                    is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import),
+                    is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
                     max_vis: Cell::new(None),
                     id,
                 };
@@ -685,7 +685,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     expansion.to_expn_id(),
                     item.span,
                     parent.no_implicit_prelude
-                        || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude),
+                        || attr::contains_name(&item.attrs, sym::no_implicit_prelude),
                 );
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
@@ -750,7 +750,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
                     let mut ctor_vis = if vis.is_public()
-                        && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive)
+                        && attr::contains_name(&item.attrs, sym::non_exhaustive)
                     {
                         ty::Visibility::Restricted(CRATE_DEF_ID)
                     } else {
@@ -1168,12 +1168,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
     }
 
     fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
-        if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) {
+        if attr::contains_name(&item.attrs, sym::proc_macro) {
             return Some((MacroKind::Bang, item.ident, item.span));
-        } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) {
+        } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
             return Some((MacroKind::Attr, item.ident, item.span));
-        } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive)
-        {
+        } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
             if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
                 if let Some(ident) = nested_meta.ident() {
                     return Some((MacroKind::Derive, ident, ident.span));
@@ -1228,7 +1227,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         if macro_rules {
             let ident = ident.normalize_to_macros_2_0();
             self.r.macro_names.insert(ident);
-            let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export);
+            let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
@@ -1488,13 +1487,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         self.r.visibilities.insert(def_id, vis);
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
-        let ctor_vis = if vis.is_public()
-            && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive)
-        {
-            ty::Visibility::Restricted(CRATE_DEF_ID)
-        } else {
-            vis
-        };
+        let ctor_vis =
+            if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) {
+                ty::Visibility::Restricted(CRATE_DEF_ID)
+            } else {
+                vis
+            };
 
         // Define a constructor name in the value namespace.
         if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index cd90fd3ef84d8..a0b9188c3159e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -23,7 +23,7 @@ extern crate tracing;
 
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
-use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
+use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
 use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
@@ -1190,7 +1190,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
             ExpnId::root(),
             krate.spans.inner_span,
-            tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude),
+            attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
             &mut module_map,
         );
         let empty_module = arenas.new_module(
@@ -1222,9 +1222,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             .map(|(name, _)| (Ident::from_str(name), Default::default()))
             .collect();
 
-        if !tcx.sess.contains_name(&krate.attrs, sym::no_core) {
+        if !attr::contains_name(&krate.attrs, sym::no_core) {
             extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
-            if !tcx.sess.contains_name(&krate.attrs, sym::no_std) {
+            if !attr::contains_name(&krate.attrs, sym::no_std) {
                 extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
             }
         }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 37153854f7e7f..9c22ed7a2d7c1 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -5,7 +5,7 @@ use crate::Namespace::*;
 use crate::{BuiltinMacroState, Determinacy};
 use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
-use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
+use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::intern::Interned;
@@ -113,7 +113,7 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
 pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
     let mut registered_tools = RegisteredTools::default();
     let krate = tcx.crate_for_resolver(()).borrow();
-    for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) {
+    for attr in attr::filter_by_name(&krate.attrs, sym::register_tool) {
         for nested_meta in attr.meta_item_list().unwrap_or_default() {
             match nested_meta.ident() {
                 Some(ident) => {
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index c3f0c4b58f57a..fdb9fae44e153 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -5,7 +5,7 @@ use crate::errors::{
     InvalidCharacterInCrateName,
 };
 use crate::Session;
-use rustc_ast as ast;
+use rustc_ast::{self as ast, attr};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 use std::path::{Path, PathBuf};
@@ -56,7 +56,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
     // the command line over one found in the #[crate_name] attribute. If we
     // find both we ensure that they're the same later on as well.
     let attr_crate_name =
-        sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
+        attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
 
     if let Some(ref s) = sess.opts.crate_name {
         let s = Symbol::intern(s);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index fdacf814dd672..700a059c368ba 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span};
-use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
+use rustc_span::{SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
 use rustc_target::spec::{
@@ -1003,40 +1003,6 @@ impl Session {
         || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
     }
 
-    pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
-        [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
-            .iter()
-            .any(|kind| attr.has_name(*kind))
-    }
-
-    pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
-        attrs.iter().any(|item| item.has_name(name))
-    }
-
-    pub fn find_by_name<'a>(
-        &'a self,
-        attrs: &'a [Attribute],
-        name: Symbol,
-    ) -> Option<&'a Attribute> {
-        attrs.iter().find(|attr| attr.has_name(name))
-    }
-
-    pub fn filter_by_name<'a>(
-        &'a self,
-        attrs: &'a [Attribute],
-        name: Symbol,
-    ) -> impl Iterator<Item = &'a Attribute> {
-        attrs.iter().filter(move |attr| attr.has_name(name))
-    }
-
-    pub fn first_attr_value_str_by_name(
-        &self,
-        attrs: &[Attribute],
-        name: Symbol,
-    ) -> Option<Symbol> {
-        attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
-    }
-
     pub fn diagnostic_width(&self) -> usize {
         let default_column_width = 140;
         if let Some(width) = self.opts.diagnostic_width {
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index eacbf6c6ec9b6..67877780c0e90 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -28,7 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
-        } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
+        } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
             check_must_use_candidate(
                 cx,
                 sig.decl,
@@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if is_public
-            && !is_proc_macro(cx.sess(), attrs)
+            && !is_proc_macro(attrs)
             && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
         {
             check_must_use_candidate(
@@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if let hir::TraitFn::Provided(eid) = *eid {
             let body = cx.tcx.hir().body(eid);
-            if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
+            if attr.is_none() && is_public && !is_proc_macro(attrs) {
                 check_must_use_candidate(
                     cx,
                     sig.decl,
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 7987a233bdc18..bc3d774540a51 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>(
 
 /// Return true if the attributes contain any of `proc_macro`,
 /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
-pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
+pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
+    attrs.iter().any(|attr| attr.is_proc_macro_attr())
 }
 
 /// Return true if the attributes contain `#[doc(hidden)]`
diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs
index 5648e1254ed7c..22e45082a9f71 100644
--- a/src/tools/rustfmt/src/attr.rs
+++ b/src/tools/rustfmt/src/attr.rs
@@ -2,7 +2,7 @@
 
 use rustc_ast::ast;
 use rustc_ast::HasAttrs;
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_span::{symbol::sym, Span};
 
 use self::doc_comment::DocCommentFormatter;
 use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle};
@@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp};
 
 mod doc_comment;
 
-pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool {
-    attrs.iter().any(|attr| attr.has_name(name))
-}
-
-pub(crate) fn first_attr_value_str_by_name(
-    attrs: &[ast::Attribute],
-    name: Symbol,
-) -> Option<Symbol> {
-    attrs
-        .iter()
-        .find(|attr| attr.has_name(name))
-        .and_then(|attr| attr.value_str())
-}
-
 /// Returns attributes on the given statement.
 pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
     stmt.attrs()
diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs
index 7ab042506bd29..6bc53159b38ba 100644
--- a/src/tools/rustfmt/src/parse/parser.rs
+++ b/src/tools/rustfmt/src/parse/parser.rs
@@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::path::{Path, PathBuf};
 
 use rustc_ast::token::TokenKind;
-use rustc_ast::{ast, ptr};
+use rustc_ast::{ast, attr, ptr};
 use rustc_errors::Diagnostic;
 use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
 use rustc_span::{sym, Span};
 use thin_vec::ThinVec;
 
-use crate::attr::first_attr_value_str_by_name;
 use crate::parse::session::ParseSess;
 use crate::Input;
 
@@ -93,7 +92,7 @@ pub(crate) enum ParserError {
 
 impl<'a> Parser<'a> {
     pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
-        let path_sym = first_attr_value_str_by_name(attrs, sym::path)?;
+        let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?;
         let path_str = path_sym.as_str();
 
         // On windows, the base path might have the form
diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs
index 9e4a668aa4930..3bddf4c1b6a41 100644
--- a/src/tools/rustfmt/src/reorder.rs
+++ b/src/tools/rustfmt/src/reorder.rs
@@ -8,7 +8,7 @@
 
 use std::cmp::{Ord, Ordering};
 
-use rustc_ast::ast;
+use rustc_ast::{ast, attr};
 use rustc_span::{symbol::sym, Span};
 
 use crate::config::{Config, GroupImportsTactic};
@@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items(
 }
 
 fn contains_macro_use_attr(item: &ast::Item) -> bool {
-    crate::attr::contains_name(&item.attrs, sym::macro_use)
+    attr::contains_name(&item.attrs, sym::macro_use)
 }
 
 /// Divides imports into three groups, corresponding to standard, external
diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
deleted file mode 100644
index a3b570ad8c40c..0000000000000
--- a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-// force-host
-
-#![feature(rustc_private)]
-
-extern crate rustc_driver;
-extern crate rustc_hir;
-extern crate rustc_lint;
-extern crate rustc_span;
-#[macro_use]
-extern crate rustc_session;
-extern crate rustc_ast;
-
-use rustc_ast::attr;
-use rustc_driver::plugin::Registry;
-use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass};
-use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::symbol::Symbol;
-
-macro_rules! fake_lint_pass {
-    ($struct:ident, $($attr:expr),*) => {
-        struct $struct;
-
-        impl LintPass for $struct {
-            fn name(&self) -> &'static str {
-                stringify!($struct)
-            }
-        }
-
-        impl LateLintPass<'_> for $struct {
-            fn check_crate(&mut self, cx: &LateContext) {
-                let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
-                let span = cx.tcx.def_span(CRATE_DEF_ID);
-                $(
-                    if !cx.sess().contains_name(attrs, $attr) {
-                        cx.lint(CRATE_NOT_OKAY, |lint| {
-                             let msg = format!("crate is not marked with #![{}]", $attr);
-                             lint.build(&msg).set_span(span).emit();
-                        });
-                    }
-                )*
-            }
-        }
-
-    }
-}
-
-declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]");
-declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]");
-declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]");
-declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]");
-declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]");
-
-fake_lint_pass! {
-    PassOkay,
-    Symbol::intern("crate_okay")
-}
-
-fake_lint_pass! {
-    PassRedBlue,
-    Symbol::intern("crate_red"), Symbol::intern("crate_blue")
-}
-
-fake_lint_pass! {
-    PassGreyGreen,
-    Symbol::intern("crate_grey"), Symbol::intern("crate_green")
-}
-
-#[no_mangle]
-fn __rustc_plugin_registrar(reg: &mut Registry) {
-    reg.lint_store.register_lints(&[
-        &CRATE_NOT_OKAY,
-        &CRATE_NOT_RED,
-        &CRATE_NOT_BLUE,
-        &CRATE_NOT_GREY,
-        &CRATE_NOT_GREEN,
-    ]);
-    reg.lint_store.register_late_pass(|_| Box::new(PassOkay));
-    reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue));
-    reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen));
-}
diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs
index 073da688c7cd9..6304c07d2c7ce 100644
--- a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs
+++ b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs
@@ -4,13 +4,13 @@
 
 extern crate rustc_driver;
 extern crate rustc_hir;
-#[macro_use]
 extern crate rustc_lint;
 #[macro_use]
 extern crate rustc_session;
 extern crate rustc_ast;
 extern crate rustc_span;
 
+use rustc_ast::attr;
 use rustc_driver::plugin::Registry;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_span::def_id::CRATE_DEF_ID;
@@ -28,12 +28,10 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
     fn check_crate(&mut self, cx: &LateContext) {
         let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
         let span = cx.tcx.def_span(CRATE_DEF_ID);
-        if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) {
-            cx.lint(
-                CRATE_NOT_OKAY,
-                "crate is not marked with #![crate_okay]",
-                |lint| lint.set_span(span)
-            );
+        if !attr::contains_name(attrs, Symbol::intern("crate_okay")) {
+            cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| {
+                lint.set_span(span)
+            });
         }
     }
 }

From 1581b97acb53217ed604dd873911870f38adbfbb Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Wed, 22 Mar 2023 22:01:19 +0100
Subject: [PATCH 19/19] make link clickable

---
 compiler/rustc_error_codes/src/error_codes/E0794.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md
index a33802885c006..4377a29247331 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0794.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0794.md
@@ -59,6 +59,6 @@ In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
 where `'a` is universally quantified and `'b` is substituted by a specific
 lifetime. It is not allowed to explicitly specify early-bound lifetime
 arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
-see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the
+see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although the
 types that are constrained by early-bound parameters can be specified (as for
 `bar_fn3`).