1
Fork 0

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/"> # The Rust Programming Language
<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>
This is the main source code repository for [Rust]. It contains the compiler, This is the main source code repository for [Rust]. It contains the compiler,
standard library, and documentation. standard library, and documentation.

View file

@ -824,7 +824,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
} }
ty => unreachable!("bswap {}", ty), ty => unreachable!("bswap {}", ty),
} }
}; }
let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T)); let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T));
ret.write_cvalue(fx, res); 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 Now that the closure has its own copy of the data, there's no need to worry
about safety. 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); self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
let mut is_loop_move = false; let mut is_loop_move = false;
let mut in_pattern = false;
for move_site in &move_site_vec { for move_site in &move_site_vec {
let move_out = self.move_data.moves[(*move_site).moi]; let move_out = self.move_data.moves[(*move_site).moi];
@ -256,6 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"ref ".to_string(), "ref ".to_string(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
in_pattern = true;
} }
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { 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 place = &self.move_data.move_paths[mpi].place;
let ty = place.ty(self.body, self.infcx.tcx).ty; 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() { if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112). // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose( err.span_suggestion_verbose(
@ -1318,21 +1321,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
let msg = match category { match category {
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
format!("{} is returned here", kind) let msg = format!("{} is returned here", kind);
err.span_note(constraint_span, &msg);
} }
ConstraintCategory::CallArgument => { ConstraintCategory::CallArgument => {
fr_name.highlight_region_name(&mut err); 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!( _ => bug!(
"report_escaping_closure_capture called with unexpected constraint \ "report_escaping_closure_capture called with unexpected constraint \
category: `{:?}`", category: `{:?}`",
category category
), ),
}; }
err.span_note(constraint_span, &msg);
err 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 /// 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` /// 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 /// 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 /// # 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 /// 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 /// 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. /// 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 /// [`Cell`]: core::cell::Cell
/// [`RefCell`]: core::cell::RefCell /// [`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 /// 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 /// 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. /// 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 /// [`Ord`]: core::cmp::Ord
/// [`Cell`]: core::cell::Cell /// [`Cell`]: core::cell::Cell

View file

@ -120,6 +120,7 @@
#![feature(receiver_trait)] #![feature(receiver_trait)]
#![cfg_attr(bootstrap, feature(min_const_generics))] #![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(set_ptr_value)]
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(slice_ptr_len)] #![feature(slice_ptr_len)]
#![feature(staged_api)] #![feature(staged_api)]

View file

@ -353,6 +353,26 @@ impl<T> Rc<T> {
/// to upgrade the weak reference before this function returns will result /// to upgrade the weak reference before this function returns will result
/// in a `None` value. However, the weak reference may be cloned freely and /// in a `None` value. However, the weak reference may be cloned freely and
/// stored for use at a later time. /// 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")] #[unstable(feature = "arc_new_cyclic", issue = "75861")]
pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> { pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
// Construct the inner in the "uninitialized" state with a single // 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) }; let offset = unsafe { data_offset(ptr) };
// Reverse the offset to find the original RcBox. // Reverse the offset to find the original RcBox.
let fake_ptr = ptr as *mut RcBox<T>; let rc_ptr =
let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) }; unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) };
unsafe { Self::from_ptr(rc_ptr) } unsafe { Self::from_ptr(rc_ptr) }
} }
@ -850,7 +870,7 @@ impl<T: ?Sized> Rc<T> {
pub fn downgrade(this: &Self) -> Weak<T> { pub fn downgrade(this: &Self) -> Weak<T> {
this.inner().inc_weak(); this.inner().inc_weak();
// Make sure we do not create a dangling 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 } Weak { ptr: this.ptr }
} }
@ -1164,7 +1184,7 @@ impl<T: ?Sized> Rc<T> {
Self::allocate_for_layout( Self::allocate_for_layout(
Layout::for_value(&*ptr), Layout::for_value(&*ptr),
|layout| Global.allocate(layout), |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\]> /// Copy elements from slice into newly allocated Rc<\[T\]>
/// ///
/// Unsafe because the caller must either take ownership or bind `T: Copy` /// 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 { pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
let address = ptr.as_ptr() as *mut () as usize; let address = ptr as *mut () as usize;
address == usize::MAX address == usize::MAX
} }
@ -1872,7 +1879,7 @@ struct WeakInner<'a> {
strong: &'a Cell<usize>, 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>`. /// 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, /// 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 { pub fn as_ptr(&self) -> *const T {
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr); let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
// SAFETY: we must offset the pointer manually, and said pointer may be if is_dangling(ptr) {
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, // If the pointer is dangling, we return the sentinel directly. This cannot be
// because we know that a pointer to unsized T was derived from a real // a valid payload address, as the payload is at least as aligned as RcBox (usize).
// unsized T, as dangling weaks are only created for sized T. wrapping_offset ptr as *const T
// is used so that we can use the same code path for the non-dangling } else {
// unsized case and the potentially dangling sized case. // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
unsafe { // The payload may be dropped at this point, and we have to maintain provenance,
let offset = data_offset(ptr as *mut T); // so use raw pointer manipulation.
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) unsafe { &raw const (*ptr).value }
} }
} }
@ -1992,22 +1999,24 @@ impl<T> Weak<T> {
/// [`new`]: Weak::new /// [`new`]: Weak::new
#[stable(feature = "weak_into_raw", since = "1.45.0")] #[stable(feature = "weak_into_raw", since = "1.45.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self { 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. // 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. let ptr = if is_dangling(ptr as *mut T) {
// SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized). // This is a dangling Weak.
let ptr = unsafe { ptr as *mut RcBox<T>
set_data_ptr(ptr as *mut RcBox<T>, (ptr as *mut u8).wrapping_offset(-offset)) } 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. // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } } Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
} }
}
impl<T: ?Sized> Weak<T> {
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
/// dropping of the inner value if successful. /// 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`). /// (i.e., when this `Weak` was created by `Weak::new`).
#[inline] #[inline]
fn inner(&self) -> Option<WeakInner<'_>> { fn inner(&self) -> Option<WeakInner<'_>> {
if is_dangling(self.ptr) { if is_dangling(self.ptr.as_ptr()) {
None None
} else { } else {
// We are careful to *not* create a reference covering the "data" field, as // 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")] #[stable(feature = "pin", since = "1.33.0")]
impl<T: ?Sized> Unpin for Rc<T> {} impl<T: ?Sized> Unpin for Rc<T> {}
/// Get the offset within an `RcBox` for /// Get the offset within an `RcBox` for the payload behind a pointer.
/// a payload of type described by a pointer.
/// ///
/// # Safety /// # Safety
/// ///
/// This has the same safety requirements as `align_of_val_raw`. In effect: /// The pointer must point to (and have valid metadata for) a previously
/// /// valid instance of T, but the T is allowed to be dropped.
/// - 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.
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
// Align the unsized value to the end of the `RcBox`. // Align the unsized value to the end of the RcBox.
// Because it is ?Sized, it will always be the last field in memory. // Because RcBox is repr(C), it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler, // SAFETY: since the only unsized types possible are slices, trait objects,
// and is not a guaranteed language detail. Do not rely on it outside of std. // 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)) } 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] #[test]
fn get_mut() { fn get_mut() {
let mut x = Rc::new(3); let mut x = Rc::new(3);
@ -294,6 +318,23 @@ fn test_unsized() {
assert_eq!(foo, foo.clone()); 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] #[test]
fn test_from_owned() { fn test_from_owned() {
let foo = 123; let foo = 123;

View file

@ -846,8 +846,7 @@ impl<T: ?Sized> Arc<T> {
let offset = data_offset(ptr); let offset = data_offset(ptr);
// Reverse the offset to find the original ArcInner. // Reverse the offset to find the original ArcInner.
let fake_ptr = ptr as *mut ArcInner<T>; let arc_ptr = (ptr as *mut ArcInner<T>).set_ptr_value((ptr as *mut u8).offset(-offset));
let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
Self::from_ptr(arc_ptr) 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) { match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
Ok(_) => { Ok(_) => {
// Make sure we do not create a dangling Weak // 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 }; return Weak { ptr: this.ptr };
} }
Err(old) => cur = old, Err(old) => cur = old,
@ -1131,7 +1130,7 @@ impl<T: ?Sized> Arc<T> {
Self::allocate_for_layout( Self::allocate_for_layout(
Layout::for_value(&*ptr), Layout::for_value(&*ptr),
|layout| Global.allocate(layout), |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\]> /// Copy elements from slice into newly allocated Arc<\[T\]>
/// ///
/// Unsafe because the caller must either take ownership or bind `T: Copy`. /// Unsafe because the caller must either take ownership or bind `T: Copy`.
@ -1653,7 +1639,7 @@ struct WeakInner<'a> {
strong: &'a atomic::AtomicUsize, 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>`. /// 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, /// 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 { pub fn as_ptr(&self) -> *const T {
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr); let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
// SAFETY: we must offset the pointer manually, and said pointer may be if is_dangling(ptr) {
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, // If the pointer is dangling, we return the sentinel directly. This cannot be
// because we know that a pointer to unsized T was derived from a real // a valid payload address, as the payload is at least as aligned as ArcInner (usize).
// unsized T, as dangling weaks are only created for sized T. wrapping_offset ptr as *const T
// is used so that we can use the same code path for the non-dangling } else {
// unsized case and the potentially dangling sized case. // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
unsafe { // The payload may be dropped at this point, and we have to maintain provenance,
let offset = data_offset(ptr as *mut T); // so use raw pointer manipulation.
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) unsafe { &raw mut (*ptr).data }
} }
} }
@ -1773,18 +1759,22 @@ impl<T> Weak<T> {
/// [`forget`]: std::mem::forget /// [`forget`]: std::mem::forget
#[stable(feature = "weak_into_raw", since = "1.45.0")] #[stable(feature = "weak_into_raw", since = "1.45.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self { 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. // 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. let ptr = if is_dangling(ptr as *mut T) {
// SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized) // This is a dangling Weak.
let ptr = unsafe { ptr as *mut ArcInner<T>
set_data_ptr(ptr as *mut ArcInner<T>, (ptr as *mut u8).wrapping_offset(-offset)) } 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. // 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`). /// (i.e., when this `Weak` was created by `Weak::new`).
#[inline] #[inline]
fn inner(&self) -> Option<WeakInner<'_>> { fn inner(&self) -> Option<WeakInner<'_>> {
if is_dangling(self.ptr) { if is_dangling(self.ptr.as_ptr()) {
None None
} else { } else {
// We are careful to *not* create a reference covering the "data" field, as // 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")] #[stable(feature = "pin", since = "1.33.0")]
impl<T: ?Sized> Unpin for Arc<T> {} impl<T: ?Sized> Unpin for Arc<T> {}
/// Get the offset within an `ArcInner` for /// Get the offset within an `ArcInner` for the payload behind a pointer.
/// a payload of type described by a pointer.
/// ///
/// # Safety /// # Safety
/// ///
/// This has the same safety requirements as `align_of_val_raw`. In effect: /// The pointer must point to (and have valid metadata for) a previously
/// /// valid instance of T, but the T is allowed to be dropped.
/// - 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.
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
// Align the unsized value to the end of the `ArcInner`. // Align the unsized value to the end of the ArcInner.
// Because it is `?Sized`, it will always be the last field in memory. // Because RcBox is repr(C), it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler, // SAFETY: since the only unsized types possible are slices, trait objects,
// and is not a guaranteed language detail. Do not rely on it outside of std. // 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)) } 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] #[test]
fn test_cowarc_clone_make_mut() { fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75); let mut cow0 = Arc::new(75);
@ -329,6 +353,23 @@ fn test_unsized() {
assert!(y.upgrade().is_none()); 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] #[test]
fn test_from_owned() { fn test_from_owned() {
let foo = 123; let foo = 123;

View file

@ -1261,6 +1261,40 @@ impl<'b, T: ?Sized> Ref<'b, T> {
Ref { value: f(orig.value), borrow: orig.borrow } 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 /// Splits a `Ref` into multiple `Ref`s for different components of the
/// borrowed data. /// borrowed data.
/// ///
@ -1372,6 +1406,58 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
RefMut { value: f(value), borrow } 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 /// Splits a `RefMut` into multiple `RefMut`s for different components of the
/// borrowed data. /// borrowed data.
/// ///

View file

@ -286,6 +286,7 @@ where
#[inline] #[inline]
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item { 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 // SAFETY: the caller must uphold the contract for
// `Iterator::__iterator_get_unchecked`. // `Iterator::__iterator_get_unchecked`.
unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } 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>>> { impl<T, E> Poll<Option<Result<T, E>>> {
/// Changes the success value of this `Poll` with the closure provided. /// 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>>> pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
where where
F: FnOnce(T) -> U, 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. /// 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>>> pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
where where
F: FnOnce(E) -> U, F: FnOnce(E) -> U,

View file

@ -2,6 +2,7 @@
use core::cell::Cell; use core::cell::Cell;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::iter::TrustedRandomAccess;
use core::iter::*; use core::iter::*;
/// An iterator wrapper that panics whenever `next` or `next_back` is called /// 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]); 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] #[test]
fn test_iterator_step_by() { fn test_iterator_step_by() {
// Identity // Identity

View file

@ -75,6 +75,7 @@
#![feature(const_option)] #![feature(const_option)]
#![feature(integer_atomics)] #![feature(integer_atomics)]
#![feature(slice_group_by)] #![feature(slice_group_by)]
#![feature(trusted_random_access)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
extern crate test; 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 /// 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 /// 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. /// 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 hash table implementation is a Rust port of Google's [SwissTable].
/// The original C++ version of SwissTable can be found [here], and this /// 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 /// 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 /// 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 /// 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 /// # Examples
/// ///

View file

@ -814,12 +814,22 @@ impl<'a> Builder<'a> {
cargo.env("REAL_LIBRARY_PATH", e); 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 { match self.build.config.color {
Color::Always => { Color::Always => {
cargo.arg("--color=always"); cargo.arg("--color=always");
for log in &color_logs {
cargo.env(log, "always");
}
} }
Color::Never => { Color::Never => {
cargo.arg("--color=never"); cargo.arg("--color=never");
for log in &color_logs {
cargo.env(log, "never");
}
} }
Color::Auto => {} // nothing to do Color::Auto => {} // nothing to do
} }

View file

@ -219,7 +219,6 @@ impl Clean<ExternalCrate> for CrateNum {
impl Clean<Item> for doctree::Module<'_> { impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item { fn clean(&self, cx: &DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![]; 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.foreigns.iter().map(|x| x.clean(cx)));
items.extend(self.mods.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()); 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) => { ItemKind::Fn(ref sig, ref generics, body_id) => {
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) 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 let items = item_ids
.iter() .iter()
.map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)) .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) => { ItemKind::ExternCrate(orig_name) => {
return clean_extern_crate(item, name, orig_name, cx); 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"), _ => unreachable!("not yet converted"),
}; };
@ -2155,17 +2157,22 @@ fn clean_extern_crate(
}] }]
} }
impl Clean<Vec<Item>> for doctree::Import<'_> { fn clean_use_statement(
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> { 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) // 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 // are "inserted" as well but directly by the compiler and they should not be
// taken into account. // taken into account.
if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
return Vec::new(); return Vec::new();
} }
let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline); let (doc_meta_item, please_inline) = import.attrs.lists(sym::doc).get_word_attr(sym::inline);
let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore; let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore;
if pub_underscore && please_inline { if pub_underscore && please_inline {
rustc_errors::struct_span_err!( rustc_errors::struct_span_err!(
@ -2174,7 +2181,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
E0780, E0780,
"anonymous imports cannot be inlined" "anonymous imports cannot be inlined"
) )
.span_label(self.span, "anonymous import") .span_label(import.span, "anonymous import")
.emit(); .emit();
} }
@ -2182,9 +2189,9 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
// forcefully don't inline if this is not public or if the // forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present. // #[doc(no_inline)] attribute is present.
// Don't inline doc(hidden) imports so they can be stripped at a later stage. // Don't inline doc(hidden) imports so they can be stripped at a later stage.
let mut denied = !self.vis.node.is_pub() let mut denied = !import.vis.node.is_pub()
|| pub_underscore || pub_underscore
|| self.attrs.iter().any(|a| { || import.attrs.iter().any(|a| {
a.has_name(sym::doc) a.has_name(sym::doc)
&& match a.meta_item_list() { && match a.meta_item_list() {
Some(l) => { Some(l) => {
@ -2194,10 +2201,12 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
None => false, None => false,
} }
}); });
// Also check whether imports were asked to be inlined, in case we're trying to re-export a // Also check whether imports were asked to be inlined, in case we're trying to re-export a
// crate in Rust 2018+ // crate in Rust 2018+
let path = self.path.clean(cx); let def_id = cx.tcx.hir().local_def_id(import.hir_id).to_def_id();
let inner = if self.glob { let path = path.clean(cx);
let inner = if kind == hir::UseKind::Glob {
if !denied { if !denied {
let mut visited = FxHashSet::default(); let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
@ -2206,7 +2215,6 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
} }
Import::new_glob(resolve_use_source(cx, path), true) Import::new_glob(resolve_use_source(cx, path), true)
} else { } else {
let name = self.name;
if !please_inline { if !please_inline {
if let Res::Def(DefKind::Mod, did) = path.res { if let Res::Def(DefKind::Mod, did) = path.res {
if !did.is_local() && did.index == CRATE_DEF_INDEX { if !did.is_local() && did.index == CRATE_DEF_INDEX {
@ -2221,39 +2229,25 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
if let Some(mut items) = inline::try_inline( if let Some(mut items) = inline::try_inline(
cx, cx,
cx.tcx.parent_module(self.id).to_def_id(), cx.tcx.parent_module(import.hir_id).to_def_id(),
path.res, path.res,
name, name,
Some(self.attrs), Some(import.attrs),
&mut visited, &mut visited,
) { ) {
items.push(Item { items.push(Item::from_def_id_and_parts(
name: None, def_id,
attrs: box self.attrs.clean(cx), None,
source: self.span.clean(cx), ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), cx,
visibility: self.vis.clean(cx), ));
kind: box ImportItem(Import::new_simple(
self.name,
resolve_use_source(cx, path),
false,
)),
});
return items; return items;
} }
} }
Import::new_simple(name, resolve_use_source(cx, path), true) Import::new_simple(name, resolve_use_source(cx, path), true)
}; };
vec![Item { vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)]
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),
}]
}
} }
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) { 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) (found_main, found_extern_crate, found_macro)
}) })
}); });

