about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs35
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs25
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs6
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs98
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs95
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs64
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs20
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs29
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--library/alloc/src/rc.rs4
-rw-r--r--library/alloc/src/sync.rs4
-rw-r--r--library/alloc/src/task.rs8
-rw-r--r--library/core/src/ops/deref.rs88
-rw-r--r--library/core/src/ops/mod.rs3
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/std/src/collections/hash/set.rs449
-rw-r--r--library/std/src/sync/mpmc/mod.rs2
-rw-r--r--library/std/src/sync/mpsc/mod.rs2
m---------src/doc/rust-by-example0
-rw-r--r--src/tools/rustbook/.gitignore1
-rw-r--r--src/tools/rustbook/Cargo.lock24
-rw-r--r--tests/crashes/131915.rs13
-rw-r--r--tests/ui-fulldeps/internal-lints/bad_opt_access.rs2
-rw-r--r--tests/ui-fulldeps/internal-lints/bad_opt_access.stderr2
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs20
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr39
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs366
-rw-r--r--tests/ui/suggestions/no-method-found-suggest-trait-args.rs30
-rw-r--r--tests/ui/suggestions/no-method-found-suggest-trait-args.stderr63
-rw-r--r--triagebot.toml5
48 files changed, 1314 insertions, 318 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 997c44cffff..5f71fb97d76 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1194,7 +1194,7 @@ impl Expr {
     ///
     /// Does not ensure that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool {
-        let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self };
+        let this = if strip_identity_block { self.maybe_unwrap_block() } else { self };
 
         if let ExprKind::Path(None, path) = &this.kind
             && path.is_potential_trivial_const_arg()
@@ -1206,14 +1206,41 @@ impl Expr {
     }
 
     /// Returns an expression with (when possible) *one* outter brace removed
-    pub fn maybe_unwrap_block(&self) -> (bool, &Expr) {
+    pub fn maybe_unwrap_block(&self) -> &Expr {
         if let ExprKind::Block(block, None) = &self.kind
             && let [stmt] = block.stmts.as_slice()
             && let StmtKind::Expr(expr) = &stmt.kind
         {
-            (true, expr)
+            expr
         } else {
-            (false, self)
+            self
+        }
+    }
+
+    /// Determines whether this expression is a macro call optionally wrapped in braces . If
+    /// `already_stripped_block` is set then we do not attempt to peel off a layer of braces.
+    ///
+    /// Returns the [`NodeId`] of the macro call and whether a layer of braces has been peeled
+    /// either before, or part of, this function.
+    pub fn optionally_braced_mac_call(
+        &self,
+        already_stripped_block: bool,
+    ) -> Option<(bool, NodeId)> {
+        match &self.kind {
+            ExprKind::Block(block, None)
+                if let [stmt] = &*block.stmts
+                    && !already_stripped_block =>
+            {
+                match &stmt.kind {
+                    StmtKind::MacCall(_) => Some((true, stmt.id)),
+                    StmtKind::Expr(expr) if let ExprKind::MacCall(_) = &expr.kind => {
+                        Some((true, expr.id))
+                    }
+                    _ => None,
+                }
+            }
+            ExprKind::MacCall(_) => Some((already_stripped_block, self.id)),
+            _ => None,
         }
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
deleted file mode 100644
index c7725e49c94..00000000000
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
-};
-use rustc_session::Session;
-
-pub(crate) struct ArArchiveBuilderBuilder;
-
-impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
-    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
-        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 19a1de53d1d..b506b1f5731 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults;
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_errors::ErrorGuaranteed;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
@@ -56,7 +55,6 @@ use crate::prelude::*;
 mod abi;
 mod allocator;
 mod analyze;
-mod archive;
 mod base;
 mod cast;
 mod codegen_i128;
@@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
             self.config.borrow().as_ref().unwrap(),
         )
     }
-
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_codegen_ssa::back::link::link_binary;
-
-        link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
-    }
 }
 
 fn target_triple(sess: &Session) -> target_lexicon::Triple {
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
deleted file mode 100644
index 82e98370b37..00000000000
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use std::path::Path;
-
-use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
-    ImportLibraryItem,
-};
-use rustc_session::Session;
-
-pub(crate) struct ArArchiveBuilderBuilder;
-
-impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
-    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
-        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
-    }
-
-    fn create_dll_import_lib(
-        &self,
-        _sess: &Session,
-        _lib_name: &str,
-        _items: Vec<ImportLibraryItem>,
-        _output_path: &Path,
-    ) {
-        unimplemented!("creating dll imports is not yet supported");
-    }
-}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index f70dc94b267..452e92bffa2 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -58,7 +58,6 @@ extern crate rustc_driver;
 
 mod abi;
 mod allocator;
-mod archive;
 mod asm;
 mod attributes;
 mod back;
@@ -103,7 +102,7 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::IntoDynSyncSend;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
+use rustc_errors::DiagCtxtHandle;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
@@ -261,17 +260,6 @@ impl CodegenBackend for GccCodegenBackend {
             .join(sess)
     }
 
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_codegen_ssa::back::link::link_binary;
-
-        link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
-    }
-
     fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
         target_features(sess, allow_unstable, &self.target_info)
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 49e616b5371..3dfb86d422d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend {
 
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
-        link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs)
+        link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index e83bfa7b70d..d4836eb7a1d 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -304,6 +304,14 @@ pub trait ArchiveBuilder {
     fn build(self: Box<Self>, output: &Path) -> bool;
 }
 
