about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs62
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs16
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs34
-rw-r--r--compiler/rustc_lexer/src/lib.rs5
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/builtin.rs34
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs88
-rw-r--r--compiler/rustc_parse_format/src/lib.rs5
-rw-r--r--library/alloc/src/rc.rs2
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/std/src/sys/pal/unix/args.rs81
-rw-r--r--library/std/src/thread/local.rs4
-rw-r--r--library/std/tests/thread.rs22
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs62
-rw-r--r--src/tools/rustfmt/src/parse/macros/mod.rs44
-rw-r--r--src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs1
-rw-r--r--src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs3
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.rs1
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr16
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.rs3
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr33
-rw-r--r--tests/ui/feature-gates/feature-gate-feature-gate.stderr2
-rw-r--r--tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs20
-rw-r--r--tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr38
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr44
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs31
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs1
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr23
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs6
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr96
-rw-r--r--tests/ui/unsafe/union_destructure.rs1
31 files changed, 556 insertions, 226 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 9c2f336e912..5564902396e 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -796,7 +796,67 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             };
         }
         match rvalue {
-            Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
+            Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {}
+            Rvalue::Aggregate(kind, fields) => match **kind {
+                AggregateKind::Tuple => {}
+                AggregateKind::Array(dest) => {
+                    for src in fields {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "array field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Adt(def_id, idx, args, _, Some(field)) => {
+                    let adt_def = self.tcx.adt_def(def_id);
+                    assert!(adt_def.is_union());
+                    assert_eq!(idx, FIRST_VARIANT);
+                    let dest = adt_def.non_enum_variant().fields[field].ty(self.tcx, args);
+                    if fields.len() != 1 {
+                        self.fail(location, "unions should have one initialized field");
+                    }
+                    if !self.mir_assign_valid_types(fields.raw[0].ty(self.body, self.tcx), dest) {
+                        self.fail(location, "union field has the wrong type");
+                    }
+                }
+                AggregateKind::Adt(def_id, idx, args, _, None) => {
+                    let adt_def = self.tcx.adt_def(def_id);
+                    assert!(!adt_def.is_union());
+                    let variant = &adt_def.variants()[idx];
+                    if variant.fields.len() != fields.len() {
+                        self.fail(location, "adt has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, &variant.fields) {
+                        if !self.mir_assign_valid_types(
+                            src.ty(self.body, self.tcx),
+                            dest.ty(self.tcx, args),
+                        ) {
+                            self.fail(location, "adt field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Closure(_, args) => {
+                    let upvars = args.as_closure().upvar_tys();
+                    if upvars.len() != fields.len() {
+                        self.fail(location, "closure has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, upvars) {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "closure field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Coroutine(_, args) => {
+                    let upvars = args.as_coroutine().upvar_tys();
+                    if upvars.len() != fields.len() {
+                        self.fail(location, "coroutine has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, upvars) {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "coroutine field has the wrong type");
+                        }
+                    }
+                }
+            },
             Rvalue::Ref(_, BorrowKind::Fake, _) => {
                 if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index b5f42e98127..27dc088d5dd 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -94,15 +94,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return false;
         };
         let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
+        let mut is_downgradable = true;
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|o| match o.trait_ref.path.res {
-                    Res::Def(DefKind::Trait, id) if Some(id) == owner => {
-                        // When we're dealing with a recursive trait, we don't want to downgrade
-                        // the error, so we consider them to be object safe always. (#119652)
-                        true
+                    Res::Def(DefKind::Trait, id) => {
+                        if Some(id) == owner {
+                            // For recursive traits, don't downgrade the error. (#119652)
+                            is_downgradable = false;
+                        }
+                        tcx.check_is_object_safe(id)
                     }
-                    Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
                     _ => false,
                 })
             }
@@ -130,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ],
                     Applicability::MachineApplicable,
                 );
-            } else if diag.is_error() {
+            } else if diag.is_error() && is_downgradable {
                 // We'll emit the object safety error already, with a structured suggestion.
                 diag.downgrade_to_delayed_bug();
             }
@@ -156,7 +158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             if !is_object_safe {
                 diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
-                if diag.is_error() {
+                if diag.is_error() && is_downgradable {
                     // We'll emit the object safety error already, with a structured suggestion.
                     diag.downgrade_to_delayed_bug();
                 }
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 9e1dab12b4d..1c120646f1f 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -165,9 +165,9 @@ impl<'tcx> InferCtxt<'tcx> {
         //
         // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
         // ourselves with a check to find bugs being required for code to compile because it made inference progress.
-        let compatible_types = self.probe(|_| {
+        self.probe(|_| {
             if a.ty() == b.ty() {
-                return Ok(());
+                return;
             }
 
             // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
@@ -177,32 +177,18 @@ impl<'tcx> InferCtxt<'tcx> {
                 relation.param_env().and((a.ty(), b.ty())),
                 &mut OriginalQueryValues::default(),
             );
-            self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
+            self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| {
+                // The error will only be reported later. If we emit an ErrorGuaranteed
+                // here, then we will never get to the code that actually emits the error.
                 self.tcx.dcx().delayed_bug(format!(
                     "cannot relate consts of different types (a={a:?}, b={b:?})",
-                ))
-            })
+                ));
+                // We treat these constants as if they were of the same type, so that any
+                // such constants being used in impls make these impls match barring other mismatches.
+                // This helps with diagnostics down the road.
+            });
         });
 
-        // If the consts have differing types, just bail with a const error with
-        // the expected const's type. Specifically, we don't want const infer vars
-        // to do any type shapeshifting before and after resolution.
-        if let Err(guar) = compatible_types {
-            // HACK: equating both sides with `[const error]` eagerly prevents us
-            // from leaving unconstrained inference vars during things like impl
-            // matching in the solver.
-            let a_error = ty::Const::new_error(self.tcx, guar, a.ty());
-            if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
-                return self.unify_const_variable(vid, a_error, relation.param_env());
-            }
-            let b_error = ty::Const::new_error(self.tcx, guar, b.ty());
-            if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
-                return self.unify_const_variable(vid, b_error, relation.param_env());
-            }
-
-            return Ok(if relation.a_is_expected() { a_error } else { b_error });
-        }
-
         match (a.kind(), b.kind()) {
             (
                 ty::ConstKind::Infer(InferConst::Var(a_vid)),
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 43dfd34a6ff..f6c9289b529 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -20,8 +20,9 @@
 //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-// We want to be able to build this crate with a stable compiler, so no
-// `#![feature]` attributes should be added.
+// We want to be able to build this crate with a stable compiler,
+// so no `#![feature]` attributes should be added.
+#![deny(unstable_features)]
 
 mod cursor;
 pub mod unescape;
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7d4afc5bad7..33f96139f20 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -148,7 +148,7 @@ lint_builtin_unsafe_impl = implementation of an `unsafe` trait
 
 lint_builtin_unsafe_trait = declaration of an `unsafe` trait
 
-lint_builtin_unstable_features = unstable feature
+lint_builtin_unstable_features = use of an unstable feature
 
 lint_builtin_unused_doc_comment = unused doc comment
     .label = rustdoc does not generate documentation for {$kind}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5e1f2ed11ac..2ce78152cc2 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1233,10 +1233,30 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
 }
 
 declare_lint! {
-    /// The `unstable_features` is deprecated and should no longer be used.
+    /// The `unstable_features` lint detects uses of `#![feature]`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unstable_features)]
+    /// #![feature(test)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In larger nightly-based projects which
+    ///
+    /// * consist of a multitude of crates where a subset of crates has to compile on
+    ///   stable either unconditionally or depending on a `cfg` flag to for example
+    ///   allow stable users to depend on them,
+    /// * don't use nightly for experimental features but for, e.g., unstable options only,
+    ///
+    /// this lint may come in handy to enforce policies of these kinds.
     UNSTABLE_FEATURES,
     Allow,
-    "enabling unstable features (deprecated. do not use)"
+    "enabling unstable features"
 }
 
 declare_lint_pass!(
@@ -1246,11 +1266,11 @@ declare_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
-        if attr.has_name(sym::feature) {
-            if let Some(items) = attr.meta_item_list() {
-                for item in items {
-                    cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
-                }
+        if attr.has_name(sym::feature)
+            && let Some(items) = attr.meta_item_list()
+        {
+            for item in items {
+                cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
             }
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 693dc49c6e8..03de79e92be 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,9 +1,8 @@
 use rustc_pattern_analysis::errors::Uncovered;
 use rustc_pattern_analysis::rustc::{
-    Constructor, DeconstructedPat, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
+    Constructor, DeconstructedPat, MatchArm, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
     UsefulnessReport, WitnessPat,
 };
-use rustc_pattern_analysis::{analyze_match, MatchArm};
 
 use crate::errors::*;
 
@@ -390,6 +389,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         }
     }
 
+    fn analyze_patterns(
+        &mut self,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        arms: &[MatchArm<'p, 'tcx>],
+        scrut_ty: Ty<'tcx>,
+    ) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
+        let report =
+            rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
+                self.error = Err(err);
+                err
+            })?;
+
+        // Warn unreachable subpatterns.
+        for (arm, is_useful) in report.arm_usefulness.iter() {
+            if let Usefulness::Useful(redundant_subpats) = is_useful
+                && !redundant_subpats.is_empty()
+            {
+                let mut redundant_subpats = redundant_subpats.clone();
+                // Emit lints in the order in which they occur in the file.
+                redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
+                for pat in redundant_subpats {
+                    report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None)
+                }
+            }
+        }
+        Ok(report)
+    }
+
     #[instrument(level = "trace", skip(self))]
     fn check_let(&mut self, pat: &'p Pat<'tcx>, scrutinee: Option<ExprId>, span: Span) {
         assert!(self.let_source != LetSource::None);
@@ -435,14 +462,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             }
         }
 
-        let scrut_ty = scrut.ty;
-        let report = match analyze_match(&cx, &tarms, scrut_ty) {
-            Ok(report) => report,
-            Err(err) => {
-                self.error = Err(err);
-                return;
-            }
-        };
+        let Ok(report) = self.analyze_patterns(&cx, &tarms, scrut.ty) else { return };
 
         match source {
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -474,7 +494,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 );
             } else {
                 self.error = Err(report_non_exhaustive_match(
-                    &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
+                    &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
                 ));
             }
         }
