about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-09 20:43:13 +0000
committerbors <bors@rust-lang.org>2022-09-09 20:43:13 +0000
commit1d37ed661a6922e7a167609b8cd7eb31e972b19b (patch)
treed05693f2376caa5a9725b030558f246f5edf995a
parent98f3001eecbe4cbd091c10ffab45b4c164bb507b (diff)
parent2e258cec0505f58ffc2d1997acb5f4ea2e279500 (diff)
downloadrust-1d37ed661a6922e7a167609b8cd7eb31e972b19b.tar.gz
rust-1d37ed661a6922e7a167609b8cd7eb31e972b19b.zip
Auto merge of #101611 - GuillaumeGomez:rollup-yw3qtug, r=GuillaumeGomez
Rollup of 5 pull requests

Successful merges:

 - #101475 (Use futex-based locks and thread parker on Hermit)
 - #101492 (Suggest adding array lengths to references to arrays if possible)
 - #101495 (Compile spin_loop_hint as pause on x86 even without sse2 enabled)
 - #101529 (Fix the example code and doctest for Formatter::sign_plus)
 - #101600 (rustdoc: simplify the codeblock tooltip)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock7
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs47
-rw-r--r--library/core/src/fmt/mod.rs3
-rw-r--r--library/core/src/hint.rs19
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/sys/hermit/condvar.rs90
-rw-r--r--library/std/src/sys/hermit/futex.rs39
-rw-r--r--library/std/src/sys/hermit/mod.rs15
-rw-r--r--library/std/src/sys/hermit/mutex.rs212
-rw-r--r--library/std/src/sys/hermit/rwlock.rs143
-rw-r--r--library/std/src/sys_common/thread_parker/mod.rs1
-rw-r--r--src/librustdoc/html/highlight.rs55
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css20
-rw-r--r--src/librustdoc/html/static/js/main.js23
-rw-r--r--src/test/rustdoc-gui/check_info_sign_position.goml8
-rw-r--r--src/test/rustdoc-gui/codeblock-tooltip.goml36
-rw-r--r--src/test/rustdoc-gui/overflow-tooltip-information.goml2
-rw-r--r--src/test/ui/array-slice-vec/suggest-array-length.fixed12
-rw-r--r--src/test/ui/array-slice-vec/suggest-array-length.rs12
-rw-r--r--src/test/ui/array-slice-vec/suggest-array-length.stderr70
21 files changed, 244 insertions, 580 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 90bcc2e4be4..4e0e72d3415 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1656,12 +1656,13 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.0"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "compiler_builtins",
  "libc",
+ "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
@@ -4608,7 +4609,7 @@ dependencies = [
  "dlmalloc",
  "fortanix-sgx-abi",
  "hashbrown",
- "hermit-abi 0.2.0",
+ "hermit-abi 0.2.6",
  "libc",
  "miniz_oxide 0.4.0",
  "object 0.26.2",
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a57fdc3bfb1..0de99f7a3db 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2401,6 +2401,14 @@ impl<'hir> Ty<'hir> {
             _ => None,
         }
     }
