diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 1b76a5f3234a2..40dc75339efd7 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -277,6 +277,8 @@ pub(crate) fn expand_test_or_bench(
                 cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
                 // #[rustc_test_marker = "test_case_sort_key"]
                 cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
+                // #[doc(hidden)]
+                cx.attr_nested_word(sym::doc, sym::hidden, attr_sp),
             ],
             // const $ident: test::TestDescAndFn =
             ast::ItemKind::Const(
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index a694d3b8c2857..400557ca260b2 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -326,8 +326,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let main_attr = ecx.attr_word(sym::rustc_main, sp);
     // #[coverage(off)]
     let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp);
-    // #[allow(missing_docs)]
-    let missing_docs_attr = ecx.attr_nested_word(sym::allow, sym::missing_docs, sp);
+    // #[doc(hidden)]
+    let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp);
 
     // pub fn main() { ... }
     let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
@@ -357,7 +357,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let main = P(ast::Item {
         ident: main_id,
-        attrs: thin_vec![main_attr, coverage_attr, missing_docs_attr],
+        attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr],
         id: ast::DUMMY_NODE_ID,
         kind: main,
         vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index afaa4a1ac6d8b..bf8ed017cf703 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             {
                 // check that the `if` expr without `else` is the fn body's expr
                 if expr.span == sp {
-                    return self.get_fn_decl(hir_id).map(|(_, fn_decl, _)| {
+                    return self.get_fn_decl(hir_id).map(|(_, fn_decl)| {
                         let (ty, span) = match fn_decl.output {
                             hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span),
                             hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span),
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index d97c590bd4109..3bada1de148b1 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1860,10 +1860,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         };
 
         // If this is due to an explicit `return`, suggest adding a return type.
-        if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id)
+        if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id)
             && !due_to_block
         {
-            fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
+            fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id);
         }
 
         // If this is due to a block, then maybe we forgot a `return`/`break`.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 9bad5633b69dc..80a179fce03bc 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.ret_coercion_span.set(Some(expr.span));
             }
             let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
-            if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
+            if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) {
                 coercion.coerce_forced_unit(
                     self,
                     &cause,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 19f7950287f93..178dc47aa1f23 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -30,7 +30,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::kw;
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
@@ -859,38 +859,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
-    /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
-    /// suggestion can be made, `None` otherwise.
+    /// Given a `HirId`, return the `HirId` of the enclosing function and its `FnDecl`.
     pub(crate) fn get_fn_decl(
         &self,
         blk_id: HirId,
-    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
+    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
         self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
             match self.tcx.hir_node(item_id) {
                 Node::Item(&hir::Item {
-                    ident,
-                    kind: hir::ItemKind::Fn(ref sig, ..),
-                    owner_id,
-                    ..
-                }) => {
-                    // This is less than ideal, it will not suggest a return type span on any
-                    // method called `main`, regardless of whether it is actually the entry point,
-                    // but it will still present it as the reason for the expected type.
-                    Some((owner_id.def_id, sig.decl, ident.name != sym::main))
-                }
+                    kind: hir::ItemKind::Fn(ref sig, ..), owner_id, ..
+                }) => Some((owner_id.def_id, sig.decl)),
                 Node::TraitItem(&hir::TraitItem {
                     kind: hir::TraitItemKind::Fn(ref sig, ..),
                     owner_id,
                     ..
-                }) => Some((owner_id.def_id, sig.decl, true)),
-                // FIXME: Suggestable if this is not a trait implementation
+                }) => Some((owner_id.def_id, sig.decl)),
                 Node::ImplItem(&hir::ImplItem {
                     kind: hir::ImplItemKind::Fn(ref sig, ..),
                     owner_id,
                     ..
-                }) => Some((owner_id.def_id, sig.decl, false)),
+                }) => Some((owner_id.def_id, sig.decl)),
                 Node::Expr(&hir::Expr {
                     hir_id,
                     kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
@@ -901,33 +891,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // FIXME(async_closures): Implement this.
                             return None;
                         }
-                        hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
+                        hir::ClosureKind::Closure => Some((def_id, fn_decl)),
                         hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                             _,
                             hir::CoroutineSource::Fn,
                         )) => {
-                            let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
+                            let (sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
                                 Node::Item(&hir::Item {
-                                    ident,
                                     kind: hir::ItemKind::Fn(ref sig, ..),
                                     owner_id,
                                     ..
-                                }) => (ident, sig, owner_id),
+                                }) => (sig, owner_id),
                                 Node::TraitItem(&hir::TraitItem {
-                                    ident,
                                     kind: hir::TraitItemKind::Fn(ref sig, ..),
                                     owner_id,
                                     ..
-                                }) => (ident, sig, owner_id),
+                                }) => (sig, owner_id),
                                 Node::ImplItem(&hir::ImplItem {
-                                    ident,
                                     kind: hir::ImplItemKind::Fn(ref sig, ..),
                                     owner_id,
                                     ..
-                                }) => (ident, sig, owner_id),
+                                }) => (sig, owner_id),
                                 _ => return None,
                             };
