about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-04-05 11:06:20 +0000
committerbors <bors@rust-lang.org>2021-04-05 11:06:20 +0000
commit39eee173fbcc21462d255b364b87715cd33b62db (patch)
treee930e86d52114de16148de08b917c974cb874669
parent58e71896506edb701f276158bd2f47e8788a1133 (diff)
parent3ca197e89c9affc76e79f0421e1bb9d65a8ec855 (diff)
downloadrust-39eee173fbcc21462d255b364b87715cd33b62db.tar.gz
rust-39eee173fbcc21462d255b364b87715cd33b62db.zip
Auto merge of #83880 - Dylan-DPC:rollup-hz9ph0e, r=Dylan-DPC
Rollup of 8 pull requests

Successful merges:

 - #81922 (Let `#[allow(unstable_name_collisions)]` work for things other than function)
 - #82483 (Use FromStr trait for number option parsing)
 - #82739 (Use the beta compiler for building bootstrap tools when `download-rustc` is set)
 - #83650 (Update Source Serif to release 4.004)
 - #83826 (List trait impls before deref methods in doc's sidebar)
 - #83831 (Add `#[inline]` to IpAddr methods)
 - #83863 (Render destructured struct function param names as underscore)
 - #83865 (Don't report disambiguator error if link would have been ignored)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_session/src/config.rs1
-rw-r--r--compiler/rustc_session/src/options.rs28
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs8
-rw-r--r--library/std/src/net/ip.rs3
-rw-r--r--src/bootstrap/bootstrap.py151
-rw-r--r--src/bootstrap/compile.rs15
-rw-r--r--src/bootstrap/config.rs98
-rw-r--r--src/bootstrap/tool.rs13
-rw-r--r--src/librustdoc/clean/utils.rs12
-rw-r--r--src/librustdoc/html/render/mod.rs15
-rw-r--r--src/librustdoc/html/render/write_shared.rs8
-rw-r--r--src/librustdoc/html/static/COPYRIGHT.txt12
-rw-r--r--src/librustdoc/html/static/SourceSerif4-Bold.ttf.woffbin0 -> 110552 bytes
-rw-r--r--src/librustdoc/html/static/SourceSerif4-It.ttf.woffbin0 -> 78108 bytes
-rw-r--r--src/librustdoc/html/static/SourceSerif4-LICENSE.md (renamed from src/librustdoc/html/static/SourceSerifPro-LICENSE.md)2
-rw-r--r--src/librustdoc/html/static/SourceSerif4-Regular.ttf.woffbin0 -> 103604 bytes
-rw-r--r--src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woffbin93248 -> 0 bytes
-rw-r--r--src/librustdoc/html/static/SourceSerifPro-It.ttf.woffbin36200 -> 0 bytes
-rw-r--r--src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woffbin88596 -> 0 bytes
-rw-r--r--src/librustdoc/html/static/rustdoc.css16
-rw-r--r--src/librustdoc/html/static_files.rs21
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs28
-rw-r--r--src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt8
-rw-r--r--src/test/run-make/emit-shared-files/Makefile6
-rw-r--r--src/test/rustdoc-ui/intra-doc/email-address-localhost.rs6
-rw-r--r--src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr15
-rw-r--r--src/test/rustdoc/intra-doc/email-address.rs6
-rw-r--r--src/test/rustdoc/struct-arg-pattern.rs10
-rw-r--r--src/test/ui/inference/issue-81522.rs31
31 files changed, 323 insertions, 194 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 82f3ee07c93..b628ae3ae3a 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1047,7 +1047,7 @@ pub unsafe fn with_llvm_pmb(
     // thresholds copied from clang.
     match (opt_level, opt_size, inline_threshold) {
         (.., Some(t)) => {
-            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
+            llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t);
         }
         (llvm::CodeGenOptLevel::Aggressive, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c45c90f24de..04d06864ee1 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -107,7 +107,7 @@ pub struct ModuleConfig {
     pub vectorize_loop: bool,
     pub vectorize_slp: bool,
     pub merge_functions: bool,
-    pub inline_threshold: Option<usize>,
+    pub inline_threshold: Option<u32>,
     pub new_llvm_pass_manager: bool,
     pub emit_lifetime_markers: bool,
 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b67feb47173..ec04bf7d054 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2332,6 +2332,7 @@ crate mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(PathBuf);
     impl_dep_tracking_hash_via_hash!(lint::Level);
     impl_dep_tracking_hash_via_hash!(Option<bool>);
+    impl_dep_tracking_hash_via_hash!(Option<u32>);
     impl_dep_tracking_hash_via_hash!(Option<usize>);
     impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index dd35cb97275..a184608ed29 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -251,9 +251,9 @@ macro_rules! options {
         pub const parse_list: &str = "a space-separated list of strings";
         pub const parse_opt_list: &str = parse_list;
         pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
-        pub const parse_uint: &str = "a number";
-        pub const parse_opt_uint: &str = parse_uint;
-        pub const parse_threads: &str = parse_uint;
+        pub const parse_number: &str = "a number";
+        pub const parse_opt_number: &str = parse_number;
+        pub const parse_threads: &str = parse_number;
         pub const parse_passes: &str = "a space-separated list of passes, or `all`";
         pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
         pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
@@ -417,16 +417,16 @@ macro_rules! options {
             }
         }
 
-        /// Use this for any uint option that has a static default.
-        fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
+        /// Use this for any numeric option that has a static default.
+        fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
             match v.and_then(|s| s.parse().ok()) {
                 Some(i) => { *slot = i; true },
                 None => false
             }
         }
 
-        /// Use this for any uint option that lacks a static default.
-        fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
+        /// Use this for any numeric option that lacks a static default.
+        fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
             match v {
                 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
                 None => false
@@ -787,13 +787,13 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "this option is deprecated and does nothing"),
     code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
         "choose the code model to use (`rustc --print code-models` for details)"),
-    codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
+    codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "divide crate into N units to optimize in parallel"),
     control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
         "use Windows Control Flow Guard (default: no)"),
     debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "explicitly enable the `cfg(debug_assertions)` directive"),