+
+    pub fn peel_refs(&self) -> &Self {
+        let mut final_ty = self;
+        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = &ty;
+        }
+        final_ty
+    }
 }
 
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 0e6a8ef8265..21392001364 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1305,31 +1305,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) {
-        if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(expr.hir_id) {
-            let ty = match self.tcx.hir().find(parent_hir_id) {
-                Some(
-                    hir::Node::Local(hir::Local { ty: Some(ty), .. })
-                    | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }),
-                ) => Some(ty),
-                _ => None,
-            };
-            if let Some(ty) = ty
-                && let hir::TyKind::Array(_, length) = ty.kind
-                && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
-                && let Some(span) = self.tcx.hir().opt_span(hir_id)
-            {
-                match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
-                    Some(mut err) => {
-                        err.span_suggestion(
-                            span,
-                            "consider specifying the array length",
-                            array_len,
-                            Applicability::MaybeIncorrect,
-                        );
-                        err.emit();
-                    }
-                    None => ()
+        let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| {
+            !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. }))
+        });
+        let Some((_,
+            hir::Node::Local(hir::Local { ty: Some(ty), .. })
+            | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }))
+        ) = parent_node else {
+            return
+        };
+        if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
+            && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+            && let Some(span) = self.tcx.hir().opt_span(hir_id)
+        {
+            match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
+                Some(mut err) => {
+                    err.span_suggestion(
+                        span,
+                        "consider specifying the array length",
+                        array_len,
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
                 }
+                None => ()
             }
         }
     }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 9d3e9abf557..905212eb372 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -1819,7 +1819,7 @@ impl<'a> Formatter<'a> {
     ///             write!(formatter,
     ///                    "Foo({}{})",
     ///                    if self.0 < 0 { '-' } else { '+' },
-    ///                    self.0)
+    ///                    self.0.abs())
     ///         } else {
     ///             write!(formatter, "Foo({})", self.0)
     ///         }
@@ -1827,6 +1827,7 @@ impl<'a> Formatter<'a> {
     /// }
     ///
     /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
+    /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)");
     /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
     /// ```
     #[must_use]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 20340d42962..764e2796202 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -160,19 +160,16 @@ pub const unsafe fn unreachable_unchecked() -> ! {
 #[inline]
 #[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
-    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
+    #[cfg(target_arch = "x86")]
     {
-        #[cfg(target_arch = "x86")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
-            unsafe { crate::arch::x86::_mm_pause() };
-        }
+        // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
+        unsafe { crate::arch::x86::_mm_pause() };
+    }
 
-        #[cfg(target_arch = "x86_64")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
-            unsafe { crate::arch::x86_64::_mm_pause() };
-        }
+    #[cfg(target_arch = "x86_64")]
+    {
+        // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
+        unsafe { crate::arch::x86_64::_mm_pause() };
     }
 
     // RISC-V platform spin loop hint implementation
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 3da9565a86d..324ecc80477 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -42,7 +42,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
deleted file mode 100644
index 22059ca0dbe..00000000000
--- a/library/std/src/sys/hermit/condvar.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::ffi::c_void;
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::hermit::abi;
-use crate::sys::locks::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-// The implementation is inspired by Andrew D. Birrell's paper
-// "Implementing Condition Variables with Semaphores"
-
-pub struct Condvar {
-    counter: AtomicUsize,
-    sem1: *const c_void,
-    sem2: *const c_void,
-}
-
-pub(crate) type MovableCondvar = LazyBox<Condvar>;
-
-impl LazyInit for Condvar {
-    fn init() -> Box<Self> {
-        Box::new(Self::new())
-    }
-}
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-impl Condvar {
-    pub fn new() -> Self {
-        let mut condvar =
-            Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
-        unsafe {
-            let _ = abi::sem_init(&mut condvar.sem1, 0);
-            let _ = abi::sem_init(&mut condvar.sem2, 0);
-        }
-        condvar
-    }
-
-    pub unsafe fn notify_one(&self) {
-        if self.counter.load(SeqCst) > 0 {
-            self.counter.fetch_sub(1, SeqCst);
-            abi::sem_post(self.sem1);
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn notify_all(&self) {
-        let counter = self.counter.swap(0, SeqCst);
-        for _ in 0..counter {
-            abi::sem_post(self.sem1);
-        }
-        for _ in 0..counter {
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        abi::sem_timedwait(self.sem1, 0);
-        abi::sem_post(self.sem2);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        let millis = dur.as_millis().min(u32::MAX as u128) as u32;
-
-        let res = if millis > 0 {
-            abi::sem_timedwait(self.sem1, millis)
-        } else {
-            abi::sem_trywait(self.sem1)
-        };
-
-        abi::sem_post(self.sem2);
-        mutex.lock();
-        res == 0
-    }
-}
-
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = abi::sem_destroy(self.sem1);
-            let _ = abi::sem_destroy(self.sem2);
-        }
-    }
-}
diff --git a/library/std/src/sys/hermit/futex.rs b/library/std/src/sys/hermit/futex.rs
new file mode 100644
index 00000000000..b64c174b06c
--- /dev/null
+++ b/library/std/src/sys/hermit/futex.rs
@@ -0,0 +1,39 @@
+use super::abi;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicU32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    // Calculate the timeout as a relative timespec.
+    //
+    // Overflows are rounded up to an infinite timeout (None).
+    let timespec = timeout.and_then(|dur| {
+        Some(abi::timespec {
+            tv_sec: dur.as_secs().try_into().ok()?,
+            tv_nsec: dur.subsec_nanos().into(),
+        })
+    });
+
+    let r = unsafe {
+        abi::futex_wait(
+            futex.as_mut_ptr(),
+            expected,
+            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
+            abi::FUTEX_RELATIVE_TIMEOUT,
+        )
+    };
+
+    r != -abi::errno::ETIMEDOUT
+}
+
+#[inline]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { abi::futex_wake(futex.as_mut_ptr(), 1) > 0 }
+}
+
+#[inline]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe {
+        abi::futex_wake(futex.as_mut_ptr(), i32::MAX);
+    }
+}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 61da096ae16..827d82900ea 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -25,6 +25,7 @@ pub mod cmath;
 pub mod env;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 #[path = "../unsupported/io.rs"]
 pub mod io;
 pub mod memchr;
