about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-22 01:14:31 +0000
committerbors <bors@rust-lang.org>2021-06-22 01:14:31 +0000
commit2c04f0bb171bb7dc573d0da4b59960106823c2cd (patch)
tree17cd6d646a69fe85d3b46de682002aa7e0cfbba0
parent4573a4a879a8e1f773944a8859e4dcd136138af8 (diff)
parent4495ce75d975136173dbd4c139f00d1f508a6994 (diff)
downloadrust-2c04f0bb171bb7dc573d0da4b59960106823c2cd.tar.gz
rust-2c04f0bb171bb7dc573d0da4b59960106823c2cd.zip
Auto merge of #86527 - JohnTitor:rollup-cbu78g4, r=JohnTitor
Rollup of 11 pull requests

Successful merges:

 - #85054 (Revert SGX inline asm syntax)
 - #85182 (Move `available_concurrency` implementation to `sys`)
 - #86037 (Add `io::Cursor::{remaining, remaining_slice, is_empty}`)
 - #86114 (Reopen #79692 (Format symbols under shared frames))
 - #86297 (Allow to pass arguments to rustdoc-gui tool)
 - #86334 (Resolve type aliases to the type they point to in intra-doc links)
 - #86367 (Fix comment about rustc_inherit_overflow_checks in abs().)
 - #86381 (Add regression test for issue #39161)
 - #86387 (Remove `#[allow(unused_lifetimes)]` which is now unnecessary)
 - #86398 (Add regression test for issue #54685)
 - #86493 (Say "this enum variant takes"/"this struct takes" instead of "this function takes")

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_data_structures/src/captures.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs28
-rw-r--r--library/core/src/num/int_macros.rs6
-rw-r--r--library/std/src/backtrace.rs5
-rw-r--r--library/std/src/io/cursor.rs89
-rw-r--r--library/std/src/os/fortanix_sgx/arch.rs12
-rw-r--r--library/std/src/sys/hermit/thread.rs6
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs4
-rw-r--r--library/std/src/sys/sgx/thread.rs6
-rw-r--r--library/std/src/sys/unix/thread.rs83
-rw-r--r--library/std/src/sys/unsupported/thread.rs5
-rw-r--r--library/std/src/sys/wasi/thread.rs5
-rw-r--r--library/std/src/sys/wasm/atomics/thread.rs6
-rw-r--r--library/std/src/sys/windows/c.rs18
-rw-r--r--library/std/src/sys/windows/thread.rs16
-rw-r--r--library/std/src/thread/available_concurrency.rs156
-rw-r--r--library/std/src/thread/mod.rs43
-rw-r--r--src/bootstrap/test.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs51
-rw-r--r--src/test/rustdoc-gui/README.md12
-rw-r--r--src/test/rustdoc/intra-doc/type-alias.rs19
-rw-r--r--src/test/ui/consts/issue-39161-bogus-error.rs13
-rw-r--r--src/test/ui/function-pointer/function-pointer-comparison-issue-54685.rs31
-rw-r--r--src/test/ui/span/missing-unit-argument.rs2
-rw-r--r--src/test/ui/span/missing-unit-argument.stderr2
-rw-r--r--src/test/ui/typeck/struct-enum-wrong-args.rs14
-rw-r--r--src/test/ui/typeck/struct-enum-wrong-args.stderr67
m---------src/tools/rust-analyzer35
-rw-r--r--src/tools/rustdoc-gui/tester.js32
-rw-r--r--src/tools/tidy/src/pal.rs1
30 files changed, 553 insertions, 219 deletions
diff --git a/compiler/rustc_data_structures/src/captures.rs b/compiler/rustc_data_structures/src/captures.rs
index 26b90ebfd5f..677ccb31454 100644
--- a/compiler/rustc_data_structures/src/captures.rs
+++ b/compiler/rustc_data_structures/src/captures.rs
@@ -3,8 +3,6 @@
 /// Basically a workaround; see [this comment] for details.
 ///
 /// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
-// FIXME(eddyb) false positive, the lifetime parameter is "phantom" but needed.
-#[allow(unused_lifetimes)]
 pub trait Captures<'a> {}
 
 impl<'a, T: ?Sized> Captures<'a> for T {}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index d6989b866c1..f65cc429fbd 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -11,7 +11,7 @@ use crate::check::{
 use rustc_ast as ast;
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -120,8 +120,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                  error_code: &str,
                                  c_variadic: bool,
                                  sugg_unit: bool| {
-            let (span, start_span, args) = match &expr.kind {
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
+            let (span, start_span, args, ctor_of) = match &expr.kind {
+                hir::ExprKind::Call(
+                    hir::Expr {
+                        span,
+                        kind:
+                            hir::ExprKind::Path(hir::QPath::Resolved(
+                                _,
+                                hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
+                            )),
+                        ..
+                    },
+                    args,
+                ) => (*span, *span, &args[..], Some(of)),
+                hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
+                    (*span, *span, &args[..], None)
+                }
                 hir::ExprKind::MethodCall(path_segment, span, args, _) => (
                     *span,
                     // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
@@ -137,6 +151,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         })
                         .unwrap_or(*span),
                     &args[1..], // Skip the receiver.
+                    None,       // methods are never ctors
                 ),
                 k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
             };