-    debuginfo: usize = (0, parse_uint, [TRACKED],
+    debuginfo: usize = (0, parse_number, [TRACKED],
         "debug info emission level (0 = no debug info, 1 = line tables only, \
         2 = full debug info with variable and type information; default: 0)"),
     default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
@@ -808,7 +808,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "force use of unwind tables"),
     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "enable incremental compilation"),
-    inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
+    inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
         "set the threshold for inlining a function"),
     link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
         "a single extra argument to append to the linker invocation (can be used several times)"),
@@ -996,9 +996,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "verify incr. comp. hashes of green query instances (default: no)"),
     inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable MIR inlining (default: no)"),
-    inline_mir_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
+    inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
         "a default MIR inlining threshold (default: 50)"),
-    inline_mir_hint_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
+    inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
         "inlining threshold for functions with inline hint (default: 100)"),
     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "control whether `#[inline]` functions are in all CGUs"),
@@ -1034,7 +1034,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
-    mir_opt_level: Option<usize> = (None, parse_opt_uint, [TRACKED],
+    mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
         "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
@@ -1155,7 +1155,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
     teach: bool = (false, parse_bool, [TRACKED],
         "show extended diagnostic help (default: no)"),
-    terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
+    terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "set the current terminal width"),
     tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select processor to schedule for (`rustc --print target-cpus` for details)"),
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index bfaf36e702f..d83b74f4ce9 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -83,6 +83,8 @@ struct ProbeContext<'a, 'tcx> {
     unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
 
     is_suggestion: IsSuggestion,
+
+    scope_expr_id: hir::HirId,
 }
 
 impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
@@ -448,6 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 orig_values,
                 steps.steps,
                 is_suggestion,
+                scope_expr_id,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -547,6 +550,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         orig_steps_var_values: OriginalQueryValues<'tcx>,
         steps: Lrc<Vec<CandidateStep<'tcx>>>,
         is_suggestion: IsSuggestion,
+        scope_expr_id: hir::HirId,
     ) -> ProbeContext<'a, 'tcx> {
         ProbeContext {
             fcx,
@@ -564,6 +568,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             private_candidate: None,
             unsatisfied_predicates: Vec::new(),
             is_suggestion,
+            scope_expr_id,
         }
     }
 