+pub struct ArArchiveBuilderBuilder;
+
+impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
+    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
+        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
+    }
+}
+
 #[must_use = "must call build() to finish building the archive"]
 pub struct ArArchiveBuilder<'a> {
     sess: &'a Session,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 3120b5bf0af..fc1f96481cf 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -69,7 +69,7 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
 pub fn link_binary(
     sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
-    codegen_results: &CodegenResults,
+    codegen_results: CodegenResults,
     outputs: &OutputFilenames,
 ) -> Result<(), ErrorGuaranteed> {
     let _timer = sess.timer("link_binary");
@@ -116,7 +116,7 @@ pub fn link_binary(
                     link_rlib(
                         sess,
                         archive_builder_builder,
-                        codegen_results,
+                        &codegen_results,
                         RlibFlavor::Normal,
                         &path,
                     )?
@@ -126,7 +126,7 @@ pub fn link_binary(
                     link_staticlib(
                         sess,
                         archive_builder_builder,
-                        codegen_results,
+                        &codegen_results,
                         &out_filename,
                         &path,
                     )?;
@@ -137,7 +137,7 @@ pub fn link_binary(
                         archive_builder_builder,
                         crate_type,
                         &out_filename,
-                        codegen_results,
+                        &codegen_results,
                         path.as_ref(),
                     )?;
                 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 676fb181d67..cbf214763b4 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -16,6 +16,8 @@ use rustc_span::symbol::Symbol;
 
 use super::CodegenObject;
 use super::write::WriteBackendMethods;
+use crate::back::archive::ArArchiveBuilderBuilder;
+use crate::back::link::link_binary;
 use crate::back::write::TargetMachineFactoryFn;
 use crate::{CodegenResults, ModuleCodegen};
 
@@ -87,7 +89,9 @@ pub trait CodegenBackend {
         sess: &Session,
         codegen_results: CodegenResults,
         outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed>;
+    ) -> Result<(), ErrorGuaranteed> {
+        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
+    }
 
     /// Returns `true` if this backend can be safely called from multiple threads.
     ///
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index c952d5f6d77..15cb331d07a 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -241,6 +241,8 @@ language_item_table! {
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
     DerefPure,               sym::deref_pure,          deref_pure_trait,           Target::Trait,          GenericRequirement::Exact(0);
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
+    Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+    ReceiverTarget,          sym::receiver_target,     receiver_target,            Target::AssocTy,        GenericRequirement::None;
     LegacyReceiver,          sym::legacy_receiver,     legacy_receiver_trait,      Target::Trait,          GenericRequirement::None;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 3a6ea545741..1802f00bc1f 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let predicates = tcx.predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
-    let is_our_default = |def: &ty::GenericParamDef| match def.kind {
-        GenericParamDefKind::Type { has_default, .. }
-        | GenericParamDefKind::Const { has_default, .. } => {
-            has_default && def.index >= generics.parent_count as u32
-        }
-        GenericParamDefKind::Lifetime => {
-            span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default")
-        }
-    };
-
     // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
     // For example, this forbids the declaration:
     //
@@ -1444,40 +1434,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     //
     // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
     for param in &generics.own_params {
-        match param.kind {
-            GenericParamDefKind::Type { .. } => {
-                if is_our_default(param) {
-                    let ty = tcx.type_of(param.def_id).instantiate_identity();
-                    // Ignore dependent defaults -- that is, where the default of one type
-                    // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
-                    // be sure if it will error or not as user might always specify the other.
-                    if !ty.has_param() {
-                        wfcx.register_wf_obligation(
-                            tcx.def_span(param.def_id),
-                            Some(WellFormedLoc::Ty(param.def_id.expect_local())),
-                            ty.into(),
-                        );
-                    }
-                }
-            }
-            GenericParamDefKind::Const { .. } => {
-                if is_our_default(param) {
-                    // FIXME(const_generics_defaults): This
-                    // is incorrect when dealing with unused args, for example
-                    // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
-                    // we should eagerly error.
-                    let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
-                    if !default_ct.has_param() {
-                        wfcx.register_wf_obligation(
-                            tcx.def_span(param.def_id),
-                            None,
-                            default_ct.into(),
-                        );
-                    }
-                }
+        if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) {
+            // Ignore dependent defaults -- that is, where the default of one type
+            // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
+            // be sure if it will error or not as user might always specify the other.
+            // FIXME(generic_const_exprs): This is incorrect when dealing with unused const params.
+            // E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should
+            // eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`.
+            if !default.has_param() {
+                wfcx.register_wf_obligation(
+                    tcx.def_span(param.def_id),
+                    matches!(param.kind, GenericParamDefKind::Type { .. })
+                        .then(|| WellFormedLoc::Ty(param.def_id.expect_local())),
+                    default,
+                );
             }
-            // Doesn't have defaults.
-            GenericParamDefKind::Lifetime => {}
         }
     }
 
@@ -1490,39 +1461,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     //
     // First we build the defaulted generic parameters.
     let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
-        match param.kind {
-            GenericParamDefKind::Lifetime => {
-                // All regions are identity.
-                tcx.mk_param_from_def(param)
-            }
-
-            GenericParamDefKind::Type { .. } => {
-                // If the param has a default, ...
-                if is_our_default(param) {
-                    let default_ty = tcx.type_of(param.def_id).instantiate_identity();
-                    // ... and it's not a dependent default, ...
-                    if !default_ty.has_param() {
-                        // ... then instantiate it with the default.
-                        return default_ty.into();
-                    }
-                }
-
-                tcx.mk_param_from_def(param)
-            }
-            GenericParamDefKind::Const { .. } => {
-                // If the param has a default, ...
-                if is_our_default(param) {
-                    let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
-                    // ... and it's not a dependent default, ...
-                    if !default_ct.has_param() {
-                        // ... then instantiate it with the default.
-                        return default_ct.into();
-                    }
-                }
-
-                tcx.mk_param_from_def(param)
-            }
+        if param.index >= generics.parent_count as u32
+            // If the param has a default, ...
+            && let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity)
+            // ... and it's not a dependent default, ...
+            && !default.has_param()
+        {
+            // ... then instantiate it with the default.
+            return default;
         }
+        tcx.mk_param_from_def(param)
     });
 
     // Now we build the instantiated predicates.
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 1774772b50b..bfdf764d299 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug", ret)]
-    pub(crate) fn check_match(
+    pub(crate) fn check_expr_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         scrut: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 20502de38a2..e6e0f62b54d 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -62,7 +62,7 @@ enum CallStep<'tcx> {
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub(crate) fn check_call(
+    pub(crate) fn check_expr_call(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
         callee_expr: &'tcx hir::Expr<'tcx>,
@@ -74,8 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .check_expr_with_expectation_and_args(
                     callee_expr,
                     Expectation::NoExpectation,
-                    arg_exprs,
-                    Some(call_expr),
+                    Some((call_expr, arg_exprs)),
                 ),
             _ => self.check_expr(callee_expr),
         };
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 2026fd9a614..51d78646373 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     }
 
     fcx.is_whole_body.set(true);
-    fcx.check_return_expr(body.value, false);
+    fcx.check_return_or_body_tail(body.value, false);
 
     // Finalize the return check by taking the LUB of the return types
     // we saw and assigning it to the expected return type. This isn't
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index b05731c6d52..354993513da 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -55,6 +55,9 @@ use crate::{
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Check an expr with an expectation type, and also demand that the expr's
+    /// evaluated type is a subtype of the expectation at the end. This is a
+    /// *hard* requirement.
     pub(crate) fn check_expr_has_type_or_error(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Check an expr with an expectation type, and also demand that the expr's
+    /// evaluated type is a coercible to the expectation at the end. This is a
+    /// *hard* requirement.
     pub(super) fn check_expr_coercible_to_type(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -128,6 +134,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Check an expr with an expectation type. Don't actually enforce that expectation
+    /// is related to the expr's evaluated type via subtyping or coercion. This is
+    /// usually called because we want to do that subtype/coerce call manually for better
+    /// diagnostics.
     pub(super) fn check_expr_with_hint(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -136,6 +146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
+    /// Check an expr with an expectation type, and also [`Needs`] which will
+    /// prompt typeck to convert any implicit immutable derefs to mutable derefs.
     fn check_expr_with_expectation_and_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -153,10 +165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Check an expr with no expectations.
     pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
+    /// Check an expr with no expectations, but with [`Needs`] which will
+    /// prompt typeck to convert any implicit immutable derefs to mutable derefs.
     pub(super) fn check_expr_with_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -165,33 +180,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
     }
 
-    /// Invariant:
-    /// If an expression has any sub-expressions that result in a type error,
-    /// inspecting that expression's type with `ty.references_error()` will return
-    /// true. Likewise, if an expression is known to diverge, inspecting its
-    /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
-    /// strict, _|_ can appear in the type of an expression that does not,
-    /// itself, diverge: for example, fn() -> _|_.)
-    /// Note that inspecting a type's structure *directly* may expose the fact
-    /// that there are actually multiple representations for `Error`, so avoid
-    /// that when err needs to be handled differently.
+    /// Check an expr with an expectation type which may be used to eagerly
+    /// guide inference when evaluating that expr.
     #[instrument(skip(self, expr), level = "debug")]
     pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_args(expr, expected, &[], None)
+        self.check_expr_with_expectation_and_args(expr, expected, None)
     }
 
-    /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
-    /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
+    /// Same as [`Self::check_expr_with_expectation`], but allows us to pass in
+    /// the arguments of a [`ExprKind::Call`] when evaluating its callee that
+    /// is an [`ExprKind::Path`]. We use this to refine the spans for certain
+    /// well-formedness guarantees for the path expr.
     pub(super) fn check_expr_with_expectation_and_args(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        args: &'tcx [hir::Expr<'tcx>],
-        call: Option<&'tcx hir::Expr<'tcx>>,
+        call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     ) -> Ty<'tcx> {
         if self.tcx().sess.verbose_internals() {
             // make this code only run with -Zverbose-internals because it is probably slow
@@ -236,9 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let ty = ensure_sufficient_stack(|| match &expr.kind {
+            // Intercept the callee path expr and give it better spans.
             hir::ExprKind::Path(
                 qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
-            ) => self.check_expr_path(qpath, expr, Some(args), call),
+            ) => self.check_expr_path(qpath, expr, call_expr_and_args),
             _ => self.check_expr_kind(expr, expected),
         });
         let ty = self.resolve_vars_if_possible(ty);
@@ -472,28 +481,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         match expr.kind {
-            ExprKind::Lit(ref lit) => self.check_lit(lit, expected),
-            ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
+            ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
+            ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
             ExprKind::Assign(lhs, rhs, span) => {
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
             ExprKind::AssignOp(op, lhs, rhs) => {
-                self.check_binop_assign(expr, op, lhs, rhs, expected)
+                self.check_expr_binop_assign(expr, op, lhs, rhs, expected)
             }
-            ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
+            ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),
             ExprKind::AddrOf(kind, mutbl, oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
             ExprKind::Path(QPath::LangItem(lang_item, _)) => {
                 self.check_lang_item_path(lang_item, expr)
             }
-            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None),
+            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
             ExprKind::InlineAsm(asm) => {
                 // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
                 self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
                 self.check_expr_asm(asm)
             }
-            ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr),
+            ExprKind::OffsetOf(container, fields) => {
+                self.check_expr_offset_of(container, fields, expr)
+            }
             ExprKind::Break(destination, ref expr_opt) => {
                 self.check_expr_break(destination, expr_opt.as_deref(), expr)
             }
@@ -512,13 +523,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_loop(body, source, expected, expr)
             }
             ExprKind::Match(discrim, arms, match_src) => {
-                self.check_match(expr, discrim, arms, expected, match_src)
+                self.check_expr_match(expr, discrim, arms, expected, match_src)
             }
             ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
-            ExprKind::Block(body, _) => self.check_block_with_expected(body, expected),
-            ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected),
+            ExprKind::Block(body, _) => self.check_expr_block(body, expected),
+            ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
             ExprKind::MethodCall(segment, receiver, args, _) => {
-                self.check_method_call(expr, segment, receiver, args, expected)
+                self.check_expr_method_call(expr, segment, receiver, args, expected)
             }
             ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(e, t) => {
@@ -528,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ascribed_ty
             }
             ExprKind::If(cond, then_expr, opt_else_expr) => {
-                self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
+                self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected)
             }
             ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
@@ -540,7 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Struct(qpath, fields, ref base_expr) => {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
-            ExprKind::Field(base, field) => self.check_field(expr, base, field, expected),
+            ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected),
             ExprKind::Index(base, idx, brackets_span) => {
                 self.check_expr_index(base, idx, expr, brackets_span)
             }
@@ -549,7 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_expr_unary(
+    fn check_expr_unop(
         &self,
         unop: hir::UnOp,
         oprnd: &'tcx hir::Expr<'tcx>,
@@ -699,8 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         qpath: &'tcx hir::QPath<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
-        args: Option<&'tcx [hir::Expr<'tcx>]>,
-        call: Option<&'tcx hir::Expr<'tcx>>,
+        call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (res, opt_ty, segs) =
@@ -730,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     segs,
                     opt_ty,
                     res,
-                    call.map_or(expr.span, |e| e.span),
+                    call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
                     expr.span,
                     expr.hir_id,
                 )
@@ -769,7 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // We just want to check sizedness, so instead of introducing
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
-                    let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span);
+                    let span = call_expr_and_args
+                        .and_then(|(_, args)| args.get(i))
+                        .map_or(expr.span, |arg| arg.span);
                     let input = self.instantiate_binder_with_fresh_vars(
                         span,
                         infer::BoundRegionConversionTime::FnCall,
@@ -795,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             self.require_type_is_sized_deferred(
                 output,
-                call.map_or(expr.span, |e| e.span),
+                call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
                 ObligationCauseCode::SizedCallReturnType,
             );
         }
@@ -972,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
             }
