diff options
| -rw-r--r-- | src/bootstrap/tool.rs | 9 | ||||
| -rw-r--r-- | src/liballoc/boxed.rs | 18 | ||||
| -rw-r--r-- | src/libcore/task/context.rs | 92 | ||||
| -rw-r--r-- | src/libcore/task/executor.rs | 90 | ||||
| -rw-r--r-- | src/libcore/task/mod.rs | 32 | ||||
| -rw-r--r-- | src/libcore/task/poll.rs | 83 | ||||
| -rw-r--r-- | src/libcore/task/task.rs | 142 | ||||
| -rw-r--r-- | src/libcore/task/wake.rs (renamed from src/libcore/task.rs) | 294 | ||||
| -rw-r--r-- | src/librustc/lint/context.rs | 6 | ||||
| -rw-r--r-- | src/librustc/lint/mod.rs | 222 | ||||
| -rw-r--r-- | src/librustc_lint/lib.rs | 84 | ||||
| -rw-r--r-- | src/librustdoc/core.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 8 |
13 files changed, 641 insertions, 443 deletions
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 0c164d86332..0a428a61d12 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -273,7 +273,7 @@ macro_rules! tool { /// Whether this tool requires LLVM to run pub fn uses_llvm_tools(&self) -> bool { match self { - $(Tool::$name => true $(&& $llvm)*,)+ + $(Tool::$name => false $(|| $llvm)*,)+ } } } @@ -340,9 +340,6 @@ macro_rules! tool { } } -// FIXME(#51459): We have only checked that RustInstaller does not require -// the LLVM binaries when running. We should go through all tools to determine -// if they really need LLVM binaries, and make `llvm_tools` a required argument. tool!( Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolRustc; ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc; @@ -350,10 +347,10 @@ tool!( Tidy, "src/tools/tidy", "tidy", Mode::ToolStd; Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolStd; CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolStd; - Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTest; + Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTest, llvm_tools = true; BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolStd; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolStd; - RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolStd, llvm_tools = false; + RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolStd; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolStd; ); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ea60c7775af..6a05ef68088 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafeTask, TaskObj}; +use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj}; use core::convert::From; use raw_vec::RawVec; @@ -933,7 +933,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox<F> { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl<F: Future<Output = ()> + Send + 'static> UnsafeTask for PinBox<F> { +unsafe impl<F: Future<Output = ()> + 'static> UnsafeTask for PinBox<F> { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } @@ -962,3 +962,17 @@ impl<F: Future<Output = ()> + Send + 'static> From<Box<F>> for TaskObj { TaskObj::new(PinBox::from(boxed)) } } + +#[unstable(feature = "futures_api", issue = "50547")] +impl<F: Future<Output = ()> + 'static> From<PinBox<F>> for LocalTaskObj { + fn from(boxed: PinBox<F>) -> Self { + LocalTaskObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<F: Future<Output = ()> + 'static> From<Box<F>> for LocalTaskObj { + fn from(boxed: Box<F>) -> Self { + LocalTaskObj::new(PinBox::from(boxed)) + } +} diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs new file mode 100644 index 00000000000..c69d45248a5 --- /dev/null +++ b/src/libcore/task/context.rs @@ -0,0 +1,92 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use super::{Executor, Waker, LocalWaker}; + +/// Information about the currently-running task. +/// +/// Contexts are always tied to the stack, since they are set up specifically +/// when performing a single `poll` step on a task. +pub struct Context<'a> { + local_waker: &'a LocalWaker, + executor: &'a mut Executor, +} + +impl<'a> fmt::Debug for Context<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .finish() + } +} + +impl<'a> Context<'a> { + /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// Get the `LocalWaker` associated with the current task. + #[inline] + pub fn local_waker(&self) -> &'a LocalWaker { + self.local_waker + } + + /// Get the `Waker` associated with the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } + } + + /// Get the default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut Executor { + self.executor + } + + /// Produce a context like the current one, but using the given waker instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task, where you want to provide some customized + /// wakeup logic. + #[inline] + pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { + Context { + local_waker, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs new file mode 100644 index 00000000000..73bf80d2f99 --- /dev/null +++ b/src/libcore/task/executor.rs @@ -0,0 +1,90 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use super::{TaskObj, LocalTaskObj}; + +/// A task executor. +/// +/// A *task* is a `()`-producing async value that runs at the top level, and will +/// be `poll`ed until completion. It's also the unit at which wake-up +/// notifications occur. Executors, such as thread pools, allow tasks to be +/// spawned and are responsible for putting tasks onto ready queues when +/// they are woken up, and polling them when they are ready. +pub trait Executor { + /// Spawn the given task, polling it until completion. + /// + /// # Errors + /// + /// The executor may be unable to spawn tasks, either because it has + /// been shut down or is resource-constrained. + fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + + /// Determine whether the executor is able to spawn new tasks. + /// + /// # Returns + /// + /// An `Ok` return means the executor is *likely* (but not guaranteed) + /// to accept a subsequent spawn attempt. Likewise, an `Err` return + /// means that `spawn` is likely, but not guaranteed, to yield an error. + #[inline] + fn status(&self) -> Result<(), SpawnErrorKind> { + Ok(()) + } +} + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: TaskObj, +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnLocalObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: LocalTaskObj, +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs new file mode 100644 index 00000000000..d167a374105 --- /dev/null +++ b/src/libcore/task/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Types and Traits for working with asynchronous tasks. + +mod context; +pub use self::context::Context; + +mod executor; +pub use self::executor::{ + Executor, SpawnErrorKind, SpawnObjError, SpawnLocalObjError +}; + +mod poll; +pub use self::poll::Poll; + +mod task; +pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; + +mod wake; +pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs new file mode 100644 index 00000000000..10c954f0e80 --- /dev/null +++ b/src/libcore/task/poll.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +/// Indicates whether a value is available or if the current task has been +/// scheduled to receive a wakeup instead. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Poll<T> { + /// Represents that a value is immediately ready. + Ready(T), + + /// Represents that a value is not ready yet. + /// + /// When a function returns `Pending`, the function *must* also + /// ensure that the current task is scheduled to be awoken when + /// progress can be made. + Pending, +} + +impl<T> Poll<T> { + /// Change the ready value of this `Poll` with the closure provided + pub fn map<U, F>(self, f: F) -> Poll<U> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(t) => Poll::Ready(f(t)), + Poll::Pending => Poll::Pending, + } + } + + /// Returns whether this is `Poll::Ready` + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + pub fn is_pending(&self) -> bool { + !self.is_ready() + } +} + +impl<T, E> Poll<Result<T, E>> { + /// Change the success value of this `Poll` with the closure provided + pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + } + } + + /// Change the error value of this `Poll` with the closure provided + pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), + Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), + Poll::Pending => Poll::Pending, + } + } +} + +impl<T> From<T> for Poll<T> { + fn from(t: T) -> Poll<T> { + Poll::Ready(t) + } +} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs new file mode 100644 index 00000000000..c5a41873db4 --- /dev/null +++ b/src/libcore/task/task.rs @@ -0,0 +1,142 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use mem::PinMut; +use super::{Context, Poll}; + +/// A custom trait object for polling tasks, roughly akin to +/// `Box<Future<Output = ()>>`. +/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. +pub struct LocalTaskObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), +} + +impl LocalTaskObj { + /// Create a `LocalTaskObj` from a custom trait object representation. + #[inline] + pub fn new<T: UnsafeTask>(t: T) -> LocalTaskObj { + LocalTaskObj { + ptr: t.into_raw(), + poll_fn: T::poll, + drop_fn: T::drop, + } + } + + /// Converts the `LocalTaskObj` into a `TaskObj` + /// To make this operation safe one has to ensure that the `UnsafeTask` + /// instance from which this `LocalTaskObj` was created actually implements + /// `Send`. + pub unsafe fn as_task_obj(self) -> TaskObj { + TaskObj(self) + } +} + +impl fmt::Debug for LocalTaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalTaskObj") + .finish() + } +} + +impl From<TaskObj> for LocalTaskObj { + fn from(task: TaskObj) -> LocalTaskObj { + task.0 + } +} + +impl Future for LocalTaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for LocalTaskObj { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom trait object for polling tasks, roughly akin to +/// `Box<Future<Output = ()> + Send>`. +pub struct TaskObj(LocalTaskObj); + +unsafe impl Send for TaskObj {} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn new<T: UnsafeTask + Send>(t: T) -> TaskObj { + TaskObj(LocalTaskObj::new(t)) + } +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +impl Future for TaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + +/// A custom implementation of a task trait object for `TaskObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeTask: 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; + + /// Drops the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(task: *mut ()); +} diff --git a/src/libcore/task.rs b/src/libcore/task/wake.rs index 1a6018ffb65..4fd45be56fb 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task/wake.rs @@ -12,82 +12,8 @@ reason = "futures in libcore are unstable", issue = "50547")] -//! Types and Traits for working with asynchronous tasks. - use fmt; use ptr::NonNull; -use future::Future; -use mem::PinMut; - -/// Indicates whether a value is available or if the current task has been -/// scheduled to receive a wakeup instead. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum Poll<T> { - /// Represents that a value is immediately ready. - Ready(T), - - /// Represents that a value is not ready yet. - /// - /// When a function returns `Pending`, the function *must* also - /// ensure that the current task is scheduled to be awoken when - /// progress can be made. - Pending, -} - -impl<T> Poll<T> { - /// Change the ready value of this `Poll` with the closure provided - pub fn map<U, F>(self, f: F) -> Poll<U> - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(t) => Poll::Ready(f(t)), - Poll::Pending => Poll::Pending, - } - } - - /// Returns whether this is `Poll::Ready` - pub fn is_ready(&self) -> bool { - match *self { - Poll::Ready(_) => true, - Poll::Pending => false, - } - } - - /// Returns whether this is `Poll::Pending` - pub fn is_pending(&self) -> bool { - !self.is_ready() - } -} - -impl<T, E> Poll<Result<T, E>> { - /// Change the success value of this `Poll` with the closure provided - pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>> - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), - Poll::Ready(Err(e)) => Poll::Ready(Err(e)), - Poll::Pending => Poll::Pending, - } - } - - /// Change the error value of this `Poll` with the closure provided - pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>> - where F: FnOnce(E) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), - Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), - Poll::Pending => Poll::Pending, - } - } -} - -impl<T> From<T> for Poll<T> { - fn from(t: T) -> Poll<T> { - Poll::Ready(t) - } -} /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. @@ -347,223 +273,3 @@ pub unsafe trait UnsafeWake: Send + Sync { self.wake() } } - -/// Information about the currently-running task. -/// -/// Contexts are always tied to the stack, since they are set up specifically -/// when performing a single `poll` step on a task. -pub struct Context<'a> { - local_waker: &'a LocalWaker, - executor: &'a mut Executor, -} - -impl<'a> fmt::Debug for Context<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Context") - .finish() - } -} - -impl<'a> Context<'a> { - /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. - #[inline] - pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { - Context { - local_waker, - executor, - } - } - - /// Get the `LocalWaker` associated with the current task. - #[inline] - pub fn local_waker(&self) -> &'a LocalWaker { - self.local_waker - } - - /// Get the `Waker` associated with the current task. - #[inline] - pub fn waker(&self) -> &'a Waker { - unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } - } - - /// Get the default executor associated with this task. - /// - /// This method is useful primarily if you want to explicitly handle - /// spawn failures. - #[inline] - pub fn executor(&mut self) -> &mut Executor { - self.executor - } - - /// Produce a context like the current one, but using the given waker instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task, where you want to provide some customized - /// wakeup logic. - #[inline] - pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { - Context { - local_waker, - executor: self.executor, - } - } - - /// Produce a context like the current one, but using the given executor - /// instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task. - #[inline] - pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> - where E: Executor - { - Context { - local_waker: self.local_waker, - executor: executor, - } - } -} - -/// A task executor. -/// -/// A *task* is a `()`-producing async value that runs at the top level, and will -/// be `poll`ed until completion. It's also the unit at which wake-up -/// notifications occur. Executors, such as thread pools, allow tasks to be -/// spawned and are responsible for putting tasks onto ready queues when -/// they are woken up, and polling them when they are ready. -pub trait Executor { - /// Spawn the given task, polling it until completion. - /// - /// # Errors - /// - /// The executor may be unable to spawn tasks, either because it has - /// been shut down or is resource-constrained. - fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; - - /// Determine whether the executor is able to spawn new tasks. - /// - /// # Returns - /// - /// An `Ok` return means the executor is *likely* (but not guaranteed) - /// to accept a subsequent spawn attempt. Likewise, an `Err` return - /// means that `spawn` is likely, but not guaranteed, to yield an error. - #[inline] - fn status(&self) -> Result<(), SpawnErrorKind> { - Ok(()) - } -} - -/// A custom trait object for polling tasks, roughly akin to -/// `Box<Future<Output = ()> + Send>`. -pub struct TaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -unsafe impl Send for TaskObj {} - -/// A custom implementation of a task trait object for `TaskObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// The implementor must guarantee that it is safe to call `poll` repeatedly (in -/// a non-concurrent fashion) with the result of `into_raw` until `drop` is -/// called. -pub unsafe trait UnsafeTask: Send + 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to repeatedly call - /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; - - /// Drops the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(task: *mut ()); -} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new<T: UnsafeTask>(t: T) -> TaskObj { - TaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for TaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// Provides the reason that an executor was unable to spawn. -pub struct SpawnErrorKind { - _hidden: (), -} - -impl fmt::Debug for SpawnErrorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("SpawnErrorKind") - .field(&"shutdown") - .finish() - } -} - -impl SpawnErrorKind { - /// Spawning is failing because the executor has been shut down. - pub fn shutdown() -> SpawnErrorKind { - SpawnErrorKind { _hidden: () } - } - - /// Check whether this error is the `shutdown` error. - pub fn is_shutdown(&self) -> bool { - true - } -} - -/// The result of a failed spawn -#[derive(Debug)] -pub struct SpawnObjError { - /// The kind of error - pub kind: SpawnErrorKind, - - /// The task for which spawning was attempted - pub task: TaskObj, -} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 824930a7eb0..c9874f510f7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -178,10 +178,10 @@ impl LintStore { sess: Option<&Session>, from_plugin: bool, pass: &Box<P>) { - for &lint in pass.get_lints() { - self.lints.push((*lint, from_plugin)); + for lint in pass.get_lints() { + self.lints.push((lint, from_plugin)); - let id = LintId::of(*lint); + let id = LintId::of(lint); if self.by_name.insert(lint.name_lower(), Id(id)).is_some() { let msg = format!("duplicate specification of lint {}", lint.name_lower()); match (sess, from_plugin) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 9338e235c53..bff596e21e5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, Lrc}; use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; -use hir::intravisit::{self, FnKind}; +use hir::intravisit; use hir; use lint::builtin::BuiltinLintDiagnostics; use session::{Session, DiagnosticMessageId}; @@ -123,12 +123,11 @@ macro_rules! declare_lint { #[macro_export] macro_rules! lint_array { ($( $lint:expr ),* $(,)?) => {{ - static ARRAY: LintArray = &[ $( &$lint ),* ]; - ARRAY + vec![$($lint),*] }} } -pub type LintArray = &'static [&'static &'static Lint]; +pub type LintArray = Vec<&'static Lint>; pub trait LintPass { /// Get descriptions of the lints this `LintPass` object can emit. @@ -140,6 +139,80 @@ pub trait LintPass { fn get_lints(&self) -> LintArray; } +#[macro_export] +macro_rules! late_lint_methods { + ($macro:path, $args:tt, [$hir:tt]) => ( + $macro!($args, [$hir], [ + fn check_body(a: &$hir hir::Body); + fn check_body_post(a: &$hir hir::Body); + fn check_name(a: Span, b: ast::Name); + fn check_crate(a: &$hir hir::Crate); + fn check_crate_post(a: &$hir hir::Crate); + fn check_mod(a: &$hir hir::Mod, b: Span, c: ast::NodeId); + fn check_mod_post(a: &$hir hir::Mod, b: Span, c: ast::NodeId); + fn check_foreign_item(a: &$hir hir::ForeignItem); + fn check_foreign_item_post(a: &$hir hir::ForeignItem); + fn check_item(a: &$hir hir::Item); + fn check_item_post(a: &$hir hir::Item); + fn check_local(a: &$hir hir::Local); + fn check_block(a: &$hir hir::Block); + fn check_block_post(a: &$hir hir::Block); + fn check_stmt(a: &$hir hir::Stmt); + fn check_arm(a: &$hir hir::Arm); + fn check_pat(a: &$hir hir::Pat); + fn check_decl(a: &$hir hir::Decl); + fn check_expr(a: &$hir hir::Expr); + fn check_expr_post(a: &$hir hir::Expr); + fn check_ty(a: &$hir hir::Ty); + fn check_generic_param(a: &$hir hir::GenericParam); + fn check_generics(a: &$hir hir::Generics); + fn check_where_predicate(a: &$hir hir::WherePredicate); + fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef, b: hir::TraitBoundModifier); + fn check_fn( + a: hir::intravisit::FnKind<$hir>, + b: &$hir hir::FnDecl, + c: &$hir hir::Body, + d: Span, + e: ast::NodeId); + fn check_fn_post( + a: hir::intravisit::FnKind<$hir>, + b: &$hir hir::FnDecl, + c: &$hir hir::Body, + d: Span, + e: ast::NodeId + ); + fn check_trait_item(a: &$hir hir::TraitItem); + fn check_trait_item_post(a: &$hir hir::TraitItem); + fn check_impl_item(a: &$hir hir::ImplItem); + fn check_impl_item_post(a: &$hir hir::ImplItem); + fn check_struct_def( + a: &$hir hir::VariantData, + b: ast::Name, + c: &$hir hir::Generics, + d: ast::NodeId + ); + fn check_struct_def_post( + a: &$hir hir::VariantData, + b: ast::Name, + c: &$hir hir::Generics, + d: ast::NodeId + ); + fn check_struct_field(a: &$hir hir::StructField); + fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_lifetime(a: &$hir hir::Lifetime); + fn check_path(a: &$hir hir::Path, b: ast::NodeId); + fn check_attribute(a: &$hir ast::Attribute); + + /// Called when entering a syntax node that can have lint attributes such + /// as `#[allow(...)]`. Called with *all* the attributes of that node. + fn enter_lint_attrs(a: &$hir [ast::Attribute]); + + /// Counterpart to `enter_lint_attrs`. + fn exit_lint_attrs(a: &$hir [ast::Attribute]); + ]); + ) +} /// Trait for types providing lint checks. /// @@ -149,90 +222,67 @@ pub trait LintPass { // // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. -pub trait LateLintPass<'a, 'tcx>: LintPass { - fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { } - fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { } - fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } - fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } - fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } - fn check_mod(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_mod_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_foreign_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } - fn check_foreign_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } - fn check_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } - fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } - fn check_local(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Local) { } - fn check_block(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } - fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } - fn check_stmt(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { } - fn check_arm(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { } - fn check_pat(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { } - fn check_decl(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { } - fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } - fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } - fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } - fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { } - fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { } - fn check_where_predicate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::WherePredicate) { } - fn check_poly_trait_ref(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::PolyTraitRef, - _: hir::TraitBoundModifier) { } - fn check_fn(&mut self, - _: &LateContext<'a, 'tcx>, - _: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Body, - _: Span, - _: ast::NodeId) { } - fn check_fn_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Body, - _: Span, - _: ast::NodeId) { } - fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } - fn check_trait_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } - fn check_impl_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } - fn check_impl_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } - fn check_struct_def(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - _: ast::NodeId) { } - fn check_struct_def_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - _: ast::NodeId) { } - fn check_struct_field(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::StructField) { } - fn check_variant(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_variant_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { } - fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { } - fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { } - /// Called when entering a syntax node that can have lint attributes such - /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } +macro_rules! expand_lint_pass_methods { + ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(#[inline(always)] fn $name(&mut self, $context, $(_: $arg),*) {})* + ) +} - /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } +macro_rules! declare_late_lint_pass { + ([], [$hir:tt], [$($methods:tt)*]) => ( + pub trait LateLintPass<'a, $hir>: LintPass { + expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]); + } + ) +} + +late_lint_methods!(declare_late_lint_pass, [], ['tcx]); + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_method { + ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({ + $($self.$passes.$name $params;)* + }) +} + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_methods { + ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(fn $name(&mut self, context: &LateContext<'a, 'tcx>, $($param: $arg),*) { + expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*)); + })* + ) +} + +#[macro_export] +macro_rules! declare_combined_late_lint_pass { + ([$name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => ( + #[allow(non_snake_case)] + struct $name { + $($passes: $passes,)* + } + + impl $name { + fn new() -> Self { + Self { + $($passes: $constructor,)* + } + } + } + + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name { + expand_combined_late_lint_pass_methods!([$($passes),*], $methods); + } + + impl LintPass for $name { + fn get_lints(&self) -> LintArray { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&self.$passes.get_lints());)* + lints + } + } + ) } pub trait EarlyLintPass: LintPass { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ba373b5c0e8..13e97a9d3e5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -41,9 +41,14 @@ extern crate rustc_target; extern crate syntax_pos; use rustc::lint; +use rustc::lint::{LateContext, LateLintPass, LintPass, LintArray}; use rustc::lint::builtin::{BARE_TRAIT_OBJECTS, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE}; use rustc::session; use rustc::util; +use rustc::hir; + +use syntax::ast; +use syntax_pos::Span; use session::Session; use syntax::edition::Edition; @@ -67,14 +72,6 @@ pub use builtin::SoftLints; /// defined in this crate and the ones defined in /// `rustc::lint::builtin`). pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { - macro_rules! add_builtin { - ($sess:ident, $($name:ident),*,) => ( - {$( - store.register_late_pass($sess, false, box $name); - )*} - ) - } - macro_rules! add_early_builtin { ($sess:ident, $($name:ident),*,) => ( {$( @@ -83,14 +80,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ) } - macro_rules! add_builtin_with_new { - ($sess:ident, $($name:ident),*,) => ( - {$( - store.register_late_pass($sess, false, box $name::new()); - )*} - ) - } - macro_rules! add_early_builtin_with_new { ($sess:ident, $($name:ident),*,) => ( {$( @@ -118,39 +107,38 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { DeprecatedAttr, ); - add_builtin!(sess, - HardwiredLints, - WhileTrue, - ImproperCTypes, - VariantSizeDifferences, - BoxPointers, - UnusedAttributes, - PathStatements, - UnusedResults, - NonCamelCaseTypes, - NonSnakeCase, - NonUpperCaseGlobals, - NonShorthandFieldPatterns, - UnsafeCode, - UnusedAllocation, - MissingCopyImplementations, - UnstableFeatures, - UnconditionalRecursion, - InvalidNoMangleItems, - PluginAsLibrary, - MutableTransmutes, - UnionsWithDropFields, - UnreachablePub, - TypeAliasBounds, - UnusedBrokenConst, - TrivialConstraints, - ); + late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ + HardwiredLints: HardwiredLints, + WhileTrue: WhileTrue, + ImproperCTypes: ImproperCTypes, + VariantSizeDifferences: VariantSizeDifferences, + BoxPointers: BoxPointers, + UnusedAttributes: UnusedAttributes, + PathStatements: PathStatements, + UnusedResults: UnusedResults, + NonCamelCaseTypes: NonCamelCaseTypes, + NonSnakeCase: NonSnakeCase, + NonUpperCaseGlobals: NonUpperCaseGlobals, + NonShorthandFieldPatterns: NonShorthandFieldPatterns, + UnsafeCode: UnsafeCode, + UnusedAllocation: UnusedAllocation, + MissingCopyImplementations: MissingCopyImplementations, + UnstableFeatures: UnstableFeatures, + UnconditionalRecursion: UnconditionalRecursion, + InvalidNoMangleItems: InvalidNoMangleItems, + PluginAsLibrary: PluginAsLibrary, + MutableTransmutes: MutableTransmutes, + UnionsWithDropFields: UnionsWithDropFields, + UnreachablePub: UnreachablePub, + TypeAliasBounds: TypeAliasBounds, + UnusedBrokenConst: UnusedBrokenConst, + TrivialConstraints: TrivialConstraints, + TypeLimits: TypeLimits::new(), + MissingDoc: MissingDoc::new(), + MissingDebugImplementations: MissingDebugImplementations::new(), + ]], ['tcx]); - add_builtin_with_new!(sess, - TypeLimits, - MissingDoc, - MissingDebugImplementations, - ); + store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new()); add_lint_group!(sess, "bad_style", diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 53ebb3a12f5..ddc9bdb384c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -190,8 +190,8 @@ pub fn run_core(search_paths: SearchPaths, let intra_link_resolution_failure_name = lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE.name; let warnings_lint_name = lint::builtin::WARNINGS.name; let lints = lint::builtin::HardwiredLints.get_lints() - .iter() - .chain(rustc_lint::SoftLints.get_lints()) + .into_iter() + .chain(rustc_lint::SoftLints.get_lints().into_iter()) .filter_map(|lint| { if lint.name == warnings_lint_name || lint.name == intra_link_resolution_failure_name { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 566e2f1ed49..284406589b3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -103,10 +103,14 @@ struct Output { } pub fn main() { - const STACK_SIZE: usize = 32_000_000; // 32MB + let thread_stack_size: usize = if cfg!(target_os = "haiku") { + 16_000_000 // 16MB on Haiku + } else { + 32_000_000 // 32MB on other platforms + }; rustc_driver::set_sigpipe_handler(); env_logger::init(); - let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { + let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { syntax::with_globals(move || { get_args().map(|args| main_args(&args)).unwrap_or(1) }) |