@@ -45,14 +46,14 @@ pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
 
-mod condvar;
-mod mutex;
-mod rwlock;
-
+#[path = "../unix/locks"]
 pub mod locks {
-    pub use super::condvar::*;
-    pub use super::mutex::*;
-    pub use super::rwlock::*;
+    mod futex_condvar;
+    mod futex_mutex;
+    mod futex_rwlock;
+    pub(crate) use futex_condvar::MovableCondvar;
+    pub(crate) use futex_mutex::{MovableMutex, Mutex};
+    pub(crate) use futex_rwlock::{MovableRwLock, RwLock};
 }
 
 use crate::io::ErrorKind;
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
deleted file mode 100644
index 30c8fc4562d..00000000000
--- a/library/std/src/sys/hermit/mutex.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::collections::VecDeque;
-use crate::hint;
-use crate::ops::{Deref, DerefMut, Drop};
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sys::hermit::abi;
-
-/// This type provides a lock based on busy waiting to realize mutual exclusion
-///
-/// # Description
-///
-/// This structure behaves a lot like a common mutex. There are some differences:
-///
-/// - By using busy waiting, it can be used outside the runtime.
-/// - It is a so called ticket lock and is completely fair.
-#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
-#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
-struct Spinlock<T: ?Sized> {
-    queue: AtomicUsize,
-    dequeue: AtomicUsize,
-    data: UnsafeCell<T>,
-}
-
-unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
-unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
-
-/// A guard to which the protected data can be accessed
-///
-/// When the guard falls out of scope it will release the lock.
-struct SpinlockGuard<'a, T: ?Sized + 'a> {
-    dequeue: &'a AtomicUsize,
-    data: &'a mut T,
-}
-
-impl<T> Spinlock<T> {
-    pub const fn new(user_data: T) -> Spinlock<T> {
-        Spinlock {
-            queue: AtomicUsize::new(0),
-            dequeue: AtomicUsize::new(1),
-            data: UnsafeCell::new(user_data),
-        }
-    }
-
-    #[inline]
-    fn obtain_lock(&self) {
-        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
-        let mut counter: u16 = 0;
-        while self.dequeue.load(Ordering::SeqCst) != ticket {
-            counter += 1;
-            if counter < 100 {
-                hint::spin_loop();
-            } else {
-                counter = 0;
-                unsafe {
-                    abi::yield_now();
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
-        self.obtain_lock();
-        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
-    }
-}
-
-impl<T: ?Sized + Default> Default for Spinlock<T> {
-    fn default() -> Spinlock<T> {
-        Spinlock::new(Default::default())
-    }
-}
-
-impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        &*self.data
-    }
-}
-
-impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut *self.data
-    }
-}
-
-impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
-    /// The dropping of the SpinlockGuard will release the lock it was created from.
-    fn drop(&mut self) {
-        self.dequeue.fetch_add(1, Ordering::SeqCst);
-    }
-}
-
-/// Realize a priority queue for tasks
-struct PriorityQueue {
-    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
-    prio_bitmap: u64,
-}
-
-impl PriorityQueue {
-    pub const fn new() -> PriorityQueue {
-        PriorityQueue {
-            queues: [
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None,
-            ],
-            prio_bitmap: 0,
-        }
-    }
-
-    /// Add a task id by its priority to the queue
-    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
-        let i: usize = prio.into().into();
-        self.prio_bitmap |= (1 << i) as u64;
-        if let Some(queue) = &mut self.queues[i] {
-            queue.push_back(id);
-        } else {
-            let mut queue = VecDeque::new();
-            queue.push_back(id);
-            self.queues[i] = Some(queue);
-        }
-    }
-
-    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
-        if let Some(queue) = &mut self.queues[queue_index] {
-            let id = queue.pop_front();
-
-            if queue.is_empty() {
-                self.prio_bitmap &= !(1 << queue_index as u64);
-            }
-
-            id
-        } else {
-            None
-        }
-    }
-
-    /// Pop the task handle with the highest priority from the queue
-    pub fn pop(&mut self) -> Option<abi::Tid> {
-        for i in 0..abi::NO_PRIORITIES {
-            if self.prio_bitmap & (1 << i) != 0 {
-                return self.pop_from_queue(i);
-            }
-        }
-
-        None
-    }
-}
-
-struct MutexInner {
-    locked: bool,
-    blocked_task: PriorityQueue,
-}
-
-impl MutexInner {
-    pub const fn new() -> MutexInner {
-        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
-    }
-}
-
-pub struct Mutex {
-    inner: Spinlock<MutexInner>,
-}
-
-pub type MovableMutex = Mutex;
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { inner: Spinlock::new(MutexInner::new()) }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        loop {
-            let mut guard = self.inner.lock();
-            if guard.locked == false {
-                guard.locked = true;
-                return;
-            } else {
-                let prio = abi::get_priority();
-                let id = abi::getpid();
-
-                guard.blocked_task.push(prio, id);
-                abi::block_current_task();
-                drop(guard);
-                abi::yield_now();
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let mut guard = self.inner.lock();
-        guard.locked = false;
-        if let Some(tid) = guard.blocked_task.pop() {
-            abi::wakeup_task(tid);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = self.inner.lock();
-        if guard.locked == false {
-            guard.locked = true;
-        }
-        guard.locked
-    }
-}
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
deleted file mode 100644
index 1adf0b2be6b..00000000000
--- a/library/std/src/sys/hermit/rwlock.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{MovableCondvar, Mutex};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: MovableCondvar,
-    state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock {
-            lock: Mutex::new(),
-            cond: MovableCondvar::new(),
-            state: UnsafeCell::new(State::Unlocked),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index cbd7832eb7a..f86a9a555d3 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -7,6 +7,7 @@ cfg_if::cfg_if! {
         target_os = "openbsd",
         target_os = "dragonfly",
         target_os = "fuchsia",
+        target_os = "hermit",
     ))] {
         mod futex;
         pub use futex::Parker;
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index bb8e46af762..84781d89838 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -52,35 +52,14 @@ pub(crate) fn render_example_with_highlighting(
     tooltip: Tooltip,
     playground_button: Option<&str>,
 ) {
-    let class = match tooltip {
-        Tooltip::Ignore => " ignore",
-        Tooltip::CompileFail => " compile_fail",
-        Tooltip::ShouldPanic => " should_panic",
-        Tooltip::Edition(_) => " edition",
-        Tooltip::None => "",
-    };
-
-    if tooltip != Tooltip::None {
-        write!(
-            out,
-            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
-            class,
-            if let Tooltip::Edition(edition_info) = tooltip {
-                format!(" data-edition=\"{}\"", edition_info)
-            } else {
-                String::new()
-            },
-        );
-    }
-
-    write_header(out, &format!("rust-example-rendered{}", class), None);
+    write_header(out, "rust-example-rendered", None, tooltip);
     write_code(out, src, None, None);
     write_footer(out, playground_button);
 }
 
 /// Highlights `src` as a macro, returning the HTML output.
 pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
-    write_header(out, "macro", None);
+    write_header(out, "macro", None, Tooltip::None);
     write_code(out, src, None, None);
     write_footer(out, None);
 }
