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:
bors 2021-01-16 20:26:20 +00:00
commit 8a6518427e
38 changed files with 615 additions and 234 deletions

View File

@ -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.

View File

@ -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);
};

View File

@ -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.

View File

@ -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
}

View File

@ -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
///

View File

@ -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

View File

@ -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

View File

@ -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)]

View File

@ -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)) }
}

View File

@ -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;

View File

@ -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)) }
}

View File

@ -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;

View File

@ -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.
///

View File

@ -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)) }

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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
///

View File

@ -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
}

View File

@ -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>) {

View File

@ -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)
})
});

View File

@ -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,

View File

@ -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(

View File

@ -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

View File

@ -41,8 +41,8 @@
"inner": {
"is_crate": false,
"items": [
"0:7",
"0:4"
"0:4",
"0:7"
]
},
"kind": "module",

View 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(())
}

View 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

View 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() {}

View 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() {}

View File

@ -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`.

View 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
}
}

View 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`.

View 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
}

View 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 ());
}