From 8b8488ce8fc047282e7159343f30609417f9fa39 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio <jorge@japaric.io>
Date: Sun, 24 Mar 2019 17:49:49 +0100
Subject: [PATCH 01/20] bootstrap: build compiler-builtins with -Z
 emit-stack-sizes

---
 src/bootstrap/bin/rustc.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index ca86aeb8100a9..6f68775a85fd3 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -181,6 +181,30 @@ fn main() {
             cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
         }
 
+        // Build `compiler_builtins` with `-Z emit-stack-sizes` to add stack usage information.
+        //
+        // When you use this flag with Cargo you get stack usage information on all crates compiled
+        // from source, and when you are using LTO you also get information on pre-compiled crates
+        // like `core` and `std`. However, there's an exception: `compiler_builtins`. This crate
+        // is special and doesn't participate in LTO because it's always linked as a separate object
+        // file. Due to this it's impossible to get information about this crate using `RUSTFLAGS`
+        // + Cargo, or `cargo rustc`.
+        //
+        // To make the stack usage information of this crate available to Cargo based stack usage
+        // analysis tools we compile `compiler_builtins` with the `-Z emit-stack-sizes` flag. The
+        // flag is known to currently work with targets that produce ELF files so we limit the use
+        // of the flag to those targets.
+        //
+        // NOTE(japaric) if this ever causes problem with an LLVM upgrade or any PR feel free to
+        // remove it or comment it out
+        if crate_name == "compiler_builtins"
+            && (target.contains("-linux-")
+                || target.contains("-none-eabi")
+                || target.ends_with("-none-elf"))
+        {
+            cmd.arg("-Z").arg("emit-stack-sizes");
+        }
+
         if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
             cmd.arg("-C").arg(format!("codegen-units={}", s));
         }

From 7d365cf27f4249fc9b61ba8abfc813abe43f1cb7 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio <jorge@japaric.io>
Date: Mon, 25 Mar 2019 22:50:07 +0100
Subject: [PATCH 02/20] compile all crates under test w/ -Zemit-stack-sizes

---
 src/bootstrap/bin/rustc.rs | 29 ++++++++++++++++-------------
 src/bootstrap/compile.rs   |  4 ++++
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 6f68775a85fd3..28c8a75a13ab4 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -181,28 +181,31 @@ fn main() {
             cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
         }
 
-        // Build `compiler_builtins` with `-Z emit-stack-sizes` to add stack usage information.
+        // Build all crates in the `std` facade with `-Z emit-stack-sizes` to add stack usage
+        // information.
         //
-        // When you use this flag with Cargo you get stack usage information on all crates compiled
-        // from source, and when you are using LTO you also get information on pre-compiled crates
-        // like `core` and `std`. However, there's an exception: `compiler_builtins`. This crate
-        // is special and doesn't participate in LTO because it's always linked as a separate object
-        // file. Due to this it's impossible to get information about this crate using `RUSTFLAGS`
-        // + Cargo, or `cargo rustc`.
+        // When you use this `-Z` flag with Cargo you get stack usage information on all crates
+        // compiled from source, and when you are using LTO you also get information on pre-compiled
+        // crates like `core` and `std`, even if they were not compiled with `-Z emit-stack-sizes`.
+        // However, there's an exception: `compiler_builtins`. This crate is special and doesn't
+        // participate in LTO because it's always linked as a separate object file. For this reason
+        // it's impossible to get stack usage information about `compiler-builtins` using
+        // `RUSTFLAGS` + Cargo, or `cargo rustc`.
         //
-        // To make the stack usage information of this crate available to Cargo based stack usage
-        // analysis tools we compile `compiler_builtins` with the `-Z emit-stack-sizes` flag. The
-        // flag is known to currently work with targets that produce ELF files so we limit the use
-        // of the flag to those targets.
+        // To make the stack usage information of all crates under the `std` facade available to
+        // Cargo based stack usage analysis tools, in both LTO and non-LTO mode, we compile them
+        // with the `-Z emit-stack-sizes` flag. The `RUSTC_EMIT_STACK_SIZES` var helps us apply this
+        // flag only to the crates in the `std` facade. The `-Z` flag is known to currently work
+        // with targets that produce ELF files so we limit its use flag to those targets.
         //
         // NOTE(japaric) if this ever causes problem with an LLVM upgrade or any PR feel free to
         // remove it or comment it out
-        if crate_name == "compiler_builtins"
+        if env::var_os("RUSTC_EMIT_STACK_SIZES").is_some()
             && (target.contains("-linux-")
                 || target.contains("-none-eabi")
                 || target.ends_with("-none-elf"))
         {
-            cmd.arg("-Z").arg("emit-stack-sizes");
+            cmd.arg("-Zemit-stack-sizes");
         }
 
         if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 9498dbb595232..0d51d7c5ef3b8 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -97,6 +97,8 @@ impl Step for Std {
         let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
         builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage,
                 &compiler.host, target));
+        // compile with `-Z emit-stack-sizes`; see bootstrap/src/rustc.rs for more details
+        cargo.env("RUSTC_EMIT_STACK_SIZES", "1");
         run_cargo(builder,
                   &mut cargo,
                   &libstd_stamp(builder, compiler, target),
@@ -382,6 +384,8 @@ impl Step for Test {
         let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
         builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage,
                 &compiler.host, target));
+        // compile with `-Z emit-stack-sizes`; see bootstrap/src/rustc.rs for more details
+        cargo.env("RUSTC_EMIT_STACK_SIZES", "1");
         run_cargo(builder,
                   &mut cargo,
                   &libtest_stamp(builder, compiler, target),

From c764890d7c508b401764c79bde9c0f3c430138e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= <matti@marinelayer.io>
Date: Wed, 27 Mar 2019 18:37:21 +0100
Subject: [PATCH 03/20] musl: build toolchain libs with -fPIC

---
 src/ci/docker/scripts/musl-toolchain.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh
index 95b7c2869c91f..3caf2852ede42 100644
--- a/src/ci/docker/scripts/musl-toolchain.sh
+++ b/src/ci/docker/scripts/musl-toolchain.sh
@@ -29,6 +29,10 @@ TARGET=$ARCH-linux-musl
 OUTPUT=/usr/local
 shift
 
+# Ancient binutils versions don't understand debug symbols produced by more recent tools.
+# Apparently applying `-fPIC` everywhere allows them to link successfully.
+export CFLAGS="-fPIC $CFLAGS"
+
 git clone https://github.com/richfelker/musl-cross-make -b v0.9.7
 cd musl-cross-make
 

From c6e3ea475b9378fd551064e7b4e74ee96855337f Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Mon, 25 Mar 2019 23:37:00 +0000
Subject: [PATCH 04/20] Visit path in `walk_mac`

---
 src/libsyntax/visit.rs                | 4 ++--
 src/libsyntax_ext/proc_macro_decls.rs | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6b3a30ccb54b7..fbd6641f7c20e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -647,8 +647,8 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
     }
 }
 
-pub fn walk_mac<'a, V: Visitor<'a>>(_: &mut V, _: &Mac) {
-    // Empty!
+pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a Mac) {
+    visitor.visit_path(&mac.node.path, DUMMY_NODE_ID);
 }
 
 pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) {
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index d5f37aff222ef..22fee902aea26 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -317,7 +317,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         self.in_root = prev_in_root;
     }
 
-    fn visit_mac(&mut self, mac: &ast::Mac) {
+    fn visit_mac(&mut self, mac: &'a ast::Mac) {
         visit::walk_mac(self, mac)
     }
 }

From 41316f0449025394fdca6606d3fdb3b8f37a9872 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 31 Jan 2019 01:36:11 +0100
Subject: [PATCH 05/20] Combine all builtin late lints

---
 src/librustc/lint/context.rs     | 383 +++++++++++++++++++------------
 src/librustc/lint/mod.rs         |  11 +-
 src/librustc_interface/passes.rs |   7 +-
 src/librustc_lint/lib.rs         | 185 +++++++++------
 4 files changed, 362 insertions(+), 224 deletions(-)

diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 953d0116aa2ba..e0bd795c342eb 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -18,7 +18,7 @@ use self::TargetLint::*;
 
 use std::slice;
 use rustc_data_structures::sync::ReadGuard;
-use crate::lint::{EarlyLintPass, EarlyLintPassObject, LateLintPassObject};
+use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
 use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer};
 use crate::lint::builtin::BuiltinLintDiagnostics;
 use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
@@ -27,7 +27,6 @@ use crate::rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use crate::session::{config, early_error, Session};
 use crate::ty::{self, TyCtxt, Ty};
 use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
-use crate::ty::query::Providers;
 use crate::util::nodemap::FxHashMap;
 use crate::util::common::time;
 
