about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock23
-rw-r--r--compiler/rustc_ast/src/entry.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs19
-rw-r--r--compiler/rustc_metadata/src/creader.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs23
-rw-r--r--compiler/rustc_passes/src/entry.rs10
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs2
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs12
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs5
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs189
-rw-r--r--library/alloc/src/collections/btree/map.rs5
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs33
-rw-r--r--library/alloc/src/collections/btree/mod.rs1
-rw-r--r--library/alloc/src/collections/btree/search.rs15
-rw-r--r--library/alloc/src/collections/btree/set.rs24
-rw-r--r--library/alloc/src/collections/btree/set/tests.rs23
-rw-r--r--library/alloc/src/collections/btree/set_val.rs29
-rw-r--r--src/librustdoc/html/format.rs80
-rw-r--r--src/librustdoc/html/highlight.rs115
-rw-r--r--src/librustdoc/html/render/span_map.rs83
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/test/rustdoc/check-source-code-urls-to-def-std.rs25
-rw-r--r--src/test/ui/associated-types/issue-87261.rs8
-rw-r--r--src/test/ui/associated-types/issue-87261.stderr24
-rw-r--r--src/test/ui/impl-trait/suggest-calling-rpit-closure.rs12
-rw-r--r--src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr21
-rw-r--r--src/test/ui/parser/expr-as-stmt.stderr4
-rw-r--r--src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr6
-rw-r--r--src/test/ui/reify-intrinsic.stderr4
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr8
-rw-r--r--src/test/ui/span/move-closure.stderr4
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63279.stderr4
42 files changed, 603 insertions, 259 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1677422122e..1108c1f4d4c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1428,9 +1428,9 @@ checksum = "d79238883cf0307100b90aba4a755d8051a3182305dfe7f649a1e9dc0517006f"
 
 [[package]]
 name = "futf"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
+checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
 dependencies = [
  "mac",
  "new_debug_unreachable",
@@ -1713,6 +1713,7 @@ version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
 dependencies = [
+ "ahash",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -2572,6 +2573,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "object"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+dependencies = [
+ "crc32fast",
+ "hashbrown 0.12.0",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
 name = "odht"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3720,7 +3733,7 @@ dependencies = [
  "itertools",
  "jobserver",
  "libc",
- "object 0.28.4",
+ "object 0.29.0",
  "pathdiff",
  "regex",
  "rustc_apfloat",
@@ -5191,9 +5204,9 @@ dependencies = [
 
 [[package]]
 name = "tendril"
-version = "0.4.1"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b"
+checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
 dependencies = [
  "futf",
  "mac",
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index c0a837985fd..3370146193a 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -2,7 +2,7 @@
 pub enum EntryPointType {
     None,
     MainNamed,
-    MainAttr,
+    RustcMainAttr,
     Start,
     OtherMain, // Not an entry point, but some other function named main
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index db8dce804a3..a08495f7671 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -147,7 +147,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
             if sess.contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
             } else if sess.contains_name(&item.attrs, sym::rustc_main) {
-                EntryPointType::MainAttr
+                EntryPointType::RustcMainAttr
             } else if item.ident.name == sym::main {
                 if depth == 0 {
                     // This is a top-level function so can be 'main'
@@ -177,12 +177,12 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
         let item = noop_flat_map_item(i, self).expect_one("noop did something");
         self.depth -= 1;
 
-        // Remove any #[main] or #[start] from the AST so it doesn't
+        // Remove any #[rustc_main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
         let item = match entry_point_type(self.sess, &item, self.depth) {
-            EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item
-                .map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
+            EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
+                item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
                     let allow_ident = Ident::new(sym::allow, self.def_site);
                     let dc_nested =
                         attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site));
@@ -197,7 +197,8 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
                         .collect();
 
                     ast::Item { id, ident, attrs, kind, vis, span, tokens }
-                }),
+                })
+            }
             EntryPointType::None | EntryPointType::OtherMain => item,
         };
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index b5c31fcebe0..c007728095f 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -906,7 +906,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             return eh_catch_typeinfo;
         }
         let tcx = self.tcx;
