From 37fdb45e372cb03931db73e231d0d90bf09e75e5 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 11 Mar 2019 16:56:00 -0700 Subject: [PATCH 01/16] Future-proof the Futures API --- src/liballoc/boxed.rs | 6 +- src/libcore/future/future.rs | 18 ++-- src/libcore/task/mod.rs | 2 +- src/libcore/task/wake.rs | 99 ++++++++++++++++++- src/libstd/future.rs | 61 +++++++----- src/libstd/macros.rs | 2 +- src/libstd/panic.rs | 6 +- .../compile-fail/must_use-in-stdlib-traits.rs | 4 +- src/test/run-pass/async-await.rs | 15 ++- src/test/run-pass/auxiliary/arc_wake.rs | 14 +-- src/test/run-pass/futures-api.rs | 17 ++-- 11 files changed, 174 insertions(+), 70 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 74325a69e15ef..e0619fc4caf06 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -81,7 +81,7 @@ use core::ops::{ CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState }; use core::ptr::{self, NonNull, Unique}; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use crate::vec::Vec; use crate::raw_vec::RawVec; @@ -911,7 +911,7 @@ impl Generator for Pin> { impl Future for Box { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { - F::poll(Pin::new(&mut *self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut *self), cx) } } diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index a143b54a61f54..114a6b9336777 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -5,7 +5,7 @@ use marker::Unpin; use ops; use pin::Pin; -use task::{Poll, Waker}; +use task::{Context, Poll}; /// A future represents an asynchronous computation. /// @@ -44,8 +44,9 @@ pub trait Future { /// Once a future has finished, clients should not `poll` it again. /// /// When a future is not ready yet, `poll` returns `Poll::Pending` and - /// stores a clone of the [`Waker`] to be woken once the future can - /// make progress. For example, a future waiting for a socket to become + /// stores a clone of the [`Waker`] copied from the current [`Context`]. + /// This [`Waker`] is then woken once the future can make progress. + /// For example, a future waiting for a socket to become /// readable would call `.clone()` on the [`Waker`] and store it. /// When a signal arrives elsewhere indicating that the socket is readable, /// `[Waker::wake]` is called and the socket future's task is awoken. @@ -88,16 +89,17 @@ pub trait Future { /// /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } impl Future for &mut F { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { - F::poll(Pin::new(&mut **self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut **self), cx) } } @@ -108,7 +110,7 @@ where { type Output = <

::Target as Future>::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { - Pin::get_mut(self).as_mut().poll(waker) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::get_mut(self).as_mut().poll(cx) } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 9b8f598116200..29bae69ea83c1 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -8,4 +8,4 @@ mod poll; pub use self::poll::Poll; mod wake; -pub use self::wake::{Waker, RawWaker, RawWakerVTable}; +pub use self::wake::{Context, Waker, RawWaker, RawWakerVTable}; diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 21f0a8cea4168..26040c5b070e4 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -3,7 +3,7 @@ issue = "50547")] use fmt; -use marker::Unpin; +use marker::{PhantomData, Unpin}; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] /// which provides customized wakeup behavior. @@ -36,6 +36,10 @@ impl RawWaker { /// The `vtable` customizes the behavior of a `Waker` which gets created /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. + #[rustc_promotable] + #[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, @@ -63,21 +67,103 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - pub clone: unsafe fn(*const ()) -> RawWaker, + clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. /// It must wake up the task associated with this [`RawWaker`]. /// /// The implemention of this function must not consume the provided data /// pointer. - pub wake: unsafe fn(*const ()), + wake: unsafe fn(*const ()), + + /// This function gets called when a [`RawWaker`] gets dropped. + /// + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + drop: unsafe fn(*const ()), +} +impl RawWakerVTable { + /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, and + /// `drop` functions. + /// + /// # `clone` + /// + /// This function will be called when the [`RawWaker`] gets cloned, e.g. when + /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. + /// + /// The implementation of this function must retain all resources that are + /// required for this additional instance of a [`RawWaker`] and associated + /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup + /// of the same task that would have been awoken by the original [`RawWaker`]. + /// + /// # `wake` + /// + /// This function will be called when `wake` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// The implemention of this function must not consume the provided data + /// pointer. + /// + /// # `drop` + /// /// This function gets called when a [`RawWaker`] gets dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - pub drop: unsafe fn(*const ()), + #[rustc_promotable] + #[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + pub const fn new( + clone: unsafe fn(*const ()) -> RawWaker, + wake: unsafe fn(*const ()), + drop: unsafe fn(*const ()), + ) -> Self { + Self { + clone, + wake, + drop, + } + } +} + +/// The `Context` of an asynchronous task. +/// +/// Currently, `Context` only serves to provide access to a `&Waker` +/// which can be used to wake the current task. +pub struct Context<'a> { + waker: &'a Waker, + // Ensure we future-proof against variance changes by including + // an `&mut` reference with the provided lifetime. + _marker: PhantomData<&'a mut ()>, +} + +impl<'a> Context<'a> { + /// Create a new `Context` from a `&Waker`. + #[inline] + pub fn from_waker(waker: &'a Waker) -> Self { + Context { + waker, + _marker: PhantomData, + } + } + + /// Returns a reference to the `Waker` for the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + &self.waker + } +} + +impl fmt::Debug for Context<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .field("waker", &self.waker) + .finish() + } } /// A `Waker` is a handle for waking up a task by notifying its executor that it @@ -98,6 +184,7 @@ unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. + #[inline] pub fn wake(&self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. @@ -115,6 +202,7 @@ impl Waker { /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. /// /// This function is primarily used for optimization purposes. + #[inline] pub fn will_wake(&self, other: &Waker) -> bool { self.waker == other.waker } @@ -124,6 +212,7 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. + #[inline] pub unsafe fn new_unchecked(waker: RawWaker) -> Waker { Waker { waker, @@ -132,6 +221,7 @@ impl Waker { } impl Clone for Waker { + #[inline] fn clone(&self) -> Self { Waker { // SAFETY: This is safe because `Waker::new_unchecked` is the only way @@ -143,6 +233,7 @@ impl Clone for Waker { } impl Drop for Waker { + #[inline] fn drop(&mut self) { // SAFETY: This is safe because `Waker::new_unchecked` is the only way // to initialize `drop` and `data` requiring the user to acknowledge diff --git a/src/libstd/future.rs b/src/libstd/future.rs index aa784746122db..898387cb9f56d 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -5,7 +5,7 @@ use core::marker::Unpin; use core::pin::Pin; use core::option::Option; use core::ptr::NonNull; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use core::ops::{Drop, Generator, GeneratorState}; #[doc(inline)] @@ -32,10 +32,10 @@ impl> !Unpin for GenFuture {} #[unstable(feature = "gen_future", issue = "50547")] impl> Future for GenFuture { type Output = T::Return; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; - set_task_waker(waker, || match gen.resume() { + set_task_context(cx, || match gen.resume() { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), }) @@ -43,61 +43,72 @@ impl> Future for GenFuture { } thread_local! { - static TLS_WAKER: Cell>> = Cell::new(None); + static TLS_CX: Cell>>> = Cell::new(None); } -struct SetOnDrop(Option>); +struct SetOnDrop(Option>>); impl Drop for SetOnDrop { fn drop(&mut self) { - TLS_WAKER.with(|tls_waker| { - tls_waker.set(self.0.take()); + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); }); } } #[unstable(feature = "gen_future", issue = "50547")] /// Sets the thread-local task context used by async/await futures. -pub fn set_task_waker(waker: &Waker, f: F) -> R +pub fn set_task_context(cx: &mut Context<'_>, f: F) -> R where F: FnOnce() -> R { - let old_waker = TLS_WAKER.with(|tls_waker| { - tls_waker.replace(Some(NonNull::from(waker))) + // transmute the context's lifetime to 'static so we can store it. + let cx = unsafe { + core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx) + }; + let old_cx = TLS_CX.with(|tls_cx| { + tls_cx.replace(Some(NonNull::from(cx))) }); - let _reset_waker = SetOnDrop(old_waker); + let _reset = SetOnDrop(old_cx); f() } #[unstable(feature = "gen_future", issue = "50547")] -/// Retrieves the thread-local task waker used by async/await futures. +/// Retrieves the thread-local task context used by async/await futures. /// -/// This function acquires exclusive access to the task waker. +/// This function acquires exclusive access to the task context. /// -/// Panics if no waker has been set or if the waker has already been -/// retrieved by a surrounding call to get_task_waker. -pub fn get_task_waker(f: F) -> R +/// Panics if no context has been set or if the context has already been +/// retrieved by a surrounding call to get_task_context. +pub fn get_task_context(f: F) -> R where - F: FnOnce(&Waker) -> R + F: FnOnce(&mut Context<'_>) -> R { - let waker_ptr = TLS_WAKER.with(|tls_waker| { + let cx_ptr = TLS_CX.with(|tls_cx| { // Clear the entry so that nested `get_task_waker` calls // will fail or set their own value. - tls_waker.replace(None) + tls_cx.replace(None) }); - let _reset_waker = SetOnDrop(waker_ptr); + let _reset = SetOnDrop(cx_ptr); - let waker_ptr = waker_ptr.expect( - "TLS Waker not set. This is a rustc bug. \ + let mut cx_ptr = cx_ptr.expect( + "TLS Context not set. This is a rustc bug. \ Please file an issue on https://github.com/rust-lang/rust."); - unsafe { f(waker_ptr.as_ref()) } + + // Safety: we've ensured exclusive access to the context by + // removing the pointer from TLS, only to be replaced once + // we're done with it. + // + // The pointer that was inserted came from an `&mut Context<'_>`, + // so it is safe to treat as mutable. + unsafe { f(cx_ptr.as_mut()) } } #[unstable(feature = "gen_future", issue = "50547")] /// Polls a future in the current thread-local task waker. -pub fn poll_with_tls_waker(f: Pin<&mut F>) -> Poll +pub fn poll_with_tls_context(f: Pin<&mut F>) -> Poll where F: Future { - get_task_waker(|waker| F::poll(f, waker)) + get_task_context(|cx| F::poll(f, cx)) } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9d0eb2e6b1cef..cc908940074e8 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -332,7 +332,7 @@ macro_rules! r#await { let mut pinned = $e; loop { if let $crate::task::Poll::Ready(x) = - $crate::future::poll_with_tls_waker(unsafe { + $crate::future::poll_with_tls_context(unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }) { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6a16414c1417e..82962792f33ad 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -12,7 +12,7 @@ use crate::panicking; use crate::ptr::{Unique, NonNull}; use crate::rc::Rc; use crate::sync::{Arc, Mutex, RwLock, atomic}; -use crate::task::{Waker, Poll}; +use crate::task::{Context, Poll}; use crate::thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -323,9 +323,9 @@ impl fmt::Debug for AssertUnwindSafe { impl Future for AssertUnwindSafe { type Output = F::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }; - F::poll(pinned_field, waker) + F::poll(pinned_field, cx) } } diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs index b4f07ab33214c..503b39e181ab7 100644 --- a/src/test/compile-fail/must_use-in-stdlib-traits.rs +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -4,7 +4,7 @@ use std::iter::Iterator; use std::future::Future; -use std::task::{Poll, Waker}; +use std::task::{Context, Poll}; use std::pin::Pin; use std::unimplemented; @@ -13,7 +13,7 @@ struct MyFuture; impl Future for MyFuture { type Output = u32; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Pending } } diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 1843feed927a2..a07ae5cc966f4 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -1,7 +1,7 @@ // edition:2018 // aux-build:arc_wake.rs -#![feature(arbitrary_self_types, async_await, await_macro, futures_api)] +#![feature(async_await, await_macro, futures_api)] extern crate arc_wake; @@ -11,9 +11,7 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; -use std::task::{ - Poll, Waker, -}; +use std::task::{Context, Poll}; use arc_wake::ArcWake; struct Counter { @@ -32,11 +30,11 @@ fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } impl Future for WakeOnceThenComplete { type Output = (); - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<()> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { if self.0 { Poll::Ready(()) } else { - waker.wake(); + cx.waker().wake(); self.0 = true; Poll::Pending } @@ -134,10 +132,11 @@ where let mut fut = Box::pin(f(9)); let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Pending, fut.as_mut().poll(&waker)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Ready(9), fut.as_mut().poll(&waker)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); } fn main() { diff --git a/src/test/run-pass/auxiliary/arc_wake.rs b/src/test/run-pass/auxiliary/arc_wake.rs index 034e378af7f19..74ec56f55171a 100644 --- a/src/test/run-pass/auxiliary/arc_wake.rs +++ b/src/test/run-pass/auxiliary/arc_wake.rs @@ -1,19 +1,19 @@ // edition:2018 -#![feature(arbitrary_self_types, futures_api)] +#![feature(futures_api)] use std::sync::Arc; use std::task::{ - Poll, Waker, RawWaker, RawWakerVTable, + Waker, RawWaker, RawWakerVTable, }; macro_rules! waker_vtable { ($ty:ident) => { - &RawWakerVTable { - clone: clone_arc_raw::<$ty>, - drop: drop_arc_raw::<$ty>, - wake: wake_arc_raw::<$ty>, - } + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) }; } diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index fd4b585d34572..5d0b0db510f41 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -1,7 +1,6 @@ // aux-build:arc_wake.rs -#![feature(arbitrary_self_types, futures_api)] -#![allow(unused)] +#![feature(futures_api)] extern crate arc_wake; @@ -12,7 +11,7 @@ use std::sync::{ atomic::{self, AtomicUsize}, }; use std::task::{ - Poll, Waker, + Context, Poll, }; use arc_wake::ArcWake; @@ -30,8 +29,9 @@ struct MyFuture; impl Future for MyFuture { type Output = (); - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Wake twice + let waker = cx.waker(); waker.wake(); waker.wake(); Poll::Ready(()) @@ -44,10 +44,11 @@ fn test_waker() { }); let waker = ArcWake::into_waker(counter.clone()); assert_eq!(2, Arc::strong_count(&counter)); - - assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&waker)); - assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); - + { + let mut context = Context::from_waker(&waker); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); + assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); + } drop(waker); assert_eq!(1, Arc::strong_count(&counter)); } From 0a1a4759537091c240cadd517159696eeca6ead2 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 1 Apr 2019 17:41:37 -0700 Subject: [PATCH 02/16] SGX target: Use linker option to avoid code CGU assignment kludge --- .../spec/x86_64_fortanix_unknown_sgx.rs | 9 ++++ src/libstd/sys/sgx/alloc.rs | 16 ++++++- src/libstd/sys/sgx/mod.rs | 9 ++++ src/libstd/sys/sgx/rwlock.rs | 42 +------------------ src/libstd/sys/sgx/stdio.rs | 18 ++++++++ 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 7c369daa2a8f6..46cf4cd8ae353 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -21,6 +21,15 @@ pub fn target() -> Result { "-Wl,--no-undefined-version", "-Wl,-Bsymbolic", "-Wl,--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-Wl,-u,__rust_abort", + "-Wl,-u,__rust_c_alloc", + "-Wl,-u,__rust_c_dealloc", + "-Wl,-u,__rust_print_err", + "-Wl,-u,__rust_rwlock_rdlock", + "-Wl,-u,__rust_rwlock_unlock", + "-Wl,-u,__rust_rwlock_wrlock", ]; const EXPORT_SYMBOLS: &[&str] = &[ diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs index 98eb8397436bf..b385d567dd8c4 100644 --- a/src/libstd/sys/sgx/alloc.rs +++ b/src/libstd/sys/sgx/alloc.rs @@ -1,4 +1,4 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::alloc::{self, GlobalAlloc, Layout, System}; use super::waitqueue::SpinMutex; @@ -30,3 +30,17 @@ unsafe impl GlobalAlloc for System { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) } } + +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { + alloc::alloc(Layout::from_size_align_unchecked(size, align)) +} + +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { + alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) +} diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index dc51a932c616c..67fffe98a8654 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -130,6 +130,15 @@ pub unsafe fn abort_internal() -> ! { abi::usercalls::exit(true) } +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub unsafe extern "C" fn __rust_abort() { + abort_internal(); +} + pub fn hashmap_random_keys() -> (u64, u64) { fn rdrand64() -> u64 { unsafe { diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 4cba36aa64dd5..5d328221b4dc8 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,10 +1,4 @@ -#[cfg(not(test))] -use crate::alloc::{self, Layout}; use crate::num::NonZeroUsize; -#[cfg(not(test))] -use crate::slice; -#[cfg(not(test))] -use crate::str; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -165,10 +159,11 @@ impl RWLock { pub unsafe fn destroy(&self) {} } +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. #[cfg(not(test))] const EINVAL: i32 = 22; -// used by libunwind port #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { @@ -198,39 +193,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { return 0; } -// the following functions are also used by the libunwind port. They're -// included here to make sure parallel codegen and LTO don't mess things up. -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = slice::from_raw_parts(m as *const u8, s as _); - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{}", s); - } -} - -#[cfg(not(test))] -#[no_mangle] -// NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { - crate::sys::abort_internal(); -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { - alloc::alloc(Layout::from_size_align_unchecked(size, align)) -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { - alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs index f2c6892bfb7fd..a575401f5f60d 100644 --- a/src/libstd/sys/sgx/stdio.rs +++ b/src/libstd/sys/sgx/stdio.rs @@ -2,6 +2,10 @@ use fortanix_sgx_abi as abi; use crate::io; use crate::sys::fd::FileDesc; +#[cfg(not(test))] +use crate::slice; +#[cfg(not(test))] +use crate::str; pub struct Stdin(()); pub struct Stdout(()); @@ -62,3 +66,17 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub fn panic_output() -> Option { super::abi::panic::SgxPanicOutput::new() } + +// This function is needed by libunwind. The symbol is named in pre-link args +// for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = slice::from_raw_parts(m as *const u8, s as _); + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{}", s); + } +} From ef648f4a4936700c7ebf85f82cbcba29a6187bcc Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 4 Apr 2019 15:04:37 +0200 Subject: [PATCH 03/16] Remove invalid assertion back::link::from add_upstream_rust_crates(). --- src/librustc_codegen_llvm/back/link.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index f10bc0516e5bf..19419a72b94dd 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -1396,10 +1396,6 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!are_upstream_rust_objects_already_included(sess)); - // Just need to tell the linker about where the library lives and // what its name is let parent = cratepath.parent(); From 79941973af54db7f7b941582fdc9537b2ee95a00 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 28 Oct 2018 15:27:29 +0900 Subject: [PATCH 04/16] Make FnBox a subtrait of FnOnce. --- src/liballoc/boxed.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index b2315c6a73907..9166f917293d1 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -735,9 +735,7 @@ impl FusedIterator for Box {} #[rustc_paren_sugar] #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -pub trait FnBox { - type Output; - +pub trait FnBox: FnOnce { fn call_box(self: Box, args: A) -> Self::Output; } @@ -746,8 +744,6 @@ pub trait FnBox { impl FnBox for F where F: FnOnce { - type Output = F::Output; - fn call_box(self: Box, args: A) -> F::Output { self.call_once(args) } From 059ec76d9b2ba33be5d7b092ffeb401590a5d39d Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 28 Oct 2018 15:28:15 +0900 Subject: [PATCH 05/16] Add Fn* blanket impls for Box. --- src/liballoc/boxed.rs | 33 +++++++++++++++++++++++++++++++++ src/liballoc/lib.rs | 1 + 2 files changed, 34 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 9166f917293d1..09554a1a34da8 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -694,6 +694,37 @@ impl ExactSizeIterator for Box { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} +#[cfg(not(stage0))] +#[unstable(feature = "boxed_closure_impls", + reason = "Box relies on unsized rvalues and needs to be tested more", + issue = "48055")] +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + default extern "rust-call" fn call_once(self, args: A) -> Self::Output { + >::call_once(*self, args) + } +} + +#[cfg(not(stage0))] +#[unstable(feature = "boxed_closure_impls", + reason = "Box relies on unsized rvalues and needs to be tested more", + issue = "48055")] +impl + ?Sized> FnMut for Box { + extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output { + >::call_mut(self, args) + } +} + +#[cfg(not(stage0))] +#[unstable(feature = "boxed_closure_impls", + reason = "Box relies on unsized rvalues and needs to be tested more", + issue = "48055")] +impl + ?Sized> Fn for Box { + extern "rust-call" fn call(&self, args: A) -> Self::Output { + >::call(self, args) + } +} /// `FnBox` is a version of the `FnOnce` intended for use with boxed /// closure objects. The idea is that where one would normally store a @@ -752,6 +783,7 @@ impl FnBox for F #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] impl FnOnce for Box + '_> { + #[cfg(stage0)] type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -762,6 +794,7 @@ impl FnOnce for Box + '_> { #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] impl FnOnce for Box + Send + '_> { + #[cfg(stage0)] type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 90ff56814fbb1..9064b4ccd6a88 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -107,6 +107,7 @@ #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsize)] +#![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(rustc_const_unstable)] From 480dcb403caa90ecd2cc717ad4801805c010d3f6 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 28 Oct 2018 15:28:47 +0900 Subject: [PATCH 06/16] Add tests for boxed_closure_impls. --- .../run-pass/unsized-locals/box-fnonce.rs | 10 +++++++ .../run-pass/unsized-locals/fnbox-compat.rs | 12 +++++++++ src/test/ui/unsized-locals/fnbox-compat.rs | 12 +++++++++ .../ui/unsized-locals/fnbox-compat.stderr | 27 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 src/test/run-pass/unsized-locals/box-fnonce.rs create mode 100644 src/test/run-pass/unsized-locals/fnbox-compat.rs create mode 100644 src/test/ui/unsized-locals/fnbox-compat.rs create mode 100644 src/test/ui/unsized-locals/fnbox-compat.stderr diff --git a/src/test/run-pass/unsized-locals/box-fnonce.rs b/src/test/run-pass/unsized-locals/box-fnonce.rs new file mode 100644 index 0000000000000..97007a9423917 --- /dev/null +++ b/src/test/run-pass/unsized-locals/box-fnonce.rs @@ -0,0 +1,10 @@ +#![feature(boxed_closure_impls)] + +fn call_it(f: Box T>) -> T { + f() +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/run-pass/unsized-locals/fnbox-compat.rs b/src/test/run-pass/unsized-locals/fnbox-compat.rs new file mode 100644 index 0000000000000..5ec54ada13bb0 --- /dev/null +++ b/src/test/run-pass/unsized-locals/fnbox-compat.rs @@ -0,0 +1,12 @@ +#![feature(fnbox)] + +use std::boxed::FnBox; + +fn call_it(f: Box T>) -> T { + f() +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/ui/unsized-locals/fnbox-compat.rs b/src/test/ui/unsized-locals/fnbox-compat.rs new file mode 100644 index 0000000000000..3cb9ac560a256 --- /dev/null +++ b/src/test/ui/unsized-locals/fnbox-compat.rs @@ -0,0 +1,12 @@ +#![feature(fnbox)] + +use std::boxed::FnBox; + +fn call_it(f: Box T>) -> T { + f(&42) +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/ui/unsized-locals/fnbox-compat.stderr b/src/test/ui/unsized-locals/fnbox-compat.stderr new file mode 100644 index 0000000000000..5172092fb1cd5 --- /dev/null +++ b/src/test/ui/unsized-locals/fnbox-compat.stderr @@ -0,0 +1,27 @@ +error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments + --> $DIR/fnbox-compat.rs:11:34 + | +LL | assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); + | ^^ + | | + | expected closure that takes 1 argument + | takes 0 arguments +help: consider changing the closure to take and ignore the expected argument + | +LL | assert_eq!(&call_it(Box::new(|_| s)) as &str, "hello"); + | ^^^ + +error[E0277]: the size for values of type `dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=_>` cannot be known at compilation time + --> $DIR/fnbox-compat.rs:11:25 + | +LL | assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=_>` + = note: to learn more, visit + = note: required by `>::new` + +error: aborting due to 2 previous errors + +Some errors occurred: E0277, E0593. +For more information about an error, try `rustc --explain E0277`. From 219097ecf6026954db100fb00089a2188915615d Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 28 Oct 2018 15:36:58 +0900 Subject: [PATCH 07/16] Add unstable-book articles on fnbox and boxed_closure_impls. --- .../library-features/boxed-closure-impls.md | 98 +++++++ .../src/library-features/fnbox.md | 252 ++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 src/doc/unstable-book/src/library-features/boxed-closure-impls.md create mode 100644 src/doc/unstable-book/src/library-features/fnbox.md diff --git a/src/doc/unstable-book/src/library-features/boxed-closure-impls.md b/src/doc/unstable-book/src/library-features/boxed-closure-impls.md new file mode 100644 index 0000000000000..0c738d0f78e03 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/boxed-closure-impls.md @@ -0,0 +1,98 @@ +# `boxed_closure_impls` + +The tracking issue for this feature is [#48055] + +[#48055]: https://github.com/rust-lang/rust/issues/48055 + +------------------------ + +This includes the following blanket impls for closure traits: + +```rust,ignore +impl + ?Sized> FnOnce for Box { + // ... +} +impl + ?Sized> FnMut for Box { + // ... +} +impl + ?Sized> Fn for Box { + // ... +} +``` + +## Usage + +`Box` can be used almost transparently. You can even use `Box` now. + +```rust +#![feature(boxed_closure_impls)] + +fn main() { + let resource = "hello".to_owned(); + // Create a boxed once-callable closure + let f: Box = Box::new(|x| { + let s = resource; + println!("{}", x); + println!("{}", s); + }); + + // Call it + f(); +} +``` + +## The reason for instability + +This is unstable because of the first impl. + +It would have been easy if we're allowed to tighten the bound: + +```rust,ignore +impl + ?Sized> FnOnce for Box { + // ... +} +``` + +However, `Box` drops out of the modified impl. +To rescue this, we had had a temporary solution called [`fnbox`][fnbox]. + +[fnbox]: library-features/fnbox.html + +Unfortunately, due to minor coherence reasons, `fnbox` and +`FnOnce for Box` had not been able to coexist. +We had preferred `fnbox` for the time being. + +Now, as [`unsized_locals`][unsized_locals] is implemented, we can just write the +original impl: + +[unsized_locals]: language-features/unsized-locals.html + +```rust,ignore +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + // *self is an unsized rvalue + >::call_once(*self, args) + } +} +``` + +However, since `unsized_locals` is a very young feature, we're careful about +this `FnOnce` impl now. + +There's another reason for instability: for compatibility with `fnbox`, +we currently allow specialization of the `Box` impl: + +```rust,ignore +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + // we have "default" here + default extern "rust-call" fn call_once(self, args: A) -> Self::Output { + >::call_once(*self, args) + } +} +``` + +This isn't what we desire in the long term. diff --git a/src/doc/unstable-book/src/library-features/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md new file mode 100644 index 0000000000000..3200601e557f6 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fnbox.md @@ -0,0 +1,252 @@ +# `fnbox` + +The tracking issue for this feature is [#28796] + +[#28796]: https://github.com/rust-lang/rust/issues/28796 + +------------------------ + +As an analogy to `&dyn Fn()` and `&mut dyn FnMut()`, you may have expected +`Box` to work. But it hadn't until the recent improvement! +`FnBox` had been a **temporary** solution for this until we are able to pass +trait objects by value. + +See [`boxed_closure_impls`][boxed_closure_impls] for the newer approach. + +[boxed_closure_impls]: library-features/boxed-closure-impls.html + +## Usage + +If you want to box `FnOnce` closures, you can use `Box` instead of `Box`. + +```rust +#![feature(fnbox)] + +use std::boxed::FnBox; + +fn main() { + let resource = "hello".to_owned(); + // Create a boxed once-callable closure + let f: Box String> = Box::new(|| resource); + + // Call it + let s = f(); + println!("{}", s); +} +``` + +## How `Box` did not work + +**Spoiler**: [`boxed_closure_impls`][boxed_closure_impls] actually implements +`Box`! This didn't work because we lacked features like +[`unsized_locals`][unsized_locals] for a long time. Therefore, this section +just explains historical reasons for `FnBox`. + +[unsized_locals]: language-features/unsized-locals.html + +### First approach: just provide `Box` adapter impl + +The first (and natural) attempt for `Box` would look like: + +```rust,ignore +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + >::call_once(*self, args) + } +} +``` + +However, this doesn't work. We have to relax the `Sized` bound for `F` because +we expect trait objects here, but `*self` must be `Sized` because it is passed +as a function argument. + +### The second attempt: add `FnOnce::call_box` + +One may come up with this workaround: modify `FnOnce`'s definition like this: + +```rust,ignore +pub trait FnOnce { + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; + // Add this new method + extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; +} +``` + +...and then, modify the `impl` like this: + +```rust,ignore +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + // We can use `call_box` here! + >::call_box(self, args) + } + // We'll have to define this in every impl of `FnOnce`. + extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output { + >::call_box(*self, args) + } +} +``` + +What's wrong with this? The problem here is crates: + +- `FnOnce` is in `libcore`, as it shouldn't depend on allocations. +- `Box` is in `liballoc`, as it:s the very allocated pointer. + +It is impossible to add `FnOnce::call_box` because it is reverse-dependency. + +There's another problem: `call_box` can't have defaults. +`default impl` from the specialization RFC may resolve this problem. + +### The third attempt: add `FnBox` that contains `call_box` + +`call_box` can't reside in `FnOnce`, but how about defining a new trait in +`liballoc`? + +`FnBox` is almost a copy of `FnOnce`, but with `call_box`: + +```rust,ignore +pub trait FnBox { + type Output; + + extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; +} +``` + +For `Sized` types (from which we coerce into `dyn FnBox`), we define +the blanket impl that proxies calls to `FnOnce`: + +```rust,ignore +impl> FnBox for F { + type Output = >::Output; + + extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output { + // Here we assume `F` to be sized. + >::call_once(*self, args) + } +} +``` + +Now it looks like that we can define `FnOnce` for `Box`. + +```rust,ignore +impl + ?Sized> FnOnce for Box { + type Output = >::Output; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + >::call_box(self, args) + } +} +``` + +## Limitations of `FnBox` + +### Interaction with HRTB + +Firstly, the actual implementation is different from the one presented above. +Instead of implementing `FnOnce` for `Box`, `liballoc` only +implements `FnOnce` for `Box`. + +```rust,ignore +impl<'a, A, R> FnOnce for Box + 'a> { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + FnBox::call_box(*self, args) + } +} + +// Sendable variant +impl<'a, A, R> FnOnce for Box + Send + 'a> { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + FnBox::call_box(*self, args) + } +} +``` + +The consequence is that the following example doesn't work: + +```rust,compile_fail +#![feature(fnbox)] + +use std::boxed::FnBox; + +fn main() { + let f: Box = Box::new(|x| println!("{}", x)); + f(42); +} +``` + +Note that `dyn FnBox(&i32)` desugars to +`dyn for<'r> FnBox<(&'r i32,), Output = ()>`. +It isn't covered in `dyn FnBox + 'a` or +`dyn FnBox + Send + 'a` due to HRTB. + +### Interaction with `Fn`/`FnMut` + +It would be natural to have the following impls: + +```rust,ignore +impl + ?Sized> FnMut for Box { + // ... +} +impl + ?Sized> Fn for Box { + // ... +} +``` + +However, we hadn't been able to write these in presense of `FnBox` +(until [`boxed_closure_impls`][boxed_closure_impls] lands). + +To have `FnMut` for `Box`, we should have (at least) this impl: + +```rust,ignore +// Note here we only impose `F: FnMut`. +// If we can write `F: FnOnce` here, that will resolve all problems. +impl + ?Sized> FnOnce for Box { + // ... +} +``` + +Unfortunately, the compiler complains that it **overlaps** with our +`dyn FnBox()` impls. At first glance, the overlap must not happen. +The `A` generic parameter does the trick here: due to coherence rules, +a downstream crate may define the following impl: + +```rust,ignore +struct MyStruct; +impl<'a> FnMut for dyn FnBox + 'a { + // ... +} +``` + +The trait solver doesn't know that `A` is always a tuple type, so this is +still possible. With this in mind, the compiler emits the overlap error. + +## Modification + +For compatibility with [`boxed_closure_impls`][boxed_closure_impls], +we now have a slightly modified version of `FnBox`: + +```rust,ignore +// It's now a subtrait of `FnOnce` +pub trait FnBox: FnOnce { + // now uses FnOnce::Output + // type Output; + + extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; +} +``` + +## The future of `fnbox` + +`FnBox` has long been considered a temporary solution for `Box` +problem. Since we have [`boxed_closure_impls`][boxed_closure_impls] now, +it may be deprecated and removed in the future. From e55d82c8a3a05e433897de4a991366bb2963470d Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 28 Oct 2018 17:53:43 +0900 Subject: [PATCH 08/16] Fix expectations on some ui tests involving FnOnce. --- .../two-phase-nonrecv-autoref.ast.nll.stderr | 32 ++++++----------- .../two-phase-nonrecv-autoref.ast.stderr | 22 ++++++------ .../two-phase-nonrecv-autoref.nll.stderr | 36 ++++++------------- .../ui/borrowck/two-phase-nonrecv-autoref.rs | 16 ++++----- ...owck-call-is-borrow-issue-12224.nll.stderr | 2 +- .../borrowck-call-is-borrow-issue-12224.rs | 2 +- ...borrowck-call-is-borrow-issue-12224.stderr | 4 +-- 7 files changed, 42 insertions(+), 72 deletions(-) diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr index d026f81b7aad6..df74feb4f0564 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr @@ -7,7 +7,7 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | fn twice_ten_so i32>(f: Box) { @@ -17,7 +17,7 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -28,19 +28,7 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | LL | f(f(10)); @@ -48,10 +36,10 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 + --> $DIR/two-phase-nonrecv-autoref.rs:125:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -60,7 +48,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | --^---- @@ -70,7 +58,7 @@ LL | i[i[3]] = 4; | mutable borrow later used here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | --^---- @@ -79,7 +67,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | mutable borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. +Some errors occurred: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr index 426939f371ca5..d98b272944fdc 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr @@ -15,7 +15,7 @@ LL | f(f(10)); | | second mutable borrow occurs here | first mutable borrow occurs here -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | f(f(10)); @@ -23,7 +23,7 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -34,7 +34,7 @@ LL | f(f(10)); | | second mutable borrow occurs here | first mutable borrow occurs here -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | LL | f(f(10)); @@ -42,10 +42,10 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `(dyn std::ops::FnOnce(i32) -> i32 + 'static)`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box<(dyn std::ops::FnOnce(i32) -> i32 + 'static)>`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:28 + --> $DIR/two-phase-nonrecv-autoref.rs:125:28 | LL | double_access(&mut a, &a); | - ^- mutable borrow ends here @@ -54,7 +54,7 @@ LL | double_access(&mut a, &a); | mutable borrow occurs here error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:135:9 + --> $DIR/two-phase-nonrecv-autoref.rs:131:9 | LL | a.m(a.i(10)); | - ^ - mutable borrow ends here @@ -63,7 +63,7 @@ LL | a.m(a.i(10)); | mutable borrow occurs here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | - ^ - mutable borrow ends here @@ -72,7 +72,7 @@ LL | i[i[3]] = 4; | mutable borrow occurs here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | - ^ - mutable borrow ends here @@ -81,7 +81,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:172:12 + --> $DIR/two-phase-nonrecv-autoref.rs:168:12 | LL | v.push(v.len()); | - ^ - mutable borrow ends here @@ -90,7 +90,7 @@ LL | v.push(v.len()); | mutable borrow occurs here error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:183:9 + --> $DIR/two-phase-nonrecv-autoref.rs:179:9 | LL | s.m(s.i(10)); | - ^ - mutable borrow ends here @@ -99,7 +99,7 @@ LL | s.m(s.i(10)); | mutable borrow occurs here error[E0502]: cannot borrow `t` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:188:9 + --> $DIR/two-phase-nonrecv-autoref.rs:184:9 | LL | t.m(t.i(10)); | - ^ - mutable borrow ends here diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index d026f81b7aad6..223de36f0df31 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -7,17 +7,15 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | fn twice_ten_so i32>(f: Box) { - | - consider adding a `Copy` constraint to this type argument + | - move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -28,30 +26,18 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | +LL | fn twice_ten_oo(f: Box i32>) { + | - move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 + --> $DIR/two-phase-nonrecv-autoref.rs:125:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -60,7 +46,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | --^---- @@ -70,7 +56,7 @@ LL | i[i[3]] = 4; | mutable borrow later used here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | --^---- @@ -79,7 +65,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | mutable borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. +Some errors occurred: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs index 1a14cb90f38ef..1005da052970b 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -67,9 +67,9 @@ fn overloaded_call_traits() { } fn twice_ten_so i32>(f: Box) { f(f(10)); - //[nll]~^ ERROR use of moved value: `*f` - //[g2p]~^^ ERROR use of moved value: `*f` - //[ast]~^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` + //[ast]~^^^ ERROR use of moved value: `f` } fn twice_ten_om(f: &mut FnMut(i32) -> i32) { @@ -83,13 +83,9 @@ fn overloaded_call_traits() { } fn twice_ten_oo(f: Box i32>) { f(f(10)); - //[nll]~^ ERROR cannot move a value of type - //[nll]~^^ ERROR cannot move a value of type - //[nll]~^^^ ERROR use of moved value: `*f` - //[g2p]~^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^ ERROR use of moved value: `*f` - //[ast]~^^^^^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` + //[ast]~^^^ ERROR use of moved value: `f` } twice_ten_sm(&mut |x| x + 1); diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr index 1a5ab7a7d56a0..4e2ab59f82245 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -18,7 +18,7 @@ LL | fn test2(f: &F) where F: FnMut() { LL | (*f)(); | ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow `*f.f` as mutable, as it is behind a `&` reference +error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 | LL | fn test4(f: &Test) { diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index cfebd6f700359..f246f1118bf4e 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -32,7 +32,7 @@ fn test3(f: &mut F) where F: FnMut() { fn test4(f: &Test) { f.f.call_mut(()) - //~^ ERROR: cannot borrow `Box` content `*f.f` of immutable binding as mutable + //~^ ERROR: cannot borrow field `f.f` of immutable binding as mutable } fn test5(f: &mut Test) { diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 6c8f477e31062..a61ee8334afff 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -19,13 +19,13 @@ LL | fn test2(f: &F) where F: FnMut() { LL | (*f)(); | ^^^^ cannot borrow as mutable -error[E0596]: cannot borrow `Box` content `*f.f` of immutable binding as mutable +error[E0596]: cannot borrow field `f.f` of immutable binding as mutable --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 | LL | fn test4(f: &Test) { | ----- use `&mut Test` here to make mutable LL | f.f.call_mut(()) - | ^^^ cannot borrow as mutable + | ^^^ cannot mutably borrow field of immutable binding error[E0504]: cannot move `f` into closure because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:56:13 From 4dcd6cc208e143309d481f0ecf4051bd9d139a18 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 3 Feb 2019 22:08:34 +0900 Subject: [PATCH 09/16] Fix failing tests. --- .../library-features/boxed-closure-impls.md | 2 +- src/test/ui/unsized-locals/fnbox-compat.rs | 3 +- .../ui/unsized-locals/fnbox-compat.stderr | 30 +++++-------------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/doc/unstable-book/src/library-features/boxed-closure-impls.md b/src/doc/unstable-book/src/library-features/boxed-closure-impls.md index 0c738d0f78e03..5ceb54ff3b96e 100644 --- a/src/doc/unstable-book/src/library-features/boxed-closure-impls.md +++ b/src/doc/unstable-book/src/library-features/boxed-closure-impls.md @@ -37,7 +37,7 @@ fn main() { }); // Call it - f(); + f(&42); } ``` diff --git a/src/test/ui/unsized-locals/fnbox-compat.rs b/src/test/ui/unsized-locals/fnbox-compat.rs index 3cb9ac560a256..c2c385e9fea56 100644 --- a/src/test/ui/unsized-locals/fnbox-compat.rs +++ b/src/test/ui/unsized-locals/fnbox-compat.rs @@ -4,9 +4,10 @@ use std::boxed::FnBox; fn call_it(f: Box T>) -> T { f(&42) + //~^ERROR implementation of `std::ops::FnOnce` is not general enough } fn main() { let s = "hello".to_owned(); - assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); + assert_eq!(&call_it(Box::new(|_| s)) as &str, "hello"); } diff --git a/src/test/ui/unsized-locals/fnbox-compat.stderr b/src/test/ui/unsized-locals/fnbox-compat.stderr index 5172092fb1cd5..c37bfaa47f7eb 100644 --- a/src/test/ui/unsized-locals/fnbox-compat.stderr +++ b/src/test/ui/unsized-locals/fnbox-compat.stderr @@ -1,27 +1,11 @@ -error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments - --> $DIR/fnbox-compat.rs:11:34 +error: implementation of `std::ops::FnOnce` is not general enough + --> $DIR/fnbox-compat.rs:6:5 | -LL | assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); - | ^^ - | | - | expected closure that takes 1 argument - | takes 0 arguments -help: consider changing the closure to take and ignore the expected argument +LL | f(&42) + | ^^^^^^ | -LL | assert_eq!(&call_it(Box::new(|_| s)) as &str, "hello"); - | ^^^ + = note: `std::ops::FnOnce<(&'0 i32,)>` would have to be implemented for the type `std::boxed::Box<(dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=T> + 'static)>`, for some specific lifetime `'0` + = note: but `std::ops::FnOnce<(&'1 i32,)>` is actually implemented for the type `std::boxed::Box<(dyn std::boxed::FnBox<(&'1 i32,), Output=T> + '_)>`, for some specific lifetime `'1` -error[E0277]: the size for values of type `dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=_>` cannot be known at compilation time - --> $DIR/fnbox-compat.rs:11:25 - | -LL | assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); - | ^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=_>` - = note: to learn more, visit - = note: required by `>::new` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0277, E0593. -For more information about an error, try `rustc --explain E0277`. From a38f29272ef4d04f0cc77e4f8d4fa5fac7ed746d Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 10 Feb 2019 19:25:56 +0900 Subject: [PATCH 10/16] We already have unsized_locals in stage0. --- src/liballoc/boxed.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 09554a1a34da8..864add1ecfe8e 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -694,7 +694,6 @@ impl ExactSizeIterator for Box { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} -#[cfg(not(stage0))] #[unstable(feature = "boxed_closure_impls", reason = "Box relies on unsized rvalues and needs to be tested more", issue = "48055")] @@ -706,7 +705,6 @@ impl + ?Sized> FnOnce for Box { } } -#[cfg(not(stage0))] #[unstable(feature = "boxed_closure_impls", reason = "Box relies on unsized rvalues and needs to be tested more", issue = "48055")] @@ -716,7 +714,6 @@ impl + ?Sized> FnMut for Box { } } -#[cfg(not(stage0))] #[unstable(feature = "boxed_closure_impls", reason = "Box relies on unsized rvalues and needs to be tested more", issue = "48055")] @@ -783,9 +780,6 @@ impl FnBox for F #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] impl FnOnce for Box + '_> { - #[cfg(stage0)] - type Output = R; - extern "rust-call" fn call_once(self, args: A) -> R { self.call_box(args) } @@ -794,9 +788,6 @@ impl FnOnce for Box + '_> { #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] impl FnOnce for Box + Send + '_> { - #[cfg(stage0)] - type Output = R; - extern "rust-call" fn call_once(self, args: A) -> R { self.call_box(args) } From 45c0b28bcb6e383cd9d24d3845ee8accda31c889 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 11 Feb 2019 10:34:24 +0900 Subject: [PATCH 11/16] Remove FnBox specialization of impl FnOnce for Box. --- src/liballoc/boxed.rs | 18 +----------------- src/test/ui/unsized-locals/fnbox-compat.rs | 13 ------------- src/test/ui/unsized-locals/fnbox-compat.stderr | 11 ----------- 3 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 src/test/ui/unsized-locals/fnbox-compat.rs delete mode 100644 src/test/ui/unsized-locals/fnbox-compat.stderr diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 864add1ecfe8e..d4fe8be36d6f5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -700,7 +700,7 @@ impl FusedIterator for Box {} impl + ?Sized> FnOnce for Box { type Output = >::Output; - default extern "rust-call" fn call_once(self, args: A) -> Self::Output { + extern "rust-call" fn call_once(self, args: A) -> Self::Output { >::call_once(*self, args) } } @@ -777,22 +777,6 @@ impl FnBox for F } } -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl FnOnce for Box + '_> { - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) - } -} - -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl FnOnce for Box + Send + '_> { - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) - } -} - #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/test/ui/unsized-locals/fnbox-compat.rs b/src/test/ui/unsized-locals/fnbox-compat.rs deleted file mode 100644 index c2c385e9fea56..0000000000000 --- a/src/test/ui/unsized-locals/fnbox-compat.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(fnbox)] - -use std::boxed::FnBox; - -fn call_it(f: Box T>) -> T { - f(&42) - //~^ERROR implementation of `std::ops::FnOnce` is not general enough -} - -fn main() { - let s = "hello".to_owned(); - assert_eq!(&call_it(Box::new(|_| s)) as &str, "hello"); -} diff --git a/src/test/ui/unsized-locals/fnbox-compat.stderr b/src/test/ui/unsized-locals/fnbox-compat.stderr deleted file mode 100644 index c37bfaa47f7eb..0000000000000 --- a/src/test/ui/unsized-locals/fnbox-compat.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: implementation of `std::ops::FnOnce` is not general enough - --> $DIR/fnbox-compat.rs:6:5 - | -LL | f(&42) - | ^^^^^^ - | - = note: `std::ops::FnOnce<(&'0 i32,)>` would have to be implemented for the type `std::boxed::Box<(dyn for<'r> std::boxed::FnBox<(&'r i32,), Output=T> + 'static)>`, for some specific lifetime `'0` - = note: but `std::ops::FnOnce<(&'1 i32,)>` is actually implemented for the type `std::boxed::Box<(dyn std::boxed::FnBox<(&'1 i32,), Output=T> + '_)>`, for some specific lifetime `'1` - -error: aborting due to previous error - From ecc3e89dd072ed20d9aa6d53be0ab1c44d160232 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Mon, 11 Feb 2019 11:09:26 +0900 Subject: [PATCH 12/16] Stabilize boxed_closure_impls in 1.35.0. --- .../library-features/boxed-closure-impls.md | 98 ------------------- src/liballoc/boxed.rs | 12 +-- .../run-pass/unsized-locals/box-fnonce.rs | 2 - 3 files changed, 3 insertions(+), 109 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/boxed-closure-impls.md diff --git a/src/doc/unstable-book/src/library-features/boxed-closure-impls.md b/src/doc/unstable-book/src/library-features/boxed-closure-impls.md deleted file mode 100644 index 5ceb54ff3b96e..0000000000000 --- a/src/doc/unstable-book/src/library-features/boxed-closure-impls.md +++ /dev/null @@ -1,98 +0,0 @@ -# `boxed_closure_impls` - -The tracking issue for this feature is [#48055] - -[#48055]: https://github.com/rust-lang/rust/issues/48055 - ------------------------- - -This includes the following blanket impls for closure traits: - -```rust,ignore -impl + ?Sized> FnOnce for Box { - // ... -} -impl + ?Sized> FnMut for Box { - // ... -} -impl + ?Sized> Fn for Box { - // ... -} -``` - -## Usage - -`Box` can be used almost transparently. You can even use `Box` now. - -```rust -#![feature(boxed_closure_impls)] - -fn main() { - let resource = "hello".to_owned(); - // Create a boxed once-callable closure - let f: Box = Box::new(|x| { - let s = resource; - println!("{}", x); - println!("{}", s); - }); - - // Call it - f(&42); -} -``` - -## The reason for instability - -This is unstable because of the first impl. - -It would have been easy if we're allowed to tighten the bound: - -```rust,ignore -impl + ?Sized> FnOnce for Box { - // ... -} -``` - -However, `Box` drops out of the modified impl. -To rescue this, we had had a temporary solution called [`fnbox`][fnbox]. - -[fnbox]: library-features/fnbox.html - -Unfortunately, due to minor coherence reasons, `fnbox` and -`FnOnce for Box` had not been able to coexist. -We had preferred `fnbox` for the time being. - -Now, as [`unsized_locals`][unsized_locals] is implemented, we can just write the -original impl: - -[unsized_locals]: language-features/unsized-locals.html - -```rust,ignore -impl + ?Sized> FnOnce for Box { - type Output = >::Output; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - // *self is an unsized rvalue - >::call_once(*self, args) - } -} -``` - -However, since `unsized_locals` is a very young feature, we're careful about -this `FnOnce` impl now. - -There's another reason for instability: for compatibility with `fnbox`, -we currently allow specialization of the `Box` impl: - -```rust,ignore -impl + ?Sized> FnOnce for Box { - type Output = >::Output; - - // we have "default" here - default extern "rust-call" fn call_once(self, args: A) -> Self::Output { - >::call_once(*self, args) - } -} -``` - -This isn't what we desire in the long term. diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d4fe8be36d6f5..f6dee7c9eefd6 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -694,9 +694,7 @@ impl ExactSizeIterator for Box { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} -#[unstable(feature = "boxed_closure_impls", - reason = "Box relies on unsized rvalues and needs to be tested more", - issue = "48055")] +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] impl + ?Sized> FnOnce for Box { type Output = >::Output; @@ -705,18 +703,14 @@ impl + ?Sized> FnOnce for Box { } } -#[unstable(feature = "boxed_closure_impls", - reason = "Box relies on unsized rvalues and needs to be tested more", - issue = "48055")] +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] impl + ?Sized> FnMut for Box { extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output { >::call_mut(self, args) } } -#[unstable(feature = "boxed_closure_impls", - reason = "Box relies on unsized rvalues and needs to be tested more", - issue = "48055")] +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] impl + ?Sized> Fn for Box { extern "rust-call" fn call(&self, args: A) -> Self::Output { >::call(self, args) diff --git a/src/test/run-pass/unsized-locals/box-fnonce.rs b/src/test/run-pass/unsized-locals/box-fnonce.rs index 97007a9423917..16bdeae4fad41 100644 --- a/src/test/run-pass/unsized-locals/box-fnonce.rs +++ b/src/test/run-pass/unsized-locals/box-fnonce.rs @@ -1,5 +1,3 @@ -#![feature(boxed_closure_impls)] - fn call_it(f: Box T>) -> T { f() } From 440e873a4739e7cb8f6aec0f675ca3796c336e60 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 11 Feb 2019 11:09:41 +0900 Subject: [PATCH 13/16] Simplify fnbox docs. --- .../src/library-features/fnbox.md | 250 ++---------------- 1 file changed, 15 insertions(+), 235 deletions(-) diff --git a/src/doc/unstable-book/src/library-features/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md index 3200601e557f6..16ebab3abeb50 100644 --- a/src/doc/unstable-book/src/library-features/fnbox.md +++ b/src/doc/unstable-book/src/library-features/fnbox.md @@ -6,247 +6,27 @@ The tracking issue for this feature is [#28796] ------------------------ -As an analogy to `&dyn Fn()` and `&mut dyn FnMut()`, you may have expected -`Box` to work. But it hadn't until the recent improvement! -`FnBox` had been a **temporary** solution for this until we are able to pass -trait objects by value. - -See [`boxed_closure_impls`][boxed_closure_impls] for the newer approach. - -[boxed_closure_impls]: library-features/boxed-closure-impls.html - -## Usage - -If you want to box `FnOnce` closures, you can use `Box` instead of `Box`. +This had been a temporary alternative to the following impls: ```rust -#![feature(fnbox)] - -use std::boxed::FnBox; - -fn main() { - let resource = "hello".to_owned(); - // Create a boxed once-callable closure - let f: Box String> = Box::new(|| resource); - - // Call it - let s = f(); - println!("{}", s); -} +impl FnOnce for Box where F: FnOnce + ?Sized {} +impl FnMut for Box where F: FnMut + ?Sized {} +impl Fn for Box where F: Fn + ?Sized {} ``` -## How `Box` did not work - -**Spoiler**: [`boxed_closure_impls`][boxed_closure_impls] actually implements -`Box`! This didn't work because we lacked features like -[`unsized_locals`][unsized_locals] for a long time. Therefore, this section -just explains historical reasons for `FnBox`. - -[unsized_locals]: language-features/unsized-locals.html - -### First approach: just provide `Box` adapter impl - -The first (and natural) attempt for `Box` would look like: - -```rust,ignore -impl + ?Sized> FnOnce for Box { - type Output = >::Output; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - >::call_once(*self, args) - } -} -``` - -However, this doesn't work. We have to relax the `Sized` bound for `F` because -we expect trait objects here, but `*self` must be `Sized` because it is passed -as a function argument. - -### The second attempt: add `FnOnce::call_box` - -One may come up with this workaround: modify `FnOnce`'s definition like this: - -```rust,ignore -pub trait FnOnce { - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - // Add this new method - extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; -} -``` - -...and then, modify the `impl` like this: - -```rust,ignore -impl + ?Sized> FnOnce for Box { - type Output = >::Output; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - // We can use `call_box` here! - >::call_box(self, args) - } - // We'll have to define this in every impl of `FnOnce`. - extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output { - >::call_box(*self, args) - } -} -``` - -What's wrong with this? The problem here is crates: - -- `FnOnce` is in `libcore`, as it shouldn't depend on allocations. -- `Box` is in `liballoc`, as it:s the very allocated pointer. - -It is impossible to add `FnOnce::call_box` because it is reverse-dependency. - -There's another problem: `call_box` can't have defaults. -`default impl` from the specialization RFC may resolve this problem. - -### The third attempt: add `FnBox` that contains `call_box` - -`call_box` can't reside in `FnOnce`, but how about defining a new trait in -`liballoc`? - -`FnBox` is almost a copy of `FnOnce`, but with `call_box`: - -```rust,ignore -pub trait FnBox { - type Output; - - extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; -} -``` - -For `Sized` types (from which we coerce into `dyn FnBox`), we define -the blanket impl that proxies calls to `FnOnce`: - -```rust,ignore -impl> FnBox for F { - type Output = >::Output; +The impls are parallel to these (relatively old) impls: - extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output { - // Here we assume `F` to be sized. - >::call_once(*self, args) - } -} -``` - -Now it looks like that we can define `FnOnce` for `Box`. - -```rust,ignore -impl + ?Sized> FnOnce for Box { - type Output = >::Output; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - >::call_box(self, args) - } -} -``` - -## Limitations of `FnBox` - -### Interaction with HRTB - -Firstly, the actual implementation is different from the one presented above. -Instead of implementing `FnOnce` for `Box`, `liballoc` only -implements `FnOnce` for `Box`. - -```rust,ignore -impl<'a, A, R> FnOnce for Box + 'a> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - FnBox::call_box(*self, args) - } -} - -// Sendable variant -impl<'a, A, R> FnOnce for Box + Send + 'a> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> Self::Output { - FnBox::call_box(*self, args) - } -} -``` - -The consequence is that the following example doesn't work: - -```rust,compile_fail -#![feature(fnbox)] - -use std::boxed::FnBox; - -fn main() { - let f: Box = Box::new(|x| println!("{}", x)); - f(42); -} -``` - -Note that `dyn FnBox(&i32)` desugars to -`dyn for<'r> FnBox<(&'r i32,), Output = ()>`. -It isn't covered in `dyn FnBox + 'a` or -`dyn FnBox + Send + 'a` due to HRTB. - -### Interaction with `Fn`/`FnMut` - -It would be natural to have the following impls: - -```rust,ignore -impl + ?Sized> FnMut for Box { - // ... -} -impl + ?Sized> Fn for Box { - // ... -} -``` - -However, we hadn't been able to write these in presense of `FnBox` -(until [`boxed_closure_impls`][boxed_closure_impls] lands). - -To have `FnMut` for `Box`, we should have (at least) this impl: - -```rust,ignore -// Note here we only impose `F: FnMut`. -// If we can write `F: FnOnce` here, that will resolve all problems. -impl + ?Sized> FnOnce for Box { - // ... -} -``` - -Unfortunately, the compiler complains that it **overlaps** with our -`dyn FnBox()` impls. At first glance, the overlap must not happen. -The `A` generic parameter does the trick here: due to coherence rules, -a downstream crate may define the following impl: - -```rust,ignore -struct MyStruct; -impl<'a> FnMut for dyn FnBox + 'a { - // ... -} +```rust +impl FnOnce for &mut F where F: FnMut + ?Sized {} +impl FnMut for &mut F where F: FnMut + ?Sized {} +impl Fn for &mut F where F: Fn + ?Sized {} +impl FnOnce for &F where F: Fn + ?Sized {} +impl FnMut for &F where F: Fn + ?Sized {} +impl Fn for &F where F: Fn + ?Sized {} ``` -The trait solver doesn't know that `A` is always a tuple type, so this is -still possible. With this in mind, the compiler emits the overlap error. - -## Modification - -For compatibility with [`boxed_closure_impls`][boxed_closure_impls], -we now have a slightly modified version of `FnBox`: +Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box` at that time. -```rust,ignore -// It's now a subtrait of `FnOnce` -pub trait FnBox: FnOnce { - // now uses FnOnce::Output - // type Output; - - extern "rust-call" fn call_box(self: Box, args: Args) -> Self::Output; -} -``` - -## The future of `fnbox` +[unsized_locals]: language-features/unsized-locals.html -`FnBox` has long been considered a temporary solution for `Box` -problem. Since we have [`boxed_closure_impls`][boxed_closure_impls] now, -it may be deprecated and removed in the future. +`FnBox()` is an alternative approach to `Box` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box` working, the `fnbox` feature is going to be removed. From 7a63c7f01050cd612787372f7a2ca7a8ec2105bc Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 11 Feb 2019 16:32:42 +0900 Subject: [PATCH 14/16] Add ignore to doc code --- src/doc/unstable-book/src/library-features/fnbox.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/library-features/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md index 16ebab3abeb50..cb3386b715211 100644 --- a/src/doc/unstable-book/src/library-features/fnbox.md +++ b/src/doc/unstable-book/src/library-features/fnbox.md @@ -8,7 +8,7 @@ The tracking issue for this feature is [#28796] This had been a temporary alternative to the following impls: -```rust +```rust,ignore impl FnOnce for Box where F: FnOnce + ?Sized {} impl FnMut for Box where F: FnMut + ?Sized {} impl Fn for Box where F: Fn + ?Sized {} @@ -16,7 +16,7 @@ impl Fn for Box where F: Fn + ?Sized {} The impls are parallel to these (relatively old) impls: -```rust +```rust,ignore impl FnOnce for &mut F where F: FnMut + ?Sized {} impl FnMut for &mut F where F: FnMut + ?Sized {} impl Fn for &mut F where F: Fn + ?Sized {} From 812d89c87d9346ac4b70426b67a8eb989a13c853 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Fri, 5 Apr 2019 12:06:29 +0800 Subject: [PATCH 15/16] Fix expectations on some ui test in nll compare mode. --- .../ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr index df74feb4f0564..223de36f0df31 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr @@ -11,13 +11,11 @@ error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | fn twice_ten_so i32>(f: Box) { - | - consider adding a `Copy` constraint to this type argument + | - move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -31,12 +29,12 @@ LL | f(f(10)); error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | +LL | fn twice_ten_oo(f: Box i32>) { + | - move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable --> $DIR/two-phase-nonrecv-autoref.rs:125:27 From a6e802ab4c84fb50b484fb12bbf397b889c70f77 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 5 Apr 2019 11:32:45 +0200 Subject: [PATCH 16/16] Add regression test for #59137. --- src/test/run-make-fulldeps/lto-dylib-dep/Makefile | 10 ++++++++++ src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs | 4 ++++ src/test/run-make-fulldeps/lto-dylib-dep/main.rs | 6 ++++++ 3 files changed, 20 insertions(+) create mode 100644 src/test/run-make-fulldeps/lto-dylib-dep/Makefile create mode 100644 src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs create mode 100644 src/test/run-make-fulldeps/lto-dylib-dep/main.rs diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/Makefile b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile new file mode 100644 index 0000000000000..ab8ee6c2ef7e1 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +# Test that we don't run into an assertion when using a Rust dylib dependency +# while compiling with full LTO. +# See https://github.com/rust-lang/rust/issues/59137 + +all: + $(RUSTC) a_dylib.rs --crate-type=dylib -C prefer-dynamic + $(RUSTC) main.rs -C lto + $(call RUN,main) diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs new file mode 100644 index 0000000000000..c5a35296f89ed --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs @@ -0,0 +1,4 @@ + +pub fn foo() { + println!("bar"); +} diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/main.rs b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs new file mode 100644 index 0000000000000..af0955e7f3520 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs @@ -0,0 +1,6 @@ + +extern crate a_dylib; + +fn main() { + a_dylib::foo(); +}