@@ -556,7 +576,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let cx = self.new_cx(refutability, None, scrut, pat.span);
         let pat = self.lower_pattern(&cx, pat)?;
         let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
-        let report = analyze_match(&cx, &arms, pat.ty().inner())?;
+        let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
         Ok((cx, report))
     }
 
@@ -567,7 +587,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
     ) -> Result<RefutableFlag, ErrorGuaranteed> {
         let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
         // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
-        // This also reports unreachable sub-patterns.
         report_arm_reachability(&cx, &report);
         // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
         // irrefutable.
@@ -851,38 +870,29 @@ fn report_irrefutable_let_patterns(
 }
 
 /// Report unreachable arms, if any.
+fn report_unreachable_pattern<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    hir_id: HirId,
+    span: Span,
+    catchall: Option<Span>,
+) {
+    cx.tcx.emit_spanned_lint(
+        UNREACHABLE_PATTERNS,
+        hir_id,
+        span,
+        UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
+    );
+}
+
+/// Report unreachable arms, if any.
 fn report_arm_reachability<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     report: &UsefulnessReport<'p, 'tcx>,
 ) {
-    let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| {
-        cx.tcx.emit_spanned_lint(
-            UNREACHABLE_PATTERNS,
-            hir_id,
-            span,
-            UnreachablePattern {
-                span: if catchall.is_some() { Some(span) } else { None },
-                catchall,
-            },
-        );
-    };
-
     let mut catchall = None;
     for (arm, is_useful) in report.arm_usefulness.iter() {
-        match is_useful {
-            Usefulness::Redundant => {
-                report_unreachable_pattern(arm.pat.data().unwrap().span, arm.arm_data, catchall)
-            }
-            Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
-            // The arm is reachable, but contains redundant subpatterns (from or-patterns).
-            Usefulness::Useful(redundant_subpats) => {
-                let mut redundant_subpats = redundant_subpats.clone();
-                // Emit lints in the order in which they occur in the file.
-                redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
-                for pat in redundant_subpats {
-                    report_unreachable_pattern(pat.data().unwrap().span, arm.arm_data, None);
-                }
-            }
+        if matches!(is_useful, Usefulness::Redundant) {
+            report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall)
         }
         if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
             catchall = Some(arm.pat.data().unwrap().span);
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 1e1d45d6f70..625764876a6 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -11,8 +11,9 @@
 )]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-// WARNING: We want to be able to build this crate with a stable compiler,