-        assert!(self.sess().target.is_like_emscripten);
+        assert!(self.sess().target.os == "emscripten");
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a18f5b9dd7f..9f364749287 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -441,7 +441,7 @@ fn try_intrinsic<'ll>(
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, try_func, data, catch_func, dest);
-    } else if bx.sess().target.is_like_emscripten {
+    } else if bx.sess().target.os == "emscripten" {
         codegen_emcc_try(bx, try_func, data, catch_func, dest);
     } else {
         codegen_gnu_try(bx, try_func, data, catch_func, dest);
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index fd8c4f78b2f..1bdc473c29b 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -42,6 +42,6 @@ rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.28.4"
+version = "0.29.0"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index edf49b8c80e..72aa790c363 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2031,7 +2031,7 @@ fn add_order_independent_options(
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
-    if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
+    if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -2051,7 +2051,7 @@ fn add_order_independent_options(
         cmd.no_crt_objects();
     }
 
-    if sess.target.is_like_emscripten {
+    if sess.target.os == "emscripten" {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 6aa96f9f403..3dd607adee5 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -130,7 +130,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     };
 
     let mut file = write::Object::new(binary_format, architecture, endianness);
-    match architecture {
+    let e_flags = match architecture {
         Architecture::Mips => {
             let arch = match sess.target.options.cpu.as_ref() {
                 "mips1" => elf::EF_MIPS_ARCH_1,
@@ -149,7 +149,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
             if sess.target.options.cpu.contains("r6") {
                 e_flags |= elf::EF_MIPS_NAN2008;
             }
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
         Architecture::Mips64 => {
             // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
@@ -160,17 +160,26 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
                 } else {
                     elf::EF_MIPS_ARCH_64R2
                 };
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
         Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
             // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
             // that the `+d` target feature represents whether the double
             // float abi is enabled.
             let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
-        _ => {}
+        _ => 0,
+    };
+    // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
+    let os_abi = match sess.target.options.os.as_ref() {
+        "hermit" => elf::ELFOSABI_STANDALONE,
+        "freebsd" => elf::ELFOSABI_FREEBSD,
+        "solaris" => elf::ELFOSABI_SOLARIS,
+        _ => elf::ELFOSABI_NONE,
     };
+    let abi_version = 0;
+    file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
     Some(file)
 }
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 947d563ae3c..555db5846ed 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -133,6 +133,10 @@ impl CStore {
         CrateNum::new(self.metas.len() - 1)
     }
 
+    pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
+        self.metas[cnum].is_some()
+    }
+
     pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
         let cdata = self.metas[cnum]
             .as_ref()
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 97e5a4983fc..200253d5755 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -5,7 +5,7 @@ use crate::ty::{
     TypeSuperFoldable,
 };
 use rustc_apfloat::ieee::{Double, Single};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -779,8 +779,8 @@ pub trait PrettyPrinter<'tcx>:
         // by looking up the projections associated with the def_id.
         let bounds = self.tcx().bound_explicit_item_bounds(def_id);
 
-        let mut traits = BTreeMap::new();
-        let mut fn_traits = BTreeMap::new();
+        let mut traits = FxIndexMap::default();
+        let mut fn_traits = FxIndexMap::default();
         let mut is_sized = false;
 
         for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
@@ -856,7 +856,7 @@ pub trait PrettyPrinter<'tcx>:
                     p!(")");
                     if let Term::Ty(ty) = return_ty.skip_binder() {
                         if !ty.is_unit() {
-                            p!("-> ", print(return_ty));
+                            p!(" -> ", print(return_ty));
                         }
                     }
                     p!(write("{}", if paren_needed { ")" } else { "" }));
@@ -970,11 +970,11 @@ pub trait PrettyPrinter<'tcx>:
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
-        traits: &mut BTreeMap<
+        traits: &mut FxIndexMap<
             ty::PolyTraitRef<'tcx>,
-            BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+            FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
-        fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+        fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
     ) {
         let trait_def_id = trait_ref.def_id();
 
@@ -1110,19 +1110,18 @@ pub trait PrettyPrinter<'tcx>:
         // Builtin bounds.
         // FIXME(eddyb) avoid printing twice (needed to ensure
         // that the auto traits are sorted *and* printed via cx).
-        let mut auto_traits: Vec<_> =
-            predicates.auto_traits().map(|did| (self.tcx().def_path_str(did), did)).collect();
+        let mut auto_traits: Vec<_> = predicates.auto_traits().collect();
 
         // The auto traits come ordered by `DefPathHash`. While
         // `DefPathHash` is *stable* in the sense that it depends on
         // neither the host nor the phase of the moon, it depends
         // "pseudorandomly" on the compiler version and the target.
         //
-        // To avoid that causing instabilities in compiletest
+        // To avoid causing instabilities in compiletest
         // output, sort the auto-traits alphabetically.
-        auto_traits.sort();
+        auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));
 
-        for (_, def_id) in auto_traits {
+        for def_id in auto_traits {
             if !first {
                 p!(" + ");
             }
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index b90d44e2af5..f9e67310452 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -56,7 +56,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
     if ctxt.tcx.sess.contains_name(attrs, sym::start) {
         EntryPointType::Start
     } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
-        EntryPointType::MainAttr
+        EntryPointType::RustcMainAttr
     } else {
         if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
             && name == sym::main {
@@ -95,7 +95,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         EntryPointType::OtherMain => {
             ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
         }
-        EntryPointType::MainAttr => {
+        EntryPointType::RustcMainAttr => {
             if ctxt.attr_main_fn.is_none() {
                 ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
@@ -103,13 +103,13 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                     ctxt.tcx.sess,
                     ctxt.tcx.def_span(id.def_id.to_def_id()),
                     E0137,
-                    "multiple functions with a `#[main]` attribute"
+                    "multiple functions with a `#[rustc_main]` attribute"
                 )
                 .span_label(
                     ctxt.tcx.def_span(id.def_id.to_def_id()),
-                    "additional `#[main]` function",
+                    "additional `#[rustc_main]` function",
                 )
-                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
+                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
                 .emit();
             }
         }
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 5411946343b..3291be05807 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -17,7 +17,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.os == "emscripten" && items.eh_catch_typeinfo().is_none() {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index e36f55b2e02..640d13ea435 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3514,7 +3514,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     })
                 });
             }
-            ExprKind::Async(..) | ExprKind::Closure(..) => {
+            // For closures, ClosureOrAsyncRibKind is added in visit_fn
+            ExprKind::Closure(..) => visit::walk_expr(self, expr),
+            ExprKind::Async(..) => {
                 self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
             }
             ExprKind::Repeat(ref elem, ref ct) => {
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index fba8cc6ef8b..25842049413 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -74,7 +74,7 @@ impl AArch64InlineAsmRegClass {
 }
 
 pub fn target_reserves_x18(target: &Target) -> bool {
-    target.os == "android" || target.is_like_fuchsia || target.is_like_osx || target.is_like_windows
+    target.os == "android" || target.os == "fuchsia" || target.is_like_osx || target.is_like_windows
 }
 
 fn reserved_x18(
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 04e30ff0c3e..b64875e32bd 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -28,7 +28,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: cvs!["unix"],
-        is_like_fuchsia: true,
         pre_link_args,
         pre_link_objects: crt_objects::new(&[
             (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index fd0c3f36e72..da0589cdd20 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1273,12 +1273,6 @@ pub struct TargetOptions {
     ///   - uses SEH-based unwinding,
     ///   - supports control flow guard mechanism.
     pub is_like_msvc: bool,
-    /// Whether the target toolchain is like Emscripten's. Only useful for compiling with
-    /// Emscripten toolchain.
-    /// Defaults to false.
-    pub is_like_emscripten: bool,
-    /// Whether the target toolchain is like Fuchsia's.
-    pub is_like_fuchsia: bool,
     /// Whether a target toolchain is like WASM.
     pub is_like_wasm: bool,
     /// Version of DWARF to use if not using the default.
@@ -1505,9 +1499,7 @@ impl Default for TargetOptions {
             is_like_osx: false,
             is_like_solaris: false,
             is_like_windows: false,
-            is_like_emscripten: false,
             is_like_msvc: false,
-            is_like_fuchsia: false,
             is_like_wasm: false,
             dwarf_version: None,
             linker_is_gnu: true,
@@ -2112,8 +2104,6 @@ impl Target {
         key!(is_like_solaris, bool);
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
-        key!(is_like_emscripten, bool);
-        key!(is_like_fuchsia, bool);
         key!(is_like_wasm, bool);
         key!(dwarf_version, Option<u32>);
         key!(linker_is_gnu, bool);
@@ -2358,8 +2348,6 @@ impl ToJson for Target {
         target_option_val!(is_like_solaris);
         target_option_val!(is_like_windows);
         target_option_val!(is_like_msvc);
-        target_option_val!(is_like_emscripten);
-        target_option_val!(is_like_fuchsia);
         target_option_val!(is_like_wasm);
         target_option_val!(dwarf_version);
         target_option_val!(linker_is_gnu);
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 6730319dcfa..0865ca7ea7d 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -8,7 +8,12 @@ pub(super) fn test_target(target: Target) {
 
 impl Target {
     fn check_consistency(&self) {
+        assert_eq!(self.is_like_osx, self.vendor == "apple");
+        assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
+        assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
+        assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64");
         assert!(self.is_like_windows || !self.is_like_msvc);
+
         // Check that LLD with the given flavor is treated identically to the linker it emulates.
         // If your target really needs to deviate from the rules below, except it and document the
         // reasons.
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 6a1a5e7a1d7..f1087db09d1 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -26,7 +26,6 @@ pub fn target() -> Target {
         // functionality, and a .wasm file.
         exe_suffix: ".js".into(),
         linker: None,
-        is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         no_default_libraries: false,
         post_link_args,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 03d91435e77..7195da863db 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -8,15 +8,14 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
-    WherePredicate,
+    Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
-use rustc_span::symbol::{kw, sym};
+use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 
@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
-        let (def_id, sig) = match *found.kind() {
-            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
+        let (def_id, output, inputs) = match *found.kind() {
+            ty::FnDef(def_id, _) => {
+                let fn_sig = found.fn_sig(self.tcx);
+                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
+            }
+            ty::Closure(def_id, substs) => {
+                let fn_sig = substs.as_closure().sig();
+                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
+            }
+            ty::Opaque(def_id, substs) => {
+                let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            args.len(),
+                        ))
+                    } else {
+                        None
+                    }
+                });
+                if let Some((output, inputs)) = sig {
+                    (def_id, output, inputs)
+                } else {
+                    return false;
+                }
+            }
             _ => return false,
         };
 
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig);
-        let sig = self.normalize_associated_types_in(expr.span, sig);
-        if self.can_coerce(sig.output(), expected) {
-            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
-                (String::new(), Applicability::MachineApplicable)
-            } else {
-                ("...".to_string(), Applicability::HasPlaceholders)
+        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
+        let output = self.normalize_associated_types_in(expr.span, output);
+        if !output.is_ty_var() && self.can_coerce(output, expected) {
+            let (sugg_call, mut applicability) = match inputs {
+                0 => ("".to_string(), Applicability::MachineApplicable),
+                1..=4 => (
+                    (0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
+                    Applicability::MachineApplicable,
+                ),
+                _ => ("...".to_string(), Applicability::HasPlaceholders),
             };
-            let mut msg = "call this function";
-            match hir.get_if_local(def_id) {
-                Some(
-                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
-                    | Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body_id), ..
-                    })
-                    | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                        ..
-                    }),
-                ) => {
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure { body: body_id, .. },
-                    span: full_closure_span,
-                    ..
-                })) => {
-                    if *full_closure_span == expr.span {
-                        return false;
-                    }
-                    msg = "call this closure";
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
-                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match def_id.as_local().map(|def_id| self.tcx.def_kind(def_id)) {
-                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
-                            msg = "instantiate this tuple variant";
-                        }
-                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
-                            msg = "instantiate this tuple struct";
-                        }
-                        _ => {}
-                    }
+
+            let msg = match self.tcx.def_kind(def_id) {
+                DefKind::Fn => "call this function",
+                DefKind::Closure | DefKind::OpaqueTy => "call this closure",
+                DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
+                DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
+                _ => "call this function",
+            };
+
+            let sugg = match expr.kind {
+                hir::ExprKind::Call(..)
+                | hir::ExprKind::Path(..)
+                | hir::ExprKind::Index(..)
+                | hir::ExprKind::Lit(..) => {
+                    vec![(expr.span.shrink_to_hi(), format!("({sugg_call})"))]
                 }
-                Some(Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Fn(_, idents, _),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
+                hir::ExprKind::Closure { .. } => {
+                    // Might be `{ expr } || { bool }`
+                    applicability = Applicability::MaybeIncorrect;
+                    vec![
+                        (expr.span.shrink_to_lo(), "(".to_string()),
+                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                    ]
                 }
-                Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
+                _ => {
+                    vec![
+                        (expr.span.shrink_to_lo(), "(".to_string()),
+                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                    ]
                 }
-                _ => {}
-            }
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_hi(),
-                &format!("use parentheses to {}", msg),
-                format!("({})", sugg_call),
+            };
+
+            err.multipart_suggestion_verbose(
+                format!("use parentheses to {msg}"),
+                sugg,
                 applicability,
             );
+
             return true;
         }
         false
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 28068a88060..0bddd7a9906 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -16,6 +16,7 @@ use super::dedup_sorted_iter::DedupSortedIter;
 use super::navigate::{LazyLeafRange, LeafRange};
 use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
 use super::search::SearchResult::*;
+use super::set_val::SetValZST;
 
 mod entry;
 
@@ -271,7 +272,7 @@ impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
     }
 }
 
-impl<K, Q: ?Sized, A: Allocator + Clone> super::Recover<Q> for BTreeMap<K, (), A>
+impl<K, Q: ?Sized, A: Allocator + Clone> super::Recover<Q> for BTreeMap<K, SetValZST, A>
 where
     K: Borrow<Q> + Ord,
     Q: Ord,
@@ -318,7 +319,7 @@ where
                     alloc: (*map.alloc).clone(),
                     _marker: PhantomData,
                 }
-                .insert(());
+                .insert(SetValZST::default());
                 None
             }
         }
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 5504959c34d..4c372b1d60a 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -897,6 +897,39 @@ fn test_range_mut() {
     map.check();
 }
 