@@ -93,20 +72,42 @@ pub(crate) fn render_source_with_highlighting(
     href_context: HrefContext<'_, '_, '_>,
     decoration_info: DecorationInfo,
 ) {
-    write_header(out, "", Some(line_numbers));
+    write_header(out, "", Some(line_numbers), Tooltip::None);
     write_code(out, src, Some(href_context), Some(decoration_info));
     write_footer(out, None);
 }
 
-fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
     write!(out, "<div class=\"example-wrap\">");
+
+    let tooltip_class = match tooltip {
+        Tooltip::Ignore => " ignore",
+        Tooltip::CompileFail => " compile_fail",
+        Tooltip::ShouldPanic => " should_panic",
+        Tooltip::Edition(_) => " edition",
+        Tooltip::None => "",
+    };
+
+    if tooltip != Tooltip::None {
+        write!(
+            out,
+            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
+            tooltip_class,
+            if let Tooltip::Edition(edition_info) = tooltip {
+                format!(" data-edition=\"{}\"", edition_info)
+            } else {
+                String::new()
+            },
+        );
+    }
+
     if let Some(extra) = extra_content {
         out.push_buffer(extra);
     }
-    if class.is_empty() {
+    if class.is_empty() && tooltip_class.is_empty() {
         write!(out, "<pre class=\"rust\">");
     } else {
-        write!(out, "<pre class=\"rust {}\">", class);
+        write!(out, "<pre class=\"rust {class}{tooltip_class}\">");
     }
     write!(out, "<code>");
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 22217a39012..ec9e3b1ecd1 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -347,10 +347,6 @@ img {
 	max-width: 100%;
 }
 
-li {
-	position: relative;
-}
-
 .source .content {
 	max-width: none;
 	overflow: visible;
@@ -652,7 +648,7 @@ h2.location a {
 	position: relative;
 }
 
-.docblock > :not(.information):not(.more-examples-toggle) {
+.docblock > :not(.more-examples-toggle):not(.example-wrap) {
 	max-width: 100%;
 	overflow-x: auto;
 }
@@ -1169,12 +1165,12 @@ pre.ignore {
 	border-left: 2px solid var(--codeblock-ignore-color);
 }
 
-pre.compile_fail:hover, .information:hover + .example-wrap pre.compile_fail,
-pre.should_panic:hover, .information:hover + .example-wrap pre.should_panic {
+.example-wrap:hover pre.compile_fail,
+.example-wrap:hover pre.should_panic {
 	border-left: 2px solid var(--codeblock-error-hover-color);
 }
 
-pre.ignore:hover, .information:hover + .example-wrap pre.ignore {
+.example-wrap:hover pre.ignore {
 	border-left: 2px solid var(--codeblock-ignore-hover-color);
 }
 
@@ -1187,12 +1183,12 @@ pre.ignore:hover, .information:hover + .example-wrap pre.ignore {
 	color:  var(--codeblock-ignore-color);
 }
 
-.information > .compile_fail:hover,
-.information > .should_panic:hover {
+.example-wrap:hover .tooltip.compile_fail,
+.example-wrap:hover .tooltip.should_panic {
 	color: var(--codeblock-error-hover-color);
 }
 
-.information > .ignore:hover {
+.example-wrap:hover .tooltip.ignore {
 	color: var(--codeblock-ignore-hover-color);
 }
 
@@ -1727,7 +1723,7 @@ in storage.js plus the media query with (max-width: 700px)
 	to prevent an overlay between the "collapse toggle" and the information tooltip.
 	However, it's not needed with smaller screen width because the doc/code block is always put
 	"one line" below. */
-	.docblock > .information:first-child > .tooltip {
+	.docblock > .example-wrap:first-child > .information > .tooltip {
 		margin-top: 16px;
 	}
 
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 7f61c95e794..6e9660ddcc9 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -699,9 +699,8 @@ function loadCss(cssFileName) {
 
     (function() {
         // To avoid checking on "rustdoc-line-numbers" value on every loop...
-        let lineNumbersFunc = () => {};
         if (getSettingValue("line-numbers") === "true") {
-            lineNumbersFunc = x => {
+            onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
                 const count = x.textContent.split("\n").length;
                 const elems = [];
                 for (let i = 0; i < count; ++i) {
@@ -711,26 +710,8 @@ function loadCss(cssFileName) {
                 addClass(node, "line-number");
                 node.innerHTML = elems.join("\n");
                 x.parentNode.insertBefore(node, x);
-            };
+            });
         }
-        onEachLazy(document.getElementsByClassName("rust-example-rendered"), e => {
-            if (hasClass(e, "compile_fail")) {
-                e.addEventListener("mouseover", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
-                });
-                e.addEventListener("mouseout", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
-                });
-            } else if (hasClass(e, "ignore")) {
-                e.addEventListener("mouseover", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
-                });
-                e.addEventListener("mouseout", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
-                });
-            }
-            lineNumbersFunc(e);
-        });
     }());
 
     let oldSidebarScrollPosition = null;
diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml
index 3bed7a0a03e..c249895503a 100644
--- a/src/test/rustdoc-gui/check_info_sign_position.goml
+++ b/src/test/rustdoc-gui/check_info_sign_position.goml
@@ -4,8 +4,8 @@ goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 // If the codeblock is the first element of the docblock, the information tooltip must have
 // have some top margin to avoid going over the toggle (the "[+]").
-assert-css: (".docblock > .information > .compile_fail", { "margin-top": "16px" })
+assert-css: (".docblock > .example-wrap > .information > .compile_fail", { "margin-top": "16px" })
 // Checks that the other codeblocks don't have this top margin.
-assert-css: ("ol > li > .information > .compile_fail", { "margin-top": "0px" })
-assert-css: ("ol > li > .information > .ignore", { "margin-top": "0px" })
-assert-css: (".docblock > .information > .ignore", { "margin-top": "0px" })
+assert-css: ("ol > li > .example-wrap > .information > .compile_fail", { "margin-top": "0px" })
+assert-css: ("ol > li > .example-wrap > .information > .ignore", { "margin-top": "0px" })
+assert-css: (".docblock > .example-wrap > .information > .ignore", { "margin-top": "0px" })
diff --git a/src/test/rustdoc-gui/codeblock-tooltip.goml b/src/test/rustdoc-gui/codeblock-tooltip.goml
index a0bb40fce8e..4e85c33c894 100644
--- a/src/test/rustdoc-gui/codeblock-tooltip.goml
+++ b/src/test/rustdoc-gui/codeblock-tooltip.goml
@@ -8,30 +8,30 @@ reload:
 
 // compile_fail block
 assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .compile_fail"
 
 assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // should_panic block
 assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .should_panic"
 
 assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // ignore block
 assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
 
 move-cursor-to: ".docblock .information .ignore"
 
 assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
 
 
 // Light theme.
@@ -39,30 +39,30 @@ local-storage: {"rustdoc-theme": "light"}
 reload:
 
 assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .compile_fail"
 
 assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // should_panic block
 assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .should_panic"
 
 assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // ignore block
 assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
 
 move-cursor-to: ".docblock .information .ignore"
 
 assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
 
 
 // Ayu theme.
@@ -70,27 +70,27 @@ local-storage: {"rustdoc-theme": "ayu"}
 reload:
 
 assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .compile_fail"
 
 assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // should_panic block
 assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
 
 move-cursor-to: ".docblock .information .should_panic"
 
 assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
 
 // ignore block
 assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
 
 move-cursor-to: ".docblock .information .ignore"
 
 assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
diff --git a/src/test/rustdoc-gui/overflow-tooltip-information.goml b/src/test/rustdoc-gui/overflow-tooltip-information.goml
index 7ef85a4c445..5be1aff8d3b 100644
--- a/src/test/rustdoc-gui/overflow-tooltip-information.goml
+++ b/src/test/rustdoc-gui/overflow-tooltip-information.goml
@@ -2,7 +2,7 @@
 // have overflow and max-width CSS rules set because they create a bug in firefox on
 // mac. For more information: https://github.com/rust-lang/rust/issues/89185
 goto: file://|DOC_PATH|/test_docs/fn.foo.html
-assert-css: (".docblock > .information", {
+assert-css: (".docblock > .example-wrap > .information", {
     "overflow-x": "visible",
     "max-width": "none"
 }, ALL)
diff --git a/src/test/ui/array-slice-vec/suggest-array-length.fixed b/src/test/ui/array-slice-vec/suggest-array-length.fixed
index bae3ab74af6..867c18a7d5e 100644
--- a/src/test/ui/array-slice-vec/suggest-array-length.fixed
+++ b/src/test/ui/array-slice-vec/suggest-array-length.fixed
@@ -5,10 +5,22 @@ fn main() {
     const Foo: [i32; 3] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    const REF_FOO: &[u8; 1] = &[1];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
     let foo: [i32; 3] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
     let bar: [i32; 3] = [0; 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    let ref_foo: &[i32; 3] = &[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let ref_bar: &[i32; 3] = &[0; 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let multiple_ref_foo: &&[i32; 3] = &&[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
 }
diff --git a/src/test/ui/array-slice-vec/suggest-array-length.rs b/src/test/ui/array-slice-vec/suggest-array-length.rs
index b0867f4e396..f66b3d4a899 100644
--- a/src/test/ui/array-slice-vec/suggest-array-length.rs
+++ b/src/test/ui/array-slice-vec/suggest-array-length.rs
@@ -5,10 +5,22 @@ fn main() {
     const Foo: [i32; _] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    const REF_FOO: &[u8; _] = &[1];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
     let foo: [i32; _] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
     let bar: [i32; _] = [0; 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    let ref_foo: &[i32; _] = &[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let ref_bar: &[i32; _] = &[0; 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
 }
diff --git a/src/test/ui/array-slice-vec/suggest-array-length.stderr b/src/test/ui/array-slice-vec/suggest-array-length.stderr
index 9000f716028..16c90a04784 100644
--- a/src/test/ui/array-slice-vec/suggest-array-length.stderr
+++ b/src/test/ui/array-slice-vec/suggest-array-length.stderr
@@ -1,21 +1,45 @@
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/suggest-array-length.rs:8:20
+  --> $DIR/suggest-array-length.rs:11:20
    |
 LL |     let foo: [i32; _] = [1, 2, 3];
    |                    ^ `_` not allowed here
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/suggest-array-length.rs:11:20
+  --> $DIR/suggest-array-length.rs:14:20
    |
 LL |     let bar: [i32; _] = [0; 3];
    |                    ^ `_` not allowed here
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:17:25
+   |
+LL |     let ref_foo: &[i32; _] = &[1, 2, 3];
+   |                         ^ `_` not allowed here
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:20:25
+   |
+LL |     let ref_bar: &[i32; _] = &[0; 3];
+   |                         ^ `_` not allowed here
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:23:35
+   |
+LL |     let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+   |                                   ^ `_` not allowed here
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
   --> $DIR/suggest-array-length.rs:5:22
    |
 LL |     const Foo: [i32; _] = [1, 2, 3];
    |                      ^ `_` not allowed here
 
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:8:26
+   |
+LL |     const REF_FOO: &[u8; _] = &[1];
+   |                          ^ `_` not allowed here
+
 error[E0658]: using `_` for array lengths is unstable
   --> $DIR/suggest-array-length.rs:5:22
    |
@@ -26,7 +50,16 @@ LL |     const Foo: [i32; _] = [1, 2, 3];
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
 error[E0658]: using `_` for array lengths is unstable
-  --> $DIR/suggest-array-length.rs:8:20
+  --> $DIR/suggest-array-length.rs:8:26
+   |
+LL |     const REF_FOO: &[u8; _] = &[1];
+   |                          ^ help: consider specifying the array length: `1`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:11:20
    |
 LL |     let foo: [i32; _] = [1, 2, 3];
    |                    ^ help: consider specifying the array length: `3`
@@ -35,7 +68,7 @@ LL |     let foo: [i32; _] = [1, 2, 3];
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
 error[E0658]: using `_` for array lengths is unstable
-  --> $DIR/suggest-array-length.rs:11:20
+  --> $DIR/suggest-array-length.rs:14:20
    |
 LL |     let bar: [i32; _] = [0; 3];
    |                    ^ help: consider specifying the array length: `3`
@@ -43,6 +76,33 @@ LL |     let bar: [i32; _] = [0; 3];
    = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
-error: aborting due to 6 previous errors
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:17:25
+   |
+LL |     let ref_foo: &[i32; _] = &[1, 2, 3];
+   |                         ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:20:25
+   |
+LL |     let ref_bar: &[i32; _] = &[0; 3];
+   |                         ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:23:35
+   |
+LL |     let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+   |                                   ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0658`.