@@ -203,13 +202,16 @@ impl LintStore {
     pub fn register_late_pass(&mut self,
                               sess: Option<&Session>,
                               from_plugin: bool,
+                              register_only: bool,
                               per_module: bool,
                               pass: LateLintPassObject) {
         self.push_pass(sess, from_plugin, &pass);
-        if per_module {
-            self.late_module_passes.as_mut().unwrap().push(pass);
-        } else {
-            self.late_passes.as_mut().unwrap().push(pass);
+        if !register_only {
+            if per_module {
+                self.late_module_passes.as_mut().unwrap().push(pass);
+            } else {
+                self.late_passes.as_mut().unwrap().push(pass);
+            }
         }
     }
 
@@ -538,6 +540,11 @@ pub struct LateContext<'a, 'tcx: 'a> {
     only_module: bool,
 }
 
+pub struct LateContextAndPass<'a, 'tcx: 'a, T: LateLintPass<'a, 'tcx>> {
+    context: LateContext<'a, 'tcx>,
+    pass: T,
+}
+
 /// Context for lint checking of the AST, after expansion, before lowering to
 /// HIR.
 pub struct EarlyContext<'a> {
@@ -560,17 +567,6 @@ pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     pass: T,
 }
 
-/// Convenience macro for calling a `LintPass` method on every pass in the context.
-macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
-    // Move the vector of passes out of `$cx` so that we can
-    // iterate over it mutably while passing `$cx` to the methods.
-    let mut passes = $cx.lint_sess_mut().passes.take().unwrap();
-    for obj in &mut passes {
-        obj.$f($cx, $($args),*);
-    }
-    $cx.lint_sess_mut().passes = Some(passes);
-}) }
-
 pub trait LintPassObject: Sized {}
 
 impl LintPassObject for EarlyLintPassObject {}
@@ -668,6 +664,10 @@ impl<'a> EarlyContext<'a> {
     }
 }
 
+macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
+    $cx.pass.$f(&$cx.context, $($args),*);
+}) }
+
 macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
@@ -778,6 +778,21 @@ impl<'a> LintContext<'a> for EarlyContext<'a> {
 }
 
 impl<'a, 'tcx> LateContext<'a, 'tcx> {
+    pub fn current_lint_root(&self) -> hir::HirId {
+        self.last_node_with_lint_attrs
+    }
+}
+
+impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
+    type Ty = Ty<'tcx>;
+    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
+
+    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.tcx.layout_of(self.param_env.and(ty))
+    }
+}
+
+impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
     /// Merge the lints specified by any lint attributes into the
     /// current lint context, call the provided function, then reset the
     /// lints in effect to their previous state.
@@ -787,107 +802,98 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
                           f: F)
         where F: FnOnce(&mut Self)
     {
-        let prev = self.last_node_with_lint_attrs;
-        self.last_node_with_lint_attrs = id;
+        let prev = self.context.last_node_with_lint_attrs;
+        self.context.last_node_with_lint_attrs = id;
         self.enter_attrs(attrs);
         f(self);
         self.exit_attrs(attrs);
-        self.last_node_with_lint_attrs = prev;
-    }
-
-    fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
-        debug!("late context: enter_attrs({:?})", attrs);
-        run_lints!(self, enter_lint_attrs, attrs);
-    }
-
-    fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
-        debug!("late context: exit_attrs({:?})", attrs);
-        run_lints!(self, exit_lint_attrs, attrs);
+        self.context.last_node_with_lint_attrs = prev;
     }
 
     fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
         where F: FnOnce(&mut Self),
     {
-        let old_param_env = self.param_env;
-        self.param_env = self.tcx.param_env(self.tcx.hir().local_def_id_from_hir_id(id));
+        let old_param_env = self.context.param_env;
+        self.context.param_env = self.context.tcx.param_env(
+            self.context.tcx.hir().local_def_id_from_hir_id(id)
+        );
         f(self);
-        self.param_env = old_param_env;
-    }
-    pub fn current_lint_root(&self) -> hir::HirId {
-        self.last_node_with_lint_attrs
+        self.context.param_env = old_param_env;
     }
 
     fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
-        run_lints!(self, check_mod, m, s, n);
+        lint_callback!(self, check_mod, m, s, n);
         hir_visit::walk_mod(self, m, n);
-        run_lints!(self, check_mod_post, m, s, n);
+        lint_callback!(self, check_mod_post, m, s, n);
     }
-}
 
-impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
+    fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
+        debug!("late context: enter_attrs({:?})", attrs);
+        lint_callback!(self, enter_lint_attrs, attrs);
+    }
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
+    fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
+        debug!("late context: exit_attrs({:?})", attrs);
+        lint_callback!(self, exit_lint_attrs, attrs);
     }
 }
 
-impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
+impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
+for LateContextAndPass<'a, 'tcx, T> {
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
     fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
-        hir_visit::NestedVisitorMap::All(&self.tcx.hir())
+        hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_tables = self.tables;
-        self.tables = self.tcx.body_tables(body);
-        let body = self.tcx.hir().body(body);
+        let old_tables = self.context.tables;
+        self.context.tables = self.context.tcx.body_tables(body);
+        let body = self.context.tcx.hir().body(body);
         self.visit_body(body);
-        self.tables = old_tables;
+        self.context.tables = old_tables;
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body) {
-        run_lints!(self, check_body, body);
+        lint_callback!(self, check_body, body);
         hir_visit::walk_body(self, body);
-        run_lints!(self, check_body_post, body);
+        lint_callback!(self, check_body_post, body);
     }
 
     fn visit_item(&mut self, it: &'tcx hir::Item) {
-        let generics = self.generics.take();
-        self.generics = it.node.generics();
+        let generics = self.context.generics.take();
+        self.context.generics = it.node.generics();
         self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
             cx.with_param_env(it.hir_id, |cx| {
-                run_lints!(cx, check_item, it);
+                lint_callback!(cx, check_item, it);
                 hir_visit::walk_item(cx, it);
-                run_lints!(cx, check_item_post, it);
+                lint_callback!(cx, check_item_post, it);
             });
         });
-        self.generics = generics;
+        self.context.generics = generics;
     }
 
     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
         self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
             cx.with_param_env(it.hir_id, |cx| {
-                run_lints!(cx, check_foreign_item, it);
+                lint_callback!(cx, check_foreign_item, it);
                 hir_visit::walk_foreign_item(cx, it);
-                run_lints!(cx, check_foreign_item_post, it);
+                lint_callback!(cx, check_foreign_item_post, it);
             });
         })
     }
 
     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
-        run_lints!(self, check_pat, p);
+        lint_callback!(self, check_pat, p);
         hir_visit::walk_pat(self, p);
     }
 
     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
         self.with_lint_attrs(e.hir_id, &e.attrs, |cx| {
-            run_lints!(cx, check_expr, e);
+            lint_callback!(cx, check_expr, e);
             hir_visit::walk_expr(cx, e);
-            run_lints!(cx, check_expr_post, e);
+            lint_callback!(cx, check_expr_post, e);
         })
     }
 
@@ -897,7 +903,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         // - local
         // - expression
         // so we keep track of lint levels there
-        run_lints!(self, check_stmt, s);
+        lint_callback!(self, check_stmt, s);
         hir_visit::walk_stmt(self, s);
     }
 
@@ -905,13 +911,13 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
                 body_id: hir::BodyId, span: Span, id: hir::HirId) {
         // Wrap in tables here, not just in visit_nested_body,
         // in order for `check_fn` to be able to use them.
-        let old_tables = self.tables;
-        self.tables = self.tcx.body_tables(body_id);
-        let body = self.tcx.hir().body(body_id);
-        run_lints!(self, check_fn, fk, decl, body, span, id);
+        let old_tables = self.context.tables;
+        self.context.tables = self.context.tcx.body_tables(body_id);
+        let body = self.context.tcx.hir().body(body_id);
+        lint_callback!(self, check_fn, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
-        run_lints!(self, check_fn_post, fk, decl, body, span, id);
-        self.tables = old_tables;
+        lint_callback!(self, check_fn_post, fk, decl, body, span, id);
+        self.context.tables = old_tables;
     }
 
     fn visit_variant_data(&mut self,
@@ -920,14 +926,14 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
                         g: &'tcx hir::Generics,
                         item_id: hir::HirId,
                         _: Span) {
-        run_lints!(self, check_struct_def, s, name, g, item_id);
+        lint_callback!(self, check_struct_def, s, name, g, item_id);
         hir_visit::walk_struct_def(self, s);
-        run_lints!(self, check_struct_def_post, s, name, g, item_id);
+        lint_callback!(self, check_struct_def_post, s, name, g, item_id);
     }
 
     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
         self.with_lint_attrs(s.hir_id, &s.attrs, |cx| {
-            run_lints!(cx, check_struct_field, s);
+            lint_callback!(cx, check_struct_field, s);
             hir_visit::walk_struct_field(cx, s);
         })
     }