@@ -1312,7 +1317,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     ) {
         self.tcx.struct_span_lint_hir(
             lint::builtin::UNSTABLE_NAME_COLLISIONS,
-            self.fcx.body_id,
+            self.scope_expr_id,
             self.span,
             |lint| {
                 let def_kind = stable_pick.item.kind.as_def_kind();
@@ -1594,6 +1599,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 self.orig_steps_var_values.clone(),
                 steps,
                 IsSuggestion(true),
+                self.scope_expr_id,
             );
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 7f8c33dac56..da2415e3610 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -993,6 +993,7 @@ impl Ord for Ipv4Addr {
 }
 
 impl IntoInner<c::in_addr> for Ipv4Addr {
+    #[inline]
     fn into_inner(self) -> c::in_addr {
         self.inner
     }
@@ -1800,11 +1801,13 @@ impl Ord for Ipv6Addr {
 }
 
 impl AsInner<c::in6_addr> for Ipv6Addr {
+    #[inline]
     fn as_inner(&self) -> &c::in6_addr {
         &self.inner
     }
 }
 impl FromInner<c::in6_addr> for Ipv6Addr {
+    #[inline]
     fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
         Ipv6Addr { inner: addr }
     }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 075756b73ba..0b024d1333f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -383,7 +383,7 @@ class RustBuild(object):
         self.nix_deps_dir = None
         self.rustc_commit = None
 
-    def download_stage0(self):
+    def download_toolchain(self, stage0=True, rustc_channel=None):
         """Fetch the build system for Rust, written in Rust
 
         This method will build a cache directory, then it will fetch the
@@ -393,43 +393,47 @@ class RustBuild(object):
         Each downloaded tarball is extracted, after that, the script
         will move all the content to the right place.
         """
-        rustc_channel = self.rustc_channel
+        if rustc_channel is None:
+            rustc_channel = self.rustc_channel
         rustfmt_channel = self.rustfmt_channel
-
-        if self.rustc().startswith(self.bin_root()) and \
-                (not os.path.exists(self.rustc()) or
-                 self.program_out_of_date(self.rustc_stamp(), self.date + str(self.rustc_commit))):
-            if os.path.exists(self.bin_root()):
-                shutil.rmtree(self.bin_root())
-            download_rustc = self.rustc_commit is not None
+        bin_root = self.bin_root(stage0)
+
+        key = self.date
+        if not stage0:
+            key += str(self.rustc_commit)
+        if self.rustc(stage0).startswith(bin_root) and \
+                (not os.path.exists(self.rustc(stage0)) or
+                 self.program_out_of_date(self.rustc_stamp(stage0), key)):
+            if os.path.exists(bin_root):
+                shutil.rmtree(bin_root)
             tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz'
             filename = "rust-std-{}-{}{}".format(
                 rustc_channel, self.build, tarball_suffix)
             pattern = "rust-std-{}".format(self.build)
-            self._download_component_helper(filename, pattern, tarball_suffix, download_rustc)
+            self._download_component_helper(filename, pattern, tarball_suffix, stage0)
             filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
-            self._download_component_helper(filename, "rustc", tarball_suffix, download_rustc)
+            self._download_component_helper(filename, "rustc", tarball_suffix, stage0)
             filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
             self._download_component_helper(filename, "cargo", tarball_suffix)
-            if self.rustc_commit is not None:
+            if not stage0:
                 filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
                 self._download_component_helper(
-                    filename, "rustc-dev", tarball_suffix, download_rustc
+                    filename, "rustc-dev", tarball_suffix, stage0
                 )
 
-            self.fix_bin_or_dylib("{}/bin/rustc".format(self.bin_root()))
-            self.fix_bin_or_dylib("{}/bin/rustdoc".format(self.bin_root()))
-            self.fix_bin_or_dylib("{}/bin/cargo".format(self.bin_root()))
-            lib_dir = "{}/lib".format(self.bin_root())
+            self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
+            self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
+            self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
+            lib_dir = "{}/lib".format(bin_root)
             for lib in os.listdir(lib_dir):
                 if lib.endswith(".so"):
                     self.fix_bin_or_dylib(os.path.join(lib_dir, lib), rpath_libz=True)
-            with output(self.rustc_stamp()) as rust_stamp:
-                rust_stamp.write(self.date + str(self.rustc_commit))
+            with output(self.rustc_stamp(stage0)) as rust_stamp:
+                rust_stamp.write(key)
 
-        if self.rustfmt() and self.rustfmt().startswith(self.bin_root()) and (
+        if self.rustfmt() and self.rustfmt().startswith(bin_root) and (
             not os.path.exists(self.rustfmt())
             or self.program_out_of_date(self.rustfmt_stamp(), self.rustfmt_channel)
         ):
@@ -440,12 +444,13 @@ class RustBuild(object):
                 self._download_component_helper(
                     filename, "rustfmt-preview", tarball_suffix, key=date
                 )
-                self.fix_bin_or_dylib("{}/bin/rustfmt".format(self.bin_root()))
-                self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(self.bin_root()))
+                self.fix_bin_or_dylib("{}/bin/rustfmt".format(bin_root))
+                self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(bin_root))
                 with output(self.rustfmt_stamp()) as rustfmt_stamp:
                     rustfmt_stamp.write(self.rustfmt_channel)
 
-        if self.downloading_llvm():
+        # Avoid downloading LLVM twice (once for stage0 and once for the master rustc)
+        if self.downloading_llvm() and stage0:
             # We want the most recent LLVM submodule update to avoid downloading
             # LLVM more often than necessary.
             #
@@ -498,27 +503,26 @@ class RustBuild(object):
             or (opt == "if-available" and self.build in supported_platforms)
 
     def _download_component_helper(
-        self, filename, pattern, tarball_suffix, download_rustc=False, key=None
+        self, filename, pattern, tarball_suffix, stage0=True, key=None
     ):
         if key is None:
-            if download_rustc:
-                key = self.rustc_commit
-            else:
+            if stage0:
                 key = self.date
+            else:
+                key = self.rustc_commit
         cache_dst = os.path.join(self.build_dir, "cache")
         rustc_cache = os.path.join(cache_dst, key)
         if not os.path.exists(rustc_cache):
             os.makedirs(rustc_cache)
 
-        if download_rustc:
-            url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(self.rustc_commit)
-        else:
+        if stage0:
             url = "{}/dist/{}".format(self._download_url, key)
+        else:
+            url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(self.rustc_commit)
         tarball = os.path.join(rustc_cache, filename)
         if not os.path.exists(tarball):
-            do_verify = not download_rustc
-            get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=do_verify)
-        unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
+            get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=stage0)
+        unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose)
 
     def _download_ci_llvm(self, llvm_sha, llvm_assertions):
         cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions)
@@ -576,10 +580,10 @@ class RustBuild(object):
         nix_os_msg = "info: you seem to be running NixOS. Attempting to patch"
         print(nix_os_msg, fname)
 
-        # Only build `stage0/.nix-deps` once.
+        # Only build `.nix-deps` once.
         nix_deps_dir = self.nix_deps_dir
         if not nix_deps_dir:
-            nix_deps_dir = "{}/.nix-deps".format(self.bin_root())
+            nix_deps_dir = ".nix-deps"
             if not os.path.exists(nix_deps_dir):
                 os.makedirs(nix_deps_dir)
 
@@ -637,8 +641,8 @@ class RustBuild(object):
             print("warning: failed to call patchelf:", reason)
             return
 
-    # Return the stage1 compiler to download, if any.
-    def maybe_download_rustc(self):
+    # If `download-rustc` is set, download the most recent commit with CI artifacts
+    def maybe_download_ci_toolchain(self):
         # If `download-rustc` is not set, default to rebuilding.
         if self.get_toml("download-rustc", section="rust") != "true":
             return None
@@ -658,17 +662,23 @@ class RustBuild(object):
         if status != 0:
             print("warning: `download-rustc` is enabled, but there are changes to compiler/")
 
-        return commit
+        if self.verbose:
+            print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
+        self.rustc_commit = commit
+        # FIXME: support downloading artifacts from the beta channel
+        self.download_toolchain(False, "nightly")
 
-    def rustc_stamp(self):
-        """Return the path for .rustc-stamp
+    def rustc_stamp(self, stage0):
+        """Return the path for .rustc-stamp at the given stage
 
         >>> rb = RustBuild()
         >>> rb.build_dir = "build"
