diff --git a/README.md b/README.md index 07c096046640..6ab11e7e2be6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ - -The Rust Programming Language - +# The Rust Programming Language This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index be5b247bb9f0..8946ac43bc65 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -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); }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index fd9698779311..effa597aad91 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -50,3 +50,24 @@ fn foo() -> Box 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(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. diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index db02ee67910b..a5fb8a1cbe8b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -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 } diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 4dfdbe0a5b45..3c515af71f5f 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -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 /// diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 944e0e65cf7c..5e63a303d22c 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -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 diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index c72e305a1f94..c2a96dd8ef47 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -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 diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cfad111aa546..d0bfa038aa13 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -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)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0973a6e362bc..ee03f15eece3 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -353,6 +353,26 @@ impl Rc { /// 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, + /// // ... more fields + /// } + /// impl Gadget { + /// pub fn new() -> Rc { + /// 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) -> Rc { // Construct the inner in the "uninitialized" state with a single @@ -829,8 +849,8 @@ impl Rc { let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcBox. - let fake_ptr = ptr as *mut RcBox; - let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) }; + let rc_ptr = + unsafe { (ptr as *mut RcBox).set_ptr_value((ptr as *mut u8).offset(-offset)) }; unsafe { Self::from_ptr(rc_ptr) } } @@ -850,7 +870,7 @@ impl Rc { pub fn downgrade(this: &Self) -> Weak { 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 Rc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, + |mem| (ptr as *mut RcBox).set_ptr_value(mem), ) } } @@ -1203,20 +1223,7 @@ impl 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(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 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 Weak { } } -pub(crate) fn is_dangling(ptr: NonNull) -> bool { - let address = ptr.as_ptr() as *mut () as usize; +pub(crate) fn is_dangling(ptr: *mut T) -> bool { + let address = ptr as *mut () as usize; address == usize::MAX } @@ -1872,7 +1879,7 @@ struct WeakInner<'a> { strong: &'a Cell, } -impl Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1902,15 +1909,15 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = 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 Weak { /// [`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, (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 + } 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).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 Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. /// @@ -2070,7 +2079,7 @@ impl Weak { /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option> { - 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 AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} -/// 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(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)) } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2d183a8c88c6..843a9b07fa93 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -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 = Rc::from("foo"); + let weak: Weak = 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 = Rc::new(123); + let weak: Weak = 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 = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + assert_eq!(format!("{:?}", x), "\"swordfish\""); + let y: Weak = 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; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 05bfeccbda13..c0d684fbb457 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -846,8 +846,7 @@ impl Arc { let offset = data_offset(ptr); // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + let arc_ptr = (ptr as *mut ArcInner).set_ptr_value((ptr as *mut u8).offset(-offset)); Self::from_ptr(arc_ptr) } @@ -888,7 +887,7 @@ impl Arc { 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 Arc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, + |mem| (ptr as *mut ArcInner).set_ptr_value(mem) as *mut ArcInner, ) } } @@ -1170,20 +1169,7 @@ impl 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(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 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 Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1683,15 +1669,15 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = 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 Weak { /// [`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, (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 + } 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).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 Weak { /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option> { - 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 AsRef for Arc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc {} -/// 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(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)) } } diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 5067af1d4ff6..4ccb32fbbf63 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -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 = Arc::from("foo"); + let weak: Weak = 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 = Arc::new(123); + let weak: Weak = 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 = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + assert_eq!(format!("{:?}", x), "\"swordfish\""); + let y: Weak = 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; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c5ab7a39ff0c..fa0fbaa35c95 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -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> = c.borrow(); + /// let b2: Result, _> = 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(orig: Ref<'b, T>, f: F) -> Result, 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> = c.borrow_mut(); + /// let mut b2: Result, _> = 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(orig: RefMut<'b, T>, f: F) -> Result, 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. /// diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 5766fd3c8874..98b8dca96140 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -286,6 +286,7 @@ where #[inline] unsafe fn get_unchecked(&mut self, idx: usize) -> ::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)) } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 6851f3fcd2fc..42c9d9f0cc03 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -84,7 +84,7 @@ impl Poll> { impl Poll>> { /// 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(self, f: F) -> Poll>> where F: FnOnce(T) -> U, @@ -98,7 +98,7 @@ impl Poll>> { } /// 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(self, f: F) -> Poll>> where F: FnOnce(E) -> U, diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 691767edea6d..bc5421bfb5f8 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -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(_a: &T) {} + assert_trusted_random_access(&z2); + assert_eq!(z2.next().unwrap(), ((1, 1), 1)); +} + #[test] fn test_iterator_step_by() { // Identity diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index bc737cd1927c..98f5982fbb2c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -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; diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 0680b1fc3297..829fc3817af2 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -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 diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index f49e5801c353..baa3026ff751 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -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 /// diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ec9ce4c820c6..62065e27dd96 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -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 } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 545f432def5a..cafb65bc7f9c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -219,7 +219,6 @@ impl Clean for CrateNum { impl Clean for doctree::Module<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let mut items: Vec = 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> for (&hir::Item<'_>, Option) { 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> for (&hir::Item<'_>, Option) { 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> for doctree::Import<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - // 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(); - } +fn clean_use_statement( + import: &hir::Item<'_>, + name: Symbol, + path: &hir::Path<'_>, + kind: hir::UseKind, + cx: &DocContext<'_>, +) -> Vec { + // 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 = !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, + // 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) } - }); - // 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; + 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 { - 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; - } + } + 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 !denied { + let mut visited = FxHashSet::default(); - if let Some(mut items) = inline::try_inline( + 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, - 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; - } + )); + return items; } - Import::new_simple(name, resolve_use_source(cx, path), true) - }; + } + 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), - }] - } + vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)] } impl Clean for (&hir::ForeignItem<'_>, Option) { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index cf51162cfb52..3de97f2dd2e5 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -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) }) }); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 4710c91f929b..f90623c03118 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -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, crate where_outer: Span, crate where_inner: Span, - crate imports: Vec>, crate mods: Vec>, 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, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f701352c486b..7d161ca3648c 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -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( diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index b0c5b16a1970..6a921266336e 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -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 diff --git a/src/test/rustdoc-json/nested.expected b/src/test/rustdoc-json/nested.expected index 65bb0c5fa036..80070e75f1e5 100644 --- a/src/test/rustdoc-json/nested.expected +++ b/src/test/rustdoc-json/nested.expected @@ -41,8 +41,8 @@ "inner": { "is_crate": false, "items": [ - "0:7", - "0:4" + "0:4", + "0:7" ] }, "kind": "module", diff --git a/src/test/rustdoc-ui/issue-80992.rs b/src/test/rustdoc-ui/issue-80992.rs new file mode 100644 index 000000000000..8983439bb64d --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.rs @@ -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(()) +} diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout new file mode 100644 index 000000000000..1dd19f468274 --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.stdout @@ -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 + diff --git a/src/test/ui/associated-item/associated-item-two-bounds.rs b/src/test/ui/associated-item/associated-item-two-bounds.rs new file mode 100644 index 000000000000..25b0d5a56bfb --- /dev/null +++ b/src/test/ui/associated-item/associated-item-two-bounds.rs @@ -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 + PartialEq; +} + +pub fn generic(t: F::T, a: A, b: B) -> bool { + t == a && t == b +} + +pub fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs new file mode 100644 index 000000000000..36f716019852 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -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>) {} + +fn spawn(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 { + loop {} + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr new file mode 100644 index 000000000000..01ffc48d6542 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -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`. diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs new file mode 100644 index 000000000000..4b42f9d4cd58 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs @@ -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 + } +} diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr new file mode 100644 index 000000000000..9373e4d95fcc --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr @@ -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`. diff --git a/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs b/src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs similarity index 100% rename from src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs rename to src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs diff --git a/src/test/ui/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs similarity index 100% rename from src/test/ui/feature-gate-edition_macro_pats.rs rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs diff --git a/src/test/ui/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr similarity index 100% rename from src/test/ui/feature-gate-edition_macro_pats.stderr rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs new file mode 100644 index 000000000000..c818f2976e1c --- /dev/null +++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs @@ -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(*mut T); + +impl Drop for Box { + fn drop(&mut self) { + } +} + +#[lang = "box_free"] +#[inline(always)] +unsafe fn box_free(ptr: *mut T) { + dealloc(ptr) +} + +#[inline(never)] +fn dealloc(_: *mut T) { +} + +pub struct Foo(T); + +pub fn foo(a: Option>>) -> usize { + let f = match a { + None => Foo(0), + Some(vec) => *vec, + }; + f.0 +} diff --git a/src/test/ui/wasm/wasm-hang-issue-76281.rs b/src/test/ui/wasm/wasm-hang-issue-76281.rs new file mode 100644 index 000000000000..a4adfa6d0446 --- /dev/null +++ b/src/test/ui/wasm/wasm-hang-issue-76281.rs @@ -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 ()); +}