-//          so no `#![feature]` attributes should be added!
+// We want to be able to build this crate with a stable compiler,
+// so no `#![feature]` attributes should be added.
+#![deny(unstable_features)]
 
 use rustc_lexer::unescape;
 pub use Alignment::*;
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 263b1449de1..f986df05846 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1924,7 +1924,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
 
             // Free the allocation without dropping its contents
             let (bptr, alloc) = Box::into_raw_with_allocator(src);
-            let src = Box::from_raw(bptr as *mut mem::ManuallyDrop<T>);
+            let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop<T>, alloc.by_ref());
             drop(src);
 
             Self::from_ptr_in(ptr, alloc)
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 5273b3cb2da..dc82c9c4111 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1869,7 +1869,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 
             // Free the allocation without dropping its contents
             let (bptr, alloc) = Box::into_raw_with_allocator(src);
-            let src = Box::from_raw(bptr as *mut mem::ManuallyDrop<T>);
+            let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop<T>, alloc.by_ref());
             drop(src);
 
             Self::from_ptr_in(ptr, alloc)
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index 9f7dcc0416e..78e82d9c194 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -201,9 +201,9 @@ mod imp {
 
     // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
     // and use underscores in their names - they're most probably
-    // are considered private and therefore should be avoided
-    // Here is another way to get arguments using Objective C
-    // runtime
+    // are considered private and therefore should be avoided.
+    // Here is another way to get arguments using the Objective-C
+    // runtime.
     //
     // In general it looks like:
     // res = Vec::new()
@@ -213,53 +213,60 @@ mod imp {
     // res
     #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
     pub fn args() -> Args {
-        use crate::ffi::OsString;
+        use crate::ffi::{c_char, c_void, OsString};
         use crate::mem;
         use crate::str;
 
-        extern "C" {
-            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
-            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
-        }
+        type Sel = *const c_void;
+        type NsId = *const c_void;
+        type NSUInteger = usize;
 
-        #[cfg(target_arch = "aarch64")]
         extern "C" {
-            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
-            #[allow(clashing_extern_declarations)]
-            #[link_name = "objc_msgSend"]
-            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
-        }
+            fn sel_registerName(name: *const c_char) -> Sel;
+            fn objc_getClass(class_name: *const c_char) -> NsId;
 
-        #[cfg(not(target_arch = "aarch64"))]
-        extern "C" {
-            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
-            #[allow(clashing_extern_declarations)]
-            #[link_name = "objc_msgSend"]
-            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
+            // This must be transmuted to an appropriate function pointer type before being called.
+            fn objc_msgSend();
         }
 
-        type Sel = *const libc::c_void;
-        type NsId = *const libc::c_void;
+        const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
+        const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
+            unsafe { mem::transmute(MSG_SEND_PTR) };
+        const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
+            NsId,
+            Sel,
+        ) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
+        const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
+            NsId,
+            Sel,
+            NSUInteger,
+        )
+            -> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
 
         let mut res = Vec::new();
 
         unsafe {
-            let process_info_sel =
-                sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar);
-            let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar);
-            let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar);
-            let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar);
-            let object_at_sel =
-                sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar);
-
-            let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar);
-            let info = objc_msgSend(klass, process_info_sel);
-            let args = objc_msgSend(info, arguments_sel);
-
-            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
+            let process_info_sel = sel_registerName(c"processInfo".as_ptr());
+            let arguments_sel = sel_registerName(c"arguments".as_ptr());
+            let count_sel = sel_registerName(c"count".as_ptr());
+            let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
+            let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
+
+            let klass = objc_getClass(c"NSProcessInfo".as_ptr());
+            // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
+            let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
+
+            // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
+            let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
+
+            let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
             for i in 0..cnt {
-                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
-                let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
+                // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
+                let ns_string =
+                    MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
+                // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
+                let utf_c_str: *const c_char =
+                    MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
                 let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                 res.push(OsString::from(str::from_utf8(bytes).unwrap()))
             }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 338567777f7..2e13f433dcf 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -186,12 +186,12 @@ macro_rules! thread_local {
     // empty (base case for the recursion)
     () => {};
 
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
+    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => (
         $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
         $crate::thread_local!($($rest)*);
     );
 
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
+    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => (
         $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
     );
 
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index 754b264c6ad..4ce81f2846e 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -1,3 +1,4 @@
+use std::cell::{Cell, RefCell};
 use std::sync::{Arc, Mutex};
 use std::thread;
 use std::time::Duration;
@@ -14,3 +15,24 @@ fn sleep() {
     thread::sleep(Duration::from_millis(100));
     assert_eq!(*finished.lock().unwrap(), false);
 }
+
+#[test]
+fn thread_local_containing_const_statements() {
+    // This exercises the `const $init:block` cases of the thread_local macro.
+    // Despite overlapping with expression syntax, the `const { ... }` is not
+    // parsed as `$init:expr`.
+    thread_local! {
+        static CELL: Cell<u32> = const {
+            let value = 1;
+            Cell::new(value)
+        };
+
+        static REFCELL: RefCell<u32> = const {
+            let value = 1;
+            RefCell::new(value)
+        };
+    }
+
+    assert_eq!(CELL.get(), 1);
+    assert_eq!(REFCELL.take(), 1);
+}
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 190f0fe3cdd..f954f01fe4e 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -803,7 +803,14 @@ impl Rustc {
 }
 
 impl Step for Rustc {
-    type Output = ();
+    // We return the stage of the "actual" compiler (not the uplifted one).
+    //
+    // By "actual" we refer to the uplifting logic where we may not compile the requested stage;
+    // instead, we uplift it from the previous stages. Which can lead to bootstrap failures in
+    // specific situations where we request stage X from other steps. However we may end up
+    // uplifting it from stage Y, causing the other stage to fail when attempting to link with
+    // stage X which was never actually built.
+    type Output = u32;
     const ONLY_HOSTS: bool = true;
     const DEFAULT: bool = false;
 
@@ -834,7 +841,7 @@ impl Step for Rustc {
     /// This will build the compiler for a particular stage of the build using
     /// the `compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
-    fn run(self, builder: &Builder<'_>) {
+    fn run(self, builder: &Builder<'_>) -> u32 {
         let compiler = self.compiler;
         let target = self.target;
 
@@ -848,7 +855,7 @@ impl Step for Rustc {
                 compiler,
                 builder.config.ci_rustc_dev_contents(),
             );
-            return;
+            return compiler.stage;
         }
 
         builder.ensure(Std::new(compiler, target));
@@ -857,7 +864,8 @@ impl Step for Rustc {
             builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
             builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
             builder.ensure(RustcLink::from_rustc(self, compiler));
-            return;
+
+            return compiler.stage;
         }
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
@@ -880,7 +888,7 @@ impl Step for Rustc {
             };
             builder.info(&msg);
             builder.ensure(RustcLink::from_rustc(self, compiler_to_use));
-            return;
+            return compiler_to_use.stage;
         }
 
         // Ensure that build scripts and proc macros have a std / libproc_macro to link against.
@@ -984,6 +992,8 @@ impl Step for Rustc {
             self,
             builder.compiler(compiler.stage, builder.config.build),
         ));
+
+        compiler.stage
     }
 }
 