+#[should_panic(expected = "range start is greater than range end in BTreeMap")]
+#[test]
+fn test_range_panic_1() {
+    let mut map = BTreeMap::new();
+    map.insert(3, "a");
+    map.insert(5, "b");
+    map.insert(8, "c");
+
+    let _invalid_range = map.range((Included(&8), Included(&3)));
+}
+
+#[should_panic(expected = "range start and end are equal and excluded in BTreeMap")]
+#[test]
+fn test_range_panic_2() {
+    let mut map = BTreeMap::new();
+    map.insert(3, "a");
+    map.insert(5, "b");
+    map.insert(8, "c");
+
+    let _invalid_range = map.range((Excluded(&5), Excluded(&5)));
+}
+
+#[should_panic(expected = "range start and end are equal and excluded in BTreeMap")]
+#[test]
+fn test_range_panic_3() {
+    let mut map: BTreeMap<i32, ()> = BTreeMap::new();
+    map.insert(3, ());
+    map.insert(5, ());
+    map.insert(8, ());
+
+    let _invalid_range = map.range((Excluded(&5), Excluded(&5)));
+}
+
 #[test]
 fn test_retain() {
     let mut map = BTreeMap::from_iter((0..100).map(|x| (x, x * 10)));
diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs
index 9571b3d594d..9d43ac5c5be 100644
--- a/library/alloc/src/collections/btree/mod.rs
+++ b/library/alloc/src/collections/btree/mod.rs
@@ -10,6 +10,7 @@ mod node;
 mod remove;
 mod search;
 pub mod set;
+mod set_val;
 mod split;
 
 #[doc(hidden)]
diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs
index 5651a03c47a..ad3522b4e04 100644
--- a/library/alloc/src/collections/btree/search.rs
+++ b/library/alloc/src/collections/btree/search.rs
@@ -97,17 +97,28 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
         K: Borrow<Q>,
         R: RangeBounds<Q>,
     {
+        // Determine if map or set is being searched
+        let is_set = <V as super::set_val::IsSetVal>::is_set_val();
+
         // Inlining these variables should be avoided. We assume the bounds reported by `range`
         // remain the same, but an adversarial implementation could change between calls (#81138).
         let (start, end) = (range.start_bound(), range.end_bound());
         match (start, end) {
             (Bound::Excluded(s), Bound::Excluded(e)) if s == e => {
-                panic!("range start and end are equal and excluded in BTreeMap")
+                if is_set {
+                    panic!("range start and end are equal and excluded in BTreeSet")
+                } else {
+                    panic!("range start and end are equal and excluded in BTreeMap")
+                }
             }
             (Bound::Included(s) | Bound::Excluded(s), Bound::Included(e) | Bound::Excluded(e))
                 if s > e =>
             {
-                panic!("range start is greater than range end in BTreeMap")
+                if is_set {
+                    panic!("range start is greater than range end in BTreeSet")
+                } else {
+                    panic!("range start is greater than range end in BTreeMap")
+                }
             }
             _ => {}
         }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 0d3fdc9019e..2cfc0807409 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -13,6 +13,7 @@ use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub};
 
 use super::map::{BTreeMap, Keys};
 use super::merge_iter::MergeIterInner;
+use super::set_val::SetValZST;
 use super::Recover;
 
 use crate::alloc::{Allocator, Global};
@@ -81,7 +82,7 @@ pub struct BTreeSet<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
 > {
-    map: BTreeMap<T, (), A>,
+    map: BTreeMap<T, SetValZST, A>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -135,7 +136,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for BTreeSet<T, A> {
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
-    iter: Keys<'a, T, ()>,
+    iter: Keys<'a, T, SetValZST>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
@@ -158,7 +159,7 @@ pub struct IntoIter<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
 > {
-    iter: super::map::IntoIter<T, (), A>,
+    iter: super::map::IntoIter<T, SetValZST, A>,
 }
 
 /// An iterator over a sub-range of items in a `BTreeSet`.
@@ -171,7 +172,7 @@ pub struct IntoIter<
 #[derive(Debug)]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, T: 'a> {
-    iter: super::map::Range<'a, T, ()>,
+    iter: super::map::Range<'a, T, SetValZST>,
 }
 
 /// A lazy iterator producing elements in the difference of `BTreeSet`s.
@@ -375,6 +376,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
     /// range from 4 to 10.
     ///
+    /// # Panics
+    ///
+    /// Panics if range `start > end`.
+    /// Panics if range `start == end` and both bounds are `Excluded`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -905,7 +911,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     where
         T: Ord,
     {
-        self.map.insert(value, ()).is_none()
+        self.map.insert(value, SetValZST::default()).is_none()
     }
 
     /// Adds a value to the set, replacing the existing element, if any, that is
@@ -1210,7 +1216,7 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {
 
 impl<T: Ord, A: Allocator + Clone> BTreeSet<T, A> {
     fn from_sorted_iter<I: Iterator<Item = T>>(iter: I, alloc: A) -> BTreeSet<T, A> {
-        let iter = iter.map(|k| (k, ()));
+        let iter = iter.map(|k| (k, SetValZST::default()));
         let map = BTreeMap::bulk_build_from_sorted_iter(iter, alloc);
         BTreeSet { map }
     }
@@ -1234,7 +1240,7 @@ impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
 
         // use stable sort to preserve the insertion order.
         arr.sort();
-        let iter = IntoIterator::into_iter(arr).map(|k| (k, ()));
+        let iter = IntoIterator::into_iter(arr).map(|k| (k, SetValZST::default()));
         let map = BTreeMap::bulk_build_from_sorted_iter(iter, Global);
         BTreeSet { map }
     }
@@ -1284,7 +1290,7 @@ pub struct DrainFilter<
     F: 'a + FnMut(&T) -> bool,
 {
     pred: F,
-    inner: super::map::DrainFilterInner<'a, T, ()>,
+    inner: super::map::DrainFilterInner<'a, T, SetValZST>,
     /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
     alloc: A,
 }
@@ -1319,7 +1325,7 @@ where
 
     fn next(&mut self) -> Option<T> {
         let pred = &mut self.pred;
-        let mut mapped_pred = |k: &T, _v: &mut ()| pred(k);
+        let mut mapped_pred = |k: &T, _v: &mut SetValZST| pred(k);
         self.inner.next(&mut mapped_pred, self.alloc.clone()).map(|(k, _)| k)
     }
 
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index 429b1644976..502d3e1d126 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -5,6 +5,7 @@ use crate::vec::Vec;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
+use std::ops::Bound::{Excluded, Included};
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
 #[test]
@@ -831,3 +832,25 @@ fn from_array() {
     let unordered_duplicates = BTreeSet::from([4, 1, 4, 3, 2]);
     assert_eq!(set, unordered_duplicates);
 }
+
+#[should_panic(expected = "range start is greater than range end in BTreeSet")]
+#[test]
+fn test_range_panic_1() {
+    let mut set = BTreeSet::new();
+    set.insert(3);
+    set.insert(5);
+    set.insert(8);
+
+    let _invalid_range = set.range((Included(&8), Included(&3)));
+}
+
+#[should_panic(expected = "range start and end are equal and excluded in BTreeSet")]
+#[test]
+fn test_range_panic_2() {
+    let mut set = BTreeSet::new();
+    set.insert(3);
+    set.insert(5);
+    set.insert(8);
+
+    let _invalid_range = set.range((Excluded(&5), Excluded(&5)));
+}
diff --git a/library/alloc/src/collections/btree/set_val.rs b/library/alloc/src/collections/btree/set_val.rs
new file mode 100644
index 00000000000..80c459bcf81
--- /dev/null
+++ b/library/alloc/src/collections/btree/set_val.rs
@@ -0,0 +1,29 @@
+/// Zero-Sized Type (ZST) for internal `BTreeSet` values.
+/// Used instead of `()` to differentiate between:
+/// * `BTreeMap<T, ()>` (possible user-defined map)
+/// * `BTreeMap<T, SetValZST>` (internal set representation)
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Default)]
+pub struct SetValZST;
+
+/// A trait to differentiate between `BTreeMap` and `BTreeSet` values.
+/// Returns `true` only for type `SetValZST`, `false` for all other types (blanket implementation).
+/// `TypeId` requires a `'static` lifetime, use of this trait avoids that restriction.
+///
+/// [`TypeId`]: std::any::TypeId
+pub trait IsSetVal {
+    fn is_set_val() -> bool;
+}
+
+// Blanket implementation
+impl<V> IsSetVal for V {
+    default fn is_set_val() -> bool {
+        false
+    }
+}
+
+// Specialization
+impl IsSetVal for SetValZST {
+    fn is_set_val() -> bool {
+        true
+    }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5baa53d5554..056eda089c1 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -8,14 +8,16 @@
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::fmt;
-use std::iter;
+use std::iter::{self, once};
 
+use rustc_ast as ast;
 use rustc_attr::{ConstStability, StabilityLevel};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
@@ -519,6 +521,7 @@ impl clean::GenericArgs {
 }
 
 // Possible errors when computing href link source for a `DefId`
+#[derive(PartialEq, Eq)]
 pub(crate) enum HrefError {
     /// This item is known to rustdoc, but from a crate that does not have documentation generated.
     ///
@@ -556,6 +559,79 @@ pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String {
     s
 }
 
+/// This function is to get the external macro path because they are not in the cache used in
+/// `href_with_root_path`.
+fn generate_macro_def_id_path(
+    def_id: DefId,
+    cx: &Context<'_>,
+    root_path: Option<&str>,
+) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
+    let tcx = cx.shared.tcx;
+    let crate_name = tcx.crate_name(def_id.krate).to_string();
+    let cache = cx.cache();
+
+    let fqp: Vec<Symbol> = tcx
+        .def_path(def_id)
+        .data
+        .into_iter()
+        .filter_map(|elem| {
+            // extern blocks (and a few others things) have an empty name.
+            match elem.data.get_opt_name() {
+                Some(s) if !s.is_empty() => Some(s),
+                _ => None,
+            }
+        })
+        .collect();
+    let relative = fqp.iter().map(|elem| elem.to_string());
+    let cstore = CStore::from_tcx(tcx);
+    // We need this to prevent a `panic` when this function is used from intra doc links...
+    if !cstore.has_crate_data(def_id.krate) {
+        debug!("No data for crate {}", crate_name);
+        return Err(HrefError::NotInExternalCache);
+    }
+    // Check to see if it is a macro 2.0 or built-in macro.
+    // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
+    let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx.sess) {
+        LoadedMacro::MacroDef(def, _) => {
+            // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
+            matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
+        }
+        _ => false,
+    };
+
+    let mut path = if is_macro_2 {
+        once(crate_name.clone()).chain(relative).collect()
+    } else {
+        vec![crate_name.clone(), relative.last().unwrap()]
+    };
+    if path.len() < 2 {
+        // The minimum we can have is the crate name followed by the macro name. If shorter, then
+        // it means that that `relative` was empty, which is an error.
+        debug!("macro path cannot be empty!");
+        return Err(HrefError::NotInExternalCache);
+    }
+
+    if let Some(last) = path.last_mut() {
+        *last = format!("macro.{}.html", last);
+    }
+
+    let url = match cache.extern_locations[&def_id.krate] {
+        ExternalLocation::Remote(ref s) => {
+            // `ExternalLocation::Remote` always end with a `/`.
+            format!("{}{}", s, path.join("/"))
+        }
+        ExternalLocation::Local => {
+            // `root_path` always end with a `/`.
+            format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
+        }
+        ExternalLocation::Unknown => {
+            debug!("crate {} not in cache when linkifying macros", crate_name);
+            return Err(HrefError::NotInExternalCache);
+        }
+    };
+    Ok((url, ItemType::Macro, fqp))
+}
+
 pub(crate) fn href_with_root_path(
     did: DefId,
     cx: &Context<'_>,
@@ -611,6 +687,8 @@ pub(crate) fn href_with_root_path(
                         ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
                     },
                 )
+            } else if matches!(def_kind, DefKind::Macro(_)) {
+                return generate_macro_def_id_path(did, cx, root_path);
             } else {
                 return Err(HrefError::NotInExternalCache);
             }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 480728b1797..d2ef89078bf 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -22,7 +22,7 @@ use super::format::{self, Buffer};
 use super::render::LinkFromSrc;
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
-pub(crate) struct ContextInfo<'a, 'b, 'c> {
+pub(crate) struct HrefContext<'a, 'b, 'c> {
     pub(crate) context: &'a Context<'b>,
     /// This span contains the current file we're going through.
     pub(crate) file_span: Span,