-        >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
+        >>> rb.rustc_stamp(True) == os.path.join("build", "stage0", ".rustc-stamp")
+        True
+        >>> rb.rustc_stamp(False) == os.path.join("build", "ci-rustc", ".rustc-stamp")
         True
         """
-        return os.path.join(self.bin_root(), '.rustc-stamp')
+        return os.path.join(self.bin_root(stage0), '.rustc-stamp')
 
     def rustfmt_stamp(self):
         """Return the path for .rustfmt-stamp
@@ -678,7 +688,7 @@ class RustBuild(object):
         >>> rb.rustfmt_stamp() == os.path.join("build", "stage0", ".rustfmt-stamp")
         True
         """
-        return os.path.join(self.bin_root(), '.rustfmt-stamp')
+        return os.path.join(self.bin_root(True), '.rustfmt-stamp')
 
     def llvm_stamp(self):
         """Return the path for .rustfmt-stamp
@@ -698,21 +708,27 @@ class RustBuild(object):
         with open(stamp_path, 'r') as stamp:
             return key != stamp.read()
 
-    def bin_root(self):
-        """Return the binary root directory
+    def bin_root(self, stage0):
+        """Return the binary root directory for the given stage
 
         >>> rb = RustBuild()
         >>> rb.build_dir = "build"
-        >>> rb.bin_root() == os.path.join("build", "stage0")
+        >>> rb.bin_root(True) == os.path.join("build", "stage0")
+        True
+        >>> rb.bin_root(False) == os.path.join("build", "ci-rustc")
         True
 
         When the 'build' property is given should be a nested directory:
 
         >>> rb.build = "devel"
-        >>> rb.bin_root() == os.path.join("build", "devel", "stage0")
+        >>> rb.bin_root(True) == os.path.join("build", "devel", "stage0")
         True
         """
-        return os.path.join(self.build_dir, self.build, "stage0")
+        if stage0:
+            subdir = "stage0"
+        else:
+            subdir = "ci-rustc"
+        return os.path.join(self.build_dir, self.build, subdir)
 
     def llvm_root(self):
         """Return the CI LLVM root directory
@@ -775,9 +791,9 @@ class RustBuild(object):
         """Return config path for cargo"""
         return self.program_config('cargo')
 
-    def rustc(self):
+    def rustc(self, stage0):
         """Return config path for rustc"""
-        return self.program_config('rustc')
+        return self.program_config('rustc', stage0)
 
     def rustfmt(self):
         """Return config path for rustfmt"""
@@ -785,23 +801,27 @@ class RustBuild(object):
             return None
         return self.program_config('rustfmt')
 
-    def program_config(self, program):
-        """Return config path for the given program
+    def program_config(self, program, stage0=True):
+        """Return config path for the given program at the given stage
 
         >>> rb = RustBuild()
         >>> rb.config_toml = 'rustc = "rustc"\\n'
         >>> rb.program_config('rustc')
         'rustc'
         >>> rb.config_toml = ''
