Skip to content

Commit

Permalink
Auto merge of #71992 - Dylan-DPC:rollup-29qjvpe, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #70733 (Add Arc::{incr,decr}_strong_count)
 - #71598 (improve Drop documentation)
 - #71783 (Detect errors caused by `async` block in 2015 edition)
 - #71903 (reword "possible candidate" import suggestion)
 - #71960 (Fix E0284 to not use incorrect wording)

Failed merges:

r? @ghost
  • Loading branch information
bors committed May 8, 2020
2 parents 1eefa67 + 14cbbf3 commit 29630ce
Show file tree
Hide file tree
Showing 64 changed files with 492 additions and 222 deletions.
73 changes: 73 additions & 0 deletions src/liballoc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,79 @@ impl<T: ?Sized> Arc<T> {
this.inner().strong.load(SeqCst)
}

/// Increments the strong reference count on the `Arc<T>` associated with the
/// provided pointer by one.
///
/// # Safety
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) for the duration of this method.
///
/// # Examples
///
/// ```
/// #![feature(arc_mutate_strong_count)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// unsafe {
/// let ptr = Arc::into_raw(five);
/// Arc::incr_strong_count(ptr);
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` between threads.
/// let five = Arc::from_raw(ptr);
/// assert_eq!(2, Arc::strong_count(&five));
/// }
/// ```
#[inline]
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn incr_strong_count(ptr: *const T) {
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
// Now increase refcount, but don't drop new refcount either
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
}

/// Decrements the strong reference count on the `Arc<T>` associated with the
/// provided pointer by one.
///
/// # Safety
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) when invoking this method. This method can be used to release the final
/// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
/// released.
///
/// # Examples
///
/// ```
/// #![feature(arc_mutate_strong_count)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// unsafe {
/// let ptr = Arc::into_raw(five);
/// Arc::decr_strong_count(ptr);
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` between threads.
/// let five = Arc::from_raw(ptr);
/// assert_eq!(0, Arc::strong_count(&five));
/// }
/// ```
#[inline]
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn decr_strong_count(ptr: *const T) {
mem::drop(Arc::from_raw(ptr));
}

#[inline]
fn inner(&self) -> &ArcInner<T> {
// This unsafety is ok because while this arc is alive we're guaranteed
Expand Down
12 changes: 7 additions & 5 deletions src/liballoc/task.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::{self, ManuallyDrop};
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;
Expand Down Expand Up @@ -60,9 +60,11 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
// Increment the reference count of the arc to clone it.
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
let waker: Arc<W> = Arc::from_raw(waker as *const W);
mem::forget(Arc::clone(&waker));
raw_waker(waker)
Arc::incr_strong_count(waker as *const W);
RawWaker::new(
waker as *const (),
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
)
}

// Wake by value, moving the Arc into the Wake::wake function
Expand All @@ -79,7 +81,7 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {

// Decrement the reference count of the Arc on drop
unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
mem::drop(Arc::from_raw(waker as *const W));
Arc::decr_strong_count(waker as *const W);
}