@@ -44,7 +44,7 @@ pub(crate) fn render_with_highlighting(
     tooltip: Option<(Option<Edition>, &str)>,
     edition: Edition,
     extra_content: Option<Buffer>,
-    context_info: Option<ContextInfo<'_, '_, '_>>,
+    href_context: Option<HrefContext<'_, '_, '_>>,
     decoration_info: Option<DecorationInfo>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
@@ -62,7 +62,7 @@ pub(crate) fn render_with_highlighting(
     }
 
     write_header(out, class, extra_content);
-    write_code(out, src, edition, context_info, decoration_info);
+    write_code(out, src, edition, href_context, decoration_info);
     write_footer(out, playground_button);
 }
 
@@ -85,8 +85,8 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
 ///
 /// Some explanations on the last arguments:
 ///
-/// In case we are rendering a code block and not a source code file, `context_info` will be `None`.
-/// To put it more simply: if `context_info` is `None`, the code won't try to generate links to an
+/// In case we are rendering a code block and not a source code file, `href_context` will be `None`.
+/// To put it more simply: if `href_context` is `None`, the code won't try to generate links to an
 /// item definition.
 ///
 /// More explanations about spans and how we use them here are provided in the
@@ -94,22 +94,27 @@ fn write_code(
     out: &mut Buffer,
     src: &str,
     edition: Edition,
-    context_info: Option<ContextInfo<'_, '_, '_>>,
+    href_context: Option<HrefContext<'_, '_, '_>>,
     decoration_info: Option<DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
+    let mut closing_tags: Vec<&'static str> = Vec::new();
     Classifier::new(
         &src,
         edition,
-        context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+        href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
         decoration_info,
     )
     .highlight(&mut |highlight| {
         match highlight {
-            Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
-            Highlight::EnterSpan { class } => enter_span(out, class),
-            Highlight::ExitSpan => exit_span(out),
+            Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
+            Highlight::EnterSpan { class } => {
+                closing_tags.push(enter_span(out, class, &href_context))
+            }
+            Highlight::ExitSpan => {
+                exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
+            }
         };
     });
 }
