Auto merge of #81089 - m-ou-se:rollup-z7iac6i, r=m-ou-se
Rollup of 17 pull requests Successful merges: - #78455 (Introduce {Ref, RefMut}::try_map for optional projections in RefCell) - #80144 (Remove giant badge in README) - #80614 (Explain why borrows can't be held across yield point in async blocks) - #80670 (TrustedRandomAaccess specialization composes incorrectly for nested iter::Zips) - #80681 (Clarify what the effects of a 'logic error' are) - #80764 (Re-stabilize Weak::as_ptr and friends for unsized T) - #80901 (Make `x.py --color always` apply to logging too) - #80902 (Add a regression test for #76281) - #80941 (Do not suggest invalid code in pattern with loop) - #80968 (Stabilize the poll_map feature) - #80971 (Put all feature gate tests under `feature-gates/`) - #81021 (Remove doctree::Import) - #81040 (doctest: Reset errors before dropping the parse session) - #81060 (Add a regression test for #50041) - #81065 (codegen_cranelift: Fix redundant semicolon warn) - #81069 (Add sample code for Rc::new_cyclic) - #81081 (Add test for #34792) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8a6518427e
@ -1,6 +1,4 @@
|
||||
<a href = "https://www.rust-lang.org/">
|
||||
<img width = "90%" height = "auto" src = "https://img.shields.io/badge/Rust-Programming%20Language-black?style=flat&logo=rust" alt = "The Rust Programming Language">
|
||||
</a>
|
||||
# The Rust Programming Language
|
||||
|
||||
This is the main source code repository for [Rust]. It contains the compiler,
|
||||
standard library, and documentation.
|
||||
|
@ -824,7 +824,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
|
||||
}
|
||||
ty => unreachable!("bswap {}", ty),
|
||||
}
|
||||
};
|
||||
}
|
||||
let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T));
|
||||
ret.write_cvalue(fx, res);
|
||||
};
|
||||
|
@ -50,3 +50,24 @@ fn foo() -> Box<Fn(u32) -> u32> {
|
||||
|
||||
Now that the closure has its own copy of the data, there's no need to worry
|
||||
about safety.
|
||||
|
||||
This error may also be encountered while using `async` blocks:
|
||||
|
||||
```compile_fail,E0373,edition2018
|
||||
use std::future::Future;
|
||||
|
||||
async fn f() {
|
||||
let v = vec![1, 2, 3i32];
|
||||
spawn(async { //~ ERROR E0373
|
||||
println!("{:?}", v)
|
||||
});
|
||||
}
|
||||
|
||||
fn spawn<F: Future + Send + 'static>(future: F) {
|
||||
unimplemented!()
|
||||
}
|
||||
```
|
||||
|
||||
Similarly to closures, `async` blocks are not executed immediately and may
|
||||
capture closed-over data by reference. For more information, see
|
||||
https://rust-lang.github.io/async-book/03_async_await/01_chapter.html.
|
||||
|
@ -141,6 +141,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
|
||||
|
||||
let mut is_loop_move = false;
|
||||
let mut in_pattern = false;
|
||||
|
||||
for move_site in &move_site_vec {
|
||||
let move_out = self.move_data.moves[(*move_site).moi];
|
||||
@ -256,6 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"ref ".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
in_pattern = true;
|
||||
}
|
||||
|
||||
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
|
||||
@ -302,7 +304,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
|
||||
if is_loop_move {
|
||||
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
|
||||
if is_loop_move & !in_pattern {
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
|
||||
err.span_suggestion_verbose(
|
||||
@ -1318,21 +1321,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
let msg = match category {
|
||||
match category {
|
||||
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
|
||||
format!("{} is returned here", kind)
|
||||
let msg = format!("{} is returned here", kind);
|
||||
err.span_note(constraint_span, &msg);
|
||||
}
|
||||
ConstraintCategory::CallArgument => {
|
||||
fr_name.highlight_region_name(&mut err);
|
||||
format!("function requires argument type to outlive `{}`", fr_name)
|
||||
if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
|
||||
err.note(
|
||||
"async blocks are not executed immediately and must either take a \
|
||||
reference or ownership of outside variables they use",
|
||||
);
|
||||
} else {
|
||||
let msg = format!("function requires argument type to outlive `{}`", fr_name);
|
||||
err.span_note(constraint_span, &msg);
|
||||
}
|
||||
}
|
||||
_ => bug!(
|
||||
"report_escaping_closure_capture called with unexpected constraint \
|
||||
category: `{:?}`",
|
||||
category
|
||||
),
|
||||
};
|
||||
err.span_note(constraint_span, &msg);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,10 @@ use super::SpecExtend;
|
||||
/// It is a logic error for an item to be modified in such a way that the
|
||||
/// item's ordering relative to any other item, as determined by the `Ord`
|
||||
/// trait, changes while it is in the heap. This is normally only possible
|
||||
/// through `Cell`, `RefCell`, global state, I/O, or unsafe code.
|
||||
/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The
|
||||
/// behavior resulting from such a logic error is not specified, but will
|
||||
/// not result in undefined behavior. This could include panics, incorrect
|
||||
/// results, aborts, memory leaks, and non-termination.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -51,6 +51,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
|
||||
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
|
||||
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
|
||||
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
|
||||
/// The behavior resulting from such a logic error is not specified, but will not result in
|
||||
/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
|
||||
/// non-termination.
|
||||
///
|
||||
/// [`Cell`]: core::cell::Cell
|
||||
/// [`RefCell`]: core::cell::RefCell
|
||||
|
@ -22,6 +22,9 @@ use super::Recover;
|
||||
/// It is a logic error for an item to be modified in such a way that the item's ordering relative
|
||||
/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
|
||||
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
|
||||
/// The behavior resulting from such a logic error is not specified, but will not result in
|
||||
/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
|
||||
/// non-termination.
|
||||
///
|
||||
/// [`Ord`]: core::cmp::Ord
|
||||
/// [`Cell`]: core::cell::Cell
|
||||
|
@ -120,6 +120,7 @@
|
||||
#![feature(receiver_trait)]
|
||||
#![cfg_attr(bootstrap, feature(min_const_generics))]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(set_ptr_value)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_ptr_len)]
|
||||
#![feature(staged_api)]
|
||||
|
@ -353,6 +353,26 @@ impl<T> Rc<T> {
|
||||
/// to upgrade the weak reference before this function returns will result
|
||||
/// in a `None` value. However, the weak reference may be cloned freely and
|
||||
/// stored for use at a later time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(arc_new_cyclic)]
|
||||
/// #![allow(dead_code)]
|
||||
/// use std::rc::{Rc, Weak};
|
||||
///
|
||||
/// struct Gadget {
|
||||
/// self_weak: Weak<Self>,
|
||||
/// // ... more fields
|
||||
/// }
|
||||
/// impl Gadget {
|
||||
/// pub fn new() -> Rc<Self> {
|
||||
/// Rc::new_cyclic(|self_weak| {
|
||||
/// Gadget { self_weak: self_weak.clone(), /* ... */ }
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "arc_new_cyclic", issue = "75861")]
|
||||
pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
|
||||
// Construct the inner in the "uninitialized" state with a single
|
||||
@ -829,8 +849,8 @@ impl<T: ?Sized> Rc<T> {
|
||||
let offset = unsafe { data_offset(ptr) };
|
||||
|
||||
// Reverse the offset to find the original RcBox.
|
||||
let fake_ptr = ptr as *mut RcBox<T>;
|
||||
let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) };
|
||||
let rc_ptr =
|
||||
unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) };
|
||||
|
||||
unsafe { Self::from_ptr(rc_ptr) }
|
||||
}
|
||||
@ -850,7 +870,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
pub fn downgrade(this: &Self) -> Weak<T> {
|
||||
this.inner().inc_weak();
|
||||
// Make sure we do not create a dangling Weak
|
||||
debug_assert!(!is_dangling(this.ptr));
|
||||
debug_assert!(!is_dangling(this.ptr.as_ptr()));
|
||||
Weak { ptr: this.ptr }
|
||||
}
|
||||
|
||||
@ -1164,7 +1184,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|layout| Global.allocate(layout),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
|
||||
|mem| (ptr as *mut RcBox<T>).set_ptr_value(mem),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1203,20 +1223,7 @@ impl<T> Rc<[T]> {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the data pointer of a `?Sized` raw pointer.
|
||||
///
|
||||
/// For a slice/trait object, this sets the `data` field and leaves the rest
|
||||
/// unchanged. For a sized raw pointer, this simply sets the pointer.
|
||||
unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
|
||||
unsafe {
|
||||
ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
impl<T> Rc<[T]> {
|
||||
/// Copy elements from slice into newly allocated Rc<\[T\]>
|
||||
///
|
||||
/// Unsafe because the caller must either take ownership or bind `T: Copy`
|
||||
@ -1860,8 +1867,8 @@ impl<T> Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
|
||||
let address = ptr.as_ptr() as *mut () as usize;
|
||||
pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
|
||||
let address = ptr as *mut () as usize;
|
||||
address == usize::MAX
|
||||
}
|
||||
|
||||
@ -1872,7 +1879,7 @@ struct WeakInner<'a> {
|
||||
strong: &'a Cell<usize>,
|
||||
}
|
||||
|
||||
impl<T> Weak<T> {
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
|
||||
///
|
||||
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
|
||||
@ -1902,15 +1909,15 @@ impl<T> Weak<T> {
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
|
||||
|
||||
// SAFETY: we must offset the pointer manually, and said pointer may be
|
||||
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
|
||||
// because we know that a pointer to unsized T was derived from a real
|
||||
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
|
||||
// is used so that we can use the same code path for the non-dangling
|
||||
// unsized case and the potentially dangling sized case.
|
||||
unsafe {
|
||||
let offset = data_offset(ptr as *mut T);
|
||||
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
|
||||
if is_dangling(ptr) {
|
||||
// If the pointer is dangling, we return the sentinel directly. This cannot be
|
||||
// a valid payload address, as the payload is at least as aligned as RcBox (usize).
|
||||
ptr as *const T
|
||||
} else {
|
||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||
// so use raw pointer manipulation.
|
||||
unsafe { &raw const (*ptr).value }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1992,22 +1999,24 @@ impl<T> Weak<T> {
|
||||
/// [`new`]: Weak::new
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
// SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
|
||||
// See Weak::as_ptr for context on how the input pointer is derived.
|
||||
let offset = unsafe { data_offset(ptr) };
|
||||
|
||||
// Reverse the offset to find the original RcBox.
|
||||
// SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized).
|
||||
let ptr = unsafe {
|
||||
set_data_ptr(ptr as *mut RcBox<T>, (ptr as *mut u8).wrapping_offset(-offset))
|
||||
let ptr = if is_dangling(ptr as *mut T) {
|
||||
// This is a dangling Weak.
|
||||
ptr as *mut RcBox<T>
|
||||
} else {
|
||||
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
||||
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
||||
let offset = unsafe { data_offset(ptr) };
|
||||
// Thus, we reverse the offset to get the whole RcBox.
|
||||
// SAFETY: the pointer originated from a Weak, so this offset is safe.
|
||||
unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) }
|
||||
};
|
||||
|
||||
// SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
|
||||
Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
|
||||
/// dropping of the inner value if successful.
|
||||
///
|
||||
@ -2070,7 +2079,7 @@ impl<T: ?Sized> Weak<T> {
|
||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||
#[inline]
|
||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||
if is_dangling(self.ptr) {
|
||||
if is_dangling(self.ptr.as_ptr()) {
|
||||
None
|
||||
} else {
|
||||
// We are careful to *not* create a reference covering the "data" field, as
|
||||
@ -2325,21 +2334,19 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<T: ?Sized> Unpin for Rc<T> {}
|
||||
|
||||
/// Get the offset within an `RcBox` for
|
||||
/// a payload of type described by a pointer.
|
||||
/// Get the offset within an `RcBox` for the payload behind a pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This has the same safety requirements as `align_of_val_raw`. In effect:
|
||||
///
|
||||
/// - This function is safe for any argument if `T` is sized, and
|
||||
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
|
||||
/// acquired from the real instance that you are getting this offset for.
|
||||
/// The pointer must point to (and have valid metadata for) a previously
|
||||
/// valid instance of T, but the T is allowed to be dropped.
|
||||
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
|
||||
// Align the unsized value to the end of the `RcBox`.
|
||||
// Because it is ?Sized, it will always be the last field in memory.
|
||||
// Note: This is a detail of the current implementation of the compiler,
|
||||
// and is not a guaranteed language detail. Do not rely on it outside of std.
|
||||
// Align the unsized value to the end of the RcBox.
|
||||
// Because RcBox is repr(C), it will always be the last field in memory.
|
||||
// SAFETY: since the only unsized types possible are slices, trait objects,
|
||||
// and extern types, the input safety requirement is currently enough to
|
||||
// satisfy the requirements of align_of_val_raw; this is an implementation
|
||||
// detail of the language that may not be relied upon outside of std.
|
||||
unsafe { data_offset_align(align_of_val_raw(ptr)) }
|
||||
}
|
||||
|
||||
|
@ -208,6 +208,30 @@ fn into_from_weak_raw() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_from_weak_raw_unsized() {
|
||||
use std::fmt::Display;
|
||||
use std::string::ToString;
|
||||
|
||||
let arc: Rc<str> = Rc::from("foo");
|
||||
let weak: Weak<str> = Rc::downgrade(&arc);
|
||||
|
||||
let ptr = Weak::into_raw(weak.clone());
|
||||
let weak2 = unsafe { Weak::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }, "foo");
|
||||
assert!(weak.ptr_eq(&weak2));
|
||||
|
||||
let arc: Rc<dyn Display> = Rc::new(123);
|
||||
let weak: Weak<dyn Display> = Rc::downgrade(&arc);
|
||||
|
||||
let ptr = Weak::into_raw(weak.clone());
|
||||
let weak2 = unsafe { Weak::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }.to_string(), "123");
|
||||
assert!(weak.ptr_eq(&weak2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut x = Rc::new(3);
|
||||
@ -294,6 +318,23 @@ fn test_unsized() {
|
||||
assert_eq!(foo, foo.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maybe_thin_unsized() {
|
||||
// If/when custom thin DSTs exist, this test should be updated to use one
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
let x: Rc<CStr> = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
|
||||
assert_eq!(format!("{:?}", x), "\"swordfish\"");
|
||||
let y: Weak<CStr> = Rc::downgrade(&x);
|
||||
drop(x);
|
||||
|
||||
// At this point, the weak points to a dropped DST
|
||||
assert!(y.upgrade().is_none());
|
||||
// But we still need to be able to get the alloc layout to drop.
|
||||
// CStr has no drop glue, but custom DSTs might, and need to work.
|
||||
drop(y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_owned() {
|
||||
let foo = 123;
|
||||
|
@ -846,8 +846,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
let offset = data_offset(ptr);
|
||||
|
||||
// Reverse the offset to find the original ArcInner.
|
||||
let fake_ptr = ptr as *mut ArcInner<T>;
|
||||
let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
|
||||
let arc_ptr = (ptr as *mut ArcInner<T>).set_ptr_value((ptr as *mut u8).offset(-offset));
|
||||
|
||||
Self::from_ptr(arc_ptr)
|
||||
}
|
||||
@ -888,7 +887,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
|
||||
Ok(_) => {
|
||||
// Make sure we do not create a dangling Weak
|
||||
debug_assert!(!is_dangling(this.ptr));
|
||||
debug_assert!(!is_dangling(this.ptr.as_ptr()));
|
||||
return Weak { ptr: this.ptr };
|
||||
}
|
||||
Err(old) => cur = old,
|
||||
@ -1131,7 +1130,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|layout| Global.allocate(layout),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>,
|
||||
|mem| (ptr as *mut ArcInner<T>).set_ptr_value(mem) as *mut ArcInner<T>,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1170,20 +1169,7 @@ impl<T> Arc<[T]> {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the data pointer of a `?Sized` raw pointer.
|
||||
///
|
||||
/// For a slice/trait object, this sets the `data` field and leaves the rest
|
||||
/// unchanged. For a sized raw pointer, this simply sets the pointer.
|
||||
unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
|
||||
unsafe {
|
||||
ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
impl<T> Arc<[T]> {
|
||||
/// Copy elements from slice into newly allocated Arc<\[T\]>
|
||||
///
|
||||
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
|
||||
@ -1653,7 +1639,7 @@ struct WeakInner<'a> {
|
||||
strong: &'a atomic::AtomicUsize,
|
||||
}
|
||||
|
||||
impl<T> Weak<T> {
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
|
||||
///
|
||||
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
|
||||
@ -1683,15 +1669,15 @@ impl<T> Weak<T> {
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
|
||||
|
||||
// SAFETY: we must offset the pointer manually, and said pointer may be
|
||||
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
|
||||
// because we know that a pointer to unsized T was derived from a real
|
||||
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
|
||||
// is used so that we can use the same code path for the non-dangling
|
||||
// unsized case and the potentially dangling sized case.
|
||||
unsafe {
|
||||
let offset = data_offset(ptr as *mut T);
|
||||
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
|
||||
if is_dangling(ptr) {
|
||||
// If the pointer is dangling, we return the sentinel directly. This cannot be
|
||||
// a valid payload address, as the payload is at least as aligned as ArcInner (usize).
|
||||
ptr as *const T
|
||||
} else {
|
||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||
// so use raw pointer manipulation.
|
||||
unsafe { &raw mut (*ptr).data }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1773,18 +1759,22 @@ impl<T> Weak<T> {
|
||||
/// [`forget`]: std::mem::forget
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
// SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
|
||||
// See Weak::as_ptr for context on how the input pointer is derived.
|
||||
let offset = unsafe { data_offset(ptr) };
|
||||
|
||||
// Reverse the offset to find the original ArcInner.
|
||||
// SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized)
|
||||
let ptr = unsafe {
|
||||
set_data_ptr(ptr as *mut ArcInner<T>, (ptr as *mut u8).wrapping_offset(-offset))
|
||||
let ptr = if is_dangling(ptr as *mut T) {
|
||||
// This is a dangling Weak.
|
||||
ptr as *mut ArcInner<T>
|
||||
} else {
|
||||
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
||||
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
||||
let offset = unsafe { data_offset(ptr) };
|
||||
// Thus, we reverse the offset to get the whole RcBox.
|
||||
// SAFETY: the pointer originated from a Weak, so this offset is safe.
|
||||
unsafe { (ptr as *mut ArcInner<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) }
|
||||
};
|
||||
|
||||
// SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
|
||||
unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
|
||||
Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1889,7 +1879,7 @@ impl<T: ?Sized> Weak<T> {
|
||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||
#[inline]
|
||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||
if is_dangling(self.ptr) {
|
||||
if is_dangling(self.ptr.as_ptr()) {
|
||||
None
|
||||
} else {
|
||||
// We are careful to *not* create a reference covering the "data" field, as
|
||||
@ -2469,21 +2459,19 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<T: ?Sized> Unpin for Arc<T> {}
|
||||
|
||||
/// Get the offset within an `ArcInner` for
|
||||
/// a payload of type described by a pointer.
|
||||
/// Get the offset within an `ArcInner` for the payload behind a pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This has the same safety requirements as `align_of_val_raw`. In effect:
|
||||
///
|
||||
/// - This function is safe for any argument if `T` is sized, and
|
||||
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
|
||||
/// acquired from the real instance that you are getting this offset for.
|
||||
/// The pointer must point to (and have valid metadata for) a previously
|
||||
/// valid instance of T, but the T is allowed to be dropped.
|
||||
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
|
||||
// Align the unsized value to the end of the `ArcInner`.
|
||||
// Because it is `?Sized`, it will always be the last field in memory.
|
||||
// Note: This is a detail of the current implementation of the compiler,
|
||||
// and is not a guaranteed language detail. Do not rely on it outside of std.
|
||||
// Align the unsized value to the end of the ArcInner.
|
||||
// Because RcBox is repr(C), it will always be the last field in memory.
|
||||
// SAFETY: since the only unsized types possible are slices, trait objects,
|
||||
// and extern types, the input safety requirement is currently enough to
|
||||
// satisfy the requirements of align_of_val_raw; this is an implementation
|
||||
// detail of the language that may not be relied upon outside of std.
|
||||
unsafe { data_offset_align(align_of_val_raw(ptr)) }
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,30 @@ fn into_from_weak_raw() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_from_weak_raw_unsized() {
|
||||
use std::fmt::Display;
|
||||
use std::string::ToString;
|
||||
|
||||
let arc: Arc<str> = Arc::from("foo");
|
||||
let weak: Weak<str> = Arc::downgrade(&arc);
|
||||
|
||||
let ptr = Weak::into_raw(weak.clone());
|
||||
let weak2 = unsafe { Weak::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }, "foo");
|
||||
assert!(weak.ptr_eq(&weak2));
|
||||
|
||||
let arc: Arc<dyn Display> = Arc::new(123);
|
||||
let weak: Weak<dyn Display> = Arc::downgrade(&arc);
|
||||
|
||||
let ptr = Weak::into_raw(weak.clone());
|
||||
let weak2 = unsafe { Weak::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }.to_string(), "123");
|
||||
assert!(weak.ptr_eq(&weak2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cowarc_clone_make_mut() {
|
||||
let mut cow0 = Arc::new(75);
|
||||
@ -329,6 +353,23 @@ fn test_unsized() {
|
||||
assert!(y.upgrade().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maybe_thin_unsized() {
|
||||
// If/when custom thin DSTs exist, this test should be updated to use one
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
let x: Arc<CStr> = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
|
||||
assert_eq!(format!("{:?}", x), "\"swordfish\"");
|
||||
let y: Weak<CStr> = Arc::downgrade(&x);
|
||||
drop(x);
|
||||
|
||||
// At this point, the weak points to a dropped DST
|
||||
assert!(y.upgrade().is_none());
|
||||
// But we still need to be able to get the alloc layout to drop.
|
||||
// CStr has no drop glue, but custom DSTs might, and need to work.
|
||||
drop(y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_owned() {
|
||||
let foo = 123;
|
||||
|
@ -1261,6 +1261,40 @@ impl<'b, T: ?Sized> Ref<'b, T> {
|
||||
Ref { value: f(orig.value), borrow: orig.borrow }
|
||||
}
|
||||
|
||||
/// Makes a new `Ref` for an optional component of the borrowed data. The
|
||||
/// original guard is returned as an `Err(..)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RefCell` is already immutably borrowed, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `Ref::filter_map(...)`. A method would interfere with methods of the same
|
||||
/// name on the contents of a `RefCell` used through `Deref`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_filter_map)]
|
||||
///
|
||||
/// use std::cell::{RefCell, Ref};
|
||||
///
|
||||
/// let c = RefCell::new(vec![1, 2, 3]);
|
||||
/// let b1: Ref<Vec<u32>> = c.borrow();
|
||||
/// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
|
||||
/// assert_eq!(*b2.unwrap(), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
|
||||
#[inline]
|
||||
pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
|
||||
where
|
||||
F: FnOnce(&T) -> Option<&U>,
|
||||
{
|
||||
match f(orig.value) {
|
||||
Some(value) => Ok(Ref { value, borrow: orig.borrow }),
|
||||
None => Err(orig),
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits a `Ref` into multiple `Ref`s for different components of the
|
||||
/// borrowed data.
|
||||
///
|
||||
@ -1372,6 +1406,58 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
|
||||
RefMut { value: f(value), borrow }
|
||||
}
|
||||
|
||||
/// Makes a new `RefMut` for an optional component of the borrowed data. The
|
||||
/// original guard is returned as an `Err(..)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RefCell` is already mutably borrowed, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RefMut::filter_map(...)`. A method would interfere with methods of the
|
||||
/// same name on the contents of a `RefCell` used through `Deref`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_filter_map)]
|
||||
///
|
||||
/// use std::cell::{RefCell, RefMut};
|
||||
///
|
||||
/// let c = RefCell::new(vec![1, 2, 3]);
|
||||
///
|
||||
/// {
|
||||
/// let b1: RefMut<Vec<u32>> = c.borrow_mut();
|
||||
/// let mut b2: Result<RefMut<u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1));
|
||||
///
|
||||
/// if let Ok(mut b2) = b2 {
|
||||
/// *b2 += 2;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(*c.borrow(), vec![1, 4, 3]);
|
||||
/// ```
|
||||
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
|
||||
#[inline]
|
||||
pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
{
|
||||
// FIXME(nll-rfc#40): fix borrow-check
|
||||
let RefMut { value, borrow } = orig;
|
||||
let value = value as *mut T;
|
||||
// SAFETY: function holds onto an exclusive reference for the duration
|
||||
// of its call through `orig`, and the pointer is only de-referenced
|
||||
// inside of the function call never allowing the exclusive reference to
|
||||
// escape.
|
||||
match f(unsafe { &mut *value }) {
|
||||
Some(value) => Ok(RefMut { value, borrow }),
|
||||
None => {
|
||||
// SAFETY: same as above.
|
||||
Err(RefMut { value: unsafe { &mut *value }, borrow })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits a `RefMut` into multiple `RefMut`s for different components of the
|
||||
/// borrowed data.
|
||||
///
|
||||
|
@ -286,6 +286,7 @@ where
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
|
||||
let idx = self.index + idx;
|
||||
// SAFETY: the caller must uphold the contract for
|
||||
// `Iterator::__iterator_get_unchecked`.
|
||||
unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
|
||||
|
@ -84,7 +84,7 @@ impl<T, E> Poll<Result<T, E>> {
|
||||
|
||||
impl<T, E> Poll<Option<Result<T, E>>> {
|
||||
/// Changes the success value of this `Poll` with the closure provided.
|
||||
#[unstable(feature = "poll_map", issue = "63514")]
|
||||
#[stable(feature = "poll_map", since = "1.51.0")]
|
||||
pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
@ -98,7 +98,7 @@ impl<T, E> Poll<Option<Result<T, E>>> {
|
||||
}
|
||||
|
||||
/// Changes the error value of this `Poll` with the closure provided.
|
||||
#[unstable(feature = "poll_map", issue = "63514")]
|
||||
#[stable(feature = "poll_map", since = "1.51.0")]
|
||||
pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
|
||||
where
|
||||
F: FnOnce(E) -> U,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::convert::TryFrom;
|
||||
use core::iter::TrustedRandomAccess;
|
||||
use core::iter::*;
|
||||
|
||||
/// An iterator wrapper that panics whenever `next` or `next_back` is called
|
||||
@ -601,6 +602,26 @@ fn test_zip_nth_back_side_effects_exhausted() {
|
||||
assert_eq!(b, vec![200, 300, 400]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zip_trusted_random_access_composition() {
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let b = a;
|
||||
let c = a;
|
||||
|
||||
let a = a.iter().copied();
|
||||
let b = b.iter().copied();
|
||||
let mut c = c.iter().copied();
|
||||
c.next();
|
||||
|
||||
let mut z1 = a.zip(b);
|
||||
assert_eq!(z1.next().unwrap(), (0, 0));
|
||||
|
||||
let mut z2 = z1.zip(c);
|
||||
fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
|
||||
assert_trusted_random_access(&z2);
|
||||
assert_eq!(z2.next().unwrap(), ((1, 1), 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_step_by() {
|
||||
// Identity
|
||||
|
@ -75,6 +75,7 @@
|
||||
#![feature(const_option)]
|
||||
#![feature(integer_atomics)]
|
||||
#![feature(slice_group_by)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate test;
|
||||
|
@ -52,6 +52,9 @@ use crate::sys;
|
||||
/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
|
||||
/// the [`Eq`] trait, changes while it is in the map. This is normally only
|
||||
/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
|
||||
/// The behavior resulting from such a logic error is not specified, but will
|
||||
/// not result in undefined behavior. This could include panics, incorrect results,
|
||||
/// aborts, memory leaks, and non-termination.
|
||||
///
|
||||
/// The hash table implementation is a Rust port of Google's [SwissTable].
|
||||
/// The original C++ version of SwissTable can be found [here], and this
|
||||
|
@ -37,7 +37,9 @@ use super::map::{map_try_reserve_error, RandomState};
|
||||
/// item's hash, as determined by the [`Hash`] trait, or its equality, as
|
||||
/// determined by the [`Eq`] trait, changes while it is in the set. This is
|
||||
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
|
||||
/// unsafe code.
|
||||
/// unsafe code. The behavior resulting from such a logic error is not
|
||||
/// specified, but will not result in undefined behavior. This could include
|
||||
/// panics, incorrect results, aborts, memory leaks, and non-termination.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -814,12 +814,22 @@ impl<'a> Builder<'a> {
|
||||
cargo.env("REAL_LIBRARY_PATH", e);
|
||||
}
|
||||
|
||||
// Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
|
||||
// from out of tree it shouldn't matter, since x.py is only used for
|
||||
// building in-tree.
|
||||
let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
|
||||
match self.build.config.color {
|
||||
Color::Always => {
|
||||
cargo.arg("--color=always");
|
||||
for log in &color_logs {
|
||||
cargo.env(log, "always");
|
||||
}
|
||||
}
|
||||
Color::Never => {
|
||||
cargo.arg("--color=never");
|
||||
for log in &color_logs {
|
||||
cargo.env(log, "never");
|
||||
}
|
||||
}
|
||||
Color::Auto => {} // nothing to do
|
||||
}
|
||||
|
@ -219,7 +219,6 @@ impl Clean<ExternalCrate> for CrateNum {
|
||||
impl Clean<Item> for doctree::Module<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
let mut items: Vec<Item> = vec![];
|
||||
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
|
||||
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
|
||||
@ -2015,7 +2014,7 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
|
||||
ItemKind::Fn(ref sig, ref generics, body_id) => {
|
||||
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
|
||||
}
|
||||
hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
|
||||
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
|
||||
let items = item_ids
|
||||
.iter()
|
||||
.map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
|
||||
@ -2034,6 +2033,9 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
return clean_extern_crate(item, name, orig_name, cx);
|
||||
}
|
||||
ItemKind::Use(path, kind) => {
|
||||
return clean_use_statement(item, name, path, kind, cx);
|
||||
}
|
||||
_ => unreachable!("not yet converted"),
|
||||
};
|
||||
|
||||
@ -2155,105 +2157,97 @@ fn clean_extern_crate(
|
||||
}]
|
||||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::Import<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
// We need this comparison because some imports (for std types for example)
|
||||
// are "inserted" as well but directly by the compiler and they should not be
|
||||
// taken into account.
|
||||
if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline);
|
||||
let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore;
|
||||
|
||||
if pub_underscore && please_inline {
|
||||
rustc_errors::struct_span_err!(
|
||||
cx.tcx.sess,
|
||||
doc_meta_item.unwrap().span(),
|
||||
E0780,
|
||||
"anonymous imports cannot be inlined"
|
||||
)
|
||||
.span_label(self.span, "anonymous import")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// We consider inlining the documentation of `pub use` statements, but we
|
||||
// forcefully don't inline if this is not public or if the
|
||||
// #[doc(no_inline)] attribute is present.
|
||||
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
|
||||
let mut denied = !self.vis.node.is_pub()
|
||||
|| pub_underscore
|
||||
|| self.attrs.iter().any(|a| {
|
||||
a.has_name(sym::doc)
|
||||
&& match a.meta_item_list() {
|
||||
Some(l) => {
|
||||
attr::list_contains_name(&l, sym::no_inline)
|
||||
|| attr::list_contains_name(&l, sym::hidden)
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
// Also check whether imports were asked to be inlined, in case we're trying to re-export a
|
||||
// crate in Rust 2018+
|
||||
let path = self.path.clean(cx);
|
||||
let inner = if self.glob {
|
||||
if !denied {
|
||||
let mut visited = FxHashSet::default();
|
||||
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Import::new_glob(resolve_use_source(cx, path), true)
|
||||
} else {
|
||||
let name = self.name;
|
||||
if !please_inline {
|
||||
if let Res::Def(DefKind::Mod, did) = path.res {
|
||||
if !did.is_local() && did.index == CRATE_DEF_INDEX {
|
||||
// if we're `pub use`ing an extern crate root, don't inline it unless we
|
||||
// were specifically asked for it
|
||||
denied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !denied {
|
||||
let mut visited = FxHashSet::default();
|
||||
|
||||
if let Some(mut items) = inline::try_inline(
|
||||
cx,
|
||||
cx.tcx.parent_module(self.id).to_def_id(),
|
||||
path.res,
|
||||
name,
|
||||
Some(self.attrs),
|
||||
&mut visited,
|
||||
) {
|
||||
items.push(Item {
|
||||
name: None,
|
||||
attrs: box self.attrs.clean(cx),
|
||||
source: self.span.clean(cx),
|
||||
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
|
||||
visibility: self.vis.clean(cx),
|
||||
kind: box ImportItem(Import::new_simple(
|
||||
self.name,
|
||||
resolve_use_source(cx, path),
|
||||
false,
|
||||
)),
|
||||
});
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Import::new_simple(name, resolve_use_source(cx, path), true)
|
||||
};
|
||||
|
||||
vec![Item {
|
||||
name: None,
|
||||
attrs: box self.attrs.clean(cx),
|
||||
source: self.span.clean(cx),
|
||||
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
|
||||
visibility: self.vis.clean(cx),
|
||||
kind: box ImportItem(inner),
|
||||
}]
|
||||
fn clean_use_statement(
|
||||
import: &hir::Item<'_>,
|
||||
name: Symbol,
|
||||
path: &hir::Path<'_>,
|
||||
kind: hir::UseKind,
|
||||
cx: &DocContext<'_>,
|
||||
) -> Vec<Item> {
|
||||
// We need this comparison because some imports (for std types for example)
|
||||
// are "inserted" as well but directly by the compiler and they should not be
|
||||
// taken into account.
|
||||
if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let (doc_meta_item, please_inline) = import.attrs.lists(sym::doc).get_word_attr(sym::inline);
|
||||
let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore;
|
||||
|
||||
if pub_underscore && please_inline {
|
||||
rustc_errors::struct_span_err!(
|
||||
cx.tcx.sess,
|
||||
doc_meta_item.unwrap().span(),
|
||||
E0780,
|
||||
"anonymous imports cannot be inlined"
|
||||
)
|
||||
.span_label(import.span, "anonymous import")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// We consider inlining the documentation of `pub use` statements, but we
|
||||
// forcefully don't inline if this is not public or if the
|
||||
// #[doc(no_inline)] attribute is present.
|
||||
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
|
||||
let mut denied = !import.vis.node.is_pub()
|
||||
|| pub_underscore
|
||||
|| import.attrs.iter().any(|a| {
|
||||
a.has_name(sym::doc)
|
||||
&& match a.meta_item_list() {
|
||||
Some(l) => {
|
||||
attr::list_contains_name(&l, sym::no_inline)
|
||||
|| attr::list_contains_name(&l, sym::hidden)
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
|
||||
// Also check whether imports were asked to be inlined, in case we're trying to re-export a
|
||||
// crate in Rust 2018+
|
||||
let def_id = cx.tcx.hir().local_def_id(import.hir_id).to_def_id();
|
||||
let path = path.clean(cx);
|
||||
let inner = if kind == hir::UseKind::Glob {
|
||||
if !denied {
|
||||
let mut visited = FxHashSet::default();
|
||||
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Import::new_glob(resolve_use_source(cx, path), true)
|
||||
} else {
|
||||
if !please_inline {
|
||||
if let Res::Def(DefKind::Mod, did) = path.res {
|
||||
if !did.is_local() && did.index == CRATE_DEF_INDEX {
|
||||
// if we're `pub use`ing an extern crate root, don't inline it unless we
|
||||
// were specifically asked for it
|
||||
denied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !denied {
|
||||
let mut visited = FxHashSet::default();
|
||||
|
||||
if let Some(mut items) = inline::try_inline(
|
||||
cx,
|
||||
cx.tcx.parent_module(import.hir_id).to_def_id(),
|
||||
path.res,
|
||||
name,
|
||||
Some(import.attrs),
|
||||
&mut visited,
|
||||
) {
|
||||
items.push(Item::from_def_id_and_parts(
|
||||
def_id,
|
||||
None,
|
||||
ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
|
||||
cx,
|
||||
));
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Import::new_simple(name, resolve_use_source(cx, path), true)
|
||||
};
|
||||
|
||||
vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)]
|
||||
}
|
||||
|
||||
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
|
||||
|
@ -500,6 +500,12 @@ crate fn make_test(
|
||||
}
|
||||
}
|
||||
|
||||
// Reset errors so that they won't be reported as compiler bugs when dropping the
|
||||
// handler. Any errors in the tests will be reported when the test file is compiled,
|
||||
// Note that we still need to cancel the errors above otherwise `DiagnosticBuilder`
|
||||
// will panic on drop.
|
||||
sess.span_diagnostic.reset_err_count();
|
||||
|
||||
(found_main, found_extern_crate, found_macro)
|
||||
})
|
||||
});
|
||||
|
@ -2,7 +2,6 @@
|
||||
//! manner (and with prettier names) before cleaning.
|
||||
crate use self::StructType::*;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_span::{self, Span, Symbol};
|
||||
|
||||
use rustc_hir as hir;
|
||||
@ -11,7 +10,6 @@ crate struct Module<'hir> {
|
||||
crate name: Option<Symbol>,
|
||||
crate where_outer: Span,
|
||||
crate where_inner: Span,
|
||||
crate imports: Vec<Import<'hir>>,
|
||||
crate mods: Vec<Module<'hir>>,
|
||||
crate id: hir::HirId,
|
||||
// (item, renamed)
|
||||
@ -28,7 +26,6 @@ impl Module<'hir> {
|
||||
id: hir::CRATE_HIR_ID,
|
||||
where_outer: rustc_span::DUMMY_SP,
|
||||
where_inner: rustc_span::DUMMY_SP,
|
||||
imports: Vec::new(),
|
||||
mods: Vec::new(),
|
||||
items: Vec::new(),
|
||||
foreigns: Vec::new(),
|
||||
@ -48,17 +45,6 @@ crate enum StructType {
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct Import<'hir> {
|
||||
crate name: Symbol,
|
||||
crate id: hir::HirId,
|
||||
crate vis: &'hir hir::Visibility<'hir>,
|
||||
crate attrs: &'hir [ast::Attribute],
|
||||
crate path: &'hir hir::Path<'hir>,
|
||||
crate glob: bool,
|
||||
crate span: Span,
|
||||
}
|
||||
|
||||
crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
|
||||
match *vdata {
|
||||
hir::VariantData::Struct(..) => Plain,
|
||||
|
@ -316,15 +316,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
om.imports.push(Import {
|
||||
name,
|
||||
id: item.hir_id,
|
||||
vis: &item.vis,
|
||||
attrs: &item.attrs,
|
||||
path,
|
||||
glob: is_glob,
|
||||
span: item.span,
|
||||
});
|
||||
om.items.push((item, renamed))
|
||||
}
|
||||
hir::ItemKind::Mod(ref m) => {
|
||||
om.mods.push(self.visit_mod_contents(
|
||||
|
@ -7,6 +7,9 @@
|
||||
# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If
|
||||
# you're on windows, replace `\` with `/`.
|
||||
|
||||
# WARNING: The error messages produced by this may be misleading, in the case of list re-ordering
|
||||
# it may point to apparently unrelated keys.
|
||||
|
||||
import copy
|
||||
import sys
|
||||
import json
|
||||
|
@ -41,8 +41,8 @@
|
||||
"inner": {
|
||||
"is_crate": false,
|
||||
"items": [
|
||||
"0:7",
|
||||
"0:4"
|
||||
"0:4",
|
||||
"0:7"
|
||||
]
|
||||
},
|
||||
"kind": "module",
|
||||
|
11
src/test/rustdoc-ui/issue-80992.rs
Normal file
11
src/test/rustdoc-ui/issue-80992.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
// compile-flags:--test
|
||||
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
|
||||
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
|
||||
pub fn test() -> Result<(), ()> {
|
||||
//! ```compile_fail
|
||||
//! fn test() -> Result< {}
|
||||
//! ```
|
||||
Ok(())
|
||||
}
|
6
src/test/rustdoc-ui/issue-80992.stdout
Normal file
6
src/test/rustdoc-ui/issue-80992.stdout
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
running 1 test
|
||||
test $DIR/issue-80992.rs - test (line 7) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
16
src/test/ui/associated-item/associated-item-two-bounds.rs
Normal file
16
src/test/ui/associated-item/associated-item-two-bounds.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// This test is a regression test for #34792
|
||||
|
||||
// check-pass
|
||||
|
||||
pub struct A;
|
||||
pub struct B;
|
||||
|
||||
pub trait Foo {
|
||||
type T: PartialEq<A> + PartialEq<B>;
|
||||
}
|
||||
|
||||
pub fn generic<F: Foo>(t: F::T, a: A, b: B) -> bool {
|
||||
t == a && t == b
|
||||
}
|
||||
|
||||
pub fn main() {}
|
33
src/test/ui/async-await/issues/issue-78938-async-block.rs
Normal file
33
src/test/ui/async-await/issues/issue-78938-async-block.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// edition:2018
|
||||
|
||||
use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}};
|
||||
|
||||
async fn f() {
|
||||
let room_ref = Arc::new(Vec::new());
|
||||
|
||||
let gameloop_handle = spawn(async { //~ ERROR E0373
|
||||
game_loop(Arc::clone(&room_ref))
|
||||
});
|
||||
gameloop_handle.await;
|
||||
}
|
||||
|
||||
fn game_loop(v: Arc<Vec<usize>>) {}
|
||||
|
||||
fn spawn<F>(future: F) -> JoinHandle
|
||||
where
|
||||
F: Future + Send + 'static,
|
||||
F::Output: Send + 'static,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
|
||||
struct JoinHandle;
|
||||
|
||||
impl Future for JoinHandle {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function
|
||||
--> $DIR/issue-78938-async-block.rs:8:39
|
||||
|
|
||||
LL | let gameloop_handle = spawn(async {
|
||||
| _______________________________________^
|
||||
LL | | game_loop(Arc::clone(&room_ref))
|
||||
| | -------- `room_ref` is borrowed here
|
||||
LL | | });
|
||||
| |_____^ may outlive borrowed value `room_ref`
|
||||
|
|
||||
= note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use
|
||||
help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | let gameloop_handle = spawn(async move {
|
||||
LL | game_loop(Arc::clone(&room_ref))
|
||||
LL | });
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0373`.
|
10
src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs
Normal file
10
src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// Regression test for #80913.
|
||||
|
||||
fn main() {
|
||||
let mut x = 42_i32;
|
||||
let mut opt = Some(&mut x);
|
||||
for _ in 0..5 {
|
||||
if let Some(mut _x) = opt {}
|
||||
//~^ ERROR: use of moved value
|
||||
}
|
||||
}
|
15
src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
Normal file
15
src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0382]: use of moved value
|
||||
--> $DIR/move-in-pattern-mut-in-loop.rs:7:21
|
||||
|
|
||||
LL | if let Some(mut _x) = opt {}
|
||||
| ^^^^^^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
|
||||
help: borrow this field in the pattern to avoid moving `opt.0`
|
||||
|
|
||||
LL | if let Some(ref mut _x) = opt {}
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
34
src/test/ui/mir/ssa-analysis-regression-50041.rs
Normal file
34
src/test/ui/mir/ssa-analysis-regression-50041.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// build-pass
|
||||
// compile-flags: -Z mir-opt-level=3
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(lang_items)]
|
||||
#![no_std]
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T: ?Sized>(*mut T);
|
||||
|
||||
impl<T: ?Sized> Drop for Box<T> {
|
||||
fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "box_free"]
|
||||
#[inline(always)]
|
||||
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
|
||||
dealloc(ptr)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn dealloc<T: ?Sized>(_: *mut T) {
|
||||
}
|
||||
|
||||
pub struct Foo<T>(T);
|
||||
|
||||
pub fn foo(a: Option<Box<Foo<usize>>>) -> usize {
|
||||
let f = match a {
|
||||
None => Foo(0),
|
||||
Some(vec) => *vec,
|
||||
};
|
||||
f.0
|
||||
}
|
12
src/test/ui/wasm/wasm-hang-issue-76281.rs
Normal file
12
src/test/ui/wasm/wasm-hang-issue-76281.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// only-wasm32
|
||||
// compile-flags: -C opt-level=2
|
||||
// build-pass
|
||||
|
||||
// Regression test for #76281.
|
||||
// This seems like an issue related to LLVM rather than
|
||||
// libs-impl so place here.
|
||||
|
||||
fn main() {
|
||||
let mut v: Vec<&()> = Vec::new();
|
||||
v.sort_by_key(|&r| r as *const ());
|
||||
}
|
Loading…
Reference in New Issue
Block a user