@@ -157,7 +172,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut err = tcx.sess.struct_span_err_with_code(
                 span,
                 &format!(
-                    "this function takes {}{} but {} {} supplied",
+                    "this {} takes {}{} but {} {} supplied",
+                    match ctor_of {
+                        Some(CtorOf::Struct) => "struct",
+                        Some(CtorOf::Variant) => "enum variant",
+                        None => "function",
+                    },
                     if c_variadic { "at least " } else { "" },
                     potentially_plural_count(expected_count, "argument"),
                     potentially_plural_count(arg_count, "argument"),
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index a0efe681285..2e466106fe5 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1772,9 +1772,9 @@ macro_rules! int_impl {
         #[inline]
         #[rustc_inherit_overflow_checks]
         pub const fn abs(self) -> Self {
-            // Note that the #[inline] above means that the overflow
-            // semantics of the subtraction depend on the crate we're being
-            // inlined into.
+            // Note that the #[rustc_inherit_overflow_checks] and #[inline]
+            // above mean that the overflow semantics of the subtraction
+            // depend on the crate we're being called from.
             if self.is_negative() {
                 -self
             } else {
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 0aae4674b29..f8884523cf4 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -399,12 +399,11 @@ impl fmt::Display for Backtrace {
         let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path);
         f.add_context()?;
         for frame in frames {
-            let mut f = f.frame();
             if frame.symbols.is_empty() {
-                f.print_raw(frame.frame.ip(), None, None, None)?;
+                f.frame().print_raw(frame.frame.ip(), None, None, None)?;
             } else {
                 for symbol in frame.symbols.iter() {
-                    f.print_raw_with_column(
+                    f.frame().print_raw_with_column(
                         frame.frame.ip(),
                         symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)),
                         symbol.filename.as_ref().map(|b| match b {
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 9527254c947..04f13cdeb88 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -205,6 +205,88 @@ impl<T> Cursor<T> {
     }
 }
 
+impl<T> Cursor<T>
+where
+    T: AsRef<[u8]>,
+{
+    /// Returns the remaining length.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cursor_remaining)]
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.remaining(), 5);
+    ///
+    /// buff.set_position(2);
+    /// assert_eq!(buff.remaining(), 3);
+    ///
+    /// buff.set_position(4);
+    /// assert_eq!(buff.remaining(), 1);
+    ///
+    /// buff.set_position(6);
+    /// assert_eq!(buff.remaining(), 0);
+    /// ```
+    #[unstable(feature = "cursor_remaining", issue = "86369")]
+    pub fn remaining(&self) -> u64 {
+        (self.inner.as_ref().len() as u64).checked_sub(self.pos).unwrap_or(0)
+    }
+
+    /// Returns the remaining slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cursor_remaining)]
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.remaining_slice(), &[1, 2, 3, 4, 5]);
+    ///
+    /// buff.set_position(2);
+    /// assert_eq!(buff.remaining_slice(), &[3, 4, 5]);
+    ///
+    /// buff.set_position(4);
+    /// assert_eq!(buff.remaining_slice(), &[5]);
+    ///
+    /// buff.set_position(6);
+    /// assert_eq!(buff.remaining_slice(), &[]);
+    /// ```
+    #[unstable(feature = "cursor_remaining", issue = "86369")]
+    pub fn remaining_slice(&self) -> &[u8] {
+        let len = self.pos.min(self.inner.as_ref().len() as u64);
+        &self.inner.as_ref()[(len as usize)..]
+    }
+
+    /// Returns `true` if the remaining slice is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cursor_remaining)]
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// buff.set_position(2);
+    /// assert!(!buff.is_empty());
+    ///
+    /// buff.set_position(5);
+    /// assert!(buff.is_empty());
+    ///
+    /// buff.set_position(10);
+    /// assert!(buff.is_empty());
+    /// ```
+    #[unstable(feature = "cursor_remaining", issue = "86369")]
+    pub fn is_empty(&self) -> bool {
+        self.pos >= self.inner.as_ref().len() as u64
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Cursor<T>
 where
@@ -268,7 +350,7 @@ where
     T: AsRef<[u8]>,
 {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        let n = Read::read(&mut self.fill_buf()?, buf)?;
+        let n = Read::read(&mut self.remaining_slice(), buf)?;
         self.pos += n as u64;
         Ok(n)
     }
@@ -291,7 +373,7 @@ where
 
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         let n = buf.len();
-        Read::read_exact(&mut self.fill_buf()?, buf)?;
+        Read::read_exact(&mut self.remaining_slice(), buf)?;
         self.pos += n as u64;
         Ok(())
     }
@@ -308,8 +390,7 @@ where
     T: AsRef<[u8]>,
 {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
-        let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
-        Ok(&self.inner.as_ref()[(amt as usize)..])
+        Ok(self.remaining_slice())
     }
     fn consume(&mut self, amt: usize) {
         self.pos += amt as u64;
diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
index b0170e67446..4ce482e23cb 100644
--- a/library/std/src/os/fortanix_sgx/arch.rs
+++ b/library/std/src/os/fortanix_sgx/arch.rs
@@ -33,13 +33,13 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
 
         asm!(
             // rbx is reserved by LLVM
-            "xchg {0}, rbx",
+            "xchg %rbx, {0}",
             "enclu",
-            "mov rbx, {0}",
+            "mov {0}, %rbx",
             inout(reg) request => _,
             inlateout("eax") ENCLU_EGETKEY => error,
             in("rcx") out.as_mut_ptr(),
-            options(nostack),
+            options(att_syntax, nostack),
         );
 
         match error {
@@ -64,14 +64,14 @@ pub fn ereport(
 
         asm!(
             // rbx is reserved by LLVM
-            "xchg {0}, rbx",
+            "xchg %rbx, {0}",
             "enclu",
-            "mov rbx, {0}",
+            "mov {0}, %rbx",
             inout(reg) targetinfo => _,
             in("eax") ENCLU_EREPORT,
             in("rcx") reportdata,
             in("rdx") report.as_mut_ptr(),
-            options(preserves_flags, nostack),
+            options(att_syntax, preserves_flags, nostack),
         );
 
         report.assume_init()
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index f35a3a8a80f..6da79d19f59 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -1,8 +1,10 @@
 #![allow(dead_code)]
 
+use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::sys::hermit::abi;
 use crate::sys::hermit::thread_local_dtor::run_dtors;
 use crate::time::Duration;
@@ -95,6 +97,10 @@ impl Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    unsupported()
+}
+
 pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> {
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index 1e743894a9f..52e8bec937c 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -36,9 +36,9 @@ pub fn image_base() -> u64 {
     let base: u64;
     unsafe {
         asm!(
-            "lea {}, qword ptr [rip + IMAGE_BASE]",
+            "lea IMAGE_BASE(%rip), {}",
             lateout(reg) base,
-            options(nostack, preserves_flags, nomem, pure),
+            options(att_syntax, nostack, preserves_flags, nomem, pure),
         )
     };
     base
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index 67e2e8b59d3..cbb8ba96401 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -1,6 +1,8 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
+use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
+use crate::num::NonZeroUsize;
 use crate::time::Duration;
 
 use super::abi::usercalls;
@@ -135,6 +137,10 @@ impl Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    unsupported()
+}
+
 pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> {
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index b8f43caec32..df2ba0a8bc8 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -2,6 +2,7 @@ use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ptr;
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
@@ -198,6 +199,88 @@ impl Drop for Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    cfg_if::cfg_if! {
+        if #[cfg(any(
+            target_os = "android",
+            target_os = "emscripten",
+            target_os = "fuchsia",
+            target_os = "ios",
+            target_os = "linux",
+            target_os = "macos",
+            target_os = "solaris",
+            target_os = "illumos",
+        ))] {
+            match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
+                -1 => Err(io::Error::last_os_error()),
+                0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
+                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
+            }
+        } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
+            use crate::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = crate::mem::size_of_val(&cpus);
+
+            unsafe {
+                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            }
+
+            // Fallback approach in case of errors or no hardware threads.
+            if cpus < 1 {
+                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+                let res = unsafe {
+                    libc::sysctl(
+                        mib.as_mut_ptr(),
+                        2,
+                        &mut cpus as *mut _ as *mut _,
+                        &mut cpus_size as *mut _ as *mut _,
+                        ptr::null_mut(),
+                        0,
+                    )
+                };
+
+                // Handle errors if any.
+                if res == -1 {
+                    return Err(io::Error::last_os_error());
+                } else if cpus == 0 {
+                    return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+                }
+            }
+            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+        } else if #[cfg(target_os = "openbsd")] {
+            use crate::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = crate::mem::size_of_val(&cpus);
+            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+            let res = unsafe {
+                libc::sysctl(
+                    mib.as_mut_ptr(),
+                    2,
+                    &mut cpus as *mut _ as *mut _,
+                    &mut cpus_size as *mut _ as *mut _,
+                    ptr::null_mut(),
+                    0,
+                )
+            };
+
+            // Handle errors if any.
+            if res == -1 {
+                return Err(io::Error::last_os_error());
+            } else if cpus == 0 {
+                return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+            }
+
+            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+        } else {
+            // FIXME: implement on vxWorks, Redox, Haiku, l4re
+            Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform"))
+        }
+    }
+}
+
 #[cfg(all(
     not(target_os = "linux"),
     not(target_os = "freebsd"),
diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs
index cda8510e1ba..dc75d4ee672 100644
--- a/library/std/src/sys/unsupported/thread.rs
+++ b/library/std/src/sys/unsupported/thread.rs
@@ -1,6 +1,7 @@
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
+use crate::num::NonZeroUsize;
 use crate::time::Duration;
 
 pub struct Thread(!);
@@ -30,6 +31,10 @@ impl Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    unsupported()
+}
+
 pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> {
diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs
index 74515553a82..9ec02bbec26 100644
--- a/library/std/src/sys/wasi/thread.rs
+++ b/library/std/src/sys/wasi/thread.rs
@@ -3,6 +3,7 @@
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::sys::unsupported;
 use crate::time::Duration;
 
@@ -63,6 +64,10 @@ impl Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    unsupported()
+}
+
 pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> {
diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs
index 54bc877aa7d..09714835104 100644
--- a/library/std/src/sys/wasm/atomics/thread.rs
+++ b/library/std/src/sys/wasm/atomics/thread.rs
@@ -1,5 +1,7 @@
+use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
+use crate::num::NonZeroUsize;
 use crate::sys::unsupported;
 use crate::time::Duration;
 
@@ -39,6 +41,10 @@ impl Thread {
     pub fn join(self) {}
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    unsupported()
+}
+
 pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> {
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index b64870401f1..193c28c7673 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -13,6 +13,7 @@ use libc::{c_void, size_t, wchar_t};
 pub use self::EXCEPTION_DISPOSITION::*;
 pub use self::FILE_INFO_BY_HANDLE_CLASS::*;
 
+pub type DWORD_PTR = ULONG_PTR;
 pub type DWORD = c_ulong;
 pub type NonZeroDWORD = NonZero_c_ulong;
 pub type HANDLE = LPVOID;
@@ -53,6 +54,7 @@ pub type LPWSADATA = *mut WSADATA;
 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
 pub type LPWSTR = *mut WCHAR;
 pub type LPFILETIME = *mut FILETIME;
+pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
 pub type LPWSABUF = *mut WSABUF;
 pub type LPWSAOVERLAPPED = *mut c_void;
 pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
@@ -534,6 +536,21 @@ pub struct FILETIME {
 }
 
 #[repr(C)]
+pub struct SYSTEM_INFO {
+    pub wProcessorArchitecture: WORD,
+    pub wReserved: WORD,
+    pub dwPageSize: DWORD,
+    pub lpMinimumApplicationAddress: LPVOID,
+    pub lpMaximumApplicationAddress: LPVOID,
+    pub dwActiveProcessorMask: DWORD_PTR,
+    pub dwNumberOfProcessors: DWORD,
+    pub dwProcessorType: DWORD,
+    pub dwAllocationGranularity: DWORD,
+    pub wProcessorLevel: WORD,
+    pub wProcessorRevision: WORD,
+}
+
+#[repr(C)]
 pub struct OVERLAPPED {
     pub Internal: *mut c_ulong,
     pub InternalHigh: *mut c_ulong,
@@ -934,6 +951,7 @@ extern "system" {
     pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
 
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
+    pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
 
     pub fn CreateEventW(
         lpEventAttributes: LPSECURITY_ATTRIBUTES,
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 38839ea5e90..ef7a9733fd8 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -1,5 +1,6 @@
 use crate::ffi::CStr;
 use crate::io;
+use crate::num::NonZeroUsize;
 use crate::ptr;
 use crate::sys::c;
 use crate::sys::handle::Handle;
@@ -98,6 +99,21 @@ impl Thread {
     }
 }
 
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    let res = unsafe {
+        let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
+        c::GetSystemInfo(&mut sysinfo);
+        sysinfo.dwNumberOfProcessors as usize
+    };
+    match res {
+        0 => Err(io::Error::new_const(
+            io::ErrorKind::NotFound,
+            &"The number of hardware threads is not known for the target platform",
+        )),
+        cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
+    }
+}
+
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
     pub type Guard = !;
diff --git a/library/std/src/thread/available_concurrency.rs b/library/std/src/thread/available_concurrency.rs
deleted file mode 100644
index e8cdde88014..00000000000
--- a/library/std/src/thread/available_concurrency.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::io;
-use crate::num::NonZeroUsize;
-
-/// Returns the number of hardware threads available to the program.
-///
-/// This value should be considered only a hint.
-///
-/// # Platform-specific behavior
-///
-/// If interpreted as the number of actual hardware threads, it may undercount on
-/// Windows systems with more than 64 hardware threads. If interpreted as the
-/// available concurrency for that process, it may overcount on Windows systems
-/// when limited by a process wide affinity mask or job object limitations, and
-/// it may overcount on Linux systems when limited by a process wide affinity
-/// mask or affected by cgroups limits.
-///
-/// # Errors
-///
-/// This function will return an error in the following situations, but is not
-/// limited to just these cases:
-///
-/// - If the number of hardware threads is not known for the target platform.
-/// - The process lacks permissions to view the number of hardware threads
-///   available.
-///
-/// # Examples
-///
-/// ```
-/// # #![allow(dead_code)]
-/// #![feature(available_concurrency)]
-/// use std::thread;
-///
-/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
-/// ```
-#[unstable(feature = "available_concurrency", issue = "74479")]
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
-    available_concurrency_internal()
-}
-
-cfg_if::cfg_if! {
-    if #[cfg(windows)] {
-        #[allow(nonstandard_style)]
-        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
-            #[repr(C)]
-            struct SYSTEM_INFO {
-                wProcessorArchitecture: u16,
-                wReserved: u16,
-                dwPageSize: u32,
-                lpMinimumApplicationAddress: *mut u8,
-                lpMaximumApplicationAddress: *mut u8,
-                dwActiveProcessorMask: *mut u8,
-                dwNumberOfProcessors: u32,
-                dwProcessorType: u32,
-                dwAllocationGranularity: u32,
-                wProcessorLevel: u16,
-                wProcessorRevision: u16,
-            }
-            extern "system" {
-                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
-            }
-            let res = unsafe {
-                let mut sysinfo = crate::mem::zeroed();
-                GetSystemInfo(&mut sysinfo);
-                sysinfo.dwNumberOfProcessors as usize
-            };
-            match res {
-                0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
-                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
-            }
-        }
-    } else if #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "solaris",
-        target_os = "illumos",
-    ))] {
-        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
-            match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-                -1 => Err(io::Error::last_os_error()),
-                0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
-                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
-            }
-        }
-    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
-        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
-            use crate::ptr;
-
-            let mut cpus: libc::c_uint = 0;
-            let mut cpus_size = crate::mem::size_of_val(&cpus);
-
-            unsafe {
-                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
-            }
-
-            // Fallback approach in case of errors or no hardware threads.
-            if cpus < 1 {
-                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-                let res = unsafe {
-                    libc::sysctl(
-                        mib.as_mut_ptr(),
-                        2,
-                        &mut cpus as *mut _ as *mut _,
-                        &mut cpus_size as *mut _ as *mut _,
-                        ptr::null_mut(),
-                        0,
-                    )
-                };
-
-                // Handle errors if any.
-                if res == -1 {
-                    return Err(io::Error::last_os_error());
-                } else if cpus == 0 {
-                    return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
-                }
-            }
-            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
-        }
-    } else if #[cfg(target_os = "openbsd")] {
-        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
-            use crate::ptr;
-
-            let mut cpus: libc::c_uint = 0;
-            let mut cpus_size = crate::mem::size_of_val(&cpus);
-            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-
-            let res = unsafe {
-                libc::sysctl(
-                    mib.as_mut_ptr(),
-                    2,
-                    &mut cpus as *mut _ as *mut _,
-                    &mut cpus_size as *mut _ as *mut _,
-                    ptr::null_mut(),
-                    0,
-                )
-            };
-
-            // Handle errors if any.
-            if res == -1 {
-                return Err(io::Error::last_os_error());
-            } else if cpus == 0 {
-                return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
-            }
-
-            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
-        }
-    } else {
-        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
-        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
-            Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"))
-        }
-    }
-}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 30d8c2a1b6f..f7e79141903 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -155,6 +155,7 @@ use crate::fmt;
 use crate::io;
 use crate::mem;
 use crate::num::NonZeroU64;
