about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dependencies.yml1
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs3
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs13
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs2
-rw-r--r--compiler/rustc_data_structures/src/vec_cache.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs5
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs7
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs16
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs87
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs11
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp.rs8
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp4.rs40
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs9
-rw-r--r--tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff12
-rw-r--r--tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff13
-rw-r--r--tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff13
-rw-r--r--tests/mir-opt/gvn_const_eval_polymorphic.rs57
-rw-r--r--tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff12
-rw-r--r--tests/mir-opt/gvn_type_id_polymorphic.rs22
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr15
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.stderr24
-rw-r--r--tests/ui/parser/macro/bad-macro-definition.rs22
-rw-r--r--tests/ui/parser/macro/bad-macro-definition.stderr56
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr10
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.rs6
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.stderr36
-rw-r--r--triagebot.toml3
39 files changed, 385 insertions, 180 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 98d8c14f7d1..9d4b6192d6e 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -19,6 +19,7 @@ env:
   PR_TITLE: Weekly `cargo update`
   PR_MESSAGE: |
     Automation to keep dependencies in `Cargo.lock` current.
+    r? dep-bumps
 
     The following is the output from `cargo update`:
   COMMIT_MESSAGE: "cargo update \n\n"
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 3b5e06c2a88..b5934f4e36e 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -284,6 +284,9 @@ pub enum AttributeKind {
     /// Represents `#[no_mangle]`
     NoMangle(Span),
 
+    /// Represents `#[non_exhaustive]`
+    NonExhaustive(Span),
+
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 145cfba8e42..02e95ddcb6f 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -36,6 +36,7 @@ impl AttributeKind {
             Naked(..) => No,
             NoImplicitPrelude(..) => No,
             NoMangle(..) => No,
+            NonExhaustive(..) => Yes,
             Optimize(..) => No,
             PassByValue(..) => Yes,
             PubTransparent(..) => Yes,
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 0898b44863a..f5ac3890a46 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -36,6 +36,7 @@ pub(crate) mod lint_helpers;
 pub(crate) mod loop_match;
 pub(crate) mod must_use;
 pub(crate) mod no_implicit_prelude;
+pub(crate) mod non_exhaustive;
 pub(crate) mod repr;
 pub(crate) mod rustc_internal;
 pub(crate) mod semantics;
diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
new file mode 100644
index 00000000000..94f6a65c74e
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
@@ -0,0 +1,13 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::{Span, Symbol, sym};
+
+use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use crate::context::Stage;
+
+pub(crate) struct NonExhaustiveParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
+    const PATH: &[Symbol] = &[sym::non_exhaustive];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 5ddb686a8c0..265e1bb6a8c 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -27,6 +27,7 @@ use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTranspa
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
+use crate::attributes::non_exhaustive::NonExhaustiveParser;
 use crate::attributes::repr::{AlignParser, ReprParser};
 use crate::attributes::rustc_internal::{
     RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -144,6 +145,7 @@ attribute_parsers!(
         Single<WithoutArgs<MayDangleParser>>,
         Single<WithoutArgs<NoImplicitPreludeParser>>,
         Single<WithoutArgs<NoMangleParser>>,
+        Single<WithoutArgs<NonExhaustiveParser>>,
         Single<WithoutArgs<PassByValueParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
         Single<WithoutArgs<TrackCallerParser>>,
diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs
index 0ffa6b3205f..599970663db 100644
--- a/compiler/rustc_data_structures/src/vec_cache.rs
+++ b/compiler/rustc_data_structures/src/vec_cache.rs
@@ -76,8 +76,8 @@ impl SlotIndex {
                 index_in_bucket: idx as usize,
             };
         }
-        // SAFETY: We already ruled out idx 0, so `checked_ilog2` can't return `None`.
-        let bucket = unsafe { idx.checked_ilog2().unwrap_unchecked() as usize };
+        // We already ruled out idx 0, so this `ilog2` never panics (and the check optimizes away)
+        let bucket = idx.ilog2() as usize;
         let entries = 1 << bucket;
         SlotIndex {
             bucket_idx: bucket - FIRST_BUCKET_SHIFT + 1,
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index dad2fd99ef2..2ffd4e3cf28 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -411,6 +411,15 @@ pub fn compile_declarative_macro(
         if let Err(e) = p.expect(exp!(FatArrow)) {
             return dummy_syn_ext(e.emit());
         }
+        if p.token == token::Eof {
+            let err_sp = p.token.span.shrink_to_hi();
+            let guar = sess
+                .dcx()
+                .struct_span_err(err_sp, "macro definition ended unexpectedly")
+                .with_span_label(err_sp, "expected right-hand side of macro rule")
+                .emit();
+            return dummy_syn_ext(guar);
+        }
         let rhs_tt = p.parse_token_tree();
         let rhs_tt = mbe::quoted::parse(
             &TokenStream::new(vec![rhs_tt]),
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index aad9b08b2a3..271104c20c6 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -779,9 +779,11 @@ fn lower_variant<'tcx>(
         fields,
         parent_did.to_def_id(),
         recovered,
-        adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
-            || variant_did
-                .is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
+        adt_kind == AdtKind::Struct
+            && find_attr!(tcx.get_all_attrs(parent_did), AttributeKind::NonExhaustive(..))
+            || variant_did.is_some_and(|variant_did| {
+                find_attr!(tcx.get_all_attrs(variant_did), AttributeKind::NonExhaustive(..))
+            }),
     )
 }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index aefae3a3b14..17a29c9ae4b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2264,9 +2264,6 @@ rustc_queries! {
     query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
         desc { "fetching potentially unused trait imports" }
     }
-    query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxIndexSet<Symbol> {
-        desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) }
-    }
 
     query stability_index(_: ()) -> &'tcx stability::Index {
         arena_cache
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 6d5a3abf665..44165b06f1c 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -4,6 +4,7 @@ use std::ops::Range;
 use std::str;
 
 use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
@@ -278,7 +279,9 @@ impl AdtDefData {
         debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
         let mut flags = AdtFlags::NO_ADT_FLAGS;
 
-        if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
+        if kind == AdtKind::Enum
+            && find_attr!(tcx.get_all_attrs(did), AttributeKind::NonExhaustive(..))
+        {
             debug!("found non-exhaustive variant list for {:?}", did);
             flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
         }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e56f98291f1..e8b15b76fd8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -3417,10 +3417,6 @@ pub struct DeducedParamAttrs {
 pub fn provide(providers: &mut Providers) {
     providers.maybe_unused_trait_imports =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
-    providers.names_imported_by_glob_use = |tcx, id| {
-        tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
-    };
-
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
     providers.is_panic_runtime =
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index e44a440b5c1..a44afed5492 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -319,9 +319,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 }
                 PatKind::Deref { subpattern }
             }
-            hir::PatKind::Box(subpattern) => {
-                PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
-            }
+            hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
+                subpattern: self.lower_pattern(subpattern),
+                borrow: hir::ByRef::No,
+            },
 
             hir::PatKind::Slice(prefix, slice, suffix) => {
                 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 47249b38df5..27355a422d1 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -303,6 +303,7 @@ fn emit_malformed_attribute(
             | sym::rustc_allow_const_fn_unstable
             | sym::naked
             | sym::no_mangle
+            | sym::non_exhaustive
             | sym::must_use
             | sym::track_caller
             | sym::link_name
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c0ef81166ea..c5ced406414 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -194,6 +194,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
                     self.check_track_caller(hir_id, *attr_span, attrs, span, target)
                 }
+                Attribute::Parsed(AttributeKind::NonExhaustive(attr_span)) => {
+                    self.check_non_exhaustive(hir_id, *attr_span, span, target, item)
+                }
                 Attribute::Parsed(
                     AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span)
                     | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span),
@@ -237,7 +240,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::no_sanitize, ..] => {
                             self.check_no_sanitize(attr, span, target)
                         }
-                        [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
                         [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
                         [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
                         [sym::doc, ..] => self.check_doc_attrs(
@@ -779,7 +781,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_non_exhaustive(
         &self,
         hir_id: HirId,
-        attr: &Attribute,
+        attr_span: Span,
         span: Span,
         target: Target,
         item: Option<ItemLike<'_>>,
@@ -794,7 +796,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     && fields.iter().any(|f| f.default.is_some())
                 {
                     self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
-                        attr_span: attr.span(),
+                        attr_span,
                         defn_span: span,
                     });
                 }
@@ -805,13 +807,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "non_exhaustive");
             }
             _ => {
-                self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
-                    attr_span: attr.span(),
-                    defn_span: span,
-                });
+                self.dcx()
+                    .emit_err(errors::NonExhaustiveWrongLocation { attr_span, defn_span: span });
             }
         }
     }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 46ced7500ea..e53cebc59ba 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -221,27 +221,19 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         let slice = match ctor {
             Struct | Variant(_) | UnionField => match ty.kind() {
                 ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
-                ty::Adt(adt, args) => {
-                    if adt.is_box() {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        reveal_and_alloc(cx, once(args.type_at(0)))
-                    } else {
-                        let variant =
-                            &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
-                        let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
-                            let is_visible =
-                                adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
-                            let is_uninhabited = cx.is_uninhabited(*ty);
-                            let is_unstable =
-                                cx.tcx.lookup_stability(field.did).is_some_and(|stab| {
-                                    stab.is_unstable() && stab.feature != sym::rustc_private
-                                });
-                            let skip = is_uninhabited && (!is_visible || is_unstable);
-                            (ty, PrivateUninhabitedField(skip))
+                ty::Adt(adt, _) => {
+                    let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
+                    let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
+                        let is_visible =
+                            adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
+                        let is_uninhabited = cx.is_uninhabited(*ty);
+                        let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| {
+                            stab.is_unstable() && stab.feature != sym::rustc_private
                         });
-                        cx.dropless_arena.alloc_from_iter(tys)
-                    }
+                        let skip = is_uninhabited && (!is_visible || is_unstable);
+                        (ty, PrivateUninhabitedField(skip))
+                    });
+                    cx.dropless_arena.alloc_from_iter(tys)
                 }
                 _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
             },