RawWaker::new(
Expand Down
142 changes: 98 additions & 44 deletions src/libcore/ops/drop.rs
Original file line number Diff line number Diff line change
@@ -1,85 +1,139 @@
/// Used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
/// Custom code within the destructor.
///
/// When a value goes out of scope, it will have its `drop` method called if
/// its type implements `Drop`. Then, any fields the value contains will also
/// be dropped recursively.
/// When a value is no longer needed, Rust will run a "destructor" on that value.
/// The most common way that a value is no longer needed is when it goes out of
/// scope. Destructors may still run in other circumstances, but we're going to
/// focus on scope for the examples here. To learn about some of those other cases,
/// please see [the reference] section on destructors.
///
/// Because of this recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
/// for some more elaboration.
/// This destructor consists of two components:
/// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type.
/// - The automatically generated "drop glue" which recursively calls the destructors
/// of the all fields of this value.
///
/// [book]: ../../book/ch15-03-drop.html
/// As Rust automatically calls the destructors of all contained fields,
/// you don't have to implement `Drop` in most cases. But there are some cases where
/// it is useful, for example for types which directly manage a resource.
/// That resource may be memory, it may be a file descriptor, it may be a network socket.
/// Once a value of that type is no longer going to be used, it should "clean up" its
/// resource by freeing the memory or closing the file or socket. This is
/// the job of a destructor, and therefore the job of `Drop::drop`.
///
/// # Examples
/// ## Examples
///
/// ## Implementing `Drop`
/// To see destructors in action, let's take a look at the following program:
///
/// The `drop` method is called when `_x` goes out of scope, and therefore
/// `main` prints `Dropping!`.
///
/// ```
/// ```rust
/// struct HasDrop;
///
/// impl Drop for HasDrop {
/// fn drop(&mut self) {
/// println!("Dropping!");
/// println!("Dropping HasDrop!");
/// }
/// }
///
/// struct HasTwoDrops {
/// one: HasDrop,
/// two: HasDrop,
/// }
///
/// impl Drop for HasTwoDrops {
/// fn drop(&mut self) {
/// println!("Dropping HasTwoDrops!");
/// }
/// }
///
/// fn main() {
/// let _x = HasDrop;
/// let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
/// println!("Running!");
/// }
/// ```
///
/// ## Dropping is done recursively
/// Rust will first call `Drop::drop` for `_x` and then for both `_x.one` and `_x.two`,
/// meaning that running this will print
///
/// When `outer` goes out of scope, the `drop` method will be called first for
/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and
/// then `Dropping Inner!`.
/// ```text
/// Running!
/// Dropping HasTwoDrops!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
///
/// Even if we remove the implementation of `Drop` for `HasTwoDrop`, the destructors of its fields are still called.
/// This would result in
///
/// ```test
/// Running!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
/// ## You cannot call `Drop::drop` yourself
///
/// Because `Drop::drop` is used to clean up a value, it may be dangerous to use this value after
/// the method has been called. As `Drop::drop` does not take ownership of its input,
/// Rust prevents misuse by not allowing you to call `Drop::drop` directly.
///
/// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error.
///
/// If you'd like explicitly call the destructor of a value, [`std::mem::drop`] can be used instead.
///
/// [`std::mem::drop`]: ../../std/mem/fn.drop.html
///
/// ## Drop order
///
/// Which of our two `HasDrop` drops first, though? For structs, it's the same
/// order that they're declared: first `one`, then `two`. If you'd like to try
/// this yourself, you can modify `HasDrop` above to contain some data, like an
/// integer, and then use it in the `println!` inside of `Drop`. This behavior is
/// guaranteed by the language.
///
/// Unlike for structs, local variables are dropped in reverse order:
///
/// ```rust
/// struct Foo;
///
/// impl Drop for Foo {
/// fn drop(&mut self) {
/// println!("Dropping Inner!");
/// println!("Dropping Foo!")
/// }
/// }
///
/// impl Drop for Outer {
/// struct Bar;
///
/// impl Drop for Bar {
/// fn drop(&mut self) {
/// println!("Dropping Outer!");
/// println!("Dropping Bar!")
/// }
/// }
///
/// fn main() {
/// let _x = Outer(Inner);
/// let _foo = Foo;
/// let _bar = Bar;
/// }
/// ```
///
/// ## Variables are dropped in reverse order of declaration
///
/// `_first` is declared first and `_second` is declared second, so `main` will
/// print `Declared second!` and then `Declared first!`.
/// This will print
///
/// ```text
/// Dropping Bar!
/// Dropping Foo!
/// ```
/// struct PrintOnDrop(&'static str);
///
/// impl Drop for PrintOnDrop {
/// fn drop(&mut self) {
/// println!("{}", self.0);
/// }
/// }
/// Please see [the reference] for the full rules.
///
/// fn main() {
/// let _first = PrintOnDrop("Declared first!");
/// let _second = PrintOnDrop("Declared second!");
/// }
/// ```
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// ## `Copy` and `Drop` are exclusive
///
/// You cannot implement both [`Copy`] and `Drop` on the same type. Types that
/// are `Copy` get implicitly duplicated by the compiler, making it very
/// hard to predict when, and how often destructors will be executed. As such,
/// these types cannot have destructors.
///
/// [`Copy`]: ../../std/marker/trait.Copy.html
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
Expand Down
Loading

0 comments on commit 29630ce

Please sign in to comment.