@@ -1642,21 +1652,6 @@ impl Step for Assemble {
             return target_compiler;
         }
 
-        // Get the compiler that we'll use to bootstrap ourselves.
-        //
-        // Note that this is where the recursive nature of the bootstrap
-        // happens, as this will request the previous stage's compiler on
-        // downwards to stage 0.
-        //
-        // Also note that we're building a compiler for the host platform. We
-        // only assume that we can run `build` artifacts, which means that to
-        // produce some other architecture compiler we need to start from
-        // `build` to get there.
-        //
-        // FIXME: It may be faster if we build just a stage 1 compiler and then
-        //        use that to bootstrap this compiler forward.
-        let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
-
         // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
         if builder.download_rustc() {
             let sysroot =
@@ -1671,19 +1666,30 @@ impl Step for Assemble {
             return target_compiler;
         }
 
+        // Get the compiler that we'll use to bootstrap ourselves.
+        //
+        // Note that this is where the recursive nature of the bootstrap
+        // happens, as this will request the previous stage's compiler on
+        // downwards to stage 0.
+        //
+        // Also note that we're building a compiler for the host platform. We
+        // only assume that we can run `build` artifacts, which means that to
+        // produce some other architecture compiler we need to start from
+        // `build` to get there.
+        //
+        // FIXME: It may be faster if we build just a stage 1 compiler and then
+        //        use that to bootstrap this compiler forward.
+        let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
+
         // Build the libraries for this compiler to link to (i.e., the libraries
         // it uses at runtime). NOTE: Crates the target compiler compiles don't
         // link to these. (FIXME: Is that correct? It seems to be correct most
         // of the time but I think we do link to these for stage2/bin compilers
         // when not performing a full bootstrap).
-        builder.ensure(Rustc::new(build_compiler, target_compiler.host));
-
-        // FIXME: For now patch over problems noted in #90244 by early returning here, even though
-        // we've not properly assembled the target sysroot. A full fix is pending further investigation,
-        // for now full bootstrap usage is rare enough that this is OK.
-        if target_compiler.stage >= 3 && !builder.config.full_bootstrap {
-            return target_compiler;
-        }
+        let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host));
+        // Current build_compiler.stage might be uplifted instead of being built; so update it
+        // to not fail while linking the artifacts.
+        build_compiler.stage = actual_stage;
 
         for &backend in builder.config.rust_codegen_backends.iter() {
             if backend == "llvm" {
diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 2dd2622174f..a9f9ea1826a 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -1,7 +1,7 @@
-use rustc_ast::token::{Delimiter, TokenKind};
+use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{ast, ptr};
-use rustc_parse::parser::{ForceCollect, Parser};
+use rustc_parse::parser::{ForceCollect, Parser, Recovery};
 use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{self, kw};
@@ -15,7 +15,7 @@ pub(crate) mod cfg_if;
 pub(crate) mod lazy_static;
 
 fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
-    stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
+    stream_to_parser(sess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden)
 }
 
 fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
@@ -24,45 +24,51 @@ fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser
 
 fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
     macro_rules! parse_macro_arg {
-        ($macro_arg:ident, $parser:expr, $f:expr) => {
+        ($macro_arg:ident, $nt_kind:expr, $try_parse:expr, $then:expr) => {
             let mut cloned_parser = (*parser).clone();
-            match $parser(&mut cloned_parser) {
-                Ok(x) => {
-                    if parser.sess.dcx.has_errors().is_some() {
+            if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) {
+                match $try_parse(&mut cloned_parser) {
+                    Ok(x) => {
+                        if parser.sess.dcx.has_errors().is_some() {
+                            parser.sess.dcx.reset_err_count();
+                        } else {
+                            // Parsing succeeded.
+                            *parser = cloned_parser;
+                            return Some(MacroArg::$macro_arg($then(x)?));
+                        }
+                    }
+                    Err(e) => {
+                        e.cancel();
                         parser.sess.dcx.reset_err_count();
-                    } else {
-                        // Parsing succeeded.
-                        *parser = cloned_parser;
-                        return Some(MacroArg::$macro_arg($f(x)?));
                     }
                 }
-                Err(e) => {
-                    e.cancel();
-                    parser.sess.dcx.reset_err_count();
-                }
             }
         };
     }
 
     parse_macro_arg!(
         Expr,
-        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
+        NonterminalKind::Expr,
+        |parser: &mut Parser<'b>| parser.parse_expr(),
         |x: ptr::P<ast::Expr>| Some(x)
     );
     parse_macro_arg!(
         Ty,
-        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
+        NonterminalKind::Ty,
+        |parser: &mut Parser<'b>| parser.parse_ty(),
         |x: ptr::P<ast::Ty>| Some(x)
     );
     parse_macro_arg!(
         Pat,
-        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None, None),
+        NonterminalKind::PatParam { inferred: false },
+        |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
         |x: ptr::P<ast::Pat>| Some(x)
     );
     // `parse_item` returns `Option<ptr::P<ast::Item>>`.
     parse_macro_arg!(
         Item,
-        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
+        NonterminalKind::Item,
+        |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No),
         |x: Option<ptr::P<ast::Item>>| x
     );
 
diff --git a/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs b/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs
new file mode 100644
index 00000000000..3db2c26ab5a
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/macros/rewrite-const-item.rs
@@ -0,0 +1 @@
+m!(const N: usize = 0;);
diff --git a/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs b/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs
new file mode 100644
index 00000000000..f7ebaf78277
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/macros/rewrite-const-item.rs
@@ -0,0 +1,3 @@
+m!(
+    const N: usize = 0;
+);
diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs
index e13dfbacd24..376b18c15b8 100644
--- a/tests/ui/const-generics/bad-subst-const-kind.rs
+++ b/tests/ui/const-generics/bad-subst-const-kind.rs
@@ -11,3 +11,4 @@ impl<const N: u64> Q for [u8; N] {
 }
 
 pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
+//~^ ERROR: the constant `13` is not of type `u64`
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
index 6f5bc567c37..c04a05573be 100644
--- a/tests/ui/const-generics/bad-subst-const-kind.stderr
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -1,9 +1,23 @@
+error: the constant `13` is not of type `u64`
+  --> $DIR/bad-subst-const-kind.rs:13:24
+   |
+LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
+   |                        ^^^^^^^^ expected `u64`, found `usize`
+   |
+note: required for `[u8; 13]` to implement `Q`
+  --> $DIR/bad-subst-const-kind.rs:8:20
+   |
+LL | impl<const N: u64> Q for [u8; N] {
+   |      ------------  ^     ^^^^^^^
+   |      |
+   |      unsatisfied trait bound introduced here
+
 error[E0308]: mismatched types
   --> $DIR/bad-subst-const-kind.rs:8:31
    |
 LL | impl<const N: u64> Q for [u8; N] {
    |                               ^ expected `usize`, found `u64`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
index 5813f098184..6b0d9e047db 100644
--- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
@@ -7,7 +7,10 @@ trait Q {
 
 impl<const N: u64> Q for [u8; N] {}
 //~^ ERROR not all trait items implemented
+//~| ERROR mismatched types
 
 pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
+//~^ ERROR the constant `13` is not of type `u64`
+//~| ERROR mismatched types
 
 pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
index c73d1022ed3..bb6d650b7ab 100644
--- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
@@ -7,6 +7,35 @@ LL |     const ASSOC: usize;
 LL | impl<const N: u64> Q for [u8; N] {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation
 
-error: aborting due to 1 previous error
+error: the constant `13` is not of type `u64`
+  --> $DIR/type_mismatch.rs:12:26
+   |
+LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
+   |                          ^^^^^^^^ expected `u64`, found `usize`
+   |
+note: required for `[u8; 13]` to implement `Q`
+  --> $DIR/type_mismatch.rs:8:20
+   |
+LL | impl<const N: u64> Q for [u8; N] {}
+   |      ------------  ^     ^^^^^^^
+   |      |
+   |      unsatisfied trait bound introduced here
+
+error[E0308]: mismatched types
+  --> $DIR/type_mismatch.rs:12:20
+   |
+LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
+   |        ------      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()`
+   |        |
+   |        implicitly returns `()` as its body has no tail or `return` expression
+
+error[E0308]: mismatched types
+  --> $DIR/type_mismatch.rs:8:31
+   |
+LL | impl<const N: u64> Q for [u8; N] {}
+   |                               ^ expected `usize`, found `u64`
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0046`.
+Some errors have detailed explanations: E0046, E0308.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/feature-gates/feature-gate-feature-gate.stderr b/tests/ui/feature-gates/feature-gate-feature-gate.stderr
index 8ff99ddbe21..6ca6c04e401 100644
--- a/tests/ui/feature-gates/feature-gate-feature-gate.stderr
+++ b/tests/ui/feature-gates/feature-gate-feature-gate.stderr
@@ -1,4 +1,4 @@
-error: unstable feature
+error: use of an unstable feature
   --> $DIR/feature-gate-feature-gate.rs:2:12
    |
 LL | #![feature(intrinsics)]
diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
index 20a8d754996..1ad335bf394 100644
--- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
+++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -160,3 +160,23 @@ fn main() {
             | (y, x) => {} //~ ERROR unreachable
     }
 }
+
+fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
+//~^ ERROR unreachable
+
+fn unreachable_in_binding() {
+    let bool_pair = (true, true);
+    let bool_option = Some(true);
+
+    let (_ | (_, _)) = bool_pair;
+    //~^ ERROR unreachable
+    for (_ | (_, _)) in [bool_pair] {}
+    //~^ ERROR unreachable
+
+    let (Some(_) | Some(true)) = bool_option else { return };
+    //~^ ERROR unreachable
+    if let Some(_) | Some(true) = bool_option {}
+    //~^ ERROR unreachable
+    while let Some(_) | Some(true) = bool_option {}
+    //~^ ERROR unreachable
+}
diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
index 3616dda9981..336530d1b32 100644
--- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
+++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -184,5 +184,41 @@ error: unreachable pattern
 LL |             | (y, x) => {}
    |               ^^^^^^
 
-error: aborting due to 29 previous errors
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:164:30
+   |
+LL | fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
+   |                              ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:171:14
+   |
+LL |     let (_ | (_, _)) = bool_pair;
+   |              ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:173:14
+   |
+LL |     for (_ | (_, _)) in [bool_pair] {}
+   |              ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:176:20
+   |
+LL |     let (Some(_) | Some(true)) = bool_option else { return };
+   |                    ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:178:22
+   |
+LL |     if let Some(_) | Some(true) = bool_option {}
+   |                      ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:180:25
+   |
+LL |     while let Some(_) | Some(true) = bool_option {}
+   |                         ^^^^^^^^^^
+
+error: aborting due to 35 previous errors
 
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
new file mode 100644
index 00000000000..fe2a72d2a31
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
@@ -0,0 +1,44 @@
+error: unreachable pattern
+  --> $DIR/unreachable.rs:17:9
+   |
+LL |         Err(!),
+   |         ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:7:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:20:19
+   |
+LL |     let (Ok(_x) | Err(!)) = res_void;
+   |                   ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:22:12
+   |
+LL |     if let Err(!) = res_void {}
+   |            ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:24:24
+   |
+LL |     if let (Ok(true) | Err(!)) = res_void {}
+   |                        ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:26:23
+   |
+LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
+   |                       ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:30:18
+   |
+LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+   |                  ^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
new file mode 100644
index 00000000000..df8e22abf62
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
@@ -0,0 +1,31 @@
+// revisions: normal exh_pats
+//[normal] check-pass
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+#![cfg_attr(exh_pats, feature(exhaustive_patterns))]
+#![allow(dead_code, unreachable_code)]
+#![deny(unreachable_patterns)]
+
+#[derive(Copy, Clone)]
+enum Void {}
+
+fn main() {
+    let res_void: Result<bool, Void> = Ok(true);
+
+    match res_void {
+        Ok(_x) => {}
+        Err(!),
+        //[exh_pats]~^ ERROR unreachable
+    }
+    let (Ok(_x) | Err(!)) = res_void;
+    //[exh_pats]~^ ERROR unreachable
+    if let Err(!) = res_void {}
+    //[exh_pats]~^ ERROR unreachable
+    if let (Ok(true) | Err(!)) = res_void {}
+    //[exh_pats]~^ ERROR unreachable
+    for (Ok(mut _x) | Err(!)) in [res_void] {}
+    //[exh_pats]~^ ERROR unreachable
+}
+
+fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+//[exh_pats]~^ ERROR unreachable
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
index 5fd7c647c25..8ceecd801d3 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
@@ -8,5 +8,6 @@ struct S<const L: usize>;
 impl<const N: i32> Copy for S<N> {}
 //~^ ERROR the constant `N` is not of type `usize`
 impl<const M: usize> Copy for S<M> {}
+//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`
 
 fn main() {}
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
index def4a413af1..3268a876733 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
@@ -1,14 +1,29 @@
+error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
+   |
+LL | impl<const N: i32> Copy for S<N> {}
+   | -------------------------------- first implementation here
+LL |
+LL | impl<const M: usize> Copy for S<M> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
+
 error: the constant `N` is not of type `usize`
   --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
    |
 LL | impl<const N: i32> Copy for S<N> {}
    |                             ^^^^ expected `usize`, found `i32`
    |
-note: required by a bound in `S`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
+note: required for `S<N>` to implement `Clone`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:5:10
    |
+LL | #[derive(Clone)]
+   |          ^^^^^
 LL | struct S<const L: usize>;
-   |          ^^^^^^^^^^^^^^ required by this bound in `S`
+   |          ----- unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `Copy`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
index f48c3d124dd..dbdfde6dd50 100644
--- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
@@ -8,16 +8,18 @@ trait A: Sized {
     //~| ERROR the trait `A` cannot be made into an object
 }
 trait B {
-    fn f(a: B) -> B;
+    fn f(b: B) -> B;
     //~^ ERROR trait objects must include the `dyn` keyword
     //~| ERROR trait objects must include the `dyn` keyword
     //~| ERROR associated item referring to unboxed trait object for its own trait
     //~| ERROR the trait `B` cannot be made into an object
 }
 trait C {
-    fn f(&self, a: C) -> C;
+    fn f(&self, c: C) -> C;
     //~^ ERROR trait objects must include the `dyn` keyword
     //~| ERROR trait objects must include the `dyn` keyword
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `C` cannot be made into an object
 }
 
 fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
index 73d5a24f831..60eb72ab4f7 100644
--- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
@@ -30,18 +30,18 @@ error: associated item referring to unboxed trait object for its own trait
    |
 LL | trait B {
    |       - in this trait
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^     ^
    |
 help: you might have meant to use `Self` to refer to the implementing type
    |
-LL |     fn f(a: Self) -> Self;
+LL |     fn f(b: Self) -> Self;
    |             ~~~~     ~~~~
 
 error[E0038]: the trait `B` cannot be made into an object
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^ `B` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
@@ -49,23 +49,53 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | trait B {
    |       - this trait cannot be made into an object...
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |        ^ ...because associated function `f` has no `self` parameter
 help: consider turning `f` into a method by giving it a `&self` argument
    |
-LL |     fn f(&self, a: B) -> B;
+LL |     fn f(&self, b: B) -> B;
    |          ++++++
 help: alternatively, consider constraining `f` so it does not apply to trait objects
    |
-LL |     fn f(a: B) -> B where Self: Sized;
+LL |     fn f(b: B) -> B where Self: Sized;
    |                     +++++++++++++++++
 
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
+   |
+LL | trait C {
+   |       - in this trait
+LL |     fn f(&self, c: C) -> C;
+   |                    ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(&self, c: Self) -> Self;
+   |                    ~~~~     ~~~~
+
+error[E0038]: the trait `C` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
+   |
+LL |     fn f(&self, c: C) -> C;
+   |          -----     ^ `C` cannot be made into an object
+   |          |
+   |          help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self`
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10
+   |
+LL | trait C {
+   |       - this trait cannot be made into an object...
+LL |     fn f(&self, c: C) -> C;
+   |          ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on
+
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
    |
 LL |     fn f(a: A) -> A;
    |             ^
    |
+   = note: `A` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `A`
    |
 LL |     fn f<T: A>(a: T) -> A;
@@ -74,10 +104,6 @@ help: you can also use an opaque type, but users won't be able to specify the ty
    |
 LL |     fn f(a: impl A) -> A;
    |             ++++
-help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(a: &dyn A) -> A;
-   |             ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
@@ -85,84 +111,66 @@ error[E0782]: trait objects must include the `dyn` keyword
 LL |     fn f(a: A) -> A;
    |                   ^
    |
-help: use `impl A` to return an opaque type, as long as you return a single underlying type
+help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type
    |
 LL |     fn f(a: A) -> impl A;
    |                   ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(a: A) -> Box<dyn A>;
-   |                   +++++++  +
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^
    |
+   = note: `B` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `B`
    |
-LL |     fn f<T: B>(a: T) -> B;
+LL |     fn f<T: B>(b: T) -> B;
    |         ++++++    ~
 help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
    |
-LL |     fn f(a: impl B) -> B;
-   |             ++++
-help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(a: &dyn B) -> B;
+LL |     fn f(b: impl B) -> B;
    |             ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |                   ^
    |
-help: use `impl B` to return an opaque type, as long as you return a single underlying type
+help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type
    |
-LL |     fn f(a: B) -> impl B;
+LL |     fn f(b: B) -> impl B;
    |                   ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(a: B) -> Box<dyn B>;
-   |                   +++++++  +
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
    |
-LL |     fn f(&self, a: C) -> C;
+LL |     fn f(&self, c: C) -> C;
    |                    ^
    |
+   = note: `C` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `C`
    |
-LL |     fn f<T: C>(&self, a: T) -> C;
+LL |     fn f<T: C>(&self, c: T) -> C;
    |         ++++++           ~
 help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
    |
-LL |     fn f(&self, a: impl C) -> C;
-   |                    ++++
-help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(&self, a: &dyn C) -> C;
+LL |     fn f(&self, c: impl C) -> C;
    |                    ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26
    |
-LL |     fn f(&self, a: C) -> C;
+LL |     fn f(&self, c: C) -> C;
    |                          ^
    |
-help: use `impl C` to return an opaque type, as long as you return a single underlying type
+help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type
    |
-LL |     fn f(&self, a: C) -> impl C;
+LL |     fn f(&self, c: C) -> impl C;
    |                          ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(&self, a: C) -> Box<dyn C>;
-   |                          +++++++  +
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0038, E0782.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/unsafe/union_destructure.rs b/tests/ui/unsafe/union_destructure.rs
index d0cf8640eaa..bb75dbf0997 100644
--- a/tests/ui/unsafe/union_destructure.rs
+++ b/tests/ui/unsafe/union_destructure.rs
@@ -1,4 +1,5 @@
 // run-pass
+#![allow(unreachable_patterns)]
 
 #[derive(Copy, Clone)]
 #[allow(dead_code)]