-        >>> cargo_path = rb.program_config('cargo')
-        >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(),
+        >>> cargo_path = rb.program_config('cargo', True)
+        >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(True),
+        ... "bin", "cargo")
+        True
+        >>> cargo_path = rb.program_config('cargo', False)
+        >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(False),
         ... "bin", "cargo")
         True
         """
         config = self.get_toml(program)
         if config:
             return os.path.expanduser(config)
-        return os.path.join(self.bin_root(), "bin", "{}{}".format(
+        return os.path.join(self.bin_root(stage0), "bin", "{}{}".format(
             program, self.exe_suffix()))
 
     @staticmethod
@@ -856,14 +876,14 @@ class RustBuild(object):
         if "CARGO_BUILD_TARGET" in env:
             del env["CARGO_BUILD_TARGET"]
         env["CARGO_TARGET_DIR"] = build_dir
-        env["RUSTC"] = self.rustc()
-        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+        env["RUSTC"] = self.rustc(True)
+        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \
             (os.pathsep + env["LD_LIBRARY_PATH"]) \
             if "LD_LIBRARY_PATH" in env else ""
-        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \
             (os.pathsep + env["DYLD_LIBRARY_PATH"]) \
             if "DYLD_LIBRARY_PATH" in env else ""
-        env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+        env["LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \
             (os.pathsep + env["LIBRARY_PATH"]) \
             if "LIBRARY_PATH" in env else ""
         # preserve existing RUSTFLAGS
@@ -886,7 +906,7 @@ class RustBuild(object):
         if self.get_toml("deny-warnings", "rust") != "false":
             env["RUSTFLAGS"] += " -Dwarnings"
 
-        env["PATH"] = os.path.join(self.bin_root(), "bin") + \
+        env["PATH"] = os.path.join(self.bin_root(True), "bin") + \
             os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
             raise Exception("no cargo executable found at `{}`".format(
@@ -1137,14 +1157,9 @@ def bootstrap(help_triggered):
     build.update_submodules()
 
     # Fetch/build the bootstrap
-    build.rustc_commit = build.maybe_download_rustc()
-    if build.rustc_commit is not None:
-        if build.verbose:
-            commit = build.rustc_commit
-            print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
-        # FIXME: support downloading artifacts from the beta channel
-        build.rustc_channel = "nightly"
-    build.download_stage0()
+    build.download_toolchain()
+    # Download the master compiler if `download-rustc` is set
+    build.maybe_download_ci_toolchain()
     sys.stdout.flush()
     build.ensure_vendored()
     build.build_bootstrap()
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 9398f211721..8244c7710ab 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -65,7 +65,9 @@ impl Step for Std {
 
         // These artifacts were already copied (in `impl Step for Sysroot`).
         // Don't recompile them.
-        if builder.config.download_rustc {
+        // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
+        // so its artifacts can't be reused.
+        if builder.config.download_rustc && compiler.stage != 0 {
             return;
         }
 
@@ -513,7 +515,9 @@ impl Step for Rustc {
         let compiler = self.compiler;
         let target = self.target;
 
-        if builder.config.download_rustc {
+        // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
+        // so its artifacts can't be reused.
+        if builder.config.download_rustc && compiler.stage != 0 {
             // Copy the existing artifacts instead of rebuilding them.
             // NOTE: this path is only taken for tools linking to rustc-dev.
             builder.ensure(Sysroot { compiler });
@@ -934,14 +938,15 @@ impl Step for Sysroot {
         t!(fs::create_dir_all(&sysroot));
 
         // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
-        if builder.config.download_rustc {
+        if builder.config.download_rustc && compiler.stage != 0 {
             assert_eq!(
                 builder.config.build, compiler.host,
                 "Cross-compiling is not yet supported with `download-rustc`",
             );
             // Copy the compiler into the correct sysroot.
-            let stage0_dir = builder.config.out.join(&*builder.config.build.triple).join("stage0");
-            builder.cp_r(&stage0_dir, &sysroot);
+            let ci_rustc_dir =
+                builder.config.out.join(&*builder.config.build.triple).join("ci-rustc");
+            builder.cp_r(&ci_rustc_dir, &sysroot);
             return INTERNER.intern_path(sysroot);
         }
 
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index b9b090bb2d2..471f671fd27 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -687,51 +687,6 @@ impl Config {
         set(&mut config.print_step_timings, build.print_step_timings);
         set(&mut config.print_step_rusage, build.print_step_rusage);
 
-        // See https://github.com/rust-lang/compiler-team/issues/326
-        config.stage = match config.cmd {
-            Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0),
-            Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0),
-            Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1),
-            Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1),
-            Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
-            Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
-            Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
-            // These are all bootstrap tools, which don't depend on the compiler.
-            // The stage we pass shouldn't matter, but use 0 just in case.
-            Subcommand::Clean { .. }
-            | Subcommand::Clippy { .. }
-            | Subcommand::Fix { .. }
-            | Subcommand::Run { .. }
-            | Subcommand::Setup { .. }
-            | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
-        };
-
-        // CI should always run stage 2 builds, unless it specifically states otherwise
-        #[cfg(not(test))]
-        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
-            match config.cmd {
-                Subcommand::Test { .. }
-                | Subcommand::Doc { .. }
-                | Subcommand::Build { .. }
-                | Subcommand::Bench { .. }
-                | Subcommand::Dist { .. }
-                | Subcommand::Install { .. } => {
-                    assert_eq!(
-                        config.stage, 2,
-                        "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`",
-                        config.stage,
-                    );
-                }
-                Subcommand::Clean { .. }
-                | Subcommand::Check { .. }
-                | Subcommand::Clippy { .. }
-                | Subcommand::Fix { .. }
-                | Subcommand::Run { .. }
-                | Subcommand::Setup { .. }
-                | Subcommand::Format { .. } => {}
-            }
-        }
-
         config.verbose = cmp::max(config.verbose, flags.verbose);
 
         if let Some(install) = toml.install {
@@ -1005,6 +960,59 @@ impl Config {
         let default = config.channel == "dev";
         config.ignore_git = ignore_git.unwrap_or(default);
 
+        let download_rustc = config.download_rustc;
+        // See https://github.com/rust-lang/compiler-team/issues/326
+        config.stage = match config.cmd {
+            Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0),
+            // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
+            Subcommand::Doc { .. } => {
+                flags.stage.or(build.doc_stage).unwrap_or(if download_rustc { 2 } else { 0 })
+            }
+            Subcommand::Build { .. } => {
+                flags.stage.or(build.build_stage).unwrap_or(if download_rustc { 2 } else { 1 })
+            }
+            Subcommand::Test { .. } => {
+                flags.stage.or(build.test_stage).unwrap_or(if download_rustc { 2 } else { 1 })
+            }
+            Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
+            Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
+            Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
+            // These are all bootstrap tools, which don't depend on the compiler.
+            // The stage we pass shouldn't matter, but use 0 just in case.
+            Subcommand::Clean { .. }
+            | Subcommand::Clippy { .. }
+            | Subcommand::Fix { .. }
+            | Subcommand::Run { .. }
+            | Subcommand::Setup { .. }
+            | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
+        };
+
+        // CI should always run stage 2 builds, unless it specifically states otherwise
+        #[cfg(not(test))]
+        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+            match config.cmd {
+                Subcommand::Test { .. }
+                | Subcommand::Doc { .. }
+                | Subcommand::Build { .. }
+                | Subcommand::Bench { .. }
+                | Subcommand::Dist { .. }
+                | Subcommand::Install { .. } => {
+                    assert_eq!(
+                        config.stage, 2,
+                        "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`",
+                        config.stage,
+                    );
+                }
+                Subcommand::Clean { .. }
+                | Subcommand::Check { .. }
+                | Subcommand::Clippy { .. }
+                | Subcommand::Fix { .. }
+                | Subcommand::Run { .. }
+                | Subcommand::Setup { .. }
+                | Subcommand::Format { .. } => {}
+            }
+        }
+
         config
     }
 
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index bfb846f3b56..f9be35d7c5e 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -513,6 +513,19 @@ impl Step for Rustdoc {
         // rustc compiler it's paired with, so it must be built with the previous stage compiler.
         let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
 
+        // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually
+        // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build
+        // it.
+        builder.ensure(compile::Std { compiler: build_compiler, target: target_compiler.host });
+        builder.ensure(compile::Rustc { compiler: build_compiler, target: target_compiler.host });
+        // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0
+        // compiler, since you do just as much work.
+        if !builder.config.dry_run && builder.config.download_rustc && build_compiler.stage == 0 {
+            println!(
+                "warning: `download-rustc` does nothing when building stage1 tools; consider using `--stage 2` instead"
+            );
+        }
+
         // The presence of `target_compiler` ensures that the necessary libraries (codegen backends,
         // compiler libraries, ...) are built. Rustdoc does not require the presence of any
         // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 60cbe9f376f..9c0ed1480fe 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -251,19 +251,9 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
     debug!("trying to get a name from pattern: {:?}", p);
 
     Symbol::intern(&match p.kind {
-        PatKind::Wild => return kw::Underscore,
+        PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
         PatKind::Binding(_, _, ident, _) => return ident.name,
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
-        PatKind::Struct(ref name, ref fields, etc) => format!(
-            "{} {{ {}{} }}",
-            qpath_to_string(name),
-            fields
-                .iter()
-                .map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat)))
-                .collect::<Vec<String>>()
-                .join(", "),
-            if etc { ", .." } else { "" }
-        ),
         PatKind::Or(ref pats) => pats
             .iter()
             .map(|p| name_from_pat(&**p).to_string())
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 7b656baa1b4..bf57e3c37d3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1915,13 +1915,6 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
         }
 
         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
-            if let Some(impl_) = v
-                .iter()
-                .filter(|i| i.inner_impl().trait_.is_some())
-                .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did)
-            {
-                sidebar_deref_methods(cx, out, impl_, v);
-            }
             let format_impls = |impls: Vec<&Impl>| {
                 let mut links = FxHashSet::default();
 
@@ -1989,6 +1982,14 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 );
                 write_sidebar_links(out, blanket_format);
             }
+
+            if let Some(impl_) = v
+                .iter()
+                .filter(|i| i.inner_impl().trait_.is_some())
+                .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did)
+            {
+                sidebar_deref_methods(cx, out, impl_, v);
+            }
         }
     }
 }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 59dc4ef9449..8fb6d68f3c6 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -26,10 +26,10 @@ crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
         "FiraSans-Regular.woff" => static_files::fira_sans::REGULAR,
         "FiraSans-Medium.woff" => static_files::fira_sans::MEDIUM,
         "FiraSans-LICENSE.txt" => static_files::fira_sans::LICENSE,
-        "SourceSerifPro-Regular.ttf.woff" => static_files::source_serif_pro::REGULAR,
-        "SourceSerifPro-Bold.ttf.woff" => static_files::source_serif_pro::BOLD,
-        "SourceSerifPro-It.ttf.woff" => static_files::source_serif_pro::ITALIC,
-        "SourceSerifPro-LICENSE.md" => static_files::source_serif_pro::LICENSE,
+        "SourceSerif4-Regular.ttf.woff" => static_files::source_serif_4::REGULAR,
+        "SourceSerif4-Bold.ttf.woff" => static_files::source_serif_4::BOLD,
+        "SourceSerif4-It.ttf.woff" => static_files::source_serif_4::ITALIC,
+        "SourceSerif4-LICENSE.md" => static_files::source_serif_4::LICENSE,
         "SourceCodePro-Regular.ttf.woff" => static_files::source_code_pro::REGULAR,
         "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
         "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt
index 24bdca6544d..16d79032fcc 100644
--- a/src/librustdoc/html/static/COPYRIGHT.txt
+++ b/src/librustdoc/html/static/COPYRIGHT.txt
@@ -33,14 +33,14 @@ included, and carry their own copyright notices and license terms:
     Licensed under the SIL Open Font License, Version 1.1.
     See SourceCodePro-LICENSE.txt.
 
-* Source Serif Pro (SourceSerifPro-Regular.ttf.woff,
-    SourceSerifPro-Bold.ttf.woff, SourceSerifPro-It.ttf.woff):
+* Source Serif 4 (SourceSerif4-Regular.ttf.woff, SourceSerif4-Bold.ttf.woff,
+    SourceSerif4-It.ttf.woff):
 
-    Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with
-    Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of
-    Adobe Systems Incorporated in the United States and/or other countries.
+    Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
+    'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
+    States and/or other countries.
 
     Licensed under the SIL Open Font License, Version 1.1.
-    See SourceSerifPro-LICENSE.txt.
+    See SourceSerif4-LICENSE.md.
 
 This copyright file is intended to be distributed with rustdoc output.
diff --git a/src/librustdoc/html/static/SourceSerif4-Bold.ttf.woff b/src/librustdoc/html/static/SourceSerif4-Bold.ttf.woff
new file mode 100644
index 00000000000..8ad41888e6e
--- /dev/null
+++ b/src/librustdoc/html/static/SourceSerif4-Bold.ttf.woff
Binary files differdiff --git a/src/librustdoc/html/static/SourceSerif4-It.ttf.woff b/src/librustdoc/html/static/SourceSerif4-It.ttf.woff
new file mode 100644
index 00000000000..2a34b5c42a8
--- /dev/null
+++ b/src/librustdoc/html/static/SourceSerif4-It.ttf.woff
Binary files differdiff --git a/src/librustdoc/html/static/SourceSerifPro-LICENSE.md b/src/librustdoc/html/static/SourceSerif4-LICENSE.md
index 22cb755f2f1..68ea1892406 100644
--- a/src/librustdoc/html/static/SourceSerifPro-LICENSE.md
+++ b/src/librustdoc/html/static/SourceSerif4-LICENSE.md
@@ -1,4 +1,4 @@
-Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
+Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
 
 This Font Software is licensed under the SIL Open Font License, Version 1.1.
 
diff --git a/src/librustdoc/html/static/SourceSerif4-Regular.ttf.woff b/src/librustdoc/html/static/SourceSerif4-Regular.ttf.woff
new file mode 100644
index 00000000000..45a5521ab0c
--- /dev/null
+++ b/src/librustdoc/html/static/SourceSerif4-Regular.ttf.woff
Binary files differdiff --git a/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff
deleted file mode 100644
index ca254318fe9..00000000000
--- a/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff
+++ /dev/null
Binary files differdiff --git a/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff
deleted file mode 100644
index a287bbe6ed3..00000000000
--- a/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff
+++ /dev/null
Binary files differdiff --git a/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff
deleted file mode 100644
index a3d55cfdf25..00000000000
--- a/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff
+++ /dev/null
Binary files differdiff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index f3ddd8ec6fa..585b7459bd7 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -18,26 +18,26 @@
 	font-display: swap;
 }
 
-/* See SourceSerifPro-LICENSE.txt for the Source Serif Pro license. */
+/* See SourceSerif4-LICENSE.md for the Source Serif 4 license. */
 @font-face {
-	font-family: 'Source Serif Pro';
+	font-family: 'Source Serif 4';
 	font-style: normal;
 	font-weight: 400;
-	src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff');
+	src: local('Source Serif 4'), url("SourceSerif4-Regular.ttf.woff") format('woff');
 	font-display: swap;
 }
 @font-face {
-	font-family: 'Source Serif Pro';
+	font-family: 'Source Serif 4';
 	font-style: italic;
 	font-weight: 400;
-	src: local('Source Serif Pro Italic'), url("SourceSerifPro-It.ttf.woff") format('woff');
+	src: local('Source Serif 4 Italic'), url("SourceSerif4-It.ttf.woff") format('woff');
 	font-display: swap;
 }
 @font-face {
-	font-family: 'Source Serif Pro';
+	font-family: 'Source Serif 4';
 	font-style: normal;
 	font-weight: 700;
-	src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff');
+	src: local('Source Serif 4 Bold'), url("SourceSerif4-Bold.ttf.woff") format('woff');
 	font-display: swap;
 }
 
@@ -90,7 +90,7 @@ html {
 /* General structure and fonts */
 
 body {
-	font: 16px/1.4 "Source Serif Pro", serif;
+	font: 16px/1.4 "Source Serif 4", serif;
 	margin: 0;
 	position: relative;
 	padding: 10px 15px 20px 15px;
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 83d4a11e620..b3ac865d55e 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -89,20 +89,19 @@ crate mod fira_sans {
     crate static LICENSE: &[u8] = include_bytes!("static/FiraSans-LICENSE.txt");
 }
 
-/// Files related to the Source Serif Pro font.
-crate mod source_serif_pro {
-    /// The file `SourceSerifPro-Regular.ttf.woff`, the Regular variant of the Source Serif Pro
-    /// font.
-    crate static REGULAR: &[u8] = include_bytes!("static/SourceSerifPro-Regular.ttf.woff");
+/// Files related to the Source Serif 4 font.
+crate mod source_serif_4 {
+    /// The file `SourceSerif4-Regular.ttf.woff`, the Regular variant of the Source Serif 4 font.
+    crate static REGULAR: &[u8] = include_bytes!("static/SourceSerif4-Regular.ttf.woff");
 
-    /// The file `SourceSerifPro-Bold.ttf.woff`, the Bold variant of the Source Serif Pro font.
-    crate static BOLD: &[u8] = include_bytes!("static/SourceSerifPro-Bold.ttf.woff");
+    /// The file `SourceSerif4-Bold.ttf.woff`, the Bold variant of the Source Serif 4 font.
+    crate static BOLD: &[u8] = include_bytes!("static/SourceSerif4-Bold.ttf.woff");
 
-    /// The file `SourceSerifPro-It.ttf.woff`, the Italic variant of the Source Serif Pro font.
-    crate static ITALIC: &[u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff");
+    /// The file `SourceSerif4-It.ttf.woff`, the Italic variant of the Source Serif 4 font.
+    crate static ITALIC: &[u8] = include_bytes!("static/SourceSerif4-It.ttf.woff");
 
-    /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font.
-    crate static LICENSE: &[u8] = include_bytes!("static/SourceSerifPro-LICENSE.md");
+    /// The file `SourceSerif4-LICENSE.txt`, the license text for the Source Serif 4 font.
+    crate static LICENSE: &[u8] = include_bytes!("static/SourceSerif4-LICENSE.md");
 }
 
 /// Files related to the Source Code Pro font.
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 437f42b26dd..545fbf26181 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -978,14 +978,18 @@ impl LinkCollector<'_, '_> {
             Ok(Some((d, path))) => (path.trim(), Some(d)),
             Ok(None) => (link.trim(), None),
             Err((err_msg, relative_range)) => {
-                let disambiguator_range = (no_backticks_range.start + relative_range.start)
-                    ..(no_backticks_range.start + relative_range.end);
-                disambiguator_error(self.cx, &item, dox, disambiguator_range, &err_msg);
+                if !should_ignore_link_with_disambiguators(link) {
+                    // Only report error if we would not have ignored this link.
+                    // See issue #83859.
+                    let disambiguator_range = (no_backticks_range.start + relative_range.start)
+                        ..(no_backticks_range.start + relative_range.end);
+                    disambiguator_error(self.cx, &item, dox, disambiguator_range, &err_msg);
+                }
                 return None;
             }
         };
 
-        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) {
+        if should_ignore_link(path_str) {
             return None;
         }
 
@@ -1515,6 +1519,22 @@ fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> {
         ..(ori_link.range.start + before_second_backtick_group)
 }
 
+/// Returns true if we should ignore `link` due to it being unlikely
+/// that it is an intra-doc link. `link` should still have disambiguators
+/// if there were any.
+///
+/// The difference between this and [`should_ignore_link()`] is that this
+/// check should only be used on links that still have disambiguators.
+fn should_ignore_link_with_disambiguators(link: &str) -> bool {
+    link.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;@()".contains(ch)))
+}
+
+/// Returns true if we should ignore `path_str` due to it being unlikely
+/// that it is an intra-doc link.
+fn should_ignore_link(path_str: &str) -> bool {
+    path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch)))
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 /// Disambiguators for a link.
 crate enum Disambiguator {
diff --git a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
index befbdab0ad9..4b20cd5d745 100644
--- a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
+++ b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
@@ -10,7 +10,7 @@ SourceCodePro-It.ttf.woff
 SourceCodePro-LICENSE.txt
 SourceCodePro-Regular.ttf.woff
 SourceCodePro-Semibold.ttf.woff
-SourceSerifPro-Bold.ttf.woff
-SourceSerifPro-It.ttf.woff
-SourceSerifPro-LICENSE.md
-SourceSerifPro-Regular.ttf.woff
+SourceSerif4-Bold.ttf.woff
+SourceSerif4-It.ttf.woff
+SourceSerif4-LICENSE.md
+SourceSerif4-Regular.ttf.woff
diff --git a/src/test/run-make/emit-shared-files/Makefile b/src/test/run-make/emit-shared-files/Makefile
index 5c4825ae66c..d89b526d430 100644
--- a/src/test/run-make/emit-shared-files/Makefile
+++ b/src/test/run-make/emit-shared-files/Makefile
@@ -14,7 +14,7 @@ invocation-only:
 	[ -e $(INVOCATION_ONLY)/x/index.html ]
 	[ -e $(INVOCATION_ONLY)/theme-xxx.css ] # generated from z.css
 	! [ -e $(INVOCATION_ONLY)/storage-xxx.js ]
-	! [ -e $(INVOCATION_ONLY)/SourceSerifPro-It.ttf.woff ]
+	! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff ]
 
 	# FIXME: this probably shouldn't have a suffix
 	[ -e $(INVOCATION_ONLY)/y-xxx.css ]
@@ -24,7 +24,7 @@ invocation-only:
 toolchain-only:
 	$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
 	[ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ]
-	! [ -e $(TOOLCHAIN_ONLY)/SourceSerifPro-It.ttf.woff ]
+	! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff ]
 	! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
 	! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
 	! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
@@ -35,7 +35,7 @@ toolchain-only:
 all-shared:
 	$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
 	[ -e $(ALL_SHARED)/storage-xxx.js ]
-	[ -e $(ALL_SHARED)/SourceSerifPro-It.ttf.woff ]
+	[ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff ]
 	! [ -e $(ALL_SHARED)/search-index-xxx.js ]
 	! [ -e $(ALL_SHARED)/settings.html ]
 	! [ -e $(ALL_SHARED)/x ]
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
new file mode 100644
index 00000000000..417618c7458
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
@@ -0,0 +1,6 @@
+#![deny(warnings)]
+
+//! Email me at <hello@localhost>.
+//~^ ERROR unknown disambiguator `hello`
+
+//! This should *not* warn: <hello@example.com>.
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
new file mode 100644
index 00000000000..de215b2163b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
@@ -0,0 +1,15 @@
+error: unknown disambiguator `hello`
+  --> $DIR/email-address-localhost.rs:3:18
+   |
+LL | //! Email me at <hello@localhost>.
+   |                  ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/email-address-localhost.rs:1:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs
new file mode 100644
index 00000000000..c407eb80da2
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/email-address.rs
@@ -0,0 +1,6 @@
+//! Email me at <hello@example.com>.
+//! Email me at <hello-world@example.com>.
+//! Email me at <hello@localhost> (this warns but will still become a link).
+// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
diff --git a/src/test/rustdoc/struct-arg-pattern.rs b/src/test/rustdoc/struct-arg-pattern.rs
new file mode 100644
index 00000000000..3c0369e3d34
--- /dev/null
+++ b/src/test/rustdoc/struct-arg-pattern.rs
@@ -0,0 +1,10 @@
+#![crate_name = "foo"]
+
+struct BodyId {
+    hir_id: usize,
+}
+
+// @has 'foo/fn.body_owner.html' '//*[@class="rust fn"]' 'pub fn body_owner(_: BodyId)'
+pub fn body_owner(BodyId { hir_id }: BodyId) {
+    // ...
+}
diff --git a/src/test/ui/inference/issue-81522.rs b/src/test/ui/inference/issue-81522.rs
new file mode 100644
index 00000000000..902f8fdde58
--- /dev/null
+++ b/src/test/ui/inference/issue-81522.rs
@@ -0,0 +1,31 @@
+// Regression test for #81522.
+// Ensures that `#[allow(unstable_name_collisions)]` appended to things other than function
+// suppresses the corresponding diagnostics emitted from inside them.
+// But note that this attribute doesn't work for macro invocations if it is appended directly.
+
+// aux-build:inference_unstable_iterator.rs
+// aux-build:inference_unstable_itertools.rs
+// run-pass
+
+extern crate inference_unstable_iterator;
+extern crate inference_unstable_itertools;
+
+#[allow(unused_imports)]
+use inference_unstable_iterator::IpuIterator;
+use inference_unstable_itertools::IpuItertools;
+
+fn main() {
+    // expression statement
+    #[allow(unstable_name_collisions)]
+    'x'.ipu_flatten();
+
+    // let statement
+    #[allow(unstable_name_collisions)]
+    let _ = 'x'.ipu_flatten();
+
+    // block expression
+    #[allow(unstable_name_collisions)]
+    {
+        'x'.ipu_flatten();
+    }
+}