@@ -937,104 +943,104 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
         self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| {
-            run_lints!(cx, check_variant, v, g);
+            lint_callback!(cx, check_variant, v, g);
             hir_visit::walk_variant(cx, v, g, item_id);
-            run_lints!(cx, check_variant_post, v, g);
+            lint_callback!(cx, check_variant_post, v, g);
         })
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
-        run_lints!(self, check_ty, t);
+        lint_callback!(self, check_ty, t);
         hir_visit::walk_ty(self, t);
     }
 
     fn visit_name(&mut self, sp: Span, name: ast::Name) {
-        run_lints!(self, check_name, sp, name);
+        lint_callback!(self, check_name, sp, name);
     }
 
     fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
-        if !self.only_module {
+        if !self.context.only_module {
             self.process_mod(m, s, n);
         }
     }
 
     fn visit_local(&mut self, l: &'tcx hir::Local) {
         self.with_lint_attrs(l.hir_id, &l.attrs, |cx| {
-            run_lints!(cx, check_local, l);
+            lint_callback!(cx, check_local, l);
             hir_visit::walk_local(cx, l);
         })
     }
 
     fn visit_block(&mut self, b: &'tcx hir::Block) {
-        run_lints!(self, check_block, b);
+        lint_callback!(self, check_block, b);
         hir_visit::walk_block(self, b);
-        run_lints!(self, check_block_post, b);
+        lint_callback!(self, check_block_post, b);
     }
 
     fn visit_arm(&mut self, a: &'tcx hir::Arm) {
-        run_lints!(self, check_arm, a);
+        lint_callback!(self, check_arm, a);
         hir_visit::walk_arm(self, a);
     }
 
     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
-        run_lints!(self, check_generic_param, p);
+        lint_callback!(self, check_generic_param, p);
         hir_visit::walk_generic_param(self, p);
     }
 
     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
-        run_lints!(self, check_generics, g);
+        lint_callback!(self, check_generics, g);
         hir_visit::walk_generics(self, g);
     }
 
     fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
-        run_lints!(self, check_where_predicate, p);
+        lint_callback!(self, check_where_predicate, p);
         hir_visit::walk_where_predicate(self, p);
     }
 
     fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef,
                             m: hir::TraitBoundModifier) {
-        run_lints!(self, check_poly_trait_ref, t, m);
+        lint_callback!(self, check_poly_trait_ref, t, m);
         hir_visit::walk_poly_trait_ref(self, t, m);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        let generics = self.generics.take();
-        self.generics = Some(&trait_item.generics);
+        let generics = self.context.generics.take();
+        self.context.generics = Some(&trait_item.generics);
         self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
             cx.with_param_env(trait_item.hir_id, |cx| {
-                run_lints!(cx, check_trait_item, trait_item);
+                lint_callback!(cx, check_trait_item, trait_item);
                 hir_visit::walk_trait_item(cx, trait_item);
-                run_lints!(cx, check_trait_item_post, trait_item);
+                lint_callback!(cx, check_trait_item_post, trait_item);
             });
         });
-        self.generics = generics;
+        self.context.generics = generics;
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        let generics = self.generics.take();
-        self.generics = Some(&impl_item.generics);
+        let generics = self.context.generics.take();
+        self.context.generics = Some(&impl_item.generics);
         self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
             cx.with_param_env(impl_item.hir_id, |cx| {
-                run_lints!(cx, check_impl_item, impl_item);
+                lint_callback!(cx, check_impl_item, impl_item);
                 hir_visit::walk_impl_item(cx, impl_item);
-                run_lints!(cx, check_impl_item_post, impl_item);
+                lint_callback!(cx, check_impl_item_post, impl_item);
             });
         });
-        self.generics = generics;
+        self.context.generics = generics;
     }
 
     fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-        run_lints!(self, check_lifetime, lt);
+        lint_callback!(self, check_lifetime, lt);
         hir_visit::walk_lifetime(self, lt);
     }
 
     fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) {
-        run_lints!(self, check_path, p, id);
+        lint_callback!(self, check_path, p, id);
         hir_visit::walk_path(self, p);
     }
 
     fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
-        run_lints!(self, check_attribute, attr);
+        lint_callback!(self, check_attribute, attr);
     }
 }
 
@@ -1222,94 +1228,182 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 }
 
-pub fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
+struct LateLintPassObjects<'a> {
+    lints: &'a mut [LateLintPassObject],
+}
+
+impl LintPass for LateLintPassObjects<'_> {
+    fn name(&self) -> &'static str {
+        panic!()
+    }
+
+    fn get_lints(&self) -> LintArray {
+        panic!()
+    }
+}
+
+macro_rules! expand_late_lint_pass_impl_methods {
+    ([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        $(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) {
+            for obj in self.lints.iter_mut() {
+                obj.$name(context, $($param),*);
+            }
+        })*
+    )
+}
+
+macro_rules! late_lint_pass_impl {
+    ([], [$hir:tt], $methods:tt) => (
+        impl LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
+            expand_late_lint_pass_impl_methods!(['a, $hir], $methods);
+        }
+    )
+}
+
+late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
+
+fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    module_def_id: DefId,
+    pass: T,
+) {
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
     let store = &tcx.sess.lint_store;
-    let passes = store.borrow_mut().late_module_passes.take();
 
-    let mut cx = LateContext {
+    let context = LateContext {
         tcx,
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
         lint_sess: LintSession {
             lints: store.borrow(),
-            passes,
+            passes: None,
         },
         last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
         generics: None,
         only_module: true,
     };
 
+    let mut cx = LateContextAndPass {
+        context,
+        pass
+    };
+
     let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
     cx.process_mod(module, span, hir_id);
 
     // Visit the crate attributes
     if hir_id == hir::CRATE_HIR_ID {
-        walk_list!(cx, visit_attribute, cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID));
+        walk_list!(cx, visit_attribute, tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID));
     }
-
-    // Put the lint store levels and passes back in the session.
-    let passes = cx.lint_sess.passes;
-    drop(cx.lint_sess.lints);
-    store.borrow_mut().late_module_passes = passes;
 }
 
-pub(crate) fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        lint_mod,
-        ..*providers
-    };
+pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    module_def_id: DefId,
+    builtin_lints: T,
+) {
+    assert!(!tcx.sess.opts.debugging_opts.no_interleave_lints);
+
+    late_lint_mod_pass(tcx, module_def_id, builtin_lints);
+
+    let mut passes = tcx.sess.lint_store.borrow_mut().late_module_passes.take().unwrap();
+
+    if !passes.is_empty() {
+        late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
+    }
+
+    // Put the passes back in the session.
+    tcx.sess.lint_store.borrow_mut().late_module_passes = Some(passes);
 }
 
-fn lint_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    pass: T
+) {
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
     let krate = tcx.hir().krate();
-    let passes = tcx.sess.lint_store.borrow_mut().late_passes.take();
-
-    let passes = {
-        let mut cx = LateContext {
-            tcx,
-            tables: &ty::TypeckTables::empty(None),
-            param_env: ty::ParamEnv::empty(),
-            access_levels,
-            lint_sess: LintSession {
-                passes,
-                lints: tcx.sess.lint_store.borrow(),
-            },
-            last_node_with_lint_attrs: hir::CRATE_HIR_ID,
-            generics: None,
-            only_module: false,
-        };
 
-        // Visit the whole crate.
-        cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| {
-            // since the root module isn't visited as an item (because it isn't an
-            // item), warn for it here.
-            run_lints!(cx, check_crate, krate);
-
-            hir_visit::walk_crate(cx, krate);
+    let context = LateContext {
+        tcx,
+        tables: &ty::TypeckTables::empty(None),
+        param_env: ty::ParamEnv::empty(),
+        access_levels,
+        lint_sess: LintSession {
+            passes: None,
+            lints: tcx.sess.lint_store.borrow(),
+        },
+        last_node_with_lint_attrs: hir::CRATE_HIR_ID,
+        generics: None,
+        only_module: false,
+    };
 
-            run_lints!(cx, check_crate_post, krate);
-        });
-        cx.lint_sess.passes
+    let mut cx = LateContextAndPass {
+        context,
+        pass
     };
 
-    // Put the lint store levels and passes back in the session.
-    tcx.sess.lint_store.borrow_mut().late_passes = passes;
+    // Visit the whole crate.
+    cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| {
+        // since the root module isn't visited as an item (because it isn't an
+        // item), warn for it here.
+        lint_callback!(cx, check_crate, krate);
+
+        hir_visit::walk_crate(cx, krate);
+
+        lint_callback!(cx, check_crate_post, krate);
+    })
+}
+
+fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    builtin_lints: T
+) {
+    let mut passes = tcx.sess.lint_store.borrow_mut().late_passes.take().unwrap();
+
+    if !tcx.sess.opts.debugging_opts.no_interleave_lints {
+        if !passes.is_empty() {
+            late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
+        }
+
+        late_lint_pass_crate(tcx, builtin_lints);
+    } else {
+        for pass in &mut passes {
+            time(tcx.sess, &format!("running late lint: {}", pass.name()), || {
+                late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
+            });
+        }
+
+        let mut passes = tcx.sess.lint_store.borrow_mut().late_module_passes.take().unwrap();
+            
+        for pass in &mut passes {
+            time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
+                late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
+            });
+        }
+
+        // Put the passes back in the session.
+        tcx.sess.lint_store.borrow_mut().late_module_passes = Some(passes);
+    }
+
+    // Put the passes back in the session.
+    tcx.sess.lint_store.borrow_mut().late_passes = Some(passes);
 }
 
 /// Performs lint checking on a crate.
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    builtin_lints: T,
+) {
     // Run per-module lints
     for &module in tcx.hir().krate().modules.keys() {
         tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
     }
 
     // Run whole crate non-incremental lints
-    lint_crate(tcx);
+    late_lint_crate(tcx, builtin_lints);
 }
 
 struct EarlyLintPassObjects<'a> {