-                            Some((owner_id.def_id, sig.decl, ident.name != sym::main))
+                            Some((owner_id.def_id, sig.decl))
                         }
                         _ => None,
                     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index bdf84f332166d..15e3ba4ffc228 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1873,7 +1873,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // that highlight errors inline.
                     let mut sp = blk.span;
                     let mut fn_span = None;
-                    if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
+                    if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) {
                         let ret_sp = decl.output.span();
                         if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
                             // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 4454703645e79..ecdd14b1f605a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -79,9 +79,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // `break` type mismatches provide better context for tail `loop` expressions.
             return false;
         }
-        if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+        if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
             pointing_at_return_type =
-                self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id);
+                self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
             self.suggest_missing_break_or_return_expr(
                 err, expr, fn_decl, expected, found, blk_id, fn_id,
             );
@@ -813,7 +813,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fn_decl: &hir::FnDecl<'tcx>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-        can_suggest: bool,
         fn_id: LocalDefId,
     ) -> bool {
         // Can't suggest `->` on a block-like coroutine
@@ -826,28 +825,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let found =
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
-        // haven't set a return type at all (and aren't `fn main()` or an impl).
+        // haven't set a return type at all (and aren't `fn main()`, impl or closure).
         match &fn_decl.output {
-            &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
-                // `fn main()` must return `()`, do not suggest changing return type
-                err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
-                return true;
-            }
+            // For closure with default returns, don't suggest adding return type
+            &hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {}
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
-                if let Some(found) = found.make_suggestable(self.tcx, false, None) {
+                if !self.can_add_return_type(fn_id) {
+                    err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
+                } else if let Some(found) = found.make_suggestable(self.tcx, false, None) {
                     err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
                         span,
                         found: found.to_string(),
                     });
-                    return true;
                 } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
                     err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
-                    return true;
                 } else {
                     // FIXME: if `found` could be `impl Iterator` we should suggest that.
                     err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
-                    return true;
                 }
+
+                return true;
             }
             hir::FnRetTy::Return(hir_ty) => {
                 if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
@@ -905,6 +902,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    /// Checks whether we can add a return type to a function.
+    /// Assumes given function doesn't have a explicit return type.
+    fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
+        match self.tcx.hir_node_by_def_id(fn_id) {
+            Node::Item(&hir::Item { ident, .. }) => {
+                // This is less than ideal, it will not suggest a return type span on any
+                // method called `main`, regardless of whether it is actually the entry point,
+                // but it will still present it as the reason for the expected type.
+                ident.name != sym::main
+            }
+            Node::ImplItem(item) => {
+                // If it doesn't impl a trait, we can add a return type
+                let Node::Item(&hir::Item {
+                    kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
+                    ..
+                }) = self.tcx.parent_hir_node(item.hir_id())
+                else {
+                    unreachable!();
+                };
+
+                of_trait.is_none()
+            }
+            _ => true,
+        }
+    }
+
     fn try_note_caller_chooses_ty_for_ty_param(
         &self,
         diag: &mut Diag<'_>,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index caf09c1177fd3..e2c1eef837f29 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -43,7 +43,7 @@ pub use coercion::can_coerce;
 use fn_ctxt::FnCtxt;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
@@ -423,6 +423,36 @@ fn report_unexpected_variant_res(
             err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
             err
         }
+        Res::Def(DefKind::Variant, _) if expr.is_none() => {
+            err.span_label(span, format!("not a {expected}"));
+
+            let fields = &tcx.expect_variant_res(res).fields.raw;
+            let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi());
+            let (msg, sugg) = if fields.is_empty() {
+                ("use the struct variant pattern syntax".to_string(), " {}".to_string())
+            } else {
+                let msg = format!(
+                    "the struct variant's field{s} {are} being ignored",
+                    s = pluralize!(fields.len()),
+                    are = pluralize!("is", fields.len())
+                );
+                let fields = fields
+                    .iter()
+                    .map(|field| format!("{}: _", field.name.to_ident_string()))
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                let sugg = format!(" {{ {} }}", fields);
+                (msg, sugg)
+            };
+
+            err.span_suggestion_verbose(
+                qpath.span().shrink_to_hi().to(span.shrink_to_hi()),
+                msg,
+                sugg,
+                Applicability::HasPlaceholders,
+            );
+            err
+        }
         _ => err.with_span_label(span, format!("not a {expected}")),
     }
     .emit()
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 14ad5830111b4..178d5dce08643 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1317,7 +1317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
                 info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
                 let mut long_ty_file = None;