@@ -273,14 +265,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             Struct | Variant(_) | UnionField => match ty.kind() {
                 ty::Tuple(fs) => fs.len(),
                 ty::Adt(adt, ..) => {
-                    if adt.is_box() {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        1
-                    } else {
-                        let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
-                        adt.variant(variant_idx).fields.len()
-                    }
+                    let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
+                    adt.variant(variant_idx).fields.len()
                 }
                 _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
             },
@@ -470,8 +456,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                 fields = vec![self.lower_pat(subpattern).at_index(0)];
                 arity = 1;
                 ctor = match ty.kind() {
-                    // This is a box pattern.
-                    ty::Adt(adt, ..) if adt.is_box() => Struct,
                     ty::Ref(..) => Ref,
                     _ => span_bug!(
                         pat.span,
@@ -501,28 +485,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                             .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
                             .collect();
                     }
-                    ty::Adt(adt, _) if adt.is_box() => {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
-                        // _)` or a box pattern. As a hack to avoid an ICE with the former, we
-                        // ignore other fields than the first one. This will trigger an error later
-                        // anyway.
-                        // See https://github.com/rust-lang/rust/issues/82772,
-                        // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
-                        // The problem is that we can't know from the type whether we'll match
-                        // normally or through box-patterns. We'll have to figure out a proper
-                        // solution when we introduce generalized deref patterns. Also need to
-                        // prevent mixing of those two options.
-                        let pattern = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
-                        if let Some(pat) = pattern {
-                            fields = vec![self.lower_pat(&pat.pattern).at_index(0)];
-                        } else {
-                            fields = vec![];
-                        }
-                        ctor = Struct;
-                        arity = 1;
-                    }
                     ty::Adt(adt, _) => {
                         ctor = match pat.kind {
                             PatKind::Leaf { .. } if adt.is_union() => UnionField,
@@ -825,11 +787,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             Bool(b) => b.to_string(),
             Str(s) => s.to_string(),
             IntRange(range) => return self.print_pat_range(range, *pat.ty()),
-            Struct if pat.ty().is_box() => {
-                // Outside of the `alloc` crate, the only way to create a struct pattern
-                // of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
-                format!("box {}", print(&pat.fields[0]))
-            }
             Struct | Variant(_) | UnionField => {
                 let enum_info = match *pat.ty().kind() {
                     ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
@@ -866,6 +823,14 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                 print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
                 s
             }
+            DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => {
+                // FIXME(deref_patterns): Remove this special handling once `box_patterns` is gone.
+                // HACK(@dianne): `box _` syntax is exposed on stable in diagnostics, e.g. to
+                // witness non-exhaustiveness of `match Box::new(0) { Box { .. } if false => {} }`.
+                // To avoid changing diagnostics before deref pattern syntax is finalized, let's use
+                // `box _` syntax unless `deref_patterns` is enabled.
+                format!("box {}", print(&pat.fields[0]))
+            }
             DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])),
             Slice(slice) => {
                 let (prefix_len, has_dot_dot) = match slice.kind {
@@ -964,12 +929,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
         ty: &Self::Ty,
     ) -> fmt::Result {
         if let ty::Adt(adt, _) = ty.kind() {
-            if adt.is_box() {
-                write!(f, "Box")?
-            } else {
-                let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
-                write!(f, "{}", variant.name)?;
-            }
+            let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
+            write!(f, "{}", variant.name)?;
         }
         Ok(())
     }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 18078b760c3..c99bc747fd2 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -5,7 +5,7 @@ use rustc_ast::{
     self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
 };
 use rustc_ast_pretty::pprust;
-use rustc_attr_data_structures::{self as attr, Stability};
+use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
@@ -1998,9 +1998,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Otherwise, point out if the struct has any private fields.
         if let Some(def_id) = res.opt_def_id()
             && !def_id.is_local()
-            && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
+            && let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span)
         {
-            non_exhaustive = Some(attr.span());
+            non_exhaustive = Some(attr_span);
         } else if let Some(span) = ctor_fields_span {
             let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
             err.subdiagnostic(label);
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index 46d67c8e510..2d465bd0efa 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -7,7 +7,7 @@ use crate::time::Duration;
 mod tcp;
 pub(crate) mod tcp4;
 
-pub struct TcpStream(#[expect(dead_code)] tcp::Tcp);
+pub struct TcpStream(tcp::Tcp);
 
 impl TcpStream {
     pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
@@ -54,12 +54,13 @@ impl TcpStream {
         false
     }
 
-    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        unsupported()
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
     }
 
-    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsupported()
+    pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
+        // FIXME: UEFI does support vectored write, so implement that.
+        crate::io::default_write_vectored(|b| self.write(b), buf)
     }
 
     pub fn is_write_vectored(&self) -> bool {
diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs
index f87accdc41d..9c3462e3468 100644
--- a/library/std/src/sys/net/connection/uefi/tcp.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp.rs
@@ -3,7 +3,7 @@ use crate::io;
 use crate::net::SocketAddr;
 
 pub(crate) enum Tcp {
-    V4(#[expect(dead_code)] tcp4::Tcp4),
+    V4(tcp4::Tcp4),
 }
 
 impl Tcp {
@@ -18,4 +18,10 @@ impl Tcp {
             SocketAddr::V6(_) => todo!(),
         }
     }
+
+    pub(crate) fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        match self {
+            Self::V4(client) => client.write(buf),
+        }
+    }
 }
diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs
index f7ca373b52b..d0f0d27d975 100644
--- a/library/std/src/sys/net/connection/uefi/tcp4.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp4.rs
@@ -88,6 +88,46 @@ impl Tcp4 {
         }
     }
 
+    pub(crate) fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let evt = unsafe { self.create_evt() }?;
+        let completion_token =
+            tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
+        let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX);
+
+        let fragment = tcp4::FragmentData {
+            fragment_length: data_len,
+            fragment_buffer: buf.as_ptr().cast::<crate::ffi::c_void>().cast_mut(),
+        };
+        let mut tx_data = tcp4::TransmitData {
+            push: r_efi::efi::Boolean::FALSE,
+            urgent: r_efi::efi::Boolean::FALSE,
+            data_length: data_len,
+            fragment_count: 1,
+            fragment_table: [fragment],
+        };
+
+        let protocol = self.protocol.as_ptr();
+        let mut token = tcp4::IoToken {
+            completion_token,
+            packet: tcp4::IoTokenPacket {
+                tx_data: (&raw mut tx_data).cast::<tcp4::TransmitData<0>>(),
+            },
+        };
+
+        let r = unsafe { ((*protocol).transmit)(protocol, &mut token) };
+        if r.is_error() {
+            return Err(io::Error::from_raw_os_error(r.as_usize()));
+        }
+
+        self.wait_for_flag();
+
+        if completion_token.status.is_error() {
+            Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
+        } else {
+            Ok(data_len as usize)
+        }
+    }
+
     unsafe fn create_evt(&self) -> io::Result<helpers::OwnedEvent> {
         self.flag.store(false, Ordering::Relaxed);
         helpers::OwnedEvent::new(
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index cc8f4bbb42c..de920469fdc 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -621,7 +621,7 @@ impl Item {
     }
 
     pub(crate) fn is_non_exhaustive(&self) -> bool {
-        self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
+        find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..))
     }
 
     /// Returns a documentation-level item type from the item.