+use crate::num::NonZeroUsize;
 use crate::panic;
 use crate::panicking;
 use crate::str;
@@ -174,15 +175,9 @@ use crate::time::Duration;
 #[macro_use]
 mod local;
 
-#[unstable(feature = "available_concurrency", issue = "74479")]
-mod available_concurrency;
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::local::{AccessError, LocalKey};
 
-#[unstable(feature = "available_concurrency", issue = "74479")]
-pub use available_concurrency::available_concurrency;
-
 // The types used by the thread_local! macro to access TLS keys. Note that there
 // are two types, the "OS" type and the "fast" type. The OS thread local key
 // type is accessed via platform-specific API calls and is slow, while the fast
@@ -1422,3 +1417,39 @@ fn _assert_sync_and_send() {
     _assert_both::<JoinHandle<()>>();
     _assert_both::<Thread>();
 }
+
+/// Returns the number of hardware threads available to the program.
+///
+/// This value should be considered only a hint.
+///
+/// # Platform-specific behavior
+///
+/// If interpreted as the number of actual hardware threads, it may undercount on
+/// Windows systems with more than 64 hardware threads. If interpreted as the
+/// available concurrency for that process, it may overcount on Windows systems
+/// when limited by a process wide affinity mask or job object limitations, and
+/// it may overcount on Linux systems when limited by a process wide affinity
+/// mask or affected by cgroups limits.
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// - If the number of hardware threads is not known for the target platform.
+/// - The process lacks permissions to view the number of hardware threads
+///   available.
+///
+/// # Examples
+///
+/// ```
+/// # #![allow(dead_code)]
+/// #![feature(available_concurrency)]
+/// use std::thread;
+///
+/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
+/// ```
+#[unstable(feature = "available_concurrency", issue = "74479")]
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    imp::available_concurrency()
+}
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 93ba8b07f5b..92ac3b364f6 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -894,6 +894,9 @@ impl Step for RustdocGUI {
                 }
             }
         }