View file

@ -2,7 +2,6 @@
//! manner (and with prettier names) before cleaning. //! manner (and with prettier names) before cleaning.
crate use self::StructType::*; crate use self::StructType::*;
use rustc_ast as ast;
use rustc_span::{self, Span, Symbol}; use rustc_span::{self, Span, Symbol};
use rustc_hir as hir; use rustc_hir as hir;
@ -11,7 +10,6 @@ crate struct Module<'hir> {
crate name: Option<Symbol>, crate name: Option<Symbol>,
crate where_outer: Span, crate where_outer: Span,
crate where_inner: Span, crate where_inner: Span,
crate imports: Vec<Import<'hir>>,
crate mods: Vec<Module<'hir>>, crate mods: Vec<Module<'hir>>,
crate id: hir::HirId, crate id: hir::HirId,
// (item, renamed) // (item, renamed)
@ -28,7 +26,6 @@ impl Module<'hir> {
id: hir::CRATE_HIR_ID, id: hir::CRATE_HIR_ID,
where_outer: rustc_span::DUMMY_SP, where_outer: rustc_span::DUMMY_SP,
where_inner: rustc_span::DUMMY_SP, where_inner: rustc_span::DUMMY_SP,
imports: Vec::new(),
mods: Vec::new(), mods: Vec::new(),
items: Vec::new(), items: Vec::new(),
foreigns: Vec::new(), foreigns: Vec::new(),
@ -48,17 +45,6 @@ crate enum StructType {
Unit, 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 { crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
match *vdata { match *vdata {
hir::VariantData::Struct(..) => Plain, hir::VariantData::Struct(..) => Plain,

View file

@ -316,15 +316,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
} }
} }
om.imports.push(Import { om.items.push((item, renamed))
name,
id: item.hir_id,
vis: &item.vis,
attrs: &item.attrs,
path,
glob: is_glob,
span: item.span,
});
} }
hir::ItemKind::Mod(ref m) => { hir::ItemKind::Mod(ref m) => {
om.mods.push(self.visit_mod_contents( 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 # and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If
# you're on windows, replace `\` with `/`. # 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 copy
import sys import sys
import json import json

View file

@ -41,8 +41,8 @@
"inner": { "inner": {
"is_crate": false, "is_crate": false,
"items": [ "items": [
"0:7", "0:4",
"0:4" "0:7"
] ]
}, },
"kind": "module", "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 ());
}