-            self.check_return_expr(e, true);
+            self.check_return_or_body_tail(e, true);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
             if self.ret_coercion_span.get().is_none() {
@@ -1035,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// `explicit_return` is `true` if we're checking an explicit `return expr`,
     /// and `false` if we're checking a trailing expression.
-    pub(super) fn check_return_expr(
+    pub(super) fn check_return_or_body_tail(
         &self,
         return_expr: &'tcx hir::Expr<'tcx>,
         explicit_return: bool,
@@ -1259,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     // A generic function for checking the 'then' and 'else' clauses in an 'if'
     // or 'if-else' expression.
-    fn check_then_else(
+    fn check_expr_if(
         &self,
         cond_expr: &'tcx hir::Expr<'tcx>,
         then_expr: &'tcx hir::Expr<'tcx>,
@@ -1542,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Checks a method call.
-    fn check_method_call(
+    fn check_expr_method_call(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         segment: &'tcx hir::PathSegment<'tcx>,
@@ -2594,7 +2606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // Check field access expressions
-    fn check_field(
+    fn check_expr_field(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         base: &'tcx hir::Expr<'tcx>,
@@ -3535,8 +3547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let previous_diverges = self.diverges.get();
 
                     // The label blocks should have unit return value or diverge.
-                    let ty =
-                        self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
+                    let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit));
                     if !ty.is_never() {
                         self.demand_suptype(block.span, self.tcx.types.unit, ty);
                         diverge = false;
@@ -3551,7 +3562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if diverge { self.tcx.types.never } else { self.tcx.types.unit }
     }
 
-    fn check_offset_of(
+    fn check_expr_offset_of(
         &self,
         container: &'tcx hir::Ty<'tcx>,
         fields: &[Ident],
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index ce0ab8a913b..c18b847d7b7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1306,30 +1306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
                         )
                         .into(),
-                    GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_args && has_default {
-                            // If we have a default, then it doesn't matter that we're not
-                            // inferring the type arguments: we provide the default where any
-                            // is missing.
-                            tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into()
-                        } else {
-                            // If no type arguments were provided, we have to infer them.
-                            // This case also occurs as a result of some malformed input, e.g.
-                            // a lifetime argument being given instead of a type parameter.
-                            // Using inference instead of `Error` gives better error messages.
-                            self.fcx.var_for_def(self.span, param)
+                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                        if !infer_args && let Some(default) = param.default_value(tcx) {
+                            // If we have a default, then it doesn't matter that we're not inferring
+                            // the type/const arguments: We provide the default where any is missing.
+                            return default.instantiate(tcx, preceding_args);
                         }
-                    }
-                    GenericParamDefKind::Const { has_default, .. } => {
-                        if has_default {
-                            if !infer_args {
-                                return tcx
-                                    .const_param_default(param.def_id)
-                                    .instantiate(tcx, preceding_args)
-                                    .into();
-                            }
-                        }
-
+                        // If no type/const arguments were provided, we have to infer them.
+                        // This case also occurs as a result of some malformed input, e.g.,
+                        // a lifetime argument being given instead of a type/const parameter.
+                        // Using inference instead of `Error` gives better error messages.
                         self.fcx.var_for_def(self.span, param)
                     }
                 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a6c249da103..50d1322eba6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // AST fragment checking
-    pub(in super::super) fn check_lit(
+    pub(in super::super) fn check_expr_lit(
         &self,
         lit: &hir::Lit,
         expected: Expectation<'tcx>,
@@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let Some(blk) = decl.origin.try_get_else() {
             let previous_diverges = self.diverges.get();
-            let else_ty = self.check_block_with_expected(blk, NoExpectation);
+            let else_ty = self.check_expr_block(blk, NoExpectation);
             let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
             if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
             {
@@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
         let unit = self.tcx.types.unit;
-        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+        let ty = self.check_expr_block(blk, ExpectHasType(unit));
 
         // if the block produces a `!` value, that can always be
         // (effectively) coerced to unit.
@@ -1814,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub(in super::super) fn check_block_with_expected(
+    pub(in super::super) fn check_expr_block(
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected: Expectation<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index f5987a11fa5..63dccf8b0ce 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
+#![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index cb20a1d7c7b..8772599e316 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3874,22 +3874,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 param.name.ident(),
                             ));
                             let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
+                            let mut applicability = Applicability::MaybeIncorrect;
+                            // Format the path of each suggested candidate, providing placeholders
+                            // for any generic arguments without defaults.
+                            let candidate_strs: Vec<_> = candidates
+                                .iter()
+                                .map(|cand| {
+                                    let cand_path = self.tcx.def_path_str(cand.def_id);
+                                    let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
+                                    let cand_args: String = cand_params
+                                        .iter()
+                                        .skip(1)
+                                        .filter_map(|param| match param.kind {
+                                            ty::GenericParamDefKind::Type {
+                                                has_default: true,
+                                                ..
+                                            }
+                                            | ty::GenericParamDefKind::Const {
+                                                has_default: true,
+                                                ..
+                                            } => None,
+                                            _ => Some(param.name.as_str()),
+                                        })
+                                        .intersperse(", ")
+                                        .collect();
+                                    if cand_args.is_empty() {
+                                        cand_path
+                                    } else {
+                                        applicability = Applicability::HasPlaceholders;
+                                        format!("{cand_path}</* {cand_args} */>")
+                                    }
+                                })
+                                .collect();
+
                             if rcvr_ty.is_ref()
                                 && param.is_impl_trait()
                                 && let Some((bounds_span, _)) = bounds_span
                             {
                                 err.multipart_suggestions(
                                     msg,
-                                    candidates.iter().map(|t| {
+                                    candidate_strs.iter().map(|cand| {
                                         vec![
                                             (param.span.shrink_to_lo(), "(".to_string()),
-                                            (
-                                                bounds_span,
-                                                format!(" + {})", self.tcx.def_path_str(t.def_id)),
-                                            ),
+                                            (bounds_span, format!(" + {cand})")),
                                         ]
                                     }),
-                                    Applicability::MaybeIncorrect,
+                                    applicability,
                                 );
                                 return;
                             }
@@ -3905,16 +3935,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     (param.span.shrink_to_hi(), Introducer::Colon, None)
                                 };
 
-                            let all_suggs = candidates.iter().map(|cand| {
-                                let suggestion = format!(
-                                    "{} {}",
-                                    match introducer {
-                                        Introducer::Plus => " +",
-                                        Introducer::Colon => ":",
-                                        Introducer::Nothing => "",
-                                    },
-                                    self.tcx.def_path_str(cand.def_id)
-                                );
+                            let all_suggs = candidate_strs.iter().map(|cand| {
+                                let suggestion = format!("{} {cand}", match introducer {
+                                    Introducer::Plus => " +",
+                                    Introducer::Colon => ":",
+                                    Introducer::Nothing => "",
+                                },);
 
                                 let mut suggs = vec![];
 
@@ -3928,11 +3954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 suggs
                             });
 
-                            err.multipart_suggestions(
-                                msg,
-                                all_suggs,
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.multipart_suggestions(msg, all_suggs, applicability);
 
                             return;
                         }
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 9a3492abc9f..72b930ee84d 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -26,7 +26,7 @@ use crate::Expectation;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
-    pub(crate) fn check_binop_assign(
+    pub(crate) fn check_expr_binop_assign(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
@@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Checks a potentially overloaded binary operator.
-    pub(crate) fn check_binop(
+    pub(crate) fn check_expr_binop(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 54ead9a7a75..b25ed1c44e1 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -463,7 +463,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
+    /// Fetch the THIR for a given body.
     query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> {
         // Perf tests revealed that hashing THIR is inefficient (see #85729).
         no_hash
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 19779740227..ce40ab18261 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -86,10 +86,10 @@ impl GenericParamDef {
         tcx: TyCtxt<'tcx>,
     ) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
         match self.kind {
-            GenericParamDefKind::Type { has_default, .. } if has_default => {
+            GenericParamDefKind::Type { has_default: true, .. } => {
                 Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
             }
-            GenericParamDefKind::Const { has_default, .. } if has_default => {
+            GenericParamDefKind::Const { has_default: true, .. } => {
                 Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index f3e6301d9d1..33e194fa246 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1005,10 +1005,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     // Runs all other queries that depend on THIR.
     tcx.ensure_with_value().mir_built(def);
     let thir = &thir.steal();
-    // If `thir` is empty, a type error occurred, skip this body.
-    if thir.exprs.is_empty() {
-        return;
-    }
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 1a5c29afdc9..c845d60ac07 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
 impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
     fn generics(&mut self) -> &mut Self {
         for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
-            match param.kind {
-                GenericParamDefKind::Lifetime => {}
-                GenericParamDefKind::Type { has_default, .. } => {
-                    if has_default {
-                        self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
-                    }
-                }
-                GenericParamDefKind::Const { has_default, .. } => {
-                    self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
-                    if has_default {
-                        self.visit(
-                            self.ev.tcx.const_param_default(param.def_id).instantiate_identity(),
-                        );
-                    }
-                }
+            if let GenericParamDefKind::Const { .. } = param.kind {
+                self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
+            }
+            if let Some(default) = param.default_value(self.ev.tcx) {
+                self.visit(default.instantiate_identity());
             }
         }
         self
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index a825458dc89..bf27b767a49 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -130,18 +130,16 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
         &self,
         anon_const: &'a AnonConst,
     ) -> Option<(PendingAnonConstInfo, NodeId)> {
-        let (block_was_stripped, expr) = anon_const.value.maybe_unwrap_block();
-        match expr {
-            Expr { kind: ExprKind::MacCall(..), id, .. } => Some((
+        anon_const.value.optionally_braced_mac_call(false).map(|(block_was_stripped, id)| {
+            (
                 PendingAnonConstInfo {
                     id: anon_const.id,
                     span: anon_const.value.span,
                     block_was_stripped,
                 },
-                *id,
-            )),
-            _ => None,
-        }
+                id,
+            )
+        })
     }
 
     /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes
@@ -161,18 +159,11 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
             panic!("Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`"),
         );
 
-        let (block_was_stripped, expr) = if pending_anon.block_was_stripped {
-            (true, const_arg_sub_expr)
-        } else {
-            const_arg_sub_expr.maybe_unwrap_block()
-        };
-
-        match expr {
-            Expr { kind: ExprKind::MacCall(..), id, .. } => {
-                Some((PendingAnonConstInfo { block_was_stripped, ..pending_anon }, *id))
-            }
-            _ => None,
-        }
+        const_arg_sub_expr.optionally_braced_mac_call(pending_anon.block_was_stripped).map(
+            |(block_was_stripped, id)| {
+                (PendingAnonConstInfo { block_was_stripped, ..pending_anon }, id)
+            },
+        )
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 087ba0522eb..f485e8cace5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -130,7 +130,7 @@ top_level_options!(
     pub struct Options {
         /// The crate config requested for the session, which may be combined
         /// with additional crate configurations during the compile process.
-        #[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")]
+        #[rustc_lint_opt_deny_field_access("use `TyCtxt::crate_types` instead of this field")]
         crate_types: Vec<CrateType> [TRACKED],
         optimize: OptLevel [TRACKED],
         /// Include the `debug_assertions` flag in dependency tracking, since it
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f89fd0f7f2a..42c6221dc57 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1568,6 +1568,8 @@ symbols! {
         readonly,
         realloc,
         reason,
+        receiver,
+        receiver_target,
         recursion_limit,
         reexport_test_harness_main,
         ref_pat_eat_one_layer_2024,
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index a68aaec5f70..4718264e685 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2932,7 +2932,9 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
 }
 
 /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
-/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
+/// managed allocation.
+///
+/// The allocation is accessed by calling [`upgrade`] on the `Weak`
 /// pointer, which returns an <code>[Option]<[Rc]\<T>></code>.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index c78a4db95ff..8520c3c196b 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -291,7 +291,9 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 }
 
 /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
-/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
+/// managed allocation.
+///
+/// The allocation is accessed by calling [`upgrade`] on the `Weak`
 /// pointer, which returns an <code>[Option]<[Arc]\<T>></code>.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 27589aed2f9..0f8e74300a4 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -176,9 +176,11 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
     )
 }
 
-/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API
-/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead
-/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`.
+/// An analogous trait to `Wake` but used to construct a `LocalWaker`.
+///
+/// This API works in exactly the same way as `Wake`,
+/// except that it uses an `Rc` instead of an `Arc`,
+/// and the result is a `LocalWaker` instead of a `Waker`.
 ///
 /// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker
 /// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 1ef9990c00a..45688727c9b 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -294,14 +294,98 @@ unsafe impl<T: ?Sized> DerefPure for &T {}
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized> DerefPure for &mut T {}
 
+/// Indicates that a struct can be used as a method receiver.
+/// That is, a type can use this type as a type of `self`, like this:
+/// ```compile_fail
+/// # // This is currently compile_fail because the compiler-side parts
+/// # // of arbitrary_self_types are not implemented
+/// use std::ops::Receiver;
+///
+/// struct SmartPointer<T>(T);
+///
+/// impl<T> Receiver for SmartPointer<T> {
+///    type Target = T;
+/// }
+///
+/// struct MyContainedType;
+///
+/// impl MyContainedType {
+///   fn method(self: SmartPointer<Self>) {
+///     // ...
+///   }
+/// }
+///
+/// fn main() {
+///   let ptr = SmartPointer(MyContainedType);
+///   ptr.method();
+/// }
+/// ```
+/// This trait is blanket implemented for any type which implements
+/// [`Deref`], which includes stdlib pointer types like `Box<T>`,`Rc<T>`, `&T`,
+/// and `Pin<P>`. For that reason, it's relatively rare to need to
+/// implement this directly. You'll typically do this only if you need
+/// to implement a smart pointer type which can't implement [`Deref`]; perhaps
+/// because you're interfacing with another programming language and can't
+/// guarantee that references comply with Rust's aliasing rules.
+///
+/// When looking for method candidates, Rust will explore a chain of possible
+/// `Receiver`s, so for example each of the following methods work:
+/// ```
+/// use std::boxed::Box;
+/// use std::rc::Rc;
+///
+/// // Both `Box` and `Rc` (indirectly) implement Receiver
+///
+/// struct MyContainedType;
+///
+/// fn main() {
+///   let t = Rc::new(Box::new(MyContainedType));
+///   t.method_a();
+///   t.method_b();
+///   t.method_c();
+/// }
+///
+/// impl MyContainedType {
+///   fn method_a(&self) {
+///
+///   }
+///   fn method_b(self: &Box<Self>) {
+///
+///   }
+///   fn method_c(self: &Rc<Box<Self>>) {
+///
+///   }
+/// }
+/// ```
+#[lang = "receiver"]
+#[cfg(not(bootstrap))]
+#[unstable(feature = "arbitrary_self_types", issue = "44874")]
+pub trait Receiver {
+    /// The target type on which the method may be called.
+    #[cfg(not(bootstrap))]
+    #[rustc_diagnostic_item = "receiver_target"]
+    #[lang = "receiver_target"]
+    #[unstable(feature = "arbitrary_self_types", issue = "44874")]
+    type Target: ?Sized;
+}
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "arbitrary_self_types", issue = "44874")]
+impl<P: ?Sized, T: ?Sized> Receiver for P
+where
+    P: Deref<Target = T>,
+{
+    type Target = T;
+}
+
 /// Indicates that a struct can be used as a method receiver, without the
 /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
 /// `Rc<T>`, `&T`, and `Pin<P>`.
 ///
 /// This trait will shortly be removed and replaced with a more generic
 /// facility based around the current "arbitrary self types" unstable feature.
-/// That new facility will use a replacement trait called `Receiver` which is
-/// why this is now named `LegacyReceiver`.
+/// That new facility will use the replacement trait above called `Receiver`
+/// which is why this is now named `LegacyReceiver`.
 #[cfg_attr(bootstrap, lang = "receiver")]
 #[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index c9f47e5daad..cea1f84f3fd 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState};
 pub use self::deref::DerefPure;
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
 pub use self::deref::LegacyReceiver;
+#[unstable(feature = "arbitrary_self_types", issue = "44874")]
+#[cfg(not(bootstrap))]
+pub use self::deref::Receiver;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::deref::{Deref, DerefMut};
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 52d2179b04d..ce9d04d01d7 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -4578,8 +4578,8 @@ impl<T> [T] {
             panic!("elements are zero-sized");
         }
 
-        let self_start = self.as_ptr() as usize;
-        let elem_start = element as *const T as usize;
+        let self_start = self.as_ptr().addr();
+        let elem_start = ptr::from_ref(element).addr();
 
         let byte_offset = elem_start.wrapping_sub(self_start);
 
@@ -4631,8 +4631,8 @@ impl<T> [T] {
             panic!("elements are zero-sized");
         }
 
-        let self_start = self.as_ptr() as usize;
-        let subslice_start = subslice.as_ptr() as usize;
+        let self_start = self.as_ptr().addr();
+        let subslice_start = subslice.as_ptr().addr();
 
         let byte_start = subslice_start.wrapping_sub(self_start);
 
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index e1e0eb36d23..f86bcdb4796 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -757,6 +757,47 @@ where
         self.base.get_or_insert_with(value, f)
     }
 
+    /// Gets the given value's corresponding entry in the set for in-place manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry::*;
+    ///
+    /// let mut singles = HashSet::new();
+    /// let mut dupes = HashSet::new();
+    ///
+    /// for ch in "a short treatise on fungi".chars() {
+    ///     if let Vacant(dupe_entry) = dupes.entry(ch) {
+    ///         // We haven't already seen a duplicate, so
+    ///         // check if we've at least seen it once.
+    ///         match singles.entry(ch) {
+    ///             Vacant(single_entry) => {
+    ///                 // We found a new character for the first time.
+    ///                 single_entry.insert()
+    ///             }
+    ///             Occupied(single_entry) => {
+    ///                 // We've already seen this once, "move" it to dupes.
+    ///                 single_entry.remove();
+    ///                 dupe_entry.insert();
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert!(!singles.contains(&'t') && dupes.contains(&'t'));
+    /// assert!(singles.contains(&'u') && !dupes.contains(&'u'));
+    /// assert!(!singles.contains(&'v') && !dupes.contains(&'v'));
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn entry(&mut self, value: T) -> Entry<'_, T, S> {
+        map_entry(self.base.entry(value))
+    }
+
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
     ///
@@ -935,6 +976,14 @@ where
     }
 }
 
+#[inline]
+fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> {
+    match raw {
+        base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }),
+        base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }),
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> Clone for HashSet<T, S>
 where
@@ -1865,6 +1914,406 @@ where
     }
 }
 
+/// A view into a single entry in a set, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`HashSet`].
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`entry`]: struct.HashSet.html#method.entry
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::HashSet;
+///
+/// let mut set = HashSet::new();
+/// set.extend(["a", "b", "c"]);
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing value (insert)
+/// let entry = set.entry("a");
+/// let _raw_o = entry.insert();
+/// assert_eq!(set.len(), 3);
+/// // Nonexistent value (insert)
+/// set.entry("d").insert();
+///
+/// // Existing value (or_insert)
+/// set.entry("b").or_insert();
+/// // Nonexistent value (or_insert)
+/// set.entry("e").or_insert();
+///
+/// println!("Our HashSet: {:?}", set);
+///
+/// let mut vec: Vec<_> = set.iter().copied().collect();
+/// // The `Iter` iterator produces items in arbitrary order, so the
+/// // items must be sorted to test them against a sorted array.
+/// vec.sort_unstable();
+/// assert_eq!(vec, ["a", "b", "c", "d", "e"]);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub enum Entry<'a, T, S> {
+    /// An occupied entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::from(["a", "b"]);
+    ///
+    /// match set.entry("a") {
+    ///     Entry::Vacant(_) => unreachable!(),
+    ///     Entry::Occupied(_) => { }
+    /// }
+    /// ```
+    Occupied(OccupiedEntry<'a, T, S>),
+
+    /// A vacant entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// match set.entry("a") {
+    ///     Entry::Occupied(_) => unreachable!(),
+    ///     Entry::Vacant(_) => { }
+    /// }
+    /// ```
+    Vacant(VacantEntry<'a, T, S>),
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for Entry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
+            Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
+        }
+    }
+}
+
+/// A view into an occupied entry in a `HashSet`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::{Entry, HashSet};
+///
+/// let mut set = HashSet::new();
+/// set.extend(["a", "b", "c"]);
+///
+/// let _entry_o = set.entry("a").insert();
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing key
+/// match set.entry("a") {
+///     Entry::Vacant(_) => unreachable!(),
+///     Entry::Occupied(view) => {
+///         assert_eq!(view.get(), &"a");
+///     }
+/// }
+///
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing key (take)
+/// match set.entry("c") {
+///     Entry::Vacant(_) => unreachable!(),
+///     Entry::Occupied(view) => {
+///         assert_eq!(view.remove(), "c");
+///     }
+/// }
+/// assert_eq!(set.get(&"c"), None);
+/// assert_eq!(set.len(), 2);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub struct OccupiedEntry<'a, T, S> {
+    base: base::OccupiedEntry<'a, T, S>,
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for OccupiedEntry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OccupiedEntry").field("value", self.get()).finish()
+    }
+}
+
+/// A view into a vacant entry in a `HashSet`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::{Entry, HashSet};
+///
+/// let mut set = HashSet::<&str>::new();
+///
+/// let entry_v = match set.entry("a") {
+///     Entry::Vacant(view) => view,
+///     Entry::Occupied(_) => unreachable!(),
+/// };
+/// entry_v.insert();
+/// assert!(set.contains("a") && set.len() == 1);
+///
+/// // Nonexistent key (insert)
+/// match set.entry("b") {
+///     Entry::Vacant(view) => view.insert(),
+///     Entry::Occupied(_) => unreachable!(),
+/// }
+/// assert!(set.contains("b") && set.len() == 2);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub struct VacantEntry<'a, T, S> {
+    base: base::VacantEntry<'a, T, S>,
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for VacantEntry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("VacantEntry").field(self.get()).finish()
+    }
+}
+
+impl<'a, T, S> Entry<'a, T, S> {
+    /// Sets the value of the entry, and returns an OccupiedEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// let entry = set.entry("horseyland").insert();
+    ///
+    /// assert_eq!(entry.get(), &"horseyland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn insert(self) -> OccupiedEntry<'a, T, S>
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        match self {
+            Entry::Occupied(entry) => entry,
+            Entry::Vacant(entry) => entry.insert_entry(),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting if it was vacant.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// // nonexistent key
+    /// set.entry("poneyland").or_insert();
+    /// assert!(set.contains("poneyland"));
+    ///
+    /// // existing key
+    /// set.entry("poneyland").or_insert();
+    /// assert!(set.contains("poneyland"));
+    /// assert_eq!(set.len(), 1);
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn or_insert(self)
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        if let Entry::Vacant(entry) = self {
+            entry.insert();
+        }
+    }
+
+    /// Returns a reference to this entry's value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// set.entry("poneyland").or_insert();
+    ///
+    /// // existing key
+    /// assert_eq!(set.entry("poneyland").get(), &"poneyland");
+    /// // nonexistent key
+    /// assert_eq!(set.entry("horseland").get(), &"horseland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        match *self {
+            Entry::Occupied(ref entry) => entry.get(),
+            Entry::Vacant(ref entry) => entry.get(),
+        }
+    }
+}
+
+impl<T, S> OccupiedEntry<'_, T, S> {
+    /// Gets a reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    /// set.entry("poneyland").or_insert();
+    ///
+    /// match set.entry("poneyland") {
+    ///     Entry::Vacant(_) => panic!(),
+    ///     Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"),
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        self.base.get()
+    }
+
+    /// Takes the value out of the entry, and returns it.
+    /// Keeps the allocated memory for reuse.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry;
+    ///
+    /// let mut set = HashSet::new();
+    /// // The set is empty
+    /// assert!(set.is_empty() && set.capacity() == 0);
+    ///
+    /// set.entry("poneyland").or_insert();
+    /// let capacity_before_remove = set.capacity();
+    ///
+    /// if let Entry::Occupied(o) = set.entry("poneyland") {
+    ///     assert_eq!(o.remove(), "poneyland");
+    /// }
+    ///
+    /// assert_eq!(set.contains("poneyland"), false);
+    /// // Now set hold none elements but capacity is equal to the old one
+    /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove);
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn remove(self) -> T {
+        self.base.remove()
+    }
+}
+
+impl<'a, T, S> VacantEntry<'a, T, S> {
+    /// Gets a reference to the value that would be used when inserting
+    /// through the `VacantEntry`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// assert_eq!(set.entry("poneyland").get(), &"poneyland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        self.base.get()
+    }
+
+    /// Take ownership of the value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// match set.entry("poneyland") {
+    ///     Entry::Occupied(_) => panic!(),
+    ///     Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"),
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn into_value(self) -> T {
+        self.base.into_value()
+    }
+
+    /// Sets the value of the entry with the VacantEntry's value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// if let Entry::Vacant(o) = set.entry("poneyland") {
+    ///     o.insert();
+    /// }
+    /// assert!(set.contains("poneyland"));
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn insert(self)
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        self.base.insert();
+    }
+
+    #[inline]
+    fn insert_entry(self) -> OccupiedEntry<'a, T, S>
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        OccupiedEntry { base: self.base.insert() }
+    }
+}
+
 #[allow(dead_code)]
 fn assert_covariance() {
     fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 44e146a89ba..0cf4902d6d5 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -153,6 +153,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`] in
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
@@ -201,6 +202,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 }
 
 /// Creates a new synchronous, bounded channel.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`]
 /// in the same order as it was sent. Like asynchronous [`channel`]s, the
 /// [`Receiver`] will block until a message becomes available. `sync_channel`
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 83a93a06369..c86b546e011 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -483,6 +483,7 @@ pub enum TrySendError<T> {
 }
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`] in
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
@@ -527,6 +528,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 }
 
 /// Creates a new synchronous, bounded channel.
+///
 /// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
 /// in the same order as it was sent. Like asynchronous [`channel`]s, the
 /// [`Receiver`] will block until a message becomes available. `sync_channel`
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 9db78608b17d5f4a6c033b8a3038466b87d6320
+Subproject e1d1f2cdcee4d52b9a01ff7c448be4372a377b7
diff --git a/src/tools/rustbook/.gitignore b/src/tools/rustbook/.gitignore
new file mode 100644
index 00000000000..ea8c4bf7f35
--- /dev/null
+++ b/src/tools/rustbook/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 27ccb205b50..914b03c8679 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -441,11 +441,12 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "5.1.2"
+version = "6.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b"
+checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315"
 dependencies = [
  "log",
+ "num-order",
  "pest",
  "pest_derive",
  "serde",
@@ -645,9 +646,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.40"
+version = "0.4.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5"
+checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -763,6 +764,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "num-modular"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
+
+[[package]]
+name = "num-order"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
+dependencies = [
+ "num-modular",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/tests/crashes/131915.rs b/tests/crashes/131915.rs
deleted file mode 100644
index 58d45adcb3b..00000000000
--- a/tests/crashes/131915.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #131915
-
-macro_rules! y {
-    ( $($matcher:tt)*) => {
-        x
-    };
-}
-
-const _: A<
-    {
-        y! { test.tou8 }
-    },
->;
diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs
index 708c3651b87..a2a94db919d 100644
--- a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs
+++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs
@@ -15,7 +15,7 @@ pub fn access_bad_option(sess: Session) {
     //~^ ERROR use `Session::split_debuginfo` instead of this field
 
     let _ = sess.opts.crate_types;
-    //~^ ERROR use `Session::crate_types` instead of this field
+    //~^ ERROR use `TyCtxt::crate_types` instead of this field
 
     let _ = sess.opts.crate_name;
     // okay!
diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr
index e4145bff8be..35b179f2a3a 100644
--- a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr
+++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr
@@ -10,7 +10,7 @@ note: the lint level is defined here
 LL | #![deny(rustc::bad_opt_access)]
    |         ^^^^^^^^^^^^^^^^^^^^^
 
-error: use `Session::crate_types` instead of this field
+error: use `TyCtxt::crate_types` instead of this field
   --> $DIR/bad_opt_access.rs:17:13
    |
 LL |     let _ = sess.opts.crate_types;
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs
new file mode 100644
index 00000000000..bce7ac5708a
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs
@@ -0,0 +1,20 @@
+// Regression test for #131915 where we did not handle macro calls as
+// statements correctly when determining if a const argument should
+// have a `DefId` created or not.
+
+macro_rules! y {
+    ( $($matcher:tt)*) => {
+        x
+        //~^ ERROR: cannot find value `x` in this scope
+    };
+}
+
+const _: A<
+    //~^ ERROR: free constant item without body
+    //~| ERROR: cannot find type `A` in this scope
+    {
+        y! { test.tou8 }
+    },
+>;
+
+fn main() {}
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr
new file mode 100644
index 00000000000..a3211b77623
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr
@@ -0,0 +1,39 @@
+error: free constant item without body
+  --> $DIR/const_arg_trivial_macro_expansion-2.rs:12:1
+   |
+LL | / const _: A<
+LL | |
+LL | |
+LL | |     {
+LL | |         y! { test.tou8 }
+LL | |     },
+LL | | >;
+   | |  ^ help: provide a definition for the constant: `= <expr>;`
+   | |__|
+   |
+
+error[E0412]: cannot find type `A` in this scope
+  --> $DIR/const_arg_trivial_macro_expansion-2.rs:12:10
+   |
+LL | const _: A<
+   |          ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/const_arg_trivial_macro_expansion-2.rs:7:9
+   |
+LL |         x
+   |         ^ not found in this scope
+...
+LL |         y! { test.tou8 }
+   |         ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a const parameter
+   |
+LL | const _<const x: /* Type */>: A<
+   |        +++++++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0412, E0425.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs
new file mode 100644
index 00000000000..2fdd703ab6f
--- /dev/null
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs
@@ -0,0 +1,366 @@
+//@ known-bug: #132647
+//@ dont-check-compiler-stderr
+#![allow(unused_braces)]
+
+// FIXME(bootstrap): This isn't a known bug, we just don't want to write any error annotations.
+// this is hard because macro expansion errors have their span be inside the *definition* of the
+// macro rather than the line *invoking* it. This means we would wind up with hundreds of error
+// annotations on the macro definitions below rather than on any of the actual lines
+// that act as a "test".
+//
+// It's also made more complicated by the fact that compiletest generates "extra" expected
+// notes to give an assertable macro backtrace as otherwise there would *nothing* to annotate
+// on the actual test lines. All of these extra notes result in needing to write hundreds of
+// unnecessary notes on almost every line in this file.
+//
+// Even though this is marked `known-bug` it should still fail if this test starts ICEing which
+// is "enough" in this case.
+
+// Test that we correctly create definitions for anon consts even when
+// the trivial-ness of the expression is obscured by macro expansions.
+//
+// Acts as a regression test for: #131915 130321 128016
+
+// macros expanding to idents
+
+macro_rules! unbraced_ident {
+    () => {
+        ident
+    };
+}
+
+macro_rules! braced_ident {
+    () => {{ ident }};
+}
+
+macro_rules! unbraced_unbraced_ident {
+    () => {
+        unbraced_ident!()
+    };
+}
+
+macro_rules! braced_unbraced_ident {
+    () => {{ unbraced_ident!() }};
+}
+
+macro_rules! unbraced_braced_ident {
+    () => {
+        braced_ident!()
+    };
+}
+
+macro_rules! braced_braced_ident {
+    () => {{ braced_ident!() }};
+}
+
+// macros expanding to complex expr
+
+macro_rules! unbraced_expr {
+    () => {
+        ident.other
+    };
+}
+
+macro_rules! braced_expr {
+    () => {{ ident.otherent }};
+}
+
+macro_rules! unbraced_unbraced_expr {
+    () => {
+        unbraced_expr!()
+    };
+}
+
+macro_rules! braced_unbraced_expr {
+    () => {{ unbraced_expr!() }};
+}
+
+macro_rules! unbraced_braced_expr {
+    () => {
+        braced_expr!()
+    };
+}
+
+macro_rules! braced_braced_expr {
+    () => {{ braced_expr!() }};
+}
+
+#[rustfmt::skip]
+mod array_paren_call {
+    // Arrays where the expanded result is a `Res::Err`
+    fn array_0() -> [(); unbraced_unbraced_ident!()] { loop {} }
+    fn array_1() -> [(); braced_unbraced_ident!()] { loop {} }
+    fn array_2() -> [(); unbraced_braced_ident!()] { loop {} }
+    fn array_3() -> [(); braced_braced_ident!()] { loop {} }
+    fn array_4() -> [(); { unbraced_unbraced_ident!() }] { loop {} }
+    fn array_5() -> [(); { braced_unbraced_ident!() }] { loop {} }
+    fn array_6() -> [(); { unbraced_braced_ident!() }] { loop {} }
+    fn array_7() -> [(); { braced_braced_ident!() }] { loop {} }
+    fn array_8() -> [(); unbraced_ident!()] { loop {} }
+    fn array_9() -> [(); braced_ident!()] { loop {} }
+    fn array_10() -> [(); { unbraced_ident!() }] { loop {} }
+    fn array_11() -> [(); { braced_ident!() }] { loop {} }
+
+    // Arrays where the expanded result is a `Res::ConstParam`
+    fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident!()] { loop {} }
+    fn array_13<const ident: usize>() -> [(); braced_unbraced_ident!()] { loop {} }
+    fn array_14<const ident: usize>() -> [(); unbraced_braced_ident!()] { loop {} }
+    fn array_15<const ident: usize>() -> [(); braced_braced_ident!()] { loop {} }
+    fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident!() }] { loop {} }
+    fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident!() }] { loop {} }
+    fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident!() }] { loop {} }
+    fn array_19<const ident: usize>() -> [(); { braced_braced_ident!() }] { loop {} }
+    fn array_20<const ident: usize>() -> [(); unbraced_ident!()] { loop {} }
+    fn array_21<const ident: usize>() -> [(); braced_ident!()] { loop {} }
+    fn array_22<const ident: usize>() -> [(); { unbraced_ident!() }] { loop {} }
+    fn array_23<const ident: usize>() -> [(); { braced_ident!() }] { loop {} }
+
+    // Arrays where the expanded result is a complex expr
+    fn array_24() -> [(); unbraced_unbraced_expr!()] { loop {} }
+    fn array_25() -> [(); braced_unbraced_expr!()] { loop {} }
+    fn array_26() -> [(); unbraced_braced_expr!()] { loop {} }
+    fn array_27() -> [(); braced_braced_expr!()] { loop {} }
+    fn array_28() -> [(); { unbraced_unbraced_expr!() }] { loop {} }
+    fn array_29() -> [(); { braced_unbraced_expr!() }] { loop {} }
+    fn array_30() -> [(); { unbraced_braced_expr!() }] { loop {} }
+    fn array_31() -> [(); { braced_braced_expr!() }] { loop {} }
+    fn array_32() -> [(); unbraced_expr!()] { loop {} }
+    fn array_33() -> [(); braced_expr!()] { loop {} }
+    fn array_34() -> [(); { unbraced_expr!() }] { loop {} }
+    fn array_35() -> [(); { braced_expr!() }] { loop {} }
+}
+
+#[rustfmt::skip]
+mod array_brace_call {
+    // Arrays where the expanded result is a `Res::Err`
+    fn array_0() -> [(); unbraced_unbraced_ident!{}] { loop {} }
+    fn array_1() -> [(); braced_unbraced_ident!{}] { loop {} }
+    fn array_2() -> [(); unbraced_braced_ident!{}] { loop {} }
+    fn array_3() -> [(); braced_braced_ident!{}] { loop {} }
+    fn array_4() -> [(); { unbraced_unbraced_ident!{} }] { loop {} }
+    fn array_5() -> [(); { braced_unbraced_ident!{} }] { loop {} }
+    fn array_6() -> [(); { unbraced_braced_ident!{} }] { loop {} }
+    fn array_7() -> [(); { braced_braced_ident!{} }] { loop {} }
+    fn array_8() -> [(); unbraced_ident!{}] { loop {} }
+    fn array_9() -> [(); braced_ident!{}] { loop {} }
+    fn array_10() -> [(); { unbraced_ident!{} }] { loop {} }
+    fn array_11() -> [(); { braced_ident!{} }] { loop {} }
+
+    // Arrays where the expanded result is a `Res::ConstParam`
+    fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident!{}] { loop {} }
+    fn array_13<const ident: usize>() -> [(); braced_unbraced_ident!{}] { loop {} }
+    fn array_14<const ident: usize>() -> [(); unbraced_braced_ident!{}] { loop {} }
+    fn array_15<const ident: usize>() -> [(); braced_braced_ident!{}] { loop {} }
+    fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident!{} }] { loop {} }
+    fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident!{} }] { loop {} }
+    fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident!{} }] { loop {} }
+    fn array_19<const ident: usize>() -> [(); { braced_braced_ident!{} }] { loop {} }
+    fn array_20<const ident: usize>() -> [(); unbraced_ident!{}] { loop {} }
+    fn array_21<const ident: usize>() -> [(); braced_ident!{}] { loop {} }
+    fn array_22<const ident: usize>() -> [(); { unbraced_ident!{} }] { loop {} }
+    fn array_23<const ident: usize>() -> [(); { braced_ident!{} }] { loop {} }
+
+    // Arrays where the expanded result is a complex expr
+    fn array_24() -> [(); unbraced_unbraced_expr!{}] { loop {} }
+    fn array_25() -> [(); braced_unbraced_expr!{}] { loop {} }
+    fn array_26() -> [(); unbraced_braced_expr!{}] { loop {} }
+    fn array_27() -> [(); braced_braced_expr!{}] { loop {} }
+    fn array_28() -> [(); { unbraced_unbraced_expr!{} }] { loop {} }
+    fn array_29() -> [(); { braced_unbraced_expr!{} }] { loop {} }
+    fn array_30() -> [(); { unbraced_braced_expr!{} }] { loop {} }
+    fn array_31() -> [(); { braced_braced_expr!{} }] { loop {} }
+    fn array_32() -> [(); unbraced_expr!{}] { loop {} }
+    fn array_33() -> [(); braced_expr!{}] { loop {} }
+    fn array_34() -> [(); { unbraced_expr!{} }] { loop {} }
+    fn array_35() -> [(); { braced_expr!{} }] { loop {} }
+}
+
+#[rustfmt::skip]
+mod array_square_call {
+    // Arrays where the expanded result is a `Res::Err`
+    fn array_0() -> [(); unbraced_unbraced_ident![]] { loop {} }
+    fn array_1() -> [(); braced_unbraced_ident![]] { loop {} }
+    fn array_2() -> [(); unbraced_braced_ident![]] { loop {} }
+    fn array_3() -> [(); braced_braced_ident![]] { loop {} }
+    fn array_4() -> [(); { unbraced_unbraced_ident![] }] { loop {} }
+    fn array_5() -> [(); { braced_unbraced_ident![] }] { loop {} }
+    fn array_6() -> [(); { unbraced_braced_ident![] }] { loop {} }
+    fn array_7() -> [(); { braced_braced_ident![] }] { loop {} }
+    fn array_8() -> [(); unbraced_ident![]] { loop {} }
+    fn array_9() -> [(); braced_ident![]] { loop {} }
+    fn array_10() -> [(); { unbraced_ident![] }] { loop {} }
+    fn array_11() -> [(); { braced_ident![] }] { loop {} }
+
+    // Arrays where the expanded result is a `Res::ConstParam`
+    fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident![]] { loop {} }
+    fn array_13<const ident: usize>() -> [(); braced_unbraced_ident![]] { loop {} }
+    fn array_14<const ident: usize>() -> [(); unbraced_braced_ident![]] { loop {} }
+    fn array_15<const ident: usize>() -> [(); braced_braced_ident![]] { loop {} }
+    fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident![] }] { loop {} }
+    fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident![] }] { loop {} }
+    fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident![] }] { loop {} }
+    fn array_19<const ident: usize>() -> [(); { braced_braced_ident![] }] { loop {} }
+    fn array_20<const ident: usize>() -> [(); unbraced_ident![]] { loop {} }
+    fn array_21<const ident: usize>() -> [(); braced_ident![]] { loop {} }
+    fn array_22<const ident: usize>() -> [(); { unbraced_ident![] }] { loop {} }
+    fn array_23<const ident: usize>() -> [(); { braced_ident![] }] { loop {} }
+
+    // Arrays where the expanded result is a complex expr
+    fn array_24() -> [(); unbraced_unbraced_expr![]] { loop {} }
+    fn array_25() -> [(); braced_unbraced_expr![]] { loop {} }
+    fn array_26() -> [(); unbraced_braced_expr![]] { loop {} }
+    fn array_27() -> [(); braced_braced_expr![]] { loop {} }
+    fn array_28() -> [(); { unbraced_unbraced_expr![] }] { loop {} }
+    fn array_29() -> [(); { braced_unbraced_expr![] }] { loop {} }
+    fn array_30() -> [(); { unbraced_braced_expr![] }] { loop {} }
+    fn array_31() -> [(); { braced_braced_expr![] }] { loop {} }
+    fn array_32() -> [(); unbraced_expr![]] { loop {} }
+    fn array_33() -> [(); braced_expr![]] { loop {} }
+    fn array_34() -> [(); { unbraced_expr![] }] { loop {} }
+    fn array_35() -> [(); { braced_expr![] }] { loop {} }
+}
+
+struct Foo<const N: usize>;
+
+#[rustfmt::skip]
+mod adt_paren_call {
+    use super::Foo;
+
+    // An ADT where the expanded result is a `Res::Err`
+    fn adt_0() -> Foo<unbraced_unbraced_ident!()> { loop {} }
+    fn adt_1() -> Foo<braced_unbraced_ident!()> { loop {} }
+    fn adt_2() -> Foo<unbraced_braced_ident!()> { loop {} }
+    fn adt_3() -> Foo<braced_braced_ident!()> { loop {} }
+    fn adt_4() -> Foo<{ unbraced_unbraced_ident!() }> { loop {} }
+    fn adt_5() -> Foo<{ braced_unbraced_ident!() }> { loop {} }
+    fn adt_6() -> Foo<{ unbraced_braced_ident!() }> { loop {} }
+    fn adt_7() -> Foo<{ braced_braced_ident!() }> { loop {} }
+    fn adt_8() -> Foo<unbraced_ident!()> { loop {} }
+    fn adt_9() -> Foo<braced_ident!()> { loop {} }
+    fn adt_10() -> Foo<{ unbraced_ident!() }> { loop {} }
+    fn adt_11() -> Foo<{ braced_ident!() }> { loop {} }
+
+    // An ADT where the expanded result is a `Res::ConstParam`
+    fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident!()> { loop {} }
+    fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident!()> { loop {} }
+    fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident!()> { loop {} }
+    fn adt_15<const ident: usize>() -> Foo<braced_braced_ident!()> { loop {} }
+    fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident!() }> { loop {} }
+    fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident!() }> { loop {} }
+    fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident!() }> { loop {} }
+    fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident!() }> { loop {} }
+    fn adt_20<const ident: usize>() -> Foo<unbraced_ident!()> { loop {} }
+    fn adt_21<const ident: usize>() -> Foo<braced_ident!()> { loop {} }
+    fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident!() }> { loop {} }
+    fn adt_23<const ident: usize>() -> Foo<{ braced_ident!() }> { loop {} }
+
+    // An ADT where the expanded result is a complex expr
+    fn array_24() -> Foo<unbraced_unbraced_expr!()> { loop {} }
+    fn array_25() -> Foo<braced_unbraced_expr!()> { loop {} }
+    fn array_26() -> Foo<unbraced_braced_expr!()> { loop {} }
+    fn array_27() -> Foo<braced_braced_expr!()> { loop {} }
+    fn array_28() -> Foo<{ unbraced_unbraced_expr!() }> { loop {} }
+    fn array_29() -> Foo<{ braced_unbraced_expr!() }> { loop {} }
+    fn array_30() -> Foo<{ unbraced_braced_expr!() }> { loop {} }
+    fn array_31() -> Foo<{ braced_braced_expr!() }> { loop {} }
+    fn array_32() -> Foo<unbraced_expr!()> { loop {} }
+    fn array_33() -> Foo<braced_expr!()> { loop {} }
+    fn array_34() -> Foo<{ unbraced_expr!() }> { loop {} }
+    fn array_35() -> Foo<{ braced_expr!() }> { loop {} }
+}
+
+#[rustfmt::skip]
+mod adt_brace_call {
+    use super::Foo;
+
+    // An ADT where the expanded result is a `Res::Err`
+    fn adt_0() -> Foo<unbraced_unbraced_ident!{}> { loop {} }
+    fn adt_1() -> Foo<braced_unbraced_ident!{}> { loop {} }
+    fn adt_2() -> Foo<unbraced_braced_ident!{}> { loop {} }
+    fn adt_3() -> Foo<braced_braced_ident!{}> { loop {} }
+    fn adt_4() -> Foo<{ unbraced_unbraced_ident!{} }> { loop {} }
+    fn adt_5() -> Foo<{ braced_unbraced_ident!{} }> { loop {} }
+    fn adt_6() -> Foo<{ unbraced_braced_ident!{} }> { loop {} }
+    fn adt_7() -> Foo<{ braced_braced_ident!{} }> { loop {} }
+    fn adt_8() -> Foo<unbraced_ident!{}> { loop {} }
+    fn adt_9() -> Foo<braced_ident!{}> { loop {} }
+    fn adt_10() -> Foo<{ unbraced_ident!{} }> { loop {} }
+    fn adt_11() -> Foo<{ braced_ident!{} }> { loop {} }
+
+    // An ADT where the expanded result is a `Res::ConstParam`
+    fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident!{}> { loop {} }
+    fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident!{}> { loop {} }
+    fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident!{}> { loop {} }
+    fn adt_15<const ident: usize>() -> Foo<braced_braced_ident!{}> { loop {} }
+    fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident!{} }> { loop {} }
+    fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident!{} }> { loop {} }
+    fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident!{} }> { loop {} }
+    fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident!{} }> { loop {} }
+    fn adt_20<const ident: usize>() -> Foo<unbraced_ident!{}> { loop {} }
+    fn adt_21<const ident: usize>() -> Foo<braced_ident!{}> { loop {} }
+    fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident!{} }> { loop {} }
+    fn adt_23<const ident: usize>() -> Foo<{ braced_ident!{} }> { loop {} }
+
+    // An ADT where the expanded result is a complex expr
+    fn array_24() -> Foo<unbraced_unbraced_expr!{}> { loop {} }
+    fn array_25() -> Foo<braced_unbraced_expr!{}> { loop {} }
+    fn array_26() -> Foo<unbraced_braced_expr!{}> { loop {} }
+    fn array_27() -> Foo<braced_braced_expr!{}> { loop {} }
+    fn array_28() -> Foo<{ unbraced_unbraced_expr!{} }> { loop {} }
+    fn array_29() -> Foo<{ braced_unbraced_expr!{} }> { loop {} }
+    fn array_30() -> Foo<{ unbraced_braced_expr!{} }> { loop {} }
+    fn array_31() -> Foo<{ braced_braced_expr!{} }> { loop {} }
+    fn array_32() -> Foo<unbraced_expr!{}> { loop {} }
+    fn array_33() -> Foo<braced_expr!{}> { loop {} }
+    fn array_34() -> Foo<{ unbraced_expr!{} }> { loop {} }
+    fn array_35() -> Foo<{ braced_expr!{} }> { loop {} }
+}
+
+#[rustfmt::skip]
+mod adt_square_call {
+    use super::Foo;
+
+    // An ADT where the expanded result is a `Res::Err`
+    fn adt_0() -> Foo<unbraced_unbraced_ident![]> { loop {} }
+    fn adt_1() -> Foo<braced_unbraced_ident![]> { loop {} }
+    fn adt_2() -> Foo<unbraced_braced_ident![]> { loop {} }
+    fn adt_3() -> Foo<braced_braced_ident![]> { loop {} }
+    fn adt_4() -> Foo<{ unbraced_unbraced_ident![] }> { loop {} }
+    fn adt_5() -> Foo<{ braced_unbraced_ident![] }> { loop {} }
+    fn adt_6() -> Foo<{ unbraced_braced_ident![] }> { loop {} }
+    fn adt_7() -> Foo<{ braced_braced_ident![] }> { loop {} }
+    fn adt_8() -> Foo<unbraced_ident![]> { loop {} }
+    fn adt_9() -> Foo<braced_ident![]> { loop {} }
+    fn adt_10() -> Foo<{ unbraced_ident![] }> { loop {} }
+    fn adt_11() -> Foo<{ braced_ident![] }> { loop {} }
+
+    // An ADT where the expanded result is a `Res::ConstParam`
+    fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident![]> { loop {} }
+    fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident![]> { loop {} }
+    fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident![]> { loop {} }
+    fn adt_15<const ident: usize>() -> Foo<braced_braced_ident![]> { loop {} }
+    fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident![] }> { loop {} }
+    fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident![] }> { loop {} }
+    fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident![] }> { loop {} }
+    fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident![] }> { loop {} }
+    fn adt_20<const ident: usize>() -> Foo<unbraced_ident![]> { loop {} }
+    fn adt_21<const ident: usize>() -> Foo<braced_ident![]> { loop {} }
+    fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident![] }> { loop {} }
+    fn adt_23<const ident: usize>() -> Foo<{ braced_ident![] }> { loop {} }
+
+    // An ADT where the expanded result is a complex expr
+    fn array_24() -> Foo<unbraced_unbraced_expr![]> { loop {} }
+    fn array_25() -> Foo<braced_unbraced_expr![]> { loop {} }
+    fn array_26() -> Foo<unbraced_braced_expr![]> { loop {} }
+    fn array_27() -> Foo<braced_braced_expr![]> { loop {} }
+    fn array_28() -> Foo<{ unbraced_unbraced_expr![] }> { loop {} }
+    fn array_29() -> Foo<{ braced_unbraced_expr![] }> { loop {} }
+    fn array_30() -> Foo<{ unbraced_braced_expr![] }> { loop {} }
+    fn array_31() -> Foo<{ braced_braced_expr![] }> { loop {} }
+    fn array_32() -> Foo<unbraced_expr![]> { loop {} }
+    fn array_33() -> Foo<braced_expr![]> { loop {} }
+    fn array_34() -> Foo<{ unbraced_expr![] }> { loop {} }
+    fn array_35() -> Foo<{ braced_expr![] }> { loop {} }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/no-method-found-suggest-trait-args.rs b/tests/ui/suggestions/no-method-found-suggest-trait-args.rs
new file mode 100644
index 00000000000..d51f86b29e8
--- /dev/null
+++ b/tests/ui/suggestions/no-method-found-suggest-trait-args.rs
@@ -0,0 +1,30 @@
+/// Tests that suggestions to add trait bounds that would enable using a method include appropriate
+/// placeholder arguments for that trait.
+
+trait Trait<I> {
+    fn method(&self) {}
+}
+
+trait Trait2<'a, A, const B: u8, C = (), const D: u8 = 0> {
+    fn method2(&self) {}
+}
+
+fn foo<T>(value: T) {
+    //~^ SUGGESTION : Trait</* I */>
+    //~| SUGGESTION : Trait2</* 'a, A, B */>
+    value.method();
+    //~^ ERROR no method named `method` found for type parameter `T` in the current scope [E0599]
+    value.method2();
+    //~^ ERROR no method named `method2` found for type parameter `T` in the current scope [E0599]
+}
+
+fn bar(value: impl Copy) {
+    //~^ SUGGESTION + Trait</* I */>
+    //~| SUGGESTION + Trait2</* 'a, A, B */>
+    value.method();
+    //~^ ERROR no method named `method` found for type parameter `impl Copy` in the current scope [E0599]
+    value.method2();
+    //~^ ERROR no method named `method2` found for type parameter `impl Copy` in the current scope [E0599]
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr b/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr
new file mode 100644
index 00000000000..3dcd4667fa0
--- /dev/null
+++ b/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr
@@ -0,0 +1,63 @@
+error[E0599]: no method named `method` found for type parameter `T` in the current scope
+  --> $DIR/no-method-found-suggest-trait-args.rs:15:11
+   |
+LL | fn foo<T>(value: T) {
+   |        - method `method` not found for this type parameter
+...
+LL |     value.method();
+   |           ^^^^^^ method not found in `T`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
+   |
+LL | fn foo<T: Trait</* I */>>(value: T) {
+   |         ++++++++++++++++
+
+error[E0599]: no method named `method2` found for type parameter `T` in the current scope
+  --> $DIR/no-method-found-suggest-trait-args.rs:17:11
+   |
+LL | fn foo<T>(value: T) {
+   |        - method `method2` not found for this type parameter
+...
+LL |     value.method2();
+   |           ^^^^^^^ method not found in `T`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `T` with it:
+   |
+LL | fn foo<T: Trait2</* 'a, A, B */>>(value: T) {
+   |         ++++++++++++++++++++++++
+
+error[E0599]: no method named `method` found for type parameter `impl Copy` in the current scope
+  --> $DIR/no-method-found-suggest-trait-args.rs:24:11
+   |
+LL | fn bar(value: impl Copy) {
+   |               --------- method `method` not found for this type parameter
+...
+LL |     value.method();
+   |           ^^^^^^ method not found in `impl Copy`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `method`, perhaps you need to restrict type parameter `impl Copy` with it:
+   |
+LL | fn bar(value: impl Copy + Trait</* I */>) {
+   |                         ++++++++++++++++
+
+error[E0599]: no method named `method2` found for type parameter `impl Copy` in the current scope
+  --> $DIR/no-method-found-suggest-trait-args.rs:26:11
+   |
+LL | fn bar(value: impl Copy) {
+   |               --------- method `method2` not found for this type parameter
+...
+LL |     value.method2();
+   |           ^^^^^^^ method not found in `impl Copy`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `impl Copy` with it:
+   |
+LL | fn bar(value: impl Copy + Trait2</* 'a, A, B */>) {
+   |                         ++++++++++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/triagebot.toml b/triagebot.toml
index 4eb80f2058d..f31dd5cd3d8 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -212,6 +212,10 @@ trigger_files = [
     "src/tools/rustdoc-gui",
     "src/tools/rustdoc-js",
     "src/tools/rustdoc-themes",
+
+    # Docs
+    "src/doc/rustdoc.md",
+    "src/doc/rustdoc/",
 ]
 exclude_labels = [
     "T-*",
@@ -971,7 +975,6 @@ cc = ["@kobzol"]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
-    "fmease",
     "jieyouxu",
     "jyn514",
     "oli-obk",