mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
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
This commit is contained in:
commit
1d37ed661a
@ -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",
|
||||
|
@ -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`.
|
||||
|
@ -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 => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
39
library/std/src/sys/hermit/futex.rs
Normal file
39
library/std/src/sys/hermit/futex.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
@ -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;
|
||||
|
@ -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>");
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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" })
|
||||
|
@ -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)"})
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user