@@ -1346,7 +1440,6 @@ macro_rules! early_lint_pass_impl {
 
 early_lint_methods!(early_lint_pass_impl, []);
 
-
 fn early_lint_crate<T: EarlyLintPass>(
     sess: &Session,
     krate: &ast::Crate,
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index cf1c5d50000fa..b54da5e5e80d8 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -42,8 +42,8 @@ use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
 pub use crate::lint::context::{LateContext, EarlyContext, LintContext, LintStore,
-                        check_crate, check_ast_crate, CheckLintNameResult,
-                        FutureIncompatibleInfo, BufferedEarlyLint};
+                        check_crate, check_ast_crate, late_lint_mod, CheckLintNameResult,
+                        FutureIncompatibleInfo, BufferedEarlyLint,};
 
 /// Specification of a single lint.
 #[derive(Copy, Clone, Debug)]
@@ -298,14 +298,14 @@ macro_rules! expand_combined_late_lint_pass_methods {
 
 #[macro_export]
 macro_rules! declare_combined_late_lint_pass {
-    ([$name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
+    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
         #[allow(non_snake_case)]
-        struct $name {
+        $v struct $name {
             $($passes: $passes,)*
         }
 
         impl $name {
-            fn new() -> Self {
+            $v fn new() -> Self {
                 Self {
                     $($passes: $constructor,)*
                 }
@@ -824,7 +824,6 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
 
 pub fn provide(providers: &mut Providers<'_>) {
     providers.lint_levels = lint_levels;
-    context::provide(providers);
 }
 
 /// Returns whether `span` originates in a foreign crate's external macro.
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 44ca11df694a9..6a6f56332a8bc 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -330,7 +330,7 @@ pub fn register_plugins<'a>(
         ls.register_early_pass(Some(sess), true, false, pass);
     }
     for pass in late_lint_passes {
-        ls.register_late_pass(Some(sess), true, false, pass);
+        ls.register_late_pass(Some(sess), true, false, false, pass);
     }
 
     for (name, (to, deprecated_name)) in lint_groups {
@@ -783,6 +783,7 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     middle::entry::provide(providers);
     cstore::provide(providers);
     lint::provide(providers);
+    rustc_lint::provide(providers);
 }
 
 pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
@@ -988,7 +989,9 @@ fn analysis<'tcx>(
                     stability::check_unused_or_stable_features(tcx)
                 });
             }, {
-                time(sess, "lint checking", || lint::check_crate(tcx));
+                time(sess, "lint checking", || {
+                    lint::check_crate(tcx, rustc_lint::BuiltinCombinedLateLintPass::new());
+                });
             });
         }, {
             time(sess, "privacy checking modules", || {
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 4c624a267af9b..c9301a32d83c4 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -45,6 +45,9 @@ use rustc::lint::builtin::{
 };
 use rustc::session;
 use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::ty::query::Providers;
+use rustc::ty::TyCtxt;
 
 use syntax::ast;
 use syntax::edition::Edition;
@@ -62,6 +65,17 @@ use unused::*;
 /// Useful for other parts of the compiler.
 pub use builtin::SoftLints;
 
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        lint_mod,
+        ..*providers
+    };
+}
+
+fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
+    lint::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
+}
+
 macro_rules! pre_expansion_lint_passes {
     ($macro:path, $args:tt) => (
         $macro!($args, [
@@ -94,6 +108,88 @@ macro_rules! declare_combined_early_pass {
 pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]);
 early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]);
 
+macro_rules! late_lint_passes {
+    ($macro:path, $args:tt) => (
+        $macro!($args, [
+            // FIXME: Look into regression when this is used as a module lint
+            // May Depend on constants elsewhere
+            UnusedBrokenConst: UnusedBrokenConst,
+
+            // Uses attr::is_used which is untracked, can't be an incremental module pass.
+            UnusedAttributes: UnusedAttributes,
+
+            // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
+            UnstableFeatures: UnstableFeatures,
+
+            // Tracks state across modules
+            UnnameableTestItems: UnnameableTestItems::new(),
+
+            // Tracks attributes of parents
+            MissingDoc: MissingDoc::new(),
+
+            // Depends on access levels
+            // FIXME: Turn the computation of types which implement Debug into a query
+            // and change this to a module lint pass
+            MissingDebugImplementations: MissingDebugImplementations::new(),
+        ]);
+    )
+}
+
+macro_rules! late_lint_mod_passes {
+    ($macro:path, $args:tt) => (
+        $macro!($args, [
+            HardwiredLints: HardwiredLints,
+            WhileTrue: WhileTrue,
+            ImproperCTypes: ImproperCTypes,
+            VariantSizeDifferences: VariantSizeDifferences,
+            BoxPointers: BoxPointers,
+            PathStatements: PathStatements,
+
+            // Depends on referenced function signatures in expressions
+            UnusedResults: UnusedResults,
+
+            NonUpperCaseGlobals: NonUpperCaseGlobals,
+            NonShorthandFieldPatterns: NonShorthandFieldPatterns,
+            UnusedAllocation: UnusedAllocation,
+
+            // Depends on types used in type definitions
+            MissingCopyImplementations: MissingCopyImplementations,
+
+            PluginAsLibrary: PluginAsLibrary,
+
+            // Depends on referenced function signatures in expressions
+            MutableTransmutes: MutableTransmutes,
+
+            // Depends on types of fields, checks if they implement Drop
+            UnionsWithDropFields: UnionsWithDropFields,
+
+            TypeAliasBounds: TypeAliasBounds,
+
+            TrivialConstraints: TrivialConstraints,
+            TypeLimits: TypeLimits::new(),
+
+            NonSnakeCase: NonSnakeCase,
+            InvalidNoMangleItems: InvalidNoMangleItems,
+
+            // Depends on access levels
+            UnreachablePub: UnreachablePub,
+
+            ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
+        ]);
+    )
+}
+
+macro_rules! declare_combined_late_pass {
+    ([$v:vis $name:ident], $passes:tt) => (
+        late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]);
+    )
+}
+
+// FIXME: Make a separate lint type which do not require typeck tables
+late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]);
+
+late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
+
 /// Tell the `LintStore` about all the built-in lints (the ones
 /// defined in this crate and the ones defined in
 /// `rustc::lint::builtin`).
@@ -104,17 +200,25 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         )
     }
 
+    macro_rules! register_pass {
+        ($method:ident, $constructor:expr, [$($args:expr),*]) => (
+            store.$method(sess, false, false, $($args,)* box $constructor);
+        )
+    }
+
     macro_rules! register_passes {
-        ([$method:ident], [$($passes:ident: $constructor:expr,)*]) => (
+        ([$method:ident, $args:tt], [$($passes:ident: $constructor:expr,)*]) => (
             $(
-                store.$method(sess, false, false, box $constructor);
+                register_pass!($method, $constructor, $args);
             )*
         )
     }
 
     if sess.map(|sess| sess.opts.debugging_opts.no_interleave_lints).unwrap_or(false) {
-        pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass]);
-        early_lint_passes!(register_passes, [register_early_pass]);
+        pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass, []]);
+        early_lint_passes!(register_passes, [register_early_pass, []]);
+        late_lint_passes!(register_passes, [register_late_pass, [false]]);
+        late_lint_mod_passes!(register_passes, [register_late_pass, [true]]);
     } else {
         store.register_pre_expansion_pass(
             sess,
@@ -123,75 +227,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             box BuiltinCombinedPreExpansionLintPass::new()
         );
         store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new());
+        store.register_late_pass(
+            sess, false, true, true, box BuiltinCombinedModuleLateLintPass::new()
+        );
+        store.register_late_pass(
+            sess, false, true, false, box BuiltinCombinedLateLintPass::new()
+        );
     }
 