@@ -776,6 +776,8 @@ impl Item {
                 } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
                 {
                     Some(format!("#[export_name = \"{name}\"]"))
+                } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr {
+                    Some("#[non_exhaustive]".to_string())
                 } else if is_json {
                     match attr {
                         // rustdoc-json stores this in `Item::deprecation`, so we
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 86d9038ec45..7dda3e0fdb9 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -4,7 +4,9 @@ use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
+use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_data_structures::find_attr;
+
 
 declare_clippy_lint! {
     /// ### What it does
@@ -85,7 +87,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
         };
         if cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && let attrs = cx.tcx.hir_attrs(item.hir_id())
-            && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
+            && !find_attr!(attrs, AttributeKind::NonExhaustive(..))
             && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 3562b1ff5cc..51696b38880 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -4,7 +4,6 @@ use clippy_utils::is_doc_hidden;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_indent;
 use itertools::Itertools;
-use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -12,7 +11,9 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
+use rustc_attr_data_structures::find_attr;
+use rustc_attr_data_structures::AttributeKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -93,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                         .then_some((v.def_id, v.span))
                 });
                 if let Ok((id, span)) = iter.exactly_one()
-                    && !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
+                    && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..))
                 {
                     self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
                 }
@@ -113,10 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                         item.span,
                         "this seems like a manual implementation of the non-exhaustive pattern",
                         |diag| {
-                            if let Some(non_exhaustive) =
-                                attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
+                            if let Some(non_exhaustive_span) =
+                                find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(span) => *span)
                             {
-                                diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive");
+                                diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive");
                             } else {
                                 let indent = snippet_indent(cx, item.span).unwrap_or_default();
                                 diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index d9dda6eadb2..22fd15d153a 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -130,7 +130,7 @@ impl LateLintPass<'_> for WildcardImports {
         }
         if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
             && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