@@ -129,7 +134,7 @@ enum Class {
     RefKeyWord,
     Self_(Span),
     Op,
-    Macro,
+    Macro(Span),
     MacroNonTerminal,
     String,
     Number,
@@ -153,7 +158,7 @@ impl Class {
             Class::RefKeyWord => "kw-2",
             Class::Self_(_) => "self",
             Class::Op => "op",
-            Class::Macro => "macro",
+            Class::Macro(_) => "macro",
             Class::MacroNonTerminal => "macro-nonterminal",
             Class::String => "string",
             Class::Number => "number",
@@ -171,8 +176,22 @@ impl Class {
     /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
     fn get_span(self) -> Option<Span> {
         match self {
-            Self::Ident(sp) | Self::Self_(sp) => Some(sp),
-            _ => None,
+            Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) => Some(sp),
+            Self::Comment
+            | Self::DocComment
+            | Self::Attribute
+            | Self::KeyWord
+            | Self::RefKeyWord
+            | Self::Op
+            | Self::MacroNonTerminal
+            | Self::String
+            | Self::Number
+            | Self::Bool
+            | Self::Lifetime
+            | Self::PreludeTy
+            | Self::PreludeVal
+            | Self::QuestionMark
+            | Self::Decoration(_) => None,
         }
     }
 }
@@ -611,7 +630,7 @@ impl<'a> Classifier<'a> {
             },
             TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
                 self.in_macro = true;
-                sink(Highlight::EnterSpan { class: Class::Macro });
+                sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) });
                 sink(Highlight::Token { text, class: None });
                 return;
             }