-    late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedModuleLateLintPass, [
-        HardwiredLints: HardwiredLints,
-        WhileTrue: WhileTrue,
-        ImproperCTypes: ImproperCTypes,
-        VariantSizeDifferences: VariantSizeDifferences,
-        BoxPointers: BoxPointers,
-        PathStatements: PathStatements,
-
-        // Depends on referenced function signatures in expressions
-        UnusedResults: UnusedResults,
-
-        NonUpperCaseGlobals: NonUpperCaseGlobals,
-        NonShorthandFieldPatterns: NonShorthandFieldPatterns,
-        UnusedAllocation: UnusedAllocation,
-
-        // Depends on types used in type definitions
-        MissingCopyImplementations: MissingCopyImplementations,
-
-        PluginAsLibrary: PluginAsLibrary,
-
-        // Depends on referenced function signatures in expressions
-        MutableTransmutes: MutableTransmutes,
-
-        // Depends on types of fields, checks if they implement Drop
-        UnionsWithDropFields: UnionsWithDropFields,
-
-        TypeAliasBounds: TypeAliasBounds,
-
-        TrivialConstraints: TrivialConstraints,
-        TypeLimits: TypeLimits::new(),
-
-        NonSnakeCase: NonSnakeCase,
-        InvalidNoMangleItems: InvalidNoMangleItems,
-
-        // Depends on access levels
-        UnreachablePub: UnreachablePub,
-
-        ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
-    ]], ['tcx]);
-
-    store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new());
-
-    late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [
-        // FIXME: Look into regression when this is used as a module lint
-        // May Depend on constants elsewhere
-        UnusedBrokenConst: UnusedBrokenConst,
-
-        // Uses attr::is_used which is untracked, can't be an incremental module pass.
-        UnusedAttributes: UnusedAttributes,
-
-        // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
-        UnstableFeatures: UnstableFeatures,
-
-        // Tracks state across modules
-        UnnameableTestItems: UnnameableTestItems::new(),
-
-        // Tracks attributes of parents
-        MissingDoc: MissingDoc::new(),
-
-        // Depends on access levels
-        // FIXME: Turn the computation of types which implement Debug into a query
-        // and change this to a module lint pass
-        MissingDebugImplementations: MissingDebugImplementations::new(),
-    ]], ['tcx]);
-
-    store.register_late_pass(sess, false, false, box BuiltinCombinedLateLintPass::new());
-
     add_lint_group!(sess,
                     "nonstandard_style",
                     NON_CAMEL_CASE_TYPES,

From cd32f9bccaaf021a3327fc28df3401dc32a644e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 31 Jan 2019 03:04:39 +0100
Subject: [PATCH 06/20] Remove LintSession and run incremental and whole crate
 lints in parallel

---
 src/librustc/lint/context.rs     | 106 ++++++++++++-------------------
 src/librustc_interface/passes.rs |   2 +-
 2 files changed, 40 insertions(+), 68 deletions(-)

diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index e0bd795c342eb..49e3eee4e52ef 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -17,7 +17,7 @@
 use self::TargetLint::*;
 
 use std::slice;
-use rustc_data_structures::sync::ReadGuard;
+use rustc_data_structures::sync::{ReadGuard, Lock, join};
 use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
 use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer};
 use crate::lint::builtin::BuiltinLintDiagnostics;
@@ -55,8 +55,8 @@ pub struct LintStore {
     /// This is only `None` while performing a lint pass.
     pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
     early_passes: Option<Vec<EarlyLintPassObject>>,
-    late_passes: Option<Vec<LateLintPassObject>>,
-    late_module_passes: Option<Vec<LateLintPassObject>>,
+    late_passes: Lock<Option<Vec<LateLintPassObject>>>,
+    late_module_passes: Lock<Option<Vec<LateLintPassObject>>>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
@@ -69,14 +69,6 @@ pub struct LintStore {
     future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
 }
 
-pub struct LintSession<'a, PassObject> {
-    /// Reference to the store of registered lints.
-    lints: ReadGuard<'a, LintStore>,
-
-    /// Trait objects for each lint pass.
-    passes: Option<Vec<PassObject>>,
-}
-
 /// Lints that are buffered up early on in the `Session` before the
 /// `LintLevels` is calculated
 #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
@@ -151,8 +143,8 @@ impl LintStore {
             lints: vec![],
             pre_expansion_passes: Some(vec![]),
             early_passes: Some(vec![]),
-            late_passes: Some(vec![]),
-            late_module_passes: Some(vec![]),
+            late_passes: Lock::new(Some(vec![])),
+            late_module_passes: Lock::new(Some(vec![])),
             by_name: Default::default(),
             future_incompatible: Default::default(),
             lint_groups: Default::default(),
@@ -208,9 +200,9 @@ impl LintStore {
         self.push_pass(sess, from_plugin, &pass);
         if !register_only {
             if per_module {
-                self.late_module_passes.as_mut().unwrap().push(pass);
+                self.late_module_passes.lock().as_mut().unwrap().push(pass);
             } else {
-                self.late_passes.as_mut().unwrap().push(pass);
+                self.late_passes.lock().as_mut().unwrap().push(pass);
             }
         }
     }
@@ -529,7 +521,7 @@ pub struct LateContext<'a, 'tcx: 'a> {
     pub access_levels: &'a AccessLevels,
 
     /// The store of registered lints and the lint levels.
-    lint_sess: LintSession<'tcx, LateLintPassObject>,
+    lint_store: ReadGuard<'a, LintStore>,
 
     last_node_with_lint_attrs: hir::HirId,
 
@@ -557,7 +549,7 @@ pub struct EarlyContext<'a> {
     builder: LintLevelsBuilder<'a>,
 
     /// The store of registered lints and the lint levels.
-    lint_sess: LintSession<'a, EarlyLintPassObject>,
+    lint_store: ReadGuard<'a, LintStore>,
 
     buffered: LintBuffer,
 }
@@ -578,8 +570,6 @@ pub trait LintContext<'tcx>: Sized {
 
     fn sess(&self) -> &Session;
     fn lints(&self) -> &LintStore;
-    fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject>;
-    fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject>;
 
     fn lookup_and_emit<S: Into<MultiSpan>>(&self,
                                            lint: &'static Lint,
@@ -654,10 +644,7 @@ impl<'a> EarlyContext<'a> {
         EarlyContext {
             sess,
             krate,
-            lint_sess: LintSession {
-                lints: sess.lint_store.borrow(),
-                passes: None,
-            },
+            lint_store: sess.lint_store.borrow(),
             builder: LintLevelSets::builder(sess),
             buffered,
         }
@@ -721,15 +708,7 @@ impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> {
     }
 
     fn lints(&self) -> &LintStore {
-        &*self.lint_sess.lints
-    }
-
-    fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject> {
-        &self.lint_sess
-    }
-
-    fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject> {
-        &mut self.lint_sess
+        &*self.lint_store
     }
 
     fn lookup<S: Into<MultiSpan>>(&self,
@@ -757,15 +736,7 @@ impl<'a> LintContext<'a> for EarlyContext<'a> {
     }
 
     fn lints(&self) -> &LintStore {
-        &*self.lint_sess.lints
-    }
-
-    fn lint_sess(&self) -> &LintSession<'a, Self::PassObject> {
-        &self.lint_sess
-    }
-
-    fn lint_sess_mut(&mut self) -> &mut LintSession<'a, Self::PassObject> {
-        &mut self.lint_sess
+        &*self.lint_store
     }
 
     fn lookup<S: Into<MultiSpan>>(&self,
@@ -1269,17 +1240,12 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
 ) {
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
-    let store = &tcx.sess.lint_store;
-
     let context = LateContext {
         tcx,
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_sess: LintSession {
-            lints: store.borrow(),
-            passes: None,
-        },
+        lint_store: tcx.sess.lint_store.borrow(),
         last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
         generics: None,
         only_module: true,
@@ -1304,18 +1270,21 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     module_def_id: DefId,
     builtin_lints: T,
 ) {
-    assert!(!tcx.sess.opts.debugging_opts.no_interleave_lints);
+    if tcx.sess.opts.debugging_opts.no_interleave_lints {
+        // These passes runs in late_lint_crate with -Z no_interleave_lints
+        return;
+    }
 
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
-    let mut passes = tcx.sess.lint_store.borrow_mut().late_module_passes.take().unwrap();
+    let mut passes = tcx.sess.lint_store.borrow().late_module_passes.lock().take().unwrap();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
     }
 
     // Put the passes back in the session.
-    tcx.sess.lint_store.borrow_mut().late_module_passes = Some(passes);
+    *tcx.sess.lint_store.borrow().late_module_passes.lock() = Some(passes);
 }
 
 fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
@@ -1331,10 +1300,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_sess: LintSession {
-            passes: None,
-            lints: tcx.sess.lint_store.borrow(),
-        },
+        lint_store: tcx.sess.lint_store.borrow(),
         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
         generics: None,
         only_module: false,
@@ -1361,7 +1327,7 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     builtin_lints: T
 ) {
-    let mut passes = tcx.sess.lint_store.borrow_mut().late_passes.take().unwrap();
+    let mut passes = tcx.sess.lint_store.borrow().late_passes.lock().take().unwrap();
 
     if !tcx.sess.opts.debugging_opts.no_interleave_lints {
         if !passes.is_empty() {
@@ -1376,8 +1342,8 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
             });
         }
 