-            && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
+            && let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&item.owner_id.def_id)
             && !used_imports.is_empty() // Already handled by `unused_imports`
             && !used_imports.contains(&kw::Underscore)
         {
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 8a0ff5323c9..4c7a589e185 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -7,9 +7,10 @@ use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
 use rustc_span::{Span, Symbol};
 use std::str::FromStr;
-
+use rustc_attr_data_structures::find_attr;
 use crate::source::SpanRangeExt;
 use crate::{sym, tokenize_with_text};
+use rustc_attr_data_structures::AttributeKind;
 
 /// Deprecation status of attributes known by Clippy.
 pub enum DeprecationStatus {
@@ -165,13 +166,13 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
 
 pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
     adt.is_variant_list_non_exhaustive()
-        || tcx.has_attr(adt.did(), sym::non_exhaustive)
+        || find_attr!(tcx.get_all_attrs(adt.did()), AttributeKind::NonExhaustive(..))
         || adt.variants().iter().any(|variant_def| {
-            variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive)
+            variant_def.is_field_list_non_exhaustive() || find_attr!(tcx.get_all_attrs(variant_def.def_id), AttributeKind::NonExhaustive(..))
         })
         || adt
             .all_fields()
-            .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
+            .any(|field_def| find_attr!(tcx.get_all_attrs(field_def.did), AttributeKind::NonExhaustive(..)))
 }
 
 /// Checks if the given span contains a `#[cfg(..)]` attribute
diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff
new file mode 100644
index 00000000000..a91561ba304
--- /dev/null
+++ b/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff
@@ -0,0 +1,12 @@
+- // MIR for `no_optimize` before GVN
++ // MIR for `no_optimize` after GVN
+  
+  fn no_optimize() -> bool {
+      let mut _0: bool;
+  
+      bb0: {
+          _0 = Eq(const no_optimize::<T>::{constant#0}, const no_optimize::<T>::{constant#1});
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff
new file mode 100644
index 00000000000..bdfa2987b23
--- /dev/null
+++ b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff
@@ -0,0 +1,13 @@
+- // MIR for `optimize_false` before GVN
++ // MIR for `optimize_false` after GVN
+  
+  fn optimize_false() -> bool {
+      let mut _0: bool;
+  
+      bb0: {
+-         _0 = Eq(const optimize_false::<T>::{constant#0}, const optimize_false::<T>::{constant#1});
++         _0 = const false;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff
new file mode 100644
index 00000000000..dc337d43fb0
--- /dev/null
+++ b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff
@@ -0,0 +1,13 @@
+- // MIR for `optimize_true` before GVN
++ // MIR for `optimize_true` after GVN
+  
+  fn optimize_true() -> bool {
+      let mut _0: bool;
+  
+      bb0: {
+-         _0 = Eq(const optimize_true::<T>::{constant#0}, const optimize_true::<T>::{constant#1});
++         _0 = const true;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.rs b/tests/mir-opt/gvn_const_eval_polymorphic.rs
new file mode 100644
index 00000000000..7320ad947ff
--- /dev/null
+++ b/tests/mir-opt/gvn_const_eval_polymorphic.rs
@@ -0,0 +1,57 @@
+//@ test-mir-pass: GVN
+//@ compile-flags: --crate-type lib
+
+//! Regressions test for a mis-optimization where some functions
+//! (`type_id` / `type_name` / `needs_drop`) could be evaluated in
+//! a generic context, even though their value depends on some type
+//! parameter `T`.
+//!
+//! In particular, `type_name_of_val(&generic::<T>)` was incorrectly
+//! evaluated to the string "crate_name::generic::<T>", and
+//! `no_optimize` was incorrectly optimized to `false`.
+
+#![feature(const_type_name)]
+
+fn generic<T>() {}
+
+const fn type_name_contains_i32<T>(_: &T) -> bool {
+    let pattern = b"i32";
+    let name = std::any::type_name::<T>().as_bytes();
+    let mut i = 0;
+    'outer: while i < name.len() - pattern.len() + 1 {
+        let mut j = 0;
+        while j < pattern.len() {
+            if name[i + j] != pattern[j] {
+                i += 1;
+                continue 'outer;
+            }
+            j += 1;
+        }
+        return true;
+    }
+    false
+}
+
+// EMIT_MIR gvn_const_eval_polymorphic.optimize_true.GVN.diff
+fn optimize_true<T>() -> bool {
+    // CHECK-LABEL: fn optimize_true(
+    // CHECK: _0 = const true;
+    // CHECK-NEXT: return;
+    (const { type_name_contains_i32(&generic::<i32>) }) == const { true }
+}
+
+// EMIT_MIR gvn_const_eval_polymorphic.optimize_false.GVN.diff
+fn optimize_false<T>() -> bool {
+    // CHECK-LABEL: fn optimize_false(
+    // CHECK: _0 = const false;
+    // CHECK-NEXT: return;
+    (const { type_name_contains_i32(&generic::<i64>) }) == const { true }
+}
+
+// EMIT_MIR gvn_const_eval_polymorphic.no_optimize.GVN.diff
+fn no_optimize<T>() -> bool {
+    // CHECK-LABEL: fn no_optimize(
+    // CHECK: _0 = Eq(const no_optimize::<T>::{constant#0}, const no_optimize::<T>::{constant#1});
+    // CHECK-NEXT: return;
+    (const { type_name_contains_i32(&generic::<T>) }) == const { true }
+}
diff --git a/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff b/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff
deleted file mode 100644
index 2f83f54d2af..00000000000
--- a/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff
+++ /dev/null
@@ -1,12 +0,0 @@
-- // MIR for `cursed_is_i32` before GVN
-+ // MIR for `cursed_is_i32` after GVN
-  
-  fn cursed_is_i32() -> bool {
-      let mut _0: bool;
-  
-      bb0: {
-          _0 = Eq(const cursed_is_i32::<T>::{constant#0}, const cursed_is_i32::<T>::{constant#1});
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/gvn_type_id_polymorphic.rs b/tests/mir-opt/gvn_type_id_polymorphic.rs
deleted file mode 100644
index 39bc5c24ecc..00000000000
--- a/tests/mir-opt/gvn_type_id_polymorphic.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//@ test-mir-pass: GVN
-//@ compile-flags: -C opt-level=2
-
-#![feature(core_intrinsics)]
-
-fn generic<T>() {}
-
-const fn type_id_of_val<T: 'static>(_: &T) -> u128 {
-    std::intrinsics::type_id::<T>()
-}
-
-// EMIT_MIR gvn_type_id_polymorphic.cursed_is_i32.GVN.diff
-fn cursed_is_i32<T: 'static>() -> bool {
-    // CHECK-LABEL: fn cursed_is_i32(
-    // CHECK: _0 = Eq(const cursed_is_i32::<T>::{constant#0}, const cursed_is_i32::<T>::{constant#1});
-    // CHECK-NEXT: return;
-    (const { type_id_of_val(&generic::<T>) } == const { type_id_of_val(&generic::<i32>) })
-}
-
-fn main() {
-    dbg!(cursed_is_i32::<i32>());
-}
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index bdebe155aba..32b0ddf87ba 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -206,12 +206,6 @@ error: malformed `automatically_derived` attribute input
 LL | #[automatically_derived = 18]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]`
 
-error: malformed `non_exhaustive` attribute input
-  --> $DIR/malformed-attrs.rs:196:1
-   |
-LL | #[non_exhaustive = 1]
-   | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
-
 error: malformed `thread_local` attribute input
   --> $DIR/malformed-attrs.rs:202:1
    |
@@ -552,6 +546,15 @@ LL | #[rustc_layout_scalar_valid_range_end]
    | expected this to be a list
    | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
 
+error[E0565]: malformed `non_exhaustive` attribute input
+  --> $DIR/malformed-attrs.rs:196:1
+   |
+LL | #[non_exhaustive = 1]
+   | ^^^^^^^^^^^^^^^^^---^
+   | |                |
+   | |                didn't expect any arguments here
+   | help: must be of the form: `#[non_exhaustive]`
+
 error: attribute should be applied to `const fn`
   --> $DIR/malformed-attrs.rs:34:1
    |
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index d9ceca2f29b..eff478d04ae 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -66,18 +66,6 @@ LL | #[should_panic]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:66:1
-   |
-LL | #[non_exhaustive]
-   | ^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:65:1
-   |
-LL | #[non_exhaustive]
-   | ^^^^^^^^^^^^^^^^^
-
-error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:70:1
    |
 LL | #[automatically_derived]
@@ -191,6 +179,18 @@ LL | #[must_use]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:66:1
+   |
+LL | #[non_exhaustive]
+   | ^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:65:1
+   |
+LL | #[non_exhaustive]
+   | ^^^^^^^^^^^^^^^^^
+
+error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:74:1
    |
 LL | #[inline(never)]
diff --git a/tests/ui/parser/macro/bad-macro-definition.rs b/tests/ui/parser/macro/bad-macro-definition.rs
new file mode 100644
index 00000000000..3c5c93ea3b3
--- /dev/null
+++ b/tests/ui/parser/macro/bad-macro-definition.rs
@@ -0,0 +1,22 @@
+#![crate_type = "lib"]
+
+macro_rules! a { {} => }
+//~^ ERROR: macro definition ended unexpectedly
+
+macro_rules! b { 0 => }
+//~^ ERROR: macro definition ended unexpectedly
+//~| ERROR: invalid macro matcher
+
+macro_rules! c { x => }
+//~^ ERROR: macro definition ended unexpectedly
+//~| ERROR: invalid macro matcher
+
+macro_rules! d { _ => }
+//~^ ERROR: macro definition ended unexpectedly
+//~| ERROR: invalid macro matcher
+
+macro_rules! e { {} }
+//~^ ERROR: expected `=>`, found end of macro arguments
+
+macro_rules! f {}
+//~^ ERROR: macros must contain at least one rule
diff --git a/tests/ui/parser/macro/bad-macro-definition.stderr b/tests/ui/parser/macro/bad-macro-definition.stderr
new file mode 100644
index 00000000000..de6d9d6a38b
--- /dev/null
+++ b/tests/ui/parser/macro/bad-macro-definition.stderr
@@ -0,0 +1,56 @@
+error: macro definition ended unexpectedly
+  --> $DIR/bad-macro-definition.rs:3:23
+   |
+LL | macro_rules! a { {} => }
+   |                       ^ expected right-hand side of macro rule
+
+error: invalid macro matcher; matchers must be contained in balanced delimiters
+  --> $DIR/bad-macro-definition.rs:6:18
+   |
+LL | macro_rules! b { 0 => }
+   |                  ^
+
+error: macro definition ended unexpectedly
+  --> $DIR/bad-macro-definition.rs:6:22
+   |
+LL | macro_rules! b { 0 => }
+   |                      ^ expected right-hand side of macro rule
+
+error: invalid macro matcher; matchers must be contained in balanced delimiters
+  --> $DIR/bad-macro-definition.rs:10:18
+   |
+LL | macro_rules! c { x => }
+   |                  ^
+
+error: macro definition ended unexpectedly
+  --> $DIR/bad-macro-definition.rs:10:22
+   |
+LL | macro_rules! c { x => }
+   |                      ^ expected right-hand side of macro rule
+
+error: invalid macro matcher; matchers must be contained in balanced delimiters
+  --> $DIR/bad-macro-definition.rs:14:18
+   |
+LL | macro_rules! d { _ => }
+   |                  ^
+
+error: macro definition ended unexpectedly
+  --> $DIR/bad-macro-definition.rs:14:22
+   |
+LL | macro_rules! d { _ => }
+   |                      ^ expected right-hand side of macro rule
+
+error: expected `=>`, found end of macro arguments
+  --> $DIR/bad-macro-definition.rs:18:20
+   |
+LL | macro_rules! e { {} }
+   |                    ^ expected `=>`
+
+error: macros must contain at least one rule
+  --> $DIR/bad-macro-definition.rs:21:1
+   |
+LL | macro_rules! f {}
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr
index 136cd763b05..1ac017aa08b 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr
@@ -1,8 +1,11 @@
-error: malformed `non_exhaustive` attribute input
+error[E0565]: malformed `non_exhaustive` attribute input
   --> $DIR/invalid-attribute.rs:1:1
    |
 LL | #[non_exhaustive(anything)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
+   | ^^^^^^^^^^^^^^^^----------^
+   | |               |
+   | |               didn't expect any arguments here
+   | help: must be of the form: `#[non_exhaustive]`
 
 error[E0701]: attribute should be applied to a struct or enum
   --> $DIR/invalid-attribute.rs:5:1
@@ -27,4 +30,5 @@ LL | | }
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0701`.
+Some errors have detailed explanations: E0565, E0701.
+For more information about an error, try `rustc --explain E0565`.
diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs
index b7429464fa5..1f30af2acc6 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.rs
+++ b/tests/ui/uninhabited/uninhabited-patterns.rs
@@ -27,7 +27,11 @@ fn main() {
 
     let x: Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]> = Err(&[]);
     match x {
-        Ok(box _) => (), //~ ERROR unreachable pattern
+        Ok(box _) => (), // We'd get a non-exhaustiveness error if this arm was removed; don't lint.
+        Err(&[]) => (),
+        Err(&[..]) => (),
+    }
+    match x { //~ ERROR non-exhaustive patterns
         Err(&[]) => (),
         Err(&[..]) => (),
     }
diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr
index 7a872767d95..62113c82a36 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-patterns.stderr
@@ -1,21 +1,23 @@
-error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:30:9
+error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
+  --> $DIR/uninhabited-patterns.rs:34:11
    |
-LL |         Ok(box _) => (),
-   |         ^^^^^^^^^-------
-   |         |
-   |         matches no values because `NotSoSecretlyEmpty` is uninhabited
-   |         help: remove the match arm
+LL |     match x {
+   |           ^ pattern `Ok(_)` not covered
    |
-   = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
-note: the lint level is defined here
-  --> $DIR/uninhabited-patterns.rs:4:9
+note: `Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Err(&[..]) => (),
+LL ~         Ok(_) => todo!(),
    |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:39:9
+  --> $DIR/uninhabited-patterns.rs:43:9
    |
 LL |         Err(Ok(_y)) => (),
    |         ^^^^^^^^^^^-------
@@ -24,9 +26,14 @@ LL |         Err(Ok(_y)) => (),
    |         help: remove the match arm
    |
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
+note: the lint level is defined here
+  --> $DIR/uninhabited-patterns.rs:4:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:42:15
+  --> $DIR/uninhabited-patterns.rs:46:15
    |
 LL |     while let Some(_y) = foo() {
    |               ^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited
@@ -35,3 +42,4 @@ LL |     while let Some(_y) = foo() {
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0004`.
diff --git a/triagebot.toml b/triagebot.toml
index 64a8a7c46b4..4e3dff219f1 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1404,6 +1404,9 @@ project-exploit-mitigations = [
 compiletest = [
     "@jieyouxu",
 ]
+dep-bumps = [
+    "@clubby789",
+]
 
 [assign.owners]
 "/.github/workflows" =                                   ["infra-ci"]