about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/tool.rs9
-rw-r--r--src/liballoc/boxed.rs18
-rw-r--r--src/libcore/task/context.rs92
-rw-r--r--src/libcore/task/executor.rs90
-rw-r--r--src/libcore/task/mod.rs32
-rw-r--r--src/libcore/task/poll.rs83
-rw-r--r--src/libcore/task/task.rs142
-rw-r--r--src/libcore/task/wake.rs (renamed from src/libcore/task.rs)294
-rw-r--r--src/librustc/lint/context.rs6
-rw-r--r--src/librustc/lint/mod.rs222
-rw-r--r--src/librustc_lint/lib.rs84
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/lib.rs8
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)
         })