@@ -658,13 +677,20 @@ impl<'a> Classifier<'a> {
 
 /// Called when we start processing a span of text that should be highlighted.
 /// The `Class` argument specifies how it should be highlighted.
-fn enter_span(out: &mut Buffer, klass: Class) {
-    write!(out, "<span class=\"{}\">", klass.as_html());
+fn enter_span(
+    out: &mut Buffer,
+    klass: Class,
+    href_context: &Option<HrefContext<'_, '_, '_>>,
+) -> &'static str {
+    string_without_closing_tag(out, "", Some(klass), href_context).expect(
+        "internal error: enter_span was called with Some(klass) but did not return a \
+            closing HTML tag",
+    )
 }
 
 /// Called at the end of a span of highlighted text.
-fn exit_span(out: &mut Buffer) {
-    out.write_str("</span>");
+fn exit_span(out: &mut Buffer, closing_tag: &str) {
+    out.write_str(closing_tag);
 }
 
 /// Called for a span of text. If the text should be highlighted differently
@@ -687,15 +713,39 @@ fn string<T: Display>(
     out: &mut Buffer,
     text: T,
     klass: Option<Class>,
-    context_info: &Option<ContextInfo<'_, '_, '_>>,
+    href_context: &Option<HrefContext<'_, '_, '_>>,
 ) {
+    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
+        out.write_str(closing_tag);
+    }
+}
+
+/// This function writes `text` into `out` with some modifications depending on `klass`:
+///
+/// * If `klass` is `None`, `text` is written into `out` with no modification.
+/// * If `klass` is `Some` but `klass.get_span()` is `None`, it writes the text wrapped in a
+///   `<span>` with the provided `klass`.
+/// * If `klass` is `Some` and has a [`rustc_span::Span`], it then tries to generate a link (`<a>`
+///   element) by retrieving the link information from the `span_correspondance_map` that was filled
+///   in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
+///   the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
+fn string_without_closing_tag<T: Display>(
+    out: &mut Buffer,
+    text: T,
+    klass: Option<Class>,
+    href_context: &Option<HrefContext<'_, '_, '_>>,
+) -> Option<&'static str> {
     let Some(klass) = klass
-    else { return write!(out, "{}", text) };
+    else {
+        write!(out, "{}", text);
+        return None;
+    };
     let Some(def_span) = klass.get_span()
     else {
-        write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text);
-        return;
+        write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
+        return Some("</span>");
     };
+
     let mut text_s = text.to_string();
     if text_s.contains("::") {
         text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
@@ -715,10 +765,10 @@ fn string<T: Display>(
             path
         });
     }
-    if let Some(context_info) = context_info {
+    if let Some(href_context) = href_context {
         if let Some(href) =
-            context_info.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
-                let context = context_info.context;
+            href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
+                let context = href_context.context;
                 // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
                 // one to the documentation page and one to the source definition.
                 // FIXME: currently, external items only generate a link to their documentation,
@@ -727,27 +777,28 @@ fn string<T: Display>(
                 match href {
                     LinkFromSrc::Local(span) => context
                         .href_from_span(*span, true)
-                        .map(|s| format!("{}{}", context_info.root_path, s)),
+                        .map(|s| format!("{}{}", href_context.root_path, s)),
                     LinkFromSrc::External(def_id) => {
-                        format::href_with_root_path(*def_id, context, Some(context_info.root_path))
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
                             .ok()
                             .map(|(url, _, _)| url)
                     }
                     LinkFromSrc::Primitive(prim) => format::href_with_root_path(
                         PrimitiveType::primitive_locations(context.tcx())[prim],
                         context,
-                        Some(context_info.root_path),
+                        Some(href_context.root_path),
                     )
                     .ok()
                     .map(|(url, _, _)| url),
                 }
             })
         {
-            write!(out, "<a class=\"{}\" href=\"{}\">{}</a>", klass.as_html(), href, text_s);
-            return;
+            write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s);
+            return Some("</a>");
         }
     }