-                let (primary_message, label) = if unimplemented_traits.len() == 1
+                let (primary_message, label, notes) = if unimplemented_traits.len() == 1
                     && unimplemented_traits_only
                 {
                     unimplemented_traits
@@ -1327,16 +1327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
                             {
                                 // Avoid crashing.
-                                return (None, None);
+                                return (None, None, Vec::new());
                             }
-                            let OnUnimplementedNote { message, label, .. } = self
+                            let OnUnimplementedNote { message, label, notes, .. } = self
                                 .err_ctxt()
                                 .on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
-                            (message, label)
+                            (message, label, notes)
                         })
                         .unwrap()
                 } else {
-                    (None, None)
+                    (None, None, Vec::new())
                 };
                 let primary_message = primary_message.unwrap_or_else(|| {
                     format!(
@@ -1363,6 +1363,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "the following trait bounds were not satisfied:\n{bound_list}"
                     ));
                 }
+                for note in notes {
+                    err.note(note);
+                }
+
                 suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
 
                 unsatisfied_bounds = true;
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index d65b1b8b3f15a..b212f6afa1717 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -96,7 +96,7 @@ impl SearchPath {
         Self::new(PathKind::All, make_target_lib_path(sysroot, triple))
     }
 
-    fn new(kind: PathKind, dir: PathBuf) -> Self {
+    pub fn new(kind: PathKind, dir: PathBuf) -> Self {
         // Get the files within the directory.
         let files = match std::fs::read_dir(&dir) {
             Ok(files) => files
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d5240a05310b6..28d18f2dfcc15 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1236,7 +1236,6 @@ symbols! {
         mir_unwind_unreachable,
         mir_variant,
         miri,
-        missing_docs,
         mmx_reg,
         modifiers,
         module,
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 3b04412e76630..21bebff96b956 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -79,41 +79,49 @@
 //! see each type's documentation, and note that the names of actual methods may
 //! differ from the tables below on certain collections.
 //!
-//! Throughout the documentation, we will follow a few conventions. For all
-//! operations, the collection's size is denoted by n. If another collection is
-//! involved in the operation, it contains m elements. Operations which have an
-//! *amortized* cost are suffixed with a `*`. Operations with an *expected*
-//! cost are suffixed with a `~`.
+//! Throughout the documentation, we will adhere to the following conventions
+//! for operation notation:
 //!
-//! All amortized costs are for the potential need to resize when capacity is
-//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
-//! automatically shrink, so removal operations aren't amortized. Over a
-//! sufficiently large series of operations, the average cost per operation will
-//! deterministically equal the given cost.
+//! * The collection's size is denoted by `n`.
+//! * If a second collection is involved, its size is denoted by `m`.
+//! * Item indices are denoted by `i`.
+//! * Operations which have an *amortized* cost are suffixed with a `*`.
+//! * Operations with an *expected* cost are suffixed with a `~`.
 //!
-//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing.
-//! It is theoretically possible, though very unlikely, for [`HashMap`] to
-//! experience worse performance.
+//! Calling operations that add to a collection will occasionally require a
+//! collection to be resized - an extra operation that takes *O*(*n*) time.
 //!
-//! ## Sequences
+//! *Amortized* costs are calculated to account for the time cost of such resize
+//! operations *over a sufficiently large series of operations*. An individual
+//! operation may be slower or faster due to the sporadic nature of collection
+//! resizing, however the average cost per operation will approach the amortized
+//! cost.
 //!
-//! |                | get(i)                 | insert(i)               | remove(i)              | append    | split_off(i)           |
-//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------|
-//! | [`Vec`]        | *O*(1)                 | *O*(*n*-*i*)*           | *O*(*n*-*i*)           | *O*(*m*)* | *O*(*n*-*i*)           |
-//! | [`VecDeque`]   | *O*(1)                 | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) |
-//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*))  | *O*(min(*i*, *n*-*i*)) | *O*(1)    | *O*(min(*i*, *n*-*i*)) |
+//! Rust's collections never automatically shrink, so removal operations aren't
+//! amortized.
 //!
-//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
-//! [`VecDeque`] is generally going to be faster than [`LinkedList`].
+//! [`HashMap`] uses *expected* costs. It is theoretically possible, though very
+//! unlikely, for [`HashMap`] to experience significantly worse performance than
+//! the expected cost. This is due to the probabilistic nature of hashing - i.e.
+//! it is possible to generate a duplicate hash given some input key that will
+//! requires extra computation to correct.
 //!
-//! ## Maps
+//! ## Cost of Collection Operations
 //!
-//! For Sets, all operations have the cost of the equivalent Map operation.
 //!
-//! |              | get           | insert        | remove        | range         | append       |
-//! |--------------|---------------|---------------|---------------|---------------|--------------|
-//! | [`HashMap`]  | *O*(1)~       | *O*(1)~*      | *O*(1)~       | N/A           | N/A          |
-//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) |
+//! |                | get(i)                 | insert(i)               | remove(i)              | append(Vec(m))    | split_off(i)           | range           | append       |
+//! |----------------|------------------------|-------------------------|------------------------|-------------------|------------------------|-----------------|--------------|
+//! | [`Vec`]        | *O*(1)                 | *O*(*n*-*i*)*           | *O*(*n*-*i*)           | *O*(*m*)*         | *O*(*n*-*i*)           | N/A             | N/A          |
+//! | [`VecDeque`]   | *O*(1)                 | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)*         | *O*(min(*i*, *n*-*i*)) | N/A             | N/A          |
+//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*))  | *O*(min(*i*, *n*-*i*)) | *O*(1)            | *O*(min(*i*, *n*-*i*)) | N/A             | N/A          |
+//! | [`HashMap`]    | *O*(1)~                | *O*(1)~*                | *O*(1)~                | N/A               | N/A                    | N/A             | N/A          |
+//! | [`BTreeMap`]   | *O*(log(*n*))          | *O*(log(*n*))           | *O*(log(*n*))          | N/A               | N/A                    | *O*(log(*n*))   | *O*(*n*+*m*) |
+//!
+//! Note that where ties occur, [`Vec`] is generally going to be faster than
+//! [`VecDeque`], and [`VecDeque`] is generally going to be faster than
+//! [`LinkedList`].
+//!
+//! For Sets, all operations have the cost of the equivalent Map operation.
 //!
 //! # Correct and Efficient Usage of Collections
 //!
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 1cc9a2b7ffa98..f5ed3e4628e1f 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -122,6 +122,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
         c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
         c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
+        c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop,
         _ => {}
     }
 
@@ -139,6 +140,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::WSAEHOSTUNREACH => HostUnreachable,
         c::WSAENETDOWN => NetworkDown,
         c::WSAENETUNREACH => NetworkUnreachable,
+        c::WSAEDQUOT => FilesystemQuotaExceeded,
 
         _ => Uncategorized,
     }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 102c9fd255432..bb07d478f71aa 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -15,6 +15,7 @@ use std::path::{Path, PathBuf};
 use std::process::Stdio;
 use std::{env, fs, str};
 
+use build_helper::git::get_closest_merge_commit;
 use serde_derive::Deserialize;
 
 use crate::core::build_steps::tool::SourceType;
@@ -26,8 +27,7 @@ use crate::core::builder::{
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
 use crate::utils::exec::command;
 use crate::utils::helpers::{
-    self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
-    symlink_dir, t, up_to_date,
+    self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
 
@@ -127,13 +127,9 @@ impl Step for Std {
         // the `rust.download-rustc=true` option.
         let force_recompile =
             if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
-                let closest_merge_commit = get_closest_merge_base_commit(
-                    Some(&builder.src),
-                    &builder.config.git_config(),
-                    &builder.config.stage0_metadata.config.git_merge_commit_email,
-                    &[],
-                )
-                .unwrap();
+                let closest_merge_commit =
+                    get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
+                        .unwrap();
 
                 // Check if `library` has changes (returns false otherwise)
                 !t!(helpers::git(Some(&builder.src))
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 91fbc57429a96..bbd81fb570bd5 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -200,6 +200,11 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
                 adjective = Some("modified");
                 match get_modified_rs_files(build) {
                     Ok(Some(files)) => {
+                        if files.is_empty() {
+                            println!("fmt info: No modified files detected for formatting.");
+                            return;
+                        }
+
                         for file in files {
                             override_builder.add(&format!("/{file}")).expect(&file);
                         }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 442638d32034b..94b03b1b1386b 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -16,6 +16,7 @@ use std::sync::OnceLock;
 use std::{env, io};
 
 use build_helper::ci::CiEnv;
+use build_helper::git::get_closest_merge_commit;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
@@ -153,10 +154,9 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
 /// This retrieves the LLVM sha we *want* to use, according to git history.
 pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
     let llvm_sha = if is_git {
-        helpers::get_closest_merge_base_commit(
+        get_closest_merge_commit(
             Some(&config.src),
             &config.git_config(),
-            &config.stage0_metadata.config.git_merge_commit_email,
             &[
                 config.src.join("src/llvm-project"),
                 config.src.join("src/bootstrap/download-ci-llvm-stamp"),
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index 8aaffab514d88..ba9b1b2fc3317 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -17,6 +17,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
         .tool_cmd(Tool::SuggestTests)
         .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
         .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
+        .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
         .run_capture_stdout(builder)
         .stdout();
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 83f65615c8ded..a7e9352bb1c4c 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2098,6 +2098,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let git_config = builder.config.git_config();
         cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
+        cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
         cmd.force_coloring_in_ci();
 
         #[cfg(feature = "build-metrics")]
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 3c2d791c2090e..a437f829ba5a6 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,6 +1,8 @@
 use std::path::PathBuf;
 use std::{env, fs};
 
+use build_helper::git::get_closest_merge_commit;
+
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
 use crate::core::builder;
@@ -8,7 +10,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
 use crate::utils::exec::{command, BootstrapCommand};
-use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t};
+use crate::utils::helpers::{add_dylib_path, exe, git, t};
 use crate::{gha, Compiler, Kind, Mode};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -576,10 +578,9 @@ impl Step for Rustdoc {
             && target_compiler.stage > 0
             && builder.rust_info().is_managed_git_subrepository()
         {
-            let commit = get_closest_merge_base_commit(
+            let commit = get_closest_merge_commit(
                 Some(&builder.config.src),
                 &builder.config.git_config(),
-                &builder.config.stage0_metadata.config.git_merge_commit_email,
                 &[],
             )
             .unwrap();
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index f509712730dee..9271e809853b7 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -14,7 +14,7 @@ use std::sync::OnceLock;
 use std::{cmp, env, fs};
 
 use build_helper::exit;
-use build_helper::git::{output_result, GitConfig};
+use build_helper::git::{get_closest_merge_commit, output_result, GitConfig};
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
 
@@ -24,7 +24,7 @@ pub use crate::core::config::flags::Subcommand;
 use crate::core::config::flags::{Color, Flags, Warnings};
 use crate::utils::cache::{Interned, INTERNER};
 use crate::utils::channel::{self, GitInfo};
-use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
+use crate::utils::helpers::{self, exe, output, t};
 
 macro_rules! check_ci_llvm {
     ($name:expr) => {
@@ -2512,6 +2512,7 @@ impl Config {
         GitConfig {
             git_repository: &self.stage0_metadata.config.git_repository,
             nightly_branch: &self.stage0_metadata.config.nightly_branch,
+            git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email,
         }
     }
 
@@ -2688,13 +2689,7 @@ impl Config {
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let commit = get_closest_merge_base_commit(
-            Some(&self.src),
-            &self.git_config(),
-            &self.stage0_metadata.config.git_merge_commit_email,
-            &[],
-        )
-        .unwrap();
+        let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
         if commit.is_empty() {
             println!("ERROR: could not find commit hash for downloading rustc");
             println!("HELP: maybe your repository history is too shallow?");
@@ -2786,13 +2781,7 @@ impl Config {
     ) -> Option<String> {
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let commit = get_closest_merge_base_commit(
-            Some(&self.src),
-            &self.git_config(),
-            &self.stage0_metadata.config.git_merge_commit_email,
-            &[],
-        )
-        .unwrap();
+        let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
         if commit.is_empty() {
             println!("error: could not find commit hash for downloading components from CI");
             println!("help: maybe your repository history is too shallow?");
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index a856c99ff55a5..beb3c5fb09842 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -10,7 +10,6 @@ use std::sync::OnceLock;
 use std::time::{Instant, SystemTime, UNIX_EPOCH};
 use std::{env, fs, io, str};
 
-use build_helper::git::{get_git_merge_base, output_result, GitConfig};
 use build_helper::util::fail;
 
 use crate::core::builder::Builder;
@@ -523,28 +522,6 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
     git
 }
 
-/// Returns the closest commit available from upstream for the given `author` and `target_paths`.
-///
-/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD.
-pub fn get_closest_merge_base_commit(
-    source_dir: Option<&Path>,
-    config: &GitConfig<'_>,
-    author: &str,
-    target_paths: &[PathBuf],
-) -> Result<String, String> {
-    let mut git = git(source_dir);
-
-    let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
-
-    git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
-
-    if !target_paths.is_empty() {
-        git.arg("--").args(target_paths);
-    }
-
-    Ok(output_result(git.as_command_mut())?.trim().to_owned())
-}
-
 /// Sets the file times for a given file at `path`.
 pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
     // Windows requires file to be writable to modify file times. But on Linux CI the file does not
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index cc48a8964a372..15d863caf0c5f 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -1,9 +1,10 @@
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 
 pub struct GitConfig<'a> {
     pub git_repository: &'a str,
     pub nightly_branch: &'a str,
+    pub git_merge_commit_email: &'a str,
 }
 
 /// Runs a command and returns the output
@@ -95,7 +96,11 @@ pub fn updated_master_branch(
     Err("Cannot find any suitable upstream master branch".to_owned())
 }
 
-pub fn get_git_merge_base(
+/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state.
+/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`.
+/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote
+/// to be configured.
+fn git_upstream_merge_base(
     config: &GitConfig<'_>,
     git_dir: Option<&Path>,
 ) -> Result<String, String> {
@@ -107,6 +112,38 @@ pub fn get_git_merge_base(
     Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
 }
 
+/// Searches for the nearest merge commit in the repository that also exists upstream.
+///
+/// If it fails to find the upstream remote, it then looks for the most recent commit made
+/// by the merge bot by matching the author's email address with the merge bot's email.
+pub fn get_closest_merge_commit(
+    git_dir: Option<&Path>,
+    config: &GitConfig<'_>,
+    target_paths: &[PathBuf],
+) -> Result<String, String> {
+    let mut git = Command::new("git");
+
+    if let Some(git_dir) = git_dir {
+        git.current_dir(git_dir);
+    }
+
+    let merge_base = git_upstream_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into());
+
+    git.args([
+        "rev-list",
+        &format!("--author={}", config.git_merge_commit_email),
+        "-n1",
+        "--first-parent",
+        &merge_base,
+    ]);
+
+    if !target_paths.is_empty() {
+        git.arg("--").args(target_paths);
+    }
+
+    Ok(output_result(&mut git)?.trim().to_owned())
+}
+
 /// Returns the files that have been modified in the current branch compared to the master branch.
 /// The `extensions` parameter can be used to filter the files by their extension.
 /// Does not include removed files.
@@ -116,7 +153,7 @@ pub fn get_git_modified_files(
     git_dir: Option<&Path>,
     extensions: &[&str],
 ) -> Result<Option<Vec<String>>, String> {
-    let merge_base = get_git_merge_base(config, git_dir)?;
+    let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
 
     let mut git = Command::new("git");
     if let Some(git_dir) = git_dir {
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 773d795f75a72..5c18179b6fe2f 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -384,6 +384,7 @@ pub struct Config {
     // Needed both to construct build_helper::git::GitConfig
     pub git_repository: String,
     pub nightly_branch: String,
+    pub git_merge_commit_email: String,
 
     /// True if the profiler runtime is enabled for this target.
     /// Used by the "needs-profiler-support" header in test files.
@@ -461,7 +462,11 @@ impl Config {
     }
 
     pub fn git_config(&self) -> GitConfig<'_> {
-        GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch }
+        GitConfig {
+            git_repository: &self.git_repository,
+            nightly_branch: &self.nightly_branch,
+            git_merge_commit_email: &self.git_merge_commit_email,
+        }
     }
 }
 
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 29e11e77f1ce1..3a9a7eb911889 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -148,6 +148,7 @@ impl ConfigBuilder {
             self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
             "--git-repository=",
             "--nightly-branch=",
+            "--git-merge-commit-email=",
         ];
         let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
 
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 33687a3dad35b..5fe73a0e29729 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -163,7 +163,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optopt("", "edition", "default Rust edition", "EDITION")
         .reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
-        .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH");
+        .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
+        .reqopt(
+            "",
+            "git-merge-commit-email",
+            "email address used for finding merge commits",
+            "EMAIL",
+        );
 
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@@ -346,6 +352,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
         git_repository: matches.opt_str("git-repository").unwrap(),
         nightly_branch: matches.opt_str("nightly-branch").unwrap(),
+        git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
 
         profiler_support: matches.opt_present("profiler-support"),
     }
diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs
index 8e3625c244916..6f09bddcf60b8 100644
--- a/src/tools/suggest-tests/src/main.rs
+++ b/src/tools/suggest-tests/src/main.rs
@@ -8,6 +8,7 @@ fn main() -> ExitCode {
         &GitConfig {
             git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
             nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
+            git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"),
         },
         None,
         &Vec::new(),
diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp
index a4b15dde4530e..31449b51dc3e1 100644
--- a/tests/pretty/tests-are-sorted.pp
+++ b/tests/pretty/tests-are-sorted.pp
@@ -12,6 +12,7 @@
 extern crate test;
 #[cfg(test)]
 #[rustc_test_marker = "m_test"]
+#[doc(hidden)]
 pub const m_test: test::TestDescAndFn =
     test::TestDescAndFn {
         desc: test::TestDesc {
@@ -36,6 +37,7 @@
 extern crate test;
 #[cfg(test)]
 #[rustc_test_marker = "z_test"]
+#[doc(hidden)]
 pub const z_test: test::TestDescAndFn =
     test::TestDescAndFn {
         desc: test::TestDesc {
@@ -61,6 +63,7 @@
 extern crate test;
 #[cfg(test)]
 #[rustc_test_marker = "a_test"]
+#[doc(hidden)]
 pub const a_test: test::TestDescAndFn =
     test::TestDescAndFn {
         desc: test::TestDesc {
@@ -83,7 +86,7 @@
 fn a_test() {}
 #[rustc_main]
 #[coverage(off)]
-#[allow(missing_docs)]
+#[doc(hidden)]
 pub fn main() -> () {
     extern crate test;
     test::test_main_static(&[&a_test, &m_test, &z_test])
diff --git a/tests/ui/closures/add_semicolon_non_block_closure.rs b/tests/ui/closures/add_semicolon_non_block_closure.rs
index 62c5e343cd345..3ae91be60c5a0 100644
--- a/tests/ui/closures/add_semicolon_non_block_closure.rs
+++ b/tests/ui/closures/add_semicolon_non_block_closure.rs
@@ -8,5 +8,4 @@ fn main() {
     foo(|| bar())
     //~^ ERROR mismatched types [E0308]
     //~| HELP consider using a semicolon here
-    //~| HELP try adding a return type
 }
diff --git a/tests/ui/closures/add_semicolon_non_block_closure.stderr b/tests/ui/closures/add_semicolon_non_block_closure.stderr
index 7883db8f98ec5..3dd8f12d55f32 100644
--- a/tests/ui/closures/add_semicolon_non_block_closure.stderr
+++ b/tests/ui/closures/add_semicolon_non_block_closure.stderr
@@ -8,10 +8,6 @@ help: consider using a semicolon here
    |
 LL |     foo(|| { bar(); })
    |            +      +++
-help: try adding a return type
-   |
-LL |     foo(|| -> i32 bar())
-   |            ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/empty/empty-struct-braces-pat-1.stderr b/tests/ui/empty/empty-struct-braces-pat-1.stderr
index 14e09fc27a06d..c16fbc7de2b29 100644
--- a/tests/ui/empty/empty-struct-braces-pat-1.stderr
+++ b/tests/ui/empty/empty-struct-braces-pat-1.stderr
@@ -3,12 +3,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
    |
 LL |         E::Empty3 => ()
    |         ^^^^^^^^^ not a unit struct, unit variant or constant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         E::Empty3 {} => ()
+   |                   ++
 
 error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-1.rs:31:9
    |
 LL |         XE::XEmpty3 => ()
    |         ^^^^^^^^^^^ not a unit struct, unit variant or constant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         XE::XEmpty3 {} => ()
+   |                     ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/empty/empty-struct-braces-pat-3.stderr b/tests/ui/empty/empty-struct-braces-pat-3.stderr
index 00c8b12e6f984..b2ab7113347ff 100644
--- a/tests/ui/empty/empty-struct-braces-pat-3.stderr
+++ b/tests/ui/empty/empty-struct-braces-pat-3.stderr
@@ -3,24 +3,44 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::E
    |
 LL |         E::Empty3() => ()
    |         ^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         E::Empty3 {} => ()
+   |                   ~~
 
 error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:21:9
    |
 LL |         XE::XEmpty3() => ()
    |         ^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         XE::XEmpty3 {} => ()
+   |                     ~~
 
 error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
    |
 LL |         E::Empty3(..) => ()
    |         ^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         E::Empty3 {} => ()
+   |                   ~~
 
 error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:29:9
    |
 LL |         XE::XEmpty3(..) => ()
    |         ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |         XE::XEmpty3 {} => ()
+   |                     ~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-63983.stderr b/tests/ui/issues/issue-63983.stderr
index f90c81116264a..3539732451ce2 100644
--- a/tests/ui/issues/issue-63983.stderr
+++ b/tests/ui/issues/issue-63983.stderr
@@ -12,6 +12,11 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
    |
 LL |         MyEnum::Struct => "",
    |         ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
+   |
+help: the struct variant's field is being ignored
+   |
+LL |         MyEnum::Struct { s: _ } => "",
+   |                        ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/lint-missing-doc-test.rs b/tests/ui/lint/lint-missing-doc-test.rs
index 93d4e4a44e928..d86ec3525df36 100644
--- a/tests/ui/lint/lint-missing-doc-test.rs
+++ b/tests/ui/lint/lint-missing-doc-test.rs
@@ -2,4 +2,9 @@
 //! on the generated test harness.
 
 //@ check-pass
-//@ compile-flags: --test -Dmissing_docs
+//@ compile-flags: --test
+
+#![forbid(missing_docs)]
+
+#[test]
+fn test() {}
diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
index 69b20d57be829..0e1565e251adc 100644
--- a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
+++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
@@ -11,6 +11,7 @@ note: the method `to_string` exists on the type `&u8`
    = note: the following trait bounds were not satisfied:
            `*const u8: std::fmt::Display`
            which is required by `*const u8: ToString`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
 error[E0599]: `*mut u8` doesn't implement `std::fmt::Display`
   --> $DIR/suggest-convert-ptr-to-ref.rs:8:22
@@ -25,6 +26,7 @@ note: the method `to_string` exists on the type `&&mut u8`
    = note: the following trait bounds were not satisfied:
            `*mut u8: std::fmt::Display`
            which is required by `*mut u8: ToString`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
 error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope
   --> $DIR/suggest-convert-ptr-to-ref.rs:9:7
diff --git a/tests/ui/parser/recover/recover-from-bad-variant.stderr b/tests/ui/parser/recover/recover-from-bad-variant.stderr
index 04968bbdf999d..0339f86951543 100644
--- a/tests/ui/parser/recover/recover-from-bad-variant.stderr
+++ b/tests/ui/parser/recover/recover-from-bad-variant.stderr
@@ -19,6 +19,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum
    |
 LL |         Enum::Foo(a, b) => {}
    |         ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: the struct variant's fields are being ignored
+   |
+LL |         Enum::Foo { a: _, b: _ } => {}
+   |                   ~~~~~~~~~~~~~~
 
 error[E0769]: tuple variant `Enum::Bar` written as struct variant
   --> $DIR/recover-from-bad-variant.rs:12:9
diff --git a/tests/ui/suggestions/issue-84700.stderr b/tests/ui/suggestions/issue-84700.stderr
index ac9f5ab0b0cbb..d07055826606d 100644
--- a/tests/ui/suggestions/issue-84700.stderr
+++ b/tests/ui/suggestions/issue-84700.stderr
@@ -12,6 +12,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Farm
    |
 LL |         FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
    |         ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: the struct variant's field is being ignored
+   |
+LL |         FarmAnimal::Chicken { num_eggs: _ } => "cluck, cluck!".to_string(),
+   |                             ~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
index 35a06d396f2bb..f882a159f9834 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
@@ -3,7 +3,6 @@
 
 fn main() -> Result<(), ()> {
     a(|| {
-        //~^ HELP: try adding a return type
         b()
         //~^ ERROR: mismatched types [E0308]
         //~| NOTE: expected `()`, found `i32`
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
index 5506456afe9ca..939285498fb69 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
@@ -1,20 +1,13 @@
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
    |
 LL |         b()
-   |         ^^^ expected `()`, found `i32`
-   |
-help: consider using a semicolon here
-   |
-LL |         b();
-   |            +
-help: try adding a return type
-   |
-LL |     a(|| -> i32 {
-   |          ++++++
+   |         ^^^- help: consider using a semicolon here: `;`
+   |         |
+   |         expected `()`, found `i32`
 
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
    |
 LL | /     if true {
 LL | |
diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs b/tests/ui/traits/custom-on-unimplemented-diagnostic.rs
new file mode 100644
index 0000000000000..d7e257ef3bbe3
--- /dev/null
+++ b/tests/ui/traits/custom-on-unimplemented-diagnostic.rs
@@ -0,0 +1,19 @@
+#[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")]
+pub trait ProviderLt {}
+
+pub trait ProviderExt {
+    fn request<R>(&self) {
+        todo!()
+    }
+}
+
+impl<T: ?Sized + ProviderLt> ProviderExt for T {}
+
+struct B;
+
+fn main() {
+    B.request();
+    //~^ my message [E0599]
+    //~| my label
+    //~| my note
+}
diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr b/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr
new file mode 100644
index 0000000000000..f9788360d06ad
--- /dev/null
+++ b/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr
@@ -0,0 +1,32 @@
+error[E0599]: my message
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:15:7
+   |
+LL | struct B;
+   | -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt`
+...
+LL |     B.request();
+   |       ^^^^^^^ my label
+   |
+note: trait bound `B: ProviderLt` was not satisfied
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:10:18
+   |
+LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {}
+   |                  ^^^^^^^^^^  -----------     -
+   |                  |
+   |                  unsatisfied trait bound introduced here
+   = note: my note
+note: the trait `ProviderLt` must be implemented
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:2:1
+   |
+LL | pub trait ProviderLt {}
+   | ^^^^^^^^^^^^^^^^^^^^
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `ProviderExt` defines an item `request`, perhaps you need to implement it
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1
+   |
+LL | pub trait ProviderExt {
+   | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
index c21c59397c79e..714b4fd7d25f6 100644
--- a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
+++ b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
@@ -14,12 +14,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
    |
 LL |     let Alias::Braced = panic!();
    |         ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |     let Alias::Braced {} = panic!();
+   |                       ++
 
 error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9
    |
 LL |     let Alias::Braced(..) = panic!();
    |         ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |
+help: use the struct variant pattern syntax
+   |
+LL |     let Alias::Braced {} = panic!();
+   |                       ~~
 
 error[E0618]: expected function, found enum variant `Alias::Unit`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5
diff --git a/tests/ui/typeck/issue-81943.stderr b/tests/ui/typeck/issue-81943.stderr
index f8da9ef0d180f..041ff10752cf0 100644
--- a/tests/ui/typeck/issue-81943.stderr
+++ b/tests/ui/typeck/issue-81943.stderr
@@ -2,9 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:7:9
    |
 LL |   f(|x| lib::d!(x));
-   |        -^^^^^^^^^^ expected `()`, found `i32`
-   |        |
-   |        help: try adding a return type: `-> i32`
+   |         ^^^^^^^^^^ expected `()`, found `i32`
    |
    = note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -12,22 +10,28 @@ error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:8:28
    |
 LL |   f(|x| match x { tmp => { g(tmp) } });
-   |                            ^^^^^^ expected `()`, found `i32`
+   |         -------------------^^^^^^----
+   |         |                  |
+   |         |                  expected `()`, found `i32`
+   |         expected this to be `()`
    |
 help: consider using a semicolon here
    |
 LL |   f(|x| match x { tmp => { g(tmp); } });
    |                                  +
-help: try adding a return type
+help: consider using a semicolon here
    |
-LL |   f(|x| -> i32 match x { tmp => { g(tmp) } });
-   |         ++++++
+LL |   f(|x| match x { tmp => { g(tmp) } };);
+   |                                      +
 
 error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:10:38
    |
 LL |     ($e:expr) => { match $e { x => { g(x) } } }
-   |                                      ^^^^ expected `()`, found `i32`
+   |                    ------------------^^^^----
+   |                    |                 |
+   |                    |                 expected `()`, found `i32`
+   |                    expected this to be `()`
 LL |   }
 LL |   f(|x| d!(x));
    |         ----- in this macro invocation
@@ -37,10 +41,10 @@ help: consider using a semicolon here
    |
 LL |     ($e:expr) => { match $e { x => { g(x); } } }
    |                                          +
-help: try adding a return type
+help: consider using a semicolon here
    |
-LL |   f(|x| -> i32 d!(x));
-   |         ++++++
+LL |     ($e:expr) => { match $e { x => { g(x) } }; }
+   |                                              +
 
 error: aborting due to 3 previous errors