-        let mut passes = tcx.sess.lint_store.borrow_mut().late_module_passes.take().unwrap();
-            
+        let mut passes = tcx.sess.lint_store.borrow().late_module_passes.lock().take().unwrap();
+
         for pass in &mut passes {
             time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
                 late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
@@ -1385,25 +1351,31 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
         }
 
         // Put the passes back in the session.
-        tcx.sess.lint_store.borrow_mut().late_module_passes = Some(passes);
+        *tcx.sess.lint_store.borrow().late_module_passes.lock() = Some(passes);
     }
 
     // Put the passes back in the session.
-    tcx.sess.lint_store.borrow_mut().late_passes = Some(passes);
+    *tcx.sess.lint_store.borrow().late_passes.lock() = Some(passes);
 }
 
 /// Performs lint checking on a crate.
 pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
-    builtin_lints: T,
+    builtin_lints: impl FnOnce() -> T + Send,
 ) {
-    // Run per-module lints
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
-    }
-
-    // Run whole crate non-incremental lints
-    late_lint_crate(tcx, builtin_lints);
+    join(|| {
+        time(tcx.sess, "crate lints", || {
+            // Run whole crate non-incremental lints
+            late_lint_crate(tcx, builtin_lints());
+        });
+    }, || {
+        time(tcx.sess, "module lints", || {
+            // Run per-module lints
+            for &module in tcx.hir().krate().modules.keys() {
+                tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
+            }
+        });
+    });
 }
 
 struct EarlyLintPassObjects<'a> {
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 6a6f56332a8bc..1547e15fd48c5 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -990,7 +990,7 @@ fn analysis<'tcx>(
                 });
             }, {
                 time(sess, "lint checking", || {
-                    lint::check_crate(tcx, rustc_lint::BuiltinCombinedLateLintPass::new());
+                    lint::check_crate(tcx, || rustc_lint::BuiltinCombinedLateLintPass::new());
                 });
             });
         }, {

From dee389f749ebe2b6a80e08550ccd8aa8e5a1f019 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 31 Jan 2019 04:36:37 +0100
Subject: [PATCH 07/20] Run module lint passes in parallel

---
 src/librustc/lint/context.rs | 24 ++++++++++--------------
 src/librustc/lint/mod.rs     |  3 +++
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 49e3eee4e52ef..e5eafd768bb0b 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -17,7 +17,7 @@
 use self::TargetLint::*;
 
 use std::slice;
-use rustc_data_structures::sync::{ReadGuard, Lock, join};
+use rustc_data_structures::sync::{ReadGuard, Lock, ParallelIterator, join, par_iter};
 use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
 use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer};
 use crate::lint::builtin::BuiltinLintDiagnostics;
@@ -56,7 +56,7 @@ pub struct LintStore {
     pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
     early_passes: Option<Vec<EarlyLintPassObject>>,
     late_passes: Lock<Option<Vec<LateLintPassObject>>>,
-    late_module_passes: Lock<Option<Vec<LateLintPassObject>>>,
+    late_module_passes: Vec<LateLintPassObject>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
@@ -144,7 +144,7 @@ impl LintStore {
             pre_expansion_passes: Some(vec![]),
             early_passes: Some(vec![]),
             late_passes: Lock::new(Some(vec![])),
-            late_module_passes: Lock::new(Some(vec![])),
+            late_module_passes: vec![],
             by_name: Default::default(),
             future_incompatible: Default::default(),
             lint_groups: Default::default(),
@@ -200,7 +200,7 @@ impl LintStore {
         self.push_pass(sess, from_plugin, &pass);
         if !register_only {
             if per_module {
-                self.late_module_passes.lock().as_mut().unwrap().push(pass);
+                self.late_module_passes.push(pass);
             } else {
                 self.late_passes.lock().as_mut().unwrap().push(pass);
             }
@@ -1277,14 +1277,12 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
 
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
-    let mut passes = tcx.sess.lint_store.borrow().late_module_passes.lock().take().unwrap();
+    let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes
+                                .iter().map(|pass| pass.fresh_late_pass()).collect();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
     }
-
-    // Put the passes back in the session.
-    *tcx.sess.lint_store.borrow().late_module_passes.lock() = Some(passes);
 }
 
 fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
@@ -1342,16 +1340,14 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
             });
         }
 
-        let mut passes = tcx.sess.lint_store.borrow().late_module_passes.lock().take().unwrap();
+        let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes
+                                    .iter().map(|pass| pass.fresh_late_pass()).collect();
 
         for pass in &mut passes {
             time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
                 late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
             });
         }
-
-        // Put the passes back in the session.
-        *tcx.sess.lint_store.borrow().late_module_passes.lock() = Some(passes);
     }
 
     // Put the passes back in the session.
@@ -1371,9 +1367,9 @@ pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     }, || {
         time(tcx.sess, "module lints", || {
             // Run per-module lints
-            for &module in tcx.hir().krate().modules.keys() {
+            par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
                 tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
-            }
+            });
         });
     });
 }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index b54da5e5e80d8..a5506bb8f59f4 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -273,6 +273,9 @@ macro_rules! expand_lint_pass_methods {
 macro_rules! declare_late_lint_pass {
     ([], [$hir:tt], [$($methods:tt)*]) => (
         pub trait LateLintPass<'a, $hir>: LintPass {
+            fn fresh_late_pass(&self) -> LateLintPassObject {
+                panic!()
+            }
             expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]);
         }
     )

From e9a8befd2d4c0e19a9ec85cc047ef335a2b8b943 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 28 Mar 2019 18:58:43 +0100
Subject: [PATCH 08/20] Remove unnecessary with_globals calls

---
 src/librustc_interface/interface.rs | 14 ++++++--------
 src/librustdoc/lib.rs               |  4 ++--
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index bec868be505b5..245a2bf92d530 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -136,14 +136,12 @@ where
     F: FnOnce(&Compiler) -> R + Send,
     R: Send,
 {
-    syntax::with_globals(move || {
-        let stderr = config.stderr.take();
-        util::spawn_thread_pool(
-            config.opts.debugging_opts.threads,
-            &stderr,
-            || run_compiler_in_existing_thread_pool(config, f),
-        )
-    })
+    let stderr = config.stderr.take();
+    util::spawn_thread_pool(
+        config.opts.debugging_opts.threads,
+        &stderr,
+        || run_compiler_in_existing_thread_pool(config, f),
+    )
 }
 
 pub fn default_thread_pool<F, R>(f: F) -> R
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fccf5a67ad465..2ebb465d53dbe 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -443,7 +443,7 @@ where R: 'static + Send,
 
     let (tx, rx) = channel();
 
-    let result = rustc_driver::report_ices_to_stderr_if_any(move || syntax::with_globals(move || {
+    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
         let crate_name = options.crate_name.clone();
         let crate_version = options.crate_version.clone();
         let (mut krate, renderinfo, renderopts, passes) = core::run_core(options);
@@ -462,7 +462,7 @@ where R: 'static + Send,
             renderopts,
             passes: passes
         })).unwrap();
