mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-28 15:43:21 +00:00
Auto merge of #98730 - matthiaskrgr:rollup-2c4d4x5, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #97629 ([core] add `Exclusive` to sync) - #98503 (fix data race in thread::scope) - #98670 (llvm-wrapper: adapt for LLVMConstExtractValue removal) - #98671 (Fix source sidebar bugs) - #98677 (For diagnostic information of Boolean, remind it as use the type: 'bool') - #98684 (add test for 72793) - #98688 (interpret: add From<&MplaceTy> for PlaceTy) - #98695 (use "or pattern") - #98709 (Remove unneeded methods declaration for old web browsers) - #98717 (get rid of tidy 'unnecessarily ignored' warnings) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ca1e68b322
@ -109,8 +109,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
|
||||
unsafe {
|
||||
assert_eq!(idx as c_uint as u64, idx);
|
||||
let us = &[idx as c_uint];
|
||||
let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
|
||||
let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap();
|
||||
|
||||
debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r);
|
||||
|
||||
|
@ -1134,11 +1134,7 @@ extern "C" {
|
||||
pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
|
||||
pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
|
||||
pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
|
||||
pub fn LLVMConstExtractValue(
|
||||
AggConstant: &Value,
|
||||
IdxList: *const c_uint,
|
||||
NumIdx: c_uint,
|
||||
) -> &Value;
|
||||
pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>;
|
||||
|
||||
// Operations on global variables, functions, and aliases (globals)
|
||||
pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
|
||||
|
@ -346,7 +346,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
ty::FnDef(_, _) => {
|
||||
ecx.write_immediate(
|
||||
Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
|
||||
&(*place).into(),
|
||||
&place.into(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@ -355,7 +355,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
|
||||
ecx.write_immediate(
|
||||
Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())),
|
||||
&(*place).into(),
|
||||
&place.into(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@ -382,7 +382,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
};
|
||||
debug!(?imm);
|
||||
|
||||
ecx.write_immediate(imm, &(*place).into()).unwrap();
|
||||
ecx.write_immediate(imm, &place.into()).unwrap();
|
||||
}
|
||||
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
|
||||
let branches = valtree.unwrap_branch();
|
||||
@ -464,11 +464,11 @@ fn valtree_into_mplace<'tcx>(
|
||||
|
||||
if let Some(variant_idx) = variant_idx {
|
||||
// don't forget filling the place with the discriminant of the enum
|
||||
ecx.write_discriminant(variant_idx, &(*place).into()).unwrap();
|
||||
ecx.write_discriminant(variant_idx, &place.into()).unwrap();
|
||||
}
|
||||
|
||||
debug!("dump of place after writing discriminant:");
|
||||
dump_place(ecx, (*place).into());
|
||||
dump_place(ecx, place.into());
|
||||
}
|
||||
_ => bug!("shouldn't have created a ValTree for {:?}", ty),
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
|
||||
let tcx = self.ecx.tcx;
|
||||
let ty = mplace.layout.ty;
|
||||
if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
|
||||
let value = self.ecx.read_immediate(&(*mplace).into())?;
|
||||
let value = self.ecx.read_immediate(&mplace.into())?;
|
||||
let mplace = self.ecx.ref_to_mplace(&value)?;
|
||||
assert_eq!(mplace.layout.ty, referenced_ty);
|
||||
// Handle trait object vtables.
|
||||
|
@ -204,6 +204,13 @@ impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
|
||||
OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(val: ImmTy<'tcx, Tag>) -> Self {
|
||||
|
@ -118,7 +118,21 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
|
||||
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
|
||||
PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout }
|
||||
PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
|
||||
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
|
||||
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
Ok((*self).into())
|
||||
Ok(self.into())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -1447,7 +1447,7 @@ impl HandlerInner {
|
||||
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
|
||||
) {
|
||||
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
|
||||
(0, _) | (1, _) => {}
|
||||
(0 | 1, _) => {}
|
||||
(count, as_bug) => panic!(
|
||||
"aborting after {} errors due to `-Z treat-err-as-bug={}`",
|
||||
count, as_bug,
|
||||
|
@ -1865,3 +1865,11 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) {
|
||||
GlobalValue *GV = unwrap<GlobalValue>(V);
|
||||
Mangler().getNameWithPrefix(OS, GV, true);
|
||||
}
|
||||
|
||||
// LLVMGetAggregateElement was added in LLVM 15. For earlier LLVM versions just
|
||||
// use its implementation.
|
||||
#if LLVM_VERSION_LT(15, 0)
|
||||
extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) {
|
||||
return wrap(unwrap<Constant>(C)->getAggregateElement(Idx));
|
||||
}
|
||||
#endif
|
||||
|
@ -1503,6 +1503,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
Some(match name {
|
||||
"byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
|
||||
"short" => sym::i16,
|
||||
"Bool" => sym::bool,
|
||||
"Boolean" => sym::bool,
|
||||
"boolean" => sym::bool,
|
||||
"int" => sym::i32,
|
||||
"long" => sym::i64,
|
||||
|
173
library/core/src/sync/exclusive.rs
Normal file
173
library/core/src/sync/exclusive.rs
Normal file
@ -0,0 +1,173 @@
|
||||
//! Defines [`Exclusive`].
|
||||
|
||||
use core::fmt;
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_
|
||||
/// access to the underlying value. It provides no _immutable_, or _shared_
|
||||
/// access to the underlying value.
|
||||
///
|
||||
/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_
|
||||
/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive`
|
||||
/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
|
||||
/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API
|
||||
/// whatsoever, making it useless, thus harmless, thus memory safe.
|
||||
///
|
||||
/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
|
||||
/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the
|
||||
/// rust compiler that something is `Sync` in practice.
|
||||
///
|
||||
/// ## Examples
|
||||
/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`
|
||||
/// ```compile_fail
|
||||
/// use core::cell::Cell;
|
||||
///
|
||||
/// async fn other() {}
|
||||
/// fn assert_sync<T: Sync>(t: T) {}
|
||||
/// struct State<F> {
|
||||
/// future: F
|
||||
/// }
|
||||
///
|
||||
/// assert_sync(State {
|
||||
/// future: async {
|
||||
/// let cell = Cell::new(1);
|
||||
/// let cell_ref = &cell;
|
||||
/// other().await;
|
||||
/// let value = cell_ref.get();
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// `Exclusive` ensures the struct is `Sync` without stripping the future of its
|
||||
/// functionality.
|
||||
/// ```
|
||||
/// #![feature(exclusive_wrapper)]
|
||||
/// use core::cell::Cell;
|
||||
/// use core::sync::Exclusive;
|
||||
///
|
||||
/// async fn other() {}
|
||||
/// fn assert_sync<T: Sync>(t: T) {}
|
||||
/// struct State<F> {
|
||||
/// future: Exclusive<F>
|
||||
/// }
|
||||
///
|
||||
/// assert_sync(State {
|
||||
/// future: Exclusive::new(async {
|
||||
/// let cell = Cell::new(1);
|
||||
/// let cell_ref = &cell;
|
||||
/// other().await;
|
||||
/// let value = cell_ref.get();
|
||||
/// })
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ## Parallels with a mutex
|
||||
/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of
|
||||
/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
|
||||
/// for any value. This is a parallel with the fact that
|
||||
/// `&` and `&mut` references together can be thought of as a _compile-time_
|
||||
/// version of a read-write lock.
|
||||
///
|
||||
///
|
||||
/// [`Sync`]: core::marker::Sync
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[doc(alias = "SyncWrapper")]
|
||||
#[doc(alias = "SyncCell")]
|
||||
#[doc(alias = "Unique")]
|
||||
// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would
|
||||
// use `&` access to the inner value, violating the `Sync` impl's safety
|
||||
// requirements.
|
||||
#[derive(Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct Exclusive<T: ?Sized> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
// See `Exclusive`'s docs for justification.
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
unsafe impl<T: ?Sized> Sync for Exclusive<T> {}
|
||||
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
impl<T: ?Sized> fmt::Debug for Exclusive<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.debug_struct("Exclusive").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> Exclusive<T> {
|
||||
/// Wrap a value in an `Exclusive`
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn new(t: T) -> Self {
|
||||
Self { inner: t }
|
||||
}
|
||||
|
||||
/// Unwrap the value contained in the `Exclusive`
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Exclusive<T> {
|
||||
/// Get exclusive access to the underlying value.
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Get pinned exclusive access to the underlying value.
|
||||
///
|
||||
/// `Exclusive` is considered to _structurally pin_ the underlying
|
||||
/// value, which means _unpinned_ `Exclusive`s can produce _unpinned_
|
||||
/// access to the underlying value, but _pinned_ `Exclusive`s only
|
||||
/// produce _pinned_ access to the underlying value.
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||
// SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
|
||||
// `Pin::map_unchecked_mut` is not const, so we do this conversion manually
|
||||
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
|
||||
}
|
||||
|
||||
/// Build a _mutable_ references to an `Exclusive<T>` from
|
||||
/// a _mutable_ reference to a `T`. This allows you to skip
|
||||
/// building an `Exclusive` with [`Exclusive::new`].
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
|
||||
// SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic
|
||||
unsafe { &mut *(r as *mut T as *mut Exclusive<T>) }
|
||||
}
|
||||
|
||||
/// Build a _pinned mutable_ references to an `Exclusive<T>` from
|
||||
/// a _pinned mutable_ reference to a `T`. This allows you to skip
|
||||
/// building an `Exclusive` with [`Exclusive::new`].
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
#[must_use]
|
||||
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
|
||||
// SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
|
||||
// `Pin::map_unchecked_mut` is not const, so we do this conversion manually
|
||||
unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
impl<T> From<T> for Exclusive<T> {
|
||||
fn from(t: T) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
impl<T: Future + ?Sized> Future for Exclusive<T> {
|
||||
type Output = T::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.get_pin_mut().poll(cx)
|
||||
}
|
||||
}
|
@ -3,3 +3,6 @@
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
pub mod atomic;
|
||||
mod exclusive;
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
pub use exclusive::Exclusive;
|
||||
|
@ -270,6 +270,7 @@
|
||||
#![feature(duration_checked_float)]
|
||||
#![feature(duration_constants)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(exclusive_wrapper)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(float_minimum_maximum)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
|
@ -155,6 +155,8 @@
|
||||
pub use alloc_crate::sync::{Arc, Weak};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::sync::atomic;
|
||||
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
|
||||
pub use core::sync::Exclusive;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::barrier::{Barrier, BarrierWaitResult};
|
||||
|
@ -159,6 +159,7 @@ use crate::cell::UnsafeCell;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
use crate::num::NonZeroU64;
|
||||
use crate::num::NonZeroUsize;
|
||||
@ -462,7 +463,7 @@ impl Builder {
|
||||
unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
|
||||
self,
|
||||
f: F,
|
||||
scope_data: Option<&'scope scoped::ScopeData>,
|
||||
scope_data: Option<Arc<scoped::ScopeData>>,
|
||||
) -> io::Result<JoinInner<'scope, T>>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
@ -479,8 +480,11 @@ impl Builder {
|
||||
}));
|
||||
let their_thread = my_thread.clone();
|
||||
|
||||
let my_packet: Arc<Packet<'scope, T>> =
|
||||
Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
|
||||
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
|
||||
scope: scope_data,
|
||||
result: UnsafeCell::new(None),
|
||||
_marker: PhantomData,
|
||||
});
|
||||
let their_packet = my_packet.clone();
|
||||
|
||||
let output_capture = crate::io::set_output_capture(None);
|
||||
@ -507,7 +511,7 @@ impl Builder {
|
||||
unsafe { *their_packet.result.get() = Some(try_result) };
|
||||
};
|
||||
|
||||
if let Some(scope_data) = scope_data {
|
||||
if let Some(scope_data) = &my_packet.scope {
|
||||
scope_data.increment_num_running_threads();
|
||||
}
|
||||
|
||||
@ -1298,8 +1302,9 @@ pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
|
||||
// An Arc to the packet is stored into a `JoinInner` which in turns is placed
|
||||
// in `JoinHandle`.
|
||||
struct Packet<'scope, T> {
|
||||
scope: Option<&'scope scoped::ScopeData>,
|
||||
scope: Option<Arc<scoped::ScopeData>>,
|
||||
result: UnsafeCell<Option<Result<T>>>,
|
||||
_marker: PhantomData<Option<&'scope scoped::ScopeData>>,
|
||||
}
|
||||
|
||||
// Due to the usage of `UnsafeCell` we need to manually implement Sync.
|
||||
@ -1330,7 +1335,7 @@ impl<'scope, T> Drop for Packet<'scope, T> {
|
||||
rtabort!("thread result panicked on drop");
|
||||
}
|
||||
// Book-keeping so the scope knows when it's done.
|
||||
if let Some(scope) = self.scope {
|
||||
if let Some(scope) = &self.scope {
|
||||
// Now that there will be no more user code running on this thread
|
||||
// that can use 'scope, mark the thread as 'finished'.
|
||||
// It's important we only do this after the `result` has been dropped,
|
||||
|
@ -11,7 +11,7 @@ use crate::sync::Arc;
|
||||
/// See [`scope`] for details.
|
||||
#[stable(feature = "scoped_threads", since = "1.63.0")]
|
||||
pub struct Scope<'scope, 'env: 'scope> {
|
||||
data: ScopeData,
|
||||
data: Arc<ScopeData>,
|
||||
/// Invariance over 'scope, to make sure 'scope cannot shrink,
|
||||
/// which is necessary for soundness.
|
||||
///
|
||||
@ -130,12 +130,14 @@ pub fn scope<'env, F, T>(f: F) -> T
|
||||
where
|
||||
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
|
||||
{
|
||||
// We put the `ScopeData` into an `Arc` so that other threads can finish their
|
||||
// `decrement_num_running_threads` even after this function returns.
|
||||
let scope = Scope {
|
||||
data: ScopeData {
|
||||
data: Arc::new(ScopeData {
|
||||
num_running_threads: AtomicUsize::new(0),
|
||||
main_thread: current(),
|
||||
a_thread_panicked: AtomicBool::new(false),
|
||||
},
|
||||
}),
|
||||
env: PhantomData,
|
||||
scope: PhantomData,
|
||||
};
|
||||
@ -250,7 +252,7 @@ impl Builder {
|
||||
F: FnOnce() -> T + Send + 'scope,
|
||||
T: Send + 'scope,
|
||||
{
|
||||
Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
|
||||
Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(scope.data.clone())) }?))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
0.9.6
|
||||
0.9.7
|
@ -1772,9 +1772,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
|
||||
/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
|
||||
so don't bump down the main content or the sidebar. */
|
||||
.source main,
|
||||
.source .sidebar {
|
||||
.rustdoc.source .sidebar {
|
||||
top: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.sidebar.shown,
|
||||
@ -1924,6 +1926,9 @@ details.rustdoc-toggle[open] > summary.hideme::after {
|
||||
width: unset;
|
||||
border-top-right-radius: unset;
|
||||
border-bottom-right-radius: unset;
|
||||
position: sticky;
|
||||
border: 0;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
#source-sidebar {
|
||||
|
@ -4,40 +4,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function(searchString, position) {
|
||||
position = position || 0;
|
||||
return this.indexOf(searchString, position) === position;
|
||||
};
|
||||
}
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function(suffix, length) {
|
||||
const l = length || this.length;
|
||||
return this.indexOf(suffix, l - suffix.length) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
if (!DOMTokenList.prototype.add) {
|
||||
DOMTokenList.prototype.add = function(className) {
|
||||
if (className && !hasClass(this, className)) {
|
||||
if (this.className && this.className.length > 0) {
|
||||
this.className += " " + className;
|
||||
} else {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!DOMTokenList.prototype.remove) {
|
||||
DOMTokenList.prototype.remove = function(className) {
|
||||
if (className && this.className) {
|
||||
this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
|
||||
.trim();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Get a value from the rustdoc-vars div, which is used to convey data from
|
||||
// Rust to the JS. If there is no such element, return null.
|
||||
function getVar(name) {
|
||||
|
@ -10,6 +10,7 @@
|
||||
(function() {
|
||||
|
||||
const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
|
||||
let oldScrollPosition = 0;
|
||||
|
||||
function createDirEntry(elem, parent, fullPath, hasFoundFile) {
|
||||
const name = document.createElement("div");
|
||||
@ -65,10 +66,24 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
|
||||
function toggleSidebar() {
|
||||
const child = this.children[0];
|
||||
if (child.innerText === ">") {
|
||||
if (window.innerWidth < 701) {
|
||||
// This is to keep the scroll position on mobile.
|
||||
oldScrollPosition = window.scrollY;
|
||||
document.body.style.position = "fixed";
|
||||
document.body.style.top = `-${oldScrollPosition}px`;
|
||||
}
|
||||
addClass(document.documentElement, "source-sidebar-expanded");
|
||||
child.innerText = "<";
|
||||
updateLocalStorage("source-sidebar-show", "true");
|
||||
} else {
|
||||
if (window.innerWidth < 701) {
|
||||
// This is to keep the scroll position on mobile.
|
||||
document.body.style.position = "";
|
||||
document.body.style.top = "";
|
||||
// The scroll position is lost when resetting the style, hence why we store it in
|
||||
// `oldScroll`.
|
||||
window.scrollTo(0, oldScrollPosition);
|
||||
}
|
||||
removeClass(document.documentElement, "source-sidebar-expanded");
|
||||
child.innerText = ">";
|
||||
updateLocalStorage("source-sidebar-show", "false");
|
||||
|
@ -116,3 +116,39 @@ assert-css: (
|
||||
"#source-sidebar .expand + .children .folders .name",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
|
||||
)
|
||||
|
||||
// Now checking on mobile devices.
|
||||
size: (500, 700)
|
||||
reload:
|
||||
// Waiting for the sidebar to be displayed...
|
||||
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
|
||||
|
||||
// We now check it takes the full size of the display.
|
||||
assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"})
|
||||
assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"})
|
||||
|
||||
// We now check the display of the toggle once the sidebar is expanded.
|
||||
assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
|
||||
assert-css: (
|
||||
"#sidebar-toggle",
|
||||
{
|
||||
"border-top-width": "0px",
|
||||
"border-right-width": "0px",
|
||||
"border-left-width": "0px",
|
||||
"border-bottom-width": "1px",
|
||||
},
|
||||
)
|
||||
|
||||
// We now check that the scroll position is kept when opening the sidebar.
|
||||
click: "#sidebar-toggle"
|
||||
wait-for-css: (".sidebar", {"width": "0px"})
|
||||
// We scroll to line 117 to change the scroll position.
|
||||
scroll-to: '//*[@id="117"]'
|
||||
assert-window-property: {"pageYOffset": "2519"}
|
||||
// Expanding the sidebar...
|
||||
click: "#sidebar-toggle"
|
||||
wait-for-css: (".sidebar", {"width": "500px"})
|
||||
click: "#sidebar-toggle"
|
||||
wait-for-css: (".sidebar", {"width": "0px"})
|
||||
// The "scrollTop" property should be the same.
|
||||
assert-window-property: {"pageYOffset": "2519"}
|
||||
|
@ -18,8 +18,8 @@ assert: "nav.sidebar"
|
||||
|
||||
// We now switch to mobile mode.
|
||||
size: (600, 600)
|
||||
// We check that the sidebar has the expected width (0 and 1px for the border).
|
||||
assert-css: ("nav.sidebar", {"width": "1px"})
|
||||
// We check that the sidebar has the expected width (0).
|
||||
assert-css: ("nav.sidebar", {"width": "0px"})
|
||||
// We expand the sidebar.
|
||||
click: "#sidebar-toggle"
|
||||
assert-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"})
|
||||
|
@ -7,6 +7,13 @@ fn main() {
|
||||
let y: long = 74802374902374923;
|
||||
//~^ ERROR cannot find type `long` in this scope
|
||||
//~| HELP perhaps you intended to use this type
|
||||
let v1: Boolean = true;
|
||||
//~^ ERROR: cannot find type `Boolean` in this scope [E0412]
|
||||
//~| HELP perhaps you intended to use this type
|
||||
let v2: Bool = true;
|
||||
//~^ ERROR: cannot find type `Bool` in this scope [E0412]
|
||||
//~| HELP a builtin type with a similar name exists
|
||||
//~| HELP perhaps you intended to use this type
|
||||
}
|
||||
|
||||
fn z(a: boolean) {
|
||||
|
@ -16,8 +16,32 @@ LL | let y: long = 74802374902374923;
|
||||
| not found in this scope
|
||||
| help: perhaps you intended to use this type: `i64`
|
||||
|
||||
error[E0412]: cannot find type `Boolean` in this scope
|
||||
--> $DIR/recommend-literal.rs:10:13
|
||||
|
|
||||
LL | let v1: Boolean = true;
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: perhaps you intended to use this type: `bool`
|
||||
|
||||
error[E0412]: cannot find type `Bool` in this scope
|
||||
--> $DIR/recommend-literal.rs:13:13
|
||||
|
|
||||
LL | let v2: Bool = true;
|
||||
| ^^^^
|
||||
|
|
||||
help: a builtin type with a similar name exists
|
||||
|
|
||||
LL | let v2: bool = true;
|
||||
| ~~~~
|
||||
help: perhaps you intended to use this type
|
||||
|
|
||||
LL | let v2: bool = true;
|
||||
| ~~~~
|
||||
|
||||
error[E0412]: cannot find type `boolean` in this scope
|
||||
--> $DIR/recommend-literal.rs:12:9
|
||||
--> $DIR/recommend-literal.rs:19:9
|
||||
|
|
||||
LL | fn z(a: boolean) {
|
||||
| ^^^^^^^
|
||||
@ -26,7 +50,7 @@ LL | fn z(a: boolean) {
|
||||
| help: perhaps you intended to use this type: `bool`
|
||||
|
||||
error[E0412]: cannot find type `byte` in this scope
|
||||
--> $DIR/recommend-literal.rs:17:11
|
||||
--> $DIR/recommend-literal.rs:24:11
|
||||
|
|
||||
LL | fn a() -> byte {
|
||||
| ^^^^
|
||||
@ -35,7 +59,7 @@ LL | fn a() -> byte {
|
||||
| help: perhaps you intended to use this type: `u8`
|
||||
|
||||
error[E0412]: cannot find type `float` in this scope
|
||||
--> $DIR/recommend-literal.rs:24:12
|
||||
--> $DIR/recommend-literal.rs:31:12
|
||||
|
|
||||
LL | width: float,
|
||||
| ^^^^^
|
||||
@ -44,7 +68,7 @@ LL | width: float,
|
||||
| help: perhaps you intended to use this type: `f32`
|
||||
|
||||
error[E0412]: cannot find type `int` in this scope
|
||||
--> $DIR/recommend-literal.rs:27:19
|
||||
--> $DIR/recommend-literal.rs:34:19
|
||||
|
|
||||
LL | depth: Option<int>,
|
||||
| ^^^ not found in this scope
|
||||
@ -59,7 +83,7 @@ LL | struct Data<int> {
|
||||
| +++++
|
||||
|
||||
error[E0412]: cannot find type `short` in this scope
|
||||
--> $DIR/recommend-literal.rs:33:16
|
||||
--> $DIR/recommend-literal.rs:40:16
|
||||
|
|
||||
LL | impl Stuff for short {}
|
||||
| ^^^^^
|
||||
@ -67,6 +91,6 @@ LL | impl Stuff for short {}
|
||||
| not found in this scope
|
||||
| help: perhaps you intended to use this type: `i16`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
||||
|
25
src/test/ui/type-alias-impl-trait/issue-72793.rs
Normal file
25
src/test/ui/type-alias-impl-trait/issue-72793.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// check-pass
|
||||
// compile-flags: -Zmir-opt-level=3
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait T { type Item; }
|
||||
|
||||
type Alias<'a> = impl T<Item = &'a ()>;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {
|
||||
type Item = &'a ();
|
||||
}
|
||||
|
||||
fn filter_positive<'a>() -> Alias<'a> {
|
||||
&S
|
||||
}
|
||||
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
fun(filter_positive());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
with_positive(|_| ());
|
||||
}
|
@ -395,9 +395,6 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
);
|
||||
};
|
||||
suppressible_tidy_err!(err, skip_file_length, "");
|
||||
} else if lines > (LINES * 7) / 10 {
|
||||
// Just set it to something that doesn't trigger the "unnecessarily ignored" warning.
|
||||
skip_file_length = Directive::Ignore(true);
|
||||
}
|
||||
|
||||
if let Directive::Ignore(false) = skip_cr {
|
||||
@ -406,12 +403,6 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
if let Directive::Ignore(false) = skip_tab {
|
||||
tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
|
||||
}
|
||||
if let Directive::Ignore(false) = skip_line_length {
|
||||
tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
|
||||
}
|
||||
if let Directive::Ignore(false) = skip_file_length {
|
||||
tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
|
||||
}
|
||||
if let Directive::Ignore(false) = skip_end_whitespace {
|
||||
tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
|
||||
}
|
||||
@ -424,5 +415,9 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
if let Directive::Ignore(false) = skip_copyright {
|
||||
tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
|
||||
}
|
||||
// We deliberately do not warn about these being unnecessary,
|
||||
// that would just lead to annoying churn.
|
||||
let _unused = skip_line_length;
|
||||
let _unused = skip_file_length;
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user