+        for test_arg in builder.config.cmd.test_args() {
+            command.arg(test_arg);
+        }
         builder.run(&mut command);
     }
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 9db83c903ab..fb82a075de0 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -544,6 +544,44 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             })
     }
 
+    /// Convert a DefId to a Res, where possible.
+    ///
+    /// This is used for resolving type aliases.
+    fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
+        use PrimitiveType::*;
+        Some(match *self.cx.tcx.type_of(ty_id).kind() {
+            ty::Bool => Res::Primitive(Bool),
+            ty::Char => Res::Primitive(Char),
+            ty::Int(ity) => Res::Primitive(ity.into()),
+            ty::Uint(uty) => Res::Primitive(uty.into()),
+            ty::Float(fty) => Res::Primitive(fty.into()),
+            ty::Str => Res::Primitive(Str),
+            ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
+            ty::Tuple(_) => Res::Primitive(Tuple),
+            ty::Array(..) => Res::Primitive(Array),
+            ty::Slice(_) => Res::Primitive(Slice),
+            ty::RawPtr(_) => Res::Primitive(RawPointer),
+            ty::Ref(..) => Res::Primitive(Reference),
+            ty::FnDef(..) => panic!("type alias to a function definition"),
+            ty::FnPtr(_) => Res::Primitive(Fn),
+            ty::Never => Res::Primitive(Never),
+            ty::Adt(&ty::AdtDef { did, .. }, _) | ty::Foreign(did) => {
+                Res::Def(self.cx.tcx.def_kind(did), did)
+            }
+            ty::Projection(_)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(_)
+            | ty::Opaque(..)
+            | ty::Dynamic(..)
+            | ty::Param(_)
+            | ty::Bound(..)
+            | ty::Placeholder(_)
+            | ty::Infer(_)
+            | ty::Error(_) => return None,
+        })
+    }
+
     /// Returns:
     /// - None if no associated item was found
     /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