-    }));
+    });
 
     match result {
         Ok(()) => rx.recv().unwrap(),

From 8dbae794b0683668d1b46d2c319ab36dcd9bd96d Mon Sep 17 00:00:00 2001
From: Matt Brubeck <mbrubeck@limpet.net>
Date: Thu, 28 Mar 2019 11:28:39 -0700
Subject: [PATCH 09/20] Use write_all instead of write in example code

---
 src/libstd/io/mod.rs   |  2 +-
 src/libstd/io/stdio.rs | 12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 7147b641e4743..14c850b6b0547 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1151,7 +1151,7 @@ pub trait Write {
     /// fn main() -> std::io::Result<()> {
     ///     let mut buffer = BufWriter::new(File::create("foo.txt")?);
     ///
-    ///     buffer.write(b"some bytes")?;
+    ///     buffer.write_all(b"some bytes")?;
     ///     buffer.flush()?;
     ///     Ok(())
     /// }
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index d53a294fa6a9e..7e151041a9ea8 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -405,7 +405,7 @@ pub struct StdoutLock<'a> {
 /// use std::io::{self, Write};
 ///
 /// fn main() -> io::Result<()> {
-///     io::stdout().write(b"hello world")?;
+///     io::stdout().write_all(b"hello world")?;
 ///
 ///     Ok(())
 /// }
@@ -420,7 +420,7 @@ pub struct StdoutLock<'a> {
 ///     let stdout = io::stdout();
 ///     let mut handle = stdout.lock();
 ///
-///     handle.write(b"hello world")?;
+///     handle.write_all(b"hello world")?;
 ///
 ///     Ok(())
 /// }
@@ -460,7 +460,7 @@ impl Stdout {
     ///     let stdout = io::stdout();
     ///     let mut handle = stdout.lock();
     ///
-    ///     handle.write(b"hello world")?;
+    ///     handle.write_all(b"hello world")?;
     ///
     ///     Ok(())
     /// }
@@ -558,7 +558,7 @@ pub struct StderrLock<'a> {
 /// use std::io::{self, Write};
 ///
 /// fn main() -> io::Result<()> {
-///     io::stderr().write(b"hello world")?;
+///     io::stderr().write_all(b"hello world")?;
 ///
 ///     Ok(())
 /// }
@@ -573,7 +573,7 @@ pub struct StderrLock<'a> {
 ///     let stderr = io::stderr();
 ///     let mut handle = stderr.lock();
 ///
-///     handle.write(b"hello world")?;
+///     handle.write_all(b"hello world")?;
 ///
 ///     Ok(())
 /// }
@@ -613,7 +613,7 @@ impl Stderr {
     ///     let stderr = io::stderr();
     ///     let mut handle = stderr.lock();
     ///
-    ///     handle.write(b"hello world")?;
+    ///     handle.write_all(b"hello world")?;
     ///
     ///     Ok(())
     /// }

From d9bdd01ac034344f32d9fd94e404e67b54dbcddb Mon Sep 17 00:00:00 2001
From: CrLF0710 <crlf0710@gmail.com>
Date: Fri, 29 Mar 2019 03:09:29 +0800
Subject: [PATCH 10/20] Stablize {f32,f64}::copysign().

---
 src/libstd/f32.rs | 3 +--
 src/libstd/f64.rs | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 796908b0df943..2952c6aea0023 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -202,7 +202,6 @@ impl f32 {
     /// # Examples
     ///
     /// ```
-    /// #![feature(copysign)]
     /// use std::f32;
     ///
     /// let f = 3.5_f32;
@@ -216,7 +215,7 @@ impl f32 {
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature="copysign", issue="55169")]
+    #[stable(feature = "copysign", since = "1.35.0")]
     pub fn copysign(self, y: f32) -> f32 {
         unsafe { intrinsics::copysignf32(self, y) }
     }
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index e679a7d2e8c04..3c3a35573adaa 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -180,7 +180,6 @@ impl f64 {
     /// # Examples
     ///
     /// ```
-    /// #![feature(copysign)]
     /// use std::f64;
     ///
     /// let f = 3.5_f64;
@@ -194,7 +193,7 @@ impl f64 {
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature="copysign", issue="55169")]
+    #[stable(feature = "copysign", since = "1.35.0")]
     pub fn copysign(self, y: f64) -> f64 {
         unsafe { intrinsics::copysignf64(self, y) }
     }

From 9f14e146ed7805c4190c0c71c28935103820f75f Mon Sep 17 00:00:00 2001
From: mark <markm@cs.wisc.edu>
Date: Sat, 23 Mar 2019 21:58:55 -0500
Subject: [PATCH 11/20] deny duplicate matcher bindings by default

---
 src/librustc/lint/builtin.rs                       |  3 ++-
 .../ui/macros/macro-multiple-matcher-bindings.rs   |  1 +
 .../macros/macro-multiple-matcher-bindings.stderr  | 14 +++++++++-----
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index ad0ed39185c1c..10a5c1479fa6a 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -354,7 +354,7 @@ declare_lint! {
 
 declare_lint! {
     pub DUPLICATE_MATCHER_BINDING_NAME,
-    Warn,
+    Deny,
     "duplicate macro matcher binding name"
 }
 
@@ -464,6 +464,7 @@ impl LintPass for HardwiredLints {
             DEPRECATED_IN_FUTURE,
             AMBIGUOUS_ASSOCIATED_ITEMS,
             NESTED_IMPL_TRAIT,
+            DUPLICATE_MATCHER_BINDING_NAME,
         )
     }
 }
diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.rs b/src/test/ui/macros/macro-multiple-matcher-bindings.rs
index 9e0fa3887163d..23d566780c855 100644
--- a/src/test/ui/macros/macro-multiple-matcher-bindings.rs
+++ b/src/test/ui/macros/macro-multiple-matcher-bindings.rs
@@ -6,6 +6,7 @@
 // compile-pass
 
 #![allow(unused_macros)]
+#![warn(duplicate_matcher_binding_name)]
 
 macro_rules! foo1 {
     ($a:ident, $a:ident) => {}; //~WARNING duplicate matcher binding
diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr
index 41e9a3286aefb..f7970dbd2eb22 100644
--- a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr
+++ b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr
@@ -1,15 +1,19 @@
 warning: duplicate matcher binding
-  --> $DIR/macro-multiple-matcher-bindings.rs:11:6
+  --> $DIR/macro-multiple-matcher-bindings.rs:12:6
    |
 LL |     ($a:ident, $a:ident) => {};
    |      ^^^^^^^^  ^^^^^^^^
    |
-   = note: #[warn(duplicate_matcher_binding_name)] on by default
+note: lint level defined here
+  --> $DIR/macro-multiple-matcher-bindings.rs:9:9
+   |
+LL | #![warn(duplicate_matcher_binding_name)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593>
 
 warning: duplicate matcher binding
-  --> $DIR/macro-multiple-matcher-bindings.rs:12:6
+  --> $DIR/macro-multiple-matcher-bindings.rs:13:6
    |
 LL |     ($a:ident, $a:path) => {};
    |      ^^^^^^^^  ^^^^^^^
@@ -18,7 +22,7 @@ LL |     ($a:ident, $a:path) => {};
    = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593>
 
 warning: duplicate matcher binding
-  --> $DIR/macro-multiple-matcher-bindings.rs:21:6
+  --> $DIR/macro-multiple-matcher-bindings.rs:22:6
    |
 LL |     ($a:ident, $($a:ident),*) => {};
    |      ^^^^^^^^    ^^^^^^^^
@@ -27,7 +31,7 @@ LL |     ($a:ident, $($a:ident),*) => {};
    = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593>
 
 warning: duplicate matcher binding
-  --> $DIR/macro-multiple-matcher-bindings.rs:22:8
+  --> $DIR/macro-multiple-matcher-bindings.rs:23:8
    |
 LL |     ($($a:ident)+ # $($($a:path),+);*) => {};
    |        ^^^^^^^^         ^^^^^^^

From 3ba7454152e65beb7519580d8f74cf433f20b724 Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Fri, 22 Mar 2019 04:38:22 +0900
Subject: [PATCH 12/20] Use track_errors

---
 src/librustc_mir/const_eval.rs | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 6ab89f80ef528..0cf6c4593e8dd 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -645,10 +645,14 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                                                    "could not evaluate static initializer");
             // Ensure that if the above error was either `TooGeneric` or `Reported`
             // an error must be reported.
-            if tcx.sess.err_count() == 0 {
-                tcx.sess.delay_span_bug(err.span,
+            let errs = tcx.sess.track_errors(|| {
+                tcx.sess.err_count();
+            });
+            match errs {
+                Ok(_) => tcx.sess.delay_span_bug(err.span,
                                         &format!("static eval failure did not emit an error: {:#?}",
-                                                 reported_err));
+                                        reported_err)),
+                Err(_) => (),
             }
             reported_err
         } else if def_id.is_local() {

From 526b3558581187c87ca8ca533254c1cbb6275e7b Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Sat, 23 Mar 2019 00:03:50 +0900
Subject: [PATCH 13/20] Remove err_count

---
 src/librustc_mir/const_eval.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 0cf6c4593e8dd..80076c6f03533 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -645,13 +645,14 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                                                    "could not evaluate static initializer");
             // Ensure that if the above error was either `TooGeneric` or `Reported`
             // an error must be reported.
-            let errs = tcx.sess.track_errors(|| {
-                tcx.sess.err_count();
+            let tracked_err = tcx.sess.track_errors(|| {
+                err.report_as_error(ecx.tcx,
+                                    "could not evaluate static initializer");
             });
-            match errs {
+            match tracked_err {
                 Ok(_) => tcx.sess.delay_span_bug(err.span,
                                         &format!("static eval failure did not emit an error: {:#?}",
-                                        reported_err)),
+                                        tracked_err)),
                 Err(_) => (),
             }
             reported_err

From ee0e1b7615b92103fa2f4ca280d5b5f189e8def9 Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Sat, 23 Mar 2019 00:51:08 +0900
Subject: [PATCH 14/20] Set ok value

---
 src/librustc_mir/const_eval.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 80076c6f03533..9f73c2aa06e6b 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -650,9 +650,9 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                                     "could not evaluate static initializer");
             });
             match tracked_err {
-                Ok(_) => tcx.sess.delay_span_bug(err.span,
+                Ok(reported_err) => tcx.sess.delay_span_bug(err.span,
                                         &format!("static eval failure did not emit an error: {:#?}",
-                                        tracked_err)),
+                                        reported_err)),
                 Err(_) => (),
             }
             reported_err