-    write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text_s);
+    write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s);
+    Some("</span>")
 }
 
 #[cfg(test)]
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 86961dc3bf1..34d590fb244 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -8,7 +8,8 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{ExprKind, HirId, Mod, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
+use rustc_span::hygiene::MacroKind;
+use rustc_span::{BytePos, ExpnKind, Span};
 
 use std::path::{Path, PathBuf};
 
@@ -63,33 +64,72 @@ struct SpanMapVisitor<'tcx> {
 
 impl<'tcx> SpanMapVisitor<'tcx> {
     /// This function is where we handle `hir::Path` elements and add them into the "span map".
-    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, path_span: Option<Span>) {
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
         let info = match path.res {
-            // FIXME: For now, we only handle `DefKind` if it's not `DefKind::TyParam` or
-            // `DefKind::Macro`. Would be nice to support them too alongside the other `DefKind`
+            // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
+            // Would be nice to support them too alongside the other `DefKind`
             // (such as primitive types!).
-            Res::Def(kind, def_id) if kind != DefKind::TyParam => {
-                if matches!(kind, DefKind::Macro(_)) {
-                    return;
-                }
-                Some(def_id)
-            }
+            Res::Def(kind, def_id) if kind != DefKind::TyParam => Some(def_id),
             Res::Local(_) => None,
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
-                let span = path_span.unwrap_or(path.span);
-                self.matches.insert(span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
+                self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
                 return;
             }
             Res::Err => return,
             _ => return,
         };
         if let Some(span) = self.tcx.hir().res_span(path.res) {
-            self.matches
-                .insert(path_span.unwrap_or(path.span), LinkFromSrc::Local(clean::Span::new(span)));
+            self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
         } else if let Some(def_id) = info {
-            self.matches.insert(path_span.unwrap_or(path.span), LinkFromSrc::External(def_id));
+            self.matches.insert(path.span, LinkFromSrc::External(def_id));
+        }
+    }
+
+    /// Adds the macro call into the span map. Returns `true` if the `span` was inside a macro
+    /// expansion, whether or not it was added to the span map.
+    ///
+    /// The idea for the macro support is to check if the current `Span` comes from expansion. If
+    /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
+    /// Finally, we get the information about the macro itself (`span` if "local", `DefId`
+    /// otherwise) and store it inside the span map.
+    fn handle_macro(&mut self, span: Span) -> bool {
+        if !span.from_expansion() {
+            return false;
+        }
+        // So if the `span` comes from a macro expansion, we need to get the original
+        // macro's `DefId`.
+        let mut data = span.ctxt().outer_expn_data();
+        let mut call_site = data.call_site;
+        // Macros can expand to code containing macros, which will in turn be expanded, etc.
+        // So the idea here is to "go up" until we're back to code that was generated from
+        // macro expansion so that we can get the `DefId` of the original macro that was at the
+        // origin of this expansion.
+        while call_site.from_expansion() {
+            data = call_site.ctxt().outer_expn_data();
+            call_site = data.call_site;
         }
+
+        let macro_name = match data.kind {
+            ExpnKind::Macro(MacroKind::Bang, macro_name) => macro_name,
+            // Even though we don't handle this kind of macro, this `data` still comes from
+            // expansion so we return `true` so we don't go any deeper in this code.
+            _ => return true,
+        };
+        let link_from_src = match data.macro_def_id {
+            Some(macro_def_id) if macro_def_id.is_local() => {
+                LinkFromSrc::Local(clean::Span::new(data.def_site))
+            }
+            Some(macro_def_id) => LinkFromSrc::External(macro_def_id),
+            None => return true,
+        };
+        let new_span = data.call_site;
+        let macro_name = macro_name.as_str();
+        // The "call_site" includes the whole macro with its "arguments". We only want
+        // the macro name.
+        let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
+        self.matches.insert(new_span, link_from_src);
+        true
     }
 }
 
@@ -101,7 +141,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     }
 
     fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
-        self.handle_path(path, None);
+        if self.handle_macro(path.span) {
+            return;
+        }
+        self.handle_path(path);
         intravisit::walk_path(self, path);
     }
 
@@ -143,12 +186,18 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
                     );
                 }
             }
+        } else if self.handle_macro(expr.span) {
+            // We don't want to go deeper into the macro.
+            return;
         }
         intravisit::walk_expr(self, expr);
     }
 
     fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
-        self.handle_path(path, None);
+        if self.handle_macro(path.span) {
+            return;
+        }
+        self.handle_path(path);
         intravisit::walk_use(self, path, id);
     }
 }
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 1971d08e5be..d0fd637ba88 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -297,7 +297,7 @@ pub(crate) fn print_src(
         None,
         edition,
         Some(line_numbers),
-        Some(highlight::ContextInfo { context, file_span, root_path }),
+        Some(highlight::HrefContext { context, file_span, root_path }),
         decoration_info,
     );
 }
diff --git a/src/test/rustdoc/check-source-code-urls-to-def-std.rs b/src/test/rustdoc/check-source-code-urls-to-def-std.rs
index b129ceb5b73..3396b234a77 100644
--- a/src/test/rustdoc/check-source-code-urls-to-def-std.rs
+++ b/src/test/rustdoc/check-source-code-urls-to-def-std.rs
@@ -15,3 +15,28 @@ pub fn foo(a: u32, b: &str, c: String) {
     let y: bool = true;
     babar();
 }
+
+macro_rules! yolo { () => {}}
+
+fn bar(a: i32) {}
+
+macro_rules! bar {
+    ($a:ident) => { bar($a) }
+}
+
+macro_rules! data {
+    ($x:expr) => { $x * 2 }
+}
+
+pub fn another_foo() {
+    // This is known limitation: if the macro doesn't generate anything, the visitor
+    // can't find any item or anything that could tell us that it comes from expansion.
+    // @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!'
+    yolo!();
+    // @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
+    eprintln!();
+    // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!'
+    let x = data!(4);
+    // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!'
+    bar!(x);
+}
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
index aae562ae722..384561f8ccd 100644
--- a/src/test/ui/associated-types/issue-87261.rs
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -83,17 +83,17 @@ fn main() {
     //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_foo());
-    //~^ ERROR type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_derived_foo());
-    //~^ ERROR type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic());
     //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic_foo());
-    //~^ ERROR type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic_duplicate());
-    //~^ ERROR type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
 }
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
index c00b48abc1c..8db4a49da3c 100644
--- a/src/test/ui/associated-types/issue-87261.stderr
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -160,7 +160,7 @@ help: consider constraining the associated type `<impl DerivedTrait as Trait>::A
 LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
    |                                                 +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:85:5
    |
 LL | fn returns_opaque_foo() -> impl Trait + Foo {
@@ -170,18 +170,18 @@ LL |     accepts_trait(returns_opaque_foo());
    |     ^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl Foo + Trait as Trait>::Associated`
+           found associated type `<impl Trait + Foo as Trait>::Associated`
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
    |
 LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
    |                           ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl Foo + Trait as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl Trait + Foo as Trait>::Associated` to `()`
    |
 LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
    |                                      +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:88:5
    |
 LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
@@ -191,8 +191,8 @@ LL |     accepts_trait(returns_opaque_derived_foo());
    |     ^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl Foo + DerivedTrait as Trait>::Associated`
-   = help: consider constraining the associated type `<impl Foo + DerivedTrait as Trait>::Associated` to `()`
+           found associated type `<impl DerivedTrait + Foo as Trait>::Associated`
+   = help: consider constraining the associated type `<impl DerivedTrait + Foo as Trait>::Associated` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
@@ -221,7 +221,7 @@ help: consider constraining the associated type `<impl GenericTrait<()> as Gener
 LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
    |                                                    +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
   --> $DIR/issue-87261.rs:94:5
    |
 LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
@@ -231,18 +231,18 @@ LL |     accepts_generic_trait(returns_opaque_generic_foo());
    |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated`