@@ -559,12 +597,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
 
         match root_res {
             Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
+            Res::Def(DefKind::TyAlias, did) => {
+                // Resolve the link on the type the alias points to.
+                // FIXME: if the associated item is defined directly on the type alias,
+                // it will show up on its documentation page, we should link there instead.
+                let res = self.def_id_to_res(did)?;
+                self.resolve_associated_item(res, item_name, ns, module_id)
+            }
             Res::Def(
-                DefKind::Struct
-                | DefKind::Union
-                | DefKind::Enum
-                | DefKind::TyAlias
-                | DefKind::ForeignTy,
+                DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy,
                 did,
             ) => {
                 debug!("looking for associated item named {} for item {:?}", item_name, did);
diff --git a/src/test/rustdoc-gui/README.md b/src/test/rustdoc-gui/README.md
index 499a98a3d22..8efe7a578b8 100644
--- a/src/test/rustdoc-gui/README.md
+++ b/src/test/rustdoc-gui/README.md
@@ -8,5 +8,17 @@ test what's being currently displayed in the web page.
 
 You can find more information and its documentation in its [repository][browser-ui-test].
 
+If you need to have more information on the tests run, you can use `--test-args`:
+
+```bash
+$ ./x.py test src/test/rustdoc-gui --stage 1 --jobs 8 --test-args --debug
+```
+
+There are three options supported:
+
+ * `--debug`: allows to see puppeteer commands.
+ * `--no-headless`: disable headless mode so you can see what's going on.
+ * `--show-text`: by default, text isn't rendered because of issues with fonts, it enables it back.
+
 [browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/
 [puppeteer]: https://pptr.dev/
diff --git a/src/test/rustdoc/intra-doc/type-alias.rs b/src/test/rustdoc/intra-doc/type-alias.rs
new file mode 100644
index 00000000000..f3609ccd0a1
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/type-alias.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #86120.
+
+#![deny(broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+/// You should really try [`Self::bar`]!
+pub type Bar = Foo;
+
+impl Bar {
+    pub fn bar() {}
+}
+
+/// The minimum is [`Self::MIN`].
+pub type Int = i32;
+
+// @has foo/type.Bar.html '//a[@href="struct.Foo.html#method.bar"]' 'Self::bar'
+// @has foo/type.Int.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MIN"]' 'Self::MIN'
diff --git a/src/test/ui/consts/issue-39161-bogus-error.rs b/src/test/ui/consts/issue-39161-bogus-error.rs
new file mode 100644
index 00000000000..a954385da41
--- /dev/null
+++ b/src/test/ui/consts/issue-39161-bogus-error.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+pub struct X {
+    pub a: i32,
+    pub b: i32,
+}
+
+fn main() {
+    const DX: X = X { a: 0, b: 0 };
+    const _X1: X = X { a: 1, ..DX };
+    let _x2 = X { a: 1, b: 2, ..DX };
+    const _X3: X = X { a: 1, b: 2, ..DX };
+}
diff --git a/src/test/ui/function-pointer/function-pointer-comparison-issue-54685.rs b/src/test/ui/function-pointer/function-pointer-comparison-issue-54685.rs
new file mode 100644
index 00000000000..a036d10e639
--- /dev/null
+++ b/src/test/ui/function-pointer/function-pointer-comparison-issue-54685.rs
@@ -0,0 +1,31 @@
+// min-llvm-version: 12.0
+// compile-flags: -C opt-level=3
+// run-pass
+
+fn foo(_i: i32) -> i32 {
+    1
+}
+fn bar(_i: i32) -> i32 {
+    1
+}
+
+fn main() {
+    let x: fn(i32) -> i32 = foo;
+    let y: fn(i32) -> i32 = bar;
+
+    let s1;
+    if x == y {
+        s1 = "same".to_string();
+    } else {
+        s1 = format!("{:?}, {:?}", x, y);
+    }
+
+    let s2;
+    if x == y {
+        s2 = "same".to_string();
+    } else {
+        s2 = format!("{:?}, {:?}", x, y);
+    }
+
+    assert_eq!(s1, s2);
+}
diff --git a/src/test/ui/span/missing-unit-argument.rs b/src/test/ui/span/missing-unit-argument.rs
index b8fb332120a..5b9861da6e8 100644
--- a/src/test/ui/span/missing-unit-argument.rs
+++ b/src/test/ui/span/missing-unit-argument.rs
@@ -8,7 +8,7 @@ impl S {
 }
 
 fn main() {
-    let _: Result<(), String> = Ok(); //~ ERROR this function takes
+    let _: Result<(), String> = Ok(); //~ ERROR this enum variant takes
     foo(); //~ ERROR this function takes
     foo(()); //~ ERROR this function takes
     bar(); //~ ERROR this function takes
diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr
index b15da2cb479..7a24ffbd81c 100644
--- a/src/test/ui/span/missing-unit-argument.stderr
+++ b/src/test/ui/span/missing-unit-argument.stderr
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:11:33
    |
 LL |     let _: Result<(), String> = Ok();
diff --git a/src/test/ui/typeck/struct-enum-wrong-args.rs b/src/test/ui/typeck/struct-enum-wrong-args.rs
new file mode 100644
index 00000000000..19de4d67729
--- /dev/null
+++ b/src/test/ui/typeck/struct-enum-wrong-args.rs
@@ -0,0 +1,14 @@
+// Regression test of #86481.
+struct Wrapper(i32);
+struct DoubleWrapper(i32, i32);
+
+fn main() {
+    let _ = Some(3, 2); //~ ERROR this enum variant takes
+    let _ = Ok(3, 6, 2); //~ ERROR this enum variant takes
+    let _ = Ok(); //~ ERROR this enum variant takes
+    let _ = Wrapper(); //~ ERROR this struct takes
+    let _ = Wrapper(5, 2); //~ ERROR this struct takes
+    let _ = DoubleWrapper(); //~ ERROR this struct takes
+    let _ = DoubleWrapper(5); //~ ERROR this struct takes
+    let _ = DoubleWrapper(5, 2, 7); //~ ERROR this struct takes
+}
diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr
new file mode 100644
index 00000000000..d77ef73028b
--- /dev/null
+++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr
@@ -0,0 +1,67 @@
+error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:6:13
+   |
+LL |     let _ = Some(3, 2);
+   |             ^^^^ -  - supplied 2 arguments
+   |             |
+   |             expected 1 argument
+
+error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:7:13
+   |
+LL |     let _ = Ok(3, 6, 2);
+   |             ^^ -  -  - supplied 3 arguments
+   |             |
+   |             expected 1 argument
+
+error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:8:13
+   |
+LL |     let _ = Ok();
+   |             ^^-- supplied 0 arguments
+   |             |
+   |             expected 1 argument
+
+error[E0061]: this struct takes 1 argument but 0 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:9:13
+   |
+LL |     let _ = Wrapper();
+   |             ^^^^^^^-- supplied 0 arguments
+   |             |
+   |             expected 1 argument
+
+error[E0061]: this struct takes 1 argument but 2 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:10:13
+   |
+LL |     let _ = Wrapper(5, 2);
+   |             ^^^^^^^ -  - supplied 2 arguments
+   |             |
+   |             expected 1 argument
+
+error[E0061]: this struct takes 2 arguments but 0 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:11:13
+   |
+LL |     let _ = DoubleWrapper();
+   |             ^^^^^^^^^^^^^-- supplied 0 arguments
+   |             |
+   |             expected 2 arguments
+
+error[E0061]: this struct takes 2 arguments but 1 argument was supplied
+  --> $DIR/struct-enum-wrong-args.rs:12:13
+   |
+LL |     let _ = DoubleWrapper(5);
+   |             ^^^^^^^^^^^^^ - supplied 1 argument
+   |             |
+   |             expected 2 arguments
+
+error[E0061]: this struct takes 2 arguments but 3 arguments were supplied
+  --> $DIR/struct-enum-wrong-args.rs:13:13
+   |
+LL |     let _ = DoubleWrapper(5, 2, 7);
+   |             ^^^^^^^^^^^^^ -  -  - supplied 3 arguments
+   |             |
+   |             expected 2 arguments
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject f0618a8f06a464840079f30b3e25bcdcca3922a
+Subproject 13da28cc2bc1b59f7af817eca36927a71edb023
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 8c8d86d5e38..416d824c564 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -11,6 +11,9 @@ function showHelp() {
     console.log("rustdoc-js options:");
     console.log("  --doc-folder [PATH]        : location of the generated doc folder");
     console.log("  --file [PATH]              : file to run (can be repeated)");
+    console.log("  --debug                    : show extra information about script run");
+    console.log("  --show-text                : render font in pages");
+    console.log("  --no-headless              : disable headless mode");
     console.log("  --help                     : show this message then quit");
     console.log("  --tests-folder [PATH]      : location of the .GOML tests folder");
 }
@@ -20,10 +23,16 @@ function parseOptions(args) {
         "doc_folder": "",
         "tests_folder": "",
         "files": [],
+        "debug": false,
+        "show_text": false,
+        "no_headless": false,
     };
     var correspondances = {
         "--doc-folder": "doc_folder",
         "--tests-folder": "tests_folder",
+        "--debug": "debug",
+        "--show-text": "show_text",
+        "--no-headless": "no_headless",
     };
 
     for (var i = 0; i < args.length; ++i) {
@@ -43,6 +52,8 @@ function parseOptions(args) {
         } else if (args[i] === "--help") {
             showHelp();
             process.exit(0);
+        } else if (correspondances[args[i]]) {
+            opts[correspondances[args[i]]] = true;
         } else {
             console.log("Unknown option `" + args[i] + "`.");
             console.log("Use `--help` to see the list of options");
@@ -68,17 +79,20 @@ async function main(argv) {
     const options = new Options();
     try {
         // This is more convenient that setting fields one by one.
-        options.parseArguments([
+        let args = [
             "--no-screenshot",
-            // This option shows what puppeteer "code" is run
-            // "--debug",
-            // This option disable the headless mode, allowing you to see what's going on.
-            // "--no-headless",
-            // The text isn't rendered by default because of a lot of small differences
-            // between hosts.
-            // "--show-text",
             "--variable", "DOC_PATH", opts["doc_folder"],
-        ]);
+        ];
+        if (opts["debug"]) {
+            args.push("--debug");
+        }
+        if (opts["show_text"]) {
+            args.push("--show-text");
+        }
+        if (opts["no_headless"]) {
+            args.push("--no-headless");
+        }
+        options.parseArguments(args);
     } catch (error) {
         console.error(`invalid argument: ${error}`);
         process.exit(1);
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index db177f75cea..31cdc6865a4 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -56,7 +56,6 @@ const EXCEPTION_PATHS: &[&str] = &[
     "library/std/src/f32.rs",
     "library/std/src/f64.rs",
     "library/std/src/path.rs",
-    "library/std/src/thread/available_concurrency.rs",
     "library/std/src/sys_common", // Should only contain abstractions over platforms
     "library/std/src/net/test.rs", // Utility helpers for tests
 ];