From 0e76b34aa7021265630cc9933f1c918f184ba8d8 Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Sun, 24 Mar 2019 14:45:27 +0900
Subject: [PATCH 15/20] WIP: remove report_as_error

---
 src/librustc_mir/const_eval.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 9f73c2aa06e6b..964f721508832 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -641,19 +641,17 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
         let err = error_to_const_error(&ecx, error);
         // errors in statics are always emitted as fatal errors
         if tcx.is_static(def_id).is_some() {
-            let reported_err = err.report_as_error(ecx.tcx,
-                                                   "could not evaluate static initializer");
             // Ensure that if the above error was either `TooGeneric` or `Reported`
             // an error must be reported.
-            let tracked_err = tcx.sess.track_errors(|| {
+            let reported_err = tcx.sess.track_errors(|| {
                 err.report_as_error(ecx.tcx,
                                     "could not evaluate static initializer");
             });
-            match tracked_err {
-                Ok(reported_err) => tcx.sess.delay_span_bug(err.span,
+            match reported_err {
+                Ok(v) => tcx.sess.delay_span_bug(err.span,
                                         &format!("static eval failure did not emit an error: {:#?}",
-                                        reported_err)),
-                Err(_) => (),
+                                        v)),
+                Err(err) => err,
             }
             reported_err
         } else if def_id.is_local() {

From f0de8e82b868f7f4484b6e3e42543791c8b24b7f Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Mon, 25 Mar 2019 03:19:48 +0900
Subject: [PATCH 16/20] Return correct values

---
 src/librustc_mir/const_eval.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 964f721508832..1542cdf1e3e77 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -645,15 +645,17 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
             // an error must be reported.
             let reported_err = tcx.sess.track_errors(|| {
                 err.report_as_error(ecx.tcx,
-                                    "could not evaluate static initializer");
+                                    "could not evaluate static initializer")
             });
             match reported_err {
-                Ok(v) => tcx.sess.delay_span_bug(err.span,
+                Ok(v) => {
+                    tcx.sess.delay_span_bug(err.span,
                                         &format!("static eval failure did not emit an error: {:#?}",
-                                        v)),
-                Err(err) => err,
+                                        v));
+                    v
+                },
+                Err(ErrorReported) => ErrorHandled::Reported,
             }
-            reported_err
         } else if def_id.is_local() {
             // constant defined in this crate, we can figure out a lint level!
             match tcx.describe_def(def_id) {

From 6c8e3a5378e41e08a323139bb7aaa8a8823ec9bc Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Mon, 25 Mar 2019 03:55:13 +0900
Subject: [PATCH 17/20] Remove unused variable

---
 src/librustc_mir/const_eval.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 1542cdf1e3e77..1c3f7882b9fcf 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -654,7 +654,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                                         v));
                     v
                 },
-                Err(ErrorReported) => ErrorHandled::Reported,
+                Err(_) => ErrorHandled::Reported,
             }
         } else if def_id.is_local() {
             // constant defined in this crate, we can figure out a lint level!

From 07788478332d645293a81686d5d225b8aafabe90 Mon Sep 17 00:00:00 2001
From: Yuki OKUSHI <huyuumi.dev@gmail.com>
Date: Fri, 29 Mar 2019 04:42:03 +0900
Subject: [PATCH 18/20] Use ErrorReported

---
 src/librustc_mir/const_eval.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 1c3f7882b9fcf..2268568c5f82d 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -14,6 +14,7 @@ use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
 use rustc::ty::layout::{self, LayoutOf, VariantIdx};
 use rustc::ty::subst::Subst;
 use rustc::traits::Reveal;
+use rustc::util::common::ErrorReported;
 use rustc_data_structures::fx::FxHashMap;
 
 use syntax::ast::Mutability;
@@ -654,7 +655,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
                                         v));
                     v
                 },
-                Err(_) => ErrorHandled::Reported,
+                Err(ErrorReported) => ErrorHandled::Reported,
             }
         } else if def_id.is_local() {
             // constant defined in this crate, we can figure out a lint level!

From 17a8aff20abdef46ae90801c85cc232e81443e1b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Thu, 28 Mar 2019 12:27:26 +1100
Subject: [PATCH 19/20] Use `SmallVec` in `TokenStreamBuilder`.

This reduces by 12% the number of allocations done for a "clean
incremental" of `webrender_api`, which reduces the instruction count by
about 0.5%.

It also reduces instruction counts by up to 1.4% across a range of
rustc-perf benchmark runs.
---
 src/libsyntax/parse/attr.rs  |  3 ++-
 src/libsyntax/tokenstream.rs | 14 ++++++++------
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 4211268f33efe..e99a86e807f7f 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -6,6 +6,7 @@ use crate::parse::parser::{Parser, TokenType, PathStyle};
 use crate::tokenstream::{TokenStream, TokenTree};
 
 use log::debug;
+use smallvec::smallvec;
 
 #[derive(Debug)]
 enum InnerAttributeParsePolicy<'a> {
@@ -171,7 +172,7 @@ impl<'a> Parser<'a> {
                 } else {
                     self.parse_unsuffixed_lit()?.tokens()
                 };
-                TokenStream::from_streams(vec![eq.into(), tokens])
+                TokenStream::from_streams(smallvec![eq.into(), tokens])
             } else {
                 TokenStream::empty()
             };
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 80a7bde606afa..2d47b982ebdd9 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -24,6 +24,7 @@ use syntax_pos::{BytePos, Mark, Span, DUMMY_SP};
 use rustc_data_structures::static_assert;
 use rustc_data_structures::sync::Lrc;
 use serialize::{Decoder, Decodable, Encoder, Encodable};
+use smallvec::{SmallVec, smallvec};
 
 use std::borrow::Cow;
 use std::{fmt, iter, mem};
@@ -224,7 +225,7 @@ impl From<Token> for TokenStream {
 
 impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-        TokenStream::from_streams(iter.into_iter().map(Into::into).collect::<Vec<_>>())
+        TokenStream::from_streams(iter.into_iter().map(Into::into).collect::<SmallVec<_>>())
     }
 }
 
@@ -256,7 +257,7 @@ impl TokenStream {
         }
     }
 
-    pub(crate) fn from_streams(mut streams: Vec<TokenStream>) -> TokenStream {
+    pub(crate) fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
         match streams.len() {
             0 => TokenStream::empty(),
             1 => streams.pop().unwrap(),
@@ -393,12 +394,13 @@ impl TokenStream {
     }
 }
 
+// 99.5%+ of the time we have 1 or 2 elements in this vector.
 #[derive(Clone)]
-pub struct TokenStreamBuilder(Vec<TokenStream>);
+pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
 
 impl TokenStreamBuilder {
     pub fn new() -> TokenStreamBuilder {
-        TokenStreamBuilder(Vec::new())
+        TokenStreamBuilder(SmallVec::new())
     }
 
     pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
@@ -485,7 +487,7 @@ impl Cursor {
         }
         let index = self.index;
         let stream = mem::replace(&mut self.stream, TokenStream(None));
-        *self = TokenStream::from_streams(vec![stream, new_stream]).into_trees();
+        *self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees();
         self.index = index;
     }
 
@@ -572,7 +574,7 @@ mod tests {
             let test_res = string_to_ts("foo::bar::baz");
             let test_fst = string_to_ts("foo::bar");
             let test_snd = string_to_ts("::baz");
-            let eq_res = TokenStream::from_streams(vec![test_fst, test_snd]);
+            let eq_res = TokenStream::from_streams(smallvec![test_fst, test_snd]);
             assert_eq!(test_res.trees().count(), 5);
             assert_eq!(eq_res.trees().count(), 5);
             assert_eq!(test_res.eq_unspanned(&eq_res), true);

From 93fb4d83178dde230eb55ce02468867ea6ac44f0 Mon Sep 17 00:00:00 2001
From: Jethro Beekman <jethro@fortanix.com>
Date: Thu, 28 Mar 2019 17:50:01 -0700
Subject: [PATCH 20/20] Fix missed fn rename in #59284

---
 src/libstd/sys/sgx/rwlock.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 7e2d13b9e2476..784303f3a65e8 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -268,7 +268,7 @@ mod tests {
 
         #[inline(never)]
         unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
-            init.set(RWLock::new());
+            init.write(RWLock::new());
         }
 
         unsafe {