+           found associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated`
 note: required by a bound in `accepts_generic_trait`
   --> $DIR/issue-87261.rs:44:46
    |
 LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
    |                                              ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
-help: consider constraining the associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+help: consider constraining the associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated` to `()`
    |
 LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
    |                                                        +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
   --> $DIR/issue-87261.rs:97:5
    |
 LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
@@ -252,8 +252,8 @@ LL |     accepts_generic_trait(returns_opaque_generic_duplicate());
    |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated`
-   = help: consider constraining the associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+           found associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 note: required by a bound in `accepts_generic_trait`
   --> $DIR/issue-87261.rs:44:46
diff --git a/src/test/ui/impl-trait/suggest-calling-rpit-closure.rs b/src/test/ui/impl-trait/suggest-calling-rpit-closure.rs
new file mode 100644
index 00000000000..640156291a3
--- /dev/null
+++ b/src/test/ui/impl-trait/suggest-calling-rpit-closure.rs
@@ -0,0 +1,12 @@
+fn whatever() -> i32 {
+    opaque()
+//~^ ERROR mismatched types
+}
+
+fn opaque() -> impl Fn() -> i32 {
+    || 0
+}
+
+fn main() {
+    let _ = whatever();
+}
diff --git a/src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr b/src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr
new file mode 100644
index 00000000000..2a328a0e6f5
--- /dev/null
+++ b/src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-calling-rpit-closure.rs:2:5
+   |
+LL | fn whatever() -> i32 {
+   |                  --- expected `i32` because of return type
+LL |     opaque()
+   |     ^^^^^^^^ expected `i32`, found opaque type
+...
+LL | fn opaque() -> impl Fn() -> i32 {
+   |                ---------------- the found opaque type
+   |
+   = note:     expected type `i32`
+           found opaque type `impl Fn() -> i32`
+help: use parentheses to call this closure
+   |
+LL |     opaque()()
+   |             ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr
index 8eb81301bc3..d4f64a7de5b 100644
--- a/src/test/ui/parser/expr-as-stmt.stderr
+++ b/src/test/ui/parser/expr-as-stmt.stderr
@@ -201,6 +201,10 @@ LL |     { true } || { true }
    |
    = note: expected type `bool`
            found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:25]`
+help: use parentheses to call this closure
+   |
+LL |     { true } (|| { true })()
+   |              +           +++
 help: parentheses are required to parse this as an expression
    |
 LL |     ({ true }) || { true }
diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
index b948ab2abb5..e71f15ebfd2 100644
--- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
+++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
@@ -25,6 +25,12 @@ LL | |     }.hi() {
    |
    = note: expected type `bool`
            found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]`
+help: use parentheses to call this closure
+   |
+LL ~     while (|| Foo {
+LL |         x: 3
+LL ~     }.hi())() {
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr
index 70a64446f6a..360557fb520 100644
--- a/src/test/ui/reify-intrinsic.stderr
+++ b/src/test/ui/reify-intrinsic.stderr
@@ -8,10 +8,6 @@ LL |     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
    |
    = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
                  found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
-help: use parentheses to call this function
-   |
-LL |     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute(...);
-   |                                                                                   +++++
 
 error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
   --> $DIR/reify-intrinsic.rs:11:13
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index dfc7fdc1ed2..f7f39bd0b9a 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1118,6 +1118,10 @@ LL |     if let Range { start: F, end } = F..|| true {}
    |
    = note: expected type `bool`
            found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]`
+help: use parentheses to call this closure
+   |
+LL |     if let Range { start: F, end } = F..(|| true)() {}
+   |                                         +       +++
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:136:8
@@ -1314,6 +1318,10 @@ LL |     while let Range { start: F, end } = F..|| true {}
    |
    = note: expected type `bool`
            found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]`
+help: use parentheses to call this closure
+   |
+LL |     while let Range { start: F, end } = F..(|| true)() {}
+   |                                            +       +++
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:200:11
diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr
index ded581dc496..3e7041f02b3 100644
--- a/src/test/ui/span/move-closure.stderr
+++ b/src/test/ui/span/move-closure.stderr
@@ -8,6 +8,10 @@ LL |     let x: () = move || ();
    |
    = note: expected unit type `()`
                 found closure `[closure@$DIR/move-closure.rs:5:17: 5:27]`
+help: use parentheses to call this closure
+   |
+LL |     let x: () = (move || ())();
+   |                 +          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index 1ed784e8f5b..25ce458f6d8 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -33,7 +33,7 @@ LL |     let _: usize = foo;
            found fn item `fn(usize, usize) -> usize {foo}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = foo(a, b);
+LL |     let _: usize = foo(_, _);
    |                       ++++++
 
 error[E0308]: mismatched types
@@ -105,7 +105,7 @@ LL |     let _: usize = T::baz;
            found fn item `fn(usize, usize) -> usize {<_ as T>::baz}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = T::baz(x, y);
+LL |     let _: usize = T::baz(_, _);
    |                          ++++++
 
 error[E0308]: mismatched types
@@ -123,7 +123,7 @@ LL |     let _: usize = T::bat;
            found fn item `fn(usize) -> usize {<_ as T>::bat}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = T::bat(x);
+LL |     let _: usize = T::bat(_);
    |                          +++
 
 error[E0308]: mismatched types
@@ -159,7 +159,7 @@ LL |     let _: usize = X::baz;
            found fn item `fn(usize, usize) -> usize {<X as T>::baz}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = X::baz(x, y);
+LL |     let _: usize = X::baz(_, _);
    |                          ++++++
 
 error[E0308]: mismatched types
@@ -177,7 +177,7 @@ LL |     let _: usize = X::bat;
            found fn item `fn(usize) -> usize {<X as T>::bat}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = X::bat(x);
+LL |     let _: usize = X::bat(_);
    |                          +++
 
 error[E0308]: mismatched types
@@ -195,7 +195,7 @@ LL |     let _: usize = X::bax;
            found fn item `fn(usize) -> usize {<X as T>::bax}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = X::bax(x);
+LL |     let _: usize = X::bax(_);
    |                          +++
 
 error[E0308]: mismatched types
@@ -213,7 +213,7 @@ LL |     let _: usize = X::bach;
            found fn item `fn(usize) -> usize {<X as T>::bach}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = X::bach(x);
+LL |     let _: usize = X::bach(_);
    |                           +++
 
 error[E0308]: mismatched types
diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
index 33f81a77aaf..ab39ee74be4 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
@@ -15,6 +15,10 @@ LL |     || -> Closure { || () }
    |
    = note: expected unit type `()`
                 found closure `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
+help: use parentheses to call this closure
+   |
+LL |     || -> Closure { (|| ())() }
+   |                     +     +++
 
 error[E0308]: mismatched types
   --> $DIR/issue-63279.rs:8:5