about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-09-24 21:46:26 +0000
committerbors <bors@rust-lang.org>2019-09-24 21:46:26 +0000
commitdcd473d7b554a82013913244da8aba1e22a002a9 (patch)
treee3d95102edba19987d74cf0c961be6c86d5d8cab
parent6ef275e6c3cb1384ec78128eceeb4963ff788dca (diff)
parentaeb24142be8f39975c72a63f57c70d0adc6cc7a6 (diff)
downloadrust-dcd473d7b554a82013913244da8aba1e22a002a9.tar.gz
rust-dcd473d7b554a82013913244da8aba1e22a002a9.zip
Auto merge of #64751 - Centril:rollup-hpbmcfj, r=Centril
Rollup of 16 pull requests

Successful merges:

 - #63356 (Issue#63183: Add fs::read_dir() and ReadDir warning about iterator order + example)
 - #63934 (Fix coherence checking for impl trait in type aliases)
 - #64016 (Streamline `Compiler`)
 - #64296 (Document the unstable iter_order_by library feature)
 - #64443 (rustdoc: general cleanup)
 - #64622 (Add a cycle detector for generic `Graph`s and `mir::Body`s)
 - #64689 (Refactor macro by example)
 - #64698 (Recover on `const X = 42;` and infer type + Error Stash API)
 - #64702 (Remove unused dependencies)
 - #64717 (update mem::discriminant test to use assert_eq and assert_ne over comparison operators)
 - #64720 ( remove rtp.rs, and move rtpSpawn and RTP_ID_ERROR to libc)
 - #64721 (Fixed issue from #64447)
 - #64725 (fix one typo)
 - #64737 (fix several issues in String docs)
 - #64742 (relnotes: make compatibility section more sterile and fix rustc version)
 - #64748 (Fix #64744. Account for the Zero sub-pattern case.)

Failed merges:

r? @ghost
-rw-r--r--Cargo.lock13
-rw-r--r--RELEASES.md8
-rw-r--r--src/liballoc/string.rs8
-rw-r--r--src/libcore/iter/traits/iterator.rs6
-rw-r--r--src/libcore/mem/mod.rs6
-rw-r--r--src/librustc/mir/mod.rs6
-rw-r--r--src/librustc/session/mod.rs1
-rw-r--r--src/librustc/traits/coherence.rs18
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs2
-rw-r--r--src/librustc_ast_borrowck/Cargo.toml2
-rw-r--r--src/librustc_codegen_ssa/Cargo.toml1
-rw-r--r--src/librustc_codegen_utils/Cargo.toml1
-rw-r--r--src/librustc_data_structures/graph/iterate/mod.rs204
-rw-r--r--src/librustc_data_structures/graph/iterate/tests.rs11
-rw-r--r--src/librustc_data_structures/graph/mod.rs10
-rw-r--r--src/librustc_driver/lib.rs3
-rw-r--r--src/librustc_errors/diagnostic_builder.rs41
-rw-r--r--src/librustc_errors/emitter.rs5
-rw-r--r--src/librustc_errors/lib.rs398
-rw-r--r--src/librustc_interface/passes.rs4
-rw-r--r--src/librustc_interface/queries.rs45
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_plugin/Cargo.toml1
-rw-r--r--src/librustc_resolve/Cargo.toml1
-rw-r--r--src/librustc_resolve/macros.rs4
-rw-r--r--src/librustc_save_analysis/Cargo.toml1
-rw-r--r--src/librustc_traits/Cargo.toml2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/pat.rs59
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/collect.rs49
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs46
-rw-r--r--src/librustdoc/html/format.rs964
-rw-r--r--src/librustdoc/html/item_type.rs39
-rw-r--r--src/librustdoc/html/layout.rs4
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render.rs1134
-rw-r--r--src/librustdoc/html/render/cache.rs675
-rw-r--r--src/librustdoc/html/toc.rs37
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs7
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/mod.rs10
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/libstd/Cargo.toml3
-rw-r--r--src/libstd/fs.rs25
-rw-r--r--src/libstd/sys/vxworks/process/mod.rs1
-rw-r--r--src/libstd/sys/vxworks/process/process_vxworks.rs5
-rw-r--r--src/libstd/sys/vxworks/process/rtp.rs298
-rw-r--r--src/libsyntax/Cargo.toml1
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/expand.rs8
-rw-r--r--src/libsyntax/ext/mbe.rs166
-rw-r--r--src/libsyntax/ext/mbe/macro_check.rs (renamed from src/libsyntax/ext/tt/macro_check.rs)4
-rw-r--r--src/libsyntax/ext/mbe/macro_parser.rs (renamed from src/libsyntax/ext/tt/macro_parser.rs)26
-rw-r--r--src/libsyntax/ext/mbe/macro_rules.rs (renamed from src/libsyntax/ext/tt/macro_rules.rs)153
-rw-r--r--src/libsyntax/ext/mbe/quoted.rs (renamed from src/libsyntax/ext/tt/quoted.rs)172
-rw-r--r--src/libsyntax/ext/mbe/transcribe.rs (renamed from src/libsyntax/ext/tt/transcribe.rs)36
-rw-r--r--src/libsyntax/lib.rs9
-rw-r--r--src/libsyntax/parse/parser/item.rs47
-rw-r--r--src/libsyntax/tokenstream.rs15
-rw-r--r--src/libsyntax_ext/Cargo.toml1
-rw-r--r--src/libsyntax_ext/format.rs4
-rw-r--r--src/test/run-make-fulldeps/issue-19371/foo.rs3
-rw-r--r--src/test/ui/error-codes/E0023.rs3
-rw-r--r--src/test/ui/error-codes/E0023.stderr15
-rw-r--r--src/test/ui/impl-trait/auto-trait.rs23
-rw-r--r--src/test/ui/impl-trait/auto-trait.stderr12
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.rs22
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.stderr14
-rw-r--r--src/test/ui/suggestions/const-no-type.rs46
-rw-r--r--src/test/ui/suggestions/const-no-type.stderr38
-rw-r--r--src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/coherence.rs17
-rw-r--r--src/test/ui/type-alias-impl-trait/coherence.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs21
78 files changed, 2725 insertions, 2323 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5bc1938fee2..d03e1cd7432 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3324,8 +3324,6 @@ dependencies = [
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_errors",
- "syntax",
  "syntax_pos",
 ]
 
@@ -3347,7 +3345,6 @@ dependencies = [
  "log",
  "memmap",
  "num_cpus",
- "parking_lot 0.9.0",
  "rustc",
  "rustc_apfloat",
  "rustc_codegen_utils",
@@ -3366,7 +3363,6 @@ dependencies = [
 name = "rustc_codegen_utils"
 version = "0.0.0"
 dependencies = [
- "flate2",
  "log",
  "punycode",
  "rustc",
@@ -3561,7 +3557,6 @@ name = "rustc_mir"
 version = "0.0.0"
 dependencies = [
  "arena",
- "byteorder",
  "either",
  "graphviz",
  "log",
@@ -3614,7 +3609,6 @@ name = "rustc_plugin_impl"
 version = "0.0.0"
 dependencies = [
  "rustc",
- "rustc_errors",
  "rustc_metadata",
  "syntax",
  "syntax_pos",
@@ -3638,7 +3632,6 @@ version = "0.0.0"
 dependencies = [
  "arena",
  "bitflags",
- "indexmap",
  "log",
  "rustc",
  "rustc_data_structures",
@@ -3660,7 +3653,6 @@ dependencies = [
  "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_target",
- "rustc_typeck",
  "serde_json",
  "syntax",
  "syntax_pos",
@@ -3691,9 +3683,7 @@ checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee"
 name = "rustc_traits"
 version = "0.0.0"
 dependencies = [
- "bitflags",
  "chalk-engine",
- "graphviz",
  "log",
  "rustc",
  "rustc_data_structures",
@@ -4056,7 +4046,6 @@ version = "0.0.0"
 dependencies = [
  "alloc",
  "backtrace",
- "cc",
  "cfg-if",
  "compiler_builtins",
  "core",
@@ -4241,7 +4230,6 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_lexer",
- "rustc_macros",
  "rustc_target",
  "scoped-tls",
  "serialize",
@@ -4257,7 +4245,6 @@ dependencies = [
  "log",
  "rustc_data_structures",
  "rustc_errors",
- "rustc_lexer",
  "rustc_target",
  "smallvec",
  "syntax",
diff --git a/RELEASES.md b/RELEASES.md
index ecf49278f4b..766cf64410c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -70,10 +70,10 @@ Misc
 
 Compatibility Notes
 -------------------
-- Unfortunately the [`x86_64-unknown-uefi` platform can not be built][62785]
-  with rustc 1.39.0.
-- The [`armv7-unknown-linux-gnueabihf` platform is also known to have
-  issues][62896] for certain crates such as libc.
+- The [`x86_64-unknown-uefi` platform can not be built][62785] with rustc
+  1.38.0.
+- The [`armv7-unknown-linux-gnueabihf` platform is known to have
+  issues][62896] with certain crates such as libc.
 
 [60260]: https://github.com/rust-lang/rust/pull/60260/
 [61457]: https://github.com/rust-lang/rust/pull/61457/
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 1166e7b5df2..e5f96ada6d5 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -429,7 +429,7 @@ impl String {
 
     /// Converts a vector of bytes to a `String`.
     ///
-    /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a vector of bytes
+    /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
     /// ([`Vec<u8>`]) is made of bytes, so this function converts between the
     /// two. Not all byte slices are valid `String`s, however: `String`
     /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that
@@ -446,7 +446,7 @@ impl String {
     /// If you need a [`&str`] instead of a `String`, consider
     /// [`str::from_utf8`].
     ///
-    /// The inverse of this method is [`as_bytes`].
+    /// The inverse of this method is [`into_bytes`].
     ///
     /// # Errors
     ///
@@ -480,11 +480,11 @@ impl String {
     /// with this error.
     ///
     /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked
-    /// [`&str`]: ../../std/primitive.str.html
+    /// [`String`]: struct.String.html
     /// [`u8`]: ../../std/primitive.u8.html
     /// [`Vec<u8>`]: ../../std/vec/struct.Vec.html
     /// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html
-    /// [`as_bytes`]: struct.String.html#method.as_bytes
+    /// [`into_bytes`]: struct.String.html#method.into_bytes
     /// [`FromUtf8Error`]: struct.FromUtf8Error.html
     /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
     #[inline]
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index da49223dfb2..0a9e076ec58 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2581,7 +2581,7 @@ pub trait Iterator {
     /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal);
     /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
     /// ```
-    #[unstable(feature = "iter_order_by", issue = "0")]
+    #[unstable(feature = "iter_order_by", issue = "64295")]
     fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
     where
         Self: Sized,
@@ -2664,7 +2664,7 @@ pub trait Iterator {
     ///     Some(Ordering::Greater)
     /// );
     /// ```
-    #[unstable(feature = "iter_order_by", issue = "0")]
+    #[unstable(feature = "iter_order_by", issue = "64295")]
     fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
     where
         Self: Sized,
@@ -2729,7 +2729,7 @@ pub trait Iterator {
     ///
     /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
     /// ```
-    #[unstable(feature = "iter_order_by", issue = "0")]
+    #[unstable(feature = "iter_order_by", issue = "64295")]
     fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
     where
         Self: Sized,
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 87ec05a243d..8767625d4ed 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -818,9 +818,9 @@ impl<T> fmt::Debug for Discriminant<T> {
 ///
 /// enum Foo { A(&'static str), B(i32), C(i32) }
 ///
-/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz")));
-/// assert!(mem::discriminant(&Foo::B(1))     == mem::discriminant(&Foo::B(2)));
-/// assert!(mem::discriminant(&Foo::B(3))     != mem::discriminant(&Foo::C(3)));
+/// assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz")));
+/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
+/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
 /// ```
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 pub fn discriminant<T>(v: &T) -> Discriminant<T> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 92efcf44dea..967d16fa0d9 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -262,6 +262,12 @@ impl<'tcx> Body<'tcx> {
         dominators(self)
     }
 
+    /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
+    /// `START_BLOCK`.
+    pub fn is_cfg_cyclic(&self) -> bool {
+        graph::is_cyclic(self)
+    }
+
     #[inline]
     pub fn local_kind(&self, local: Local) -> LocalKind {
         let index = local.as_usize();
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index a24fed8f21c..49342d95fdb 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -321,6 +321,7 @@ impl Session {
     }
     pub fn compile_status(&self) -> Result<(), ErrorReported> {
         if self.has_errors() {
+            self.diagnostic().emit_stashed_diagnostics();
             Err(ErrorReported)
         } else {
             Ok(())
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index b6f0addd771..ee318b127ae 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -432,7 +432,7 @@ fn orphan_check_trait_ref<'tcx>(
 }
 
 fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(ty, in_crate) {
+    if ty_is_local_constructor(tcx, ty, in_crate) {
         vec![]
     } else if fundamental_ty(ty) {
         ty.walk_shallow()
@@ -451,7 +451,7 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
 }
 
 fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
-    ty_is_local_constructor(ty, in_crate) ||
+    ty_is_local_constructor(tcx, ty, in_crate) ||
         fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
 }
 
@@ -472,7 +472,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
     }
 }
 
-fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
     debug!("ty_is_local_constructor({:?})", ty);
 
     match ty.sty {
@@ -504,6 +504,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
 
         ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
         ty::Foreign(did) => def_id_is_local(did, in_crate),
+        ty::Opaque(did, _) => {
+            // Check the underlying type that this opaque
+            // type resolves to.
+            // This recursion will eventually terminate,
+            // since we've already managed to successfully
+            // resolve all opaque types by this point
+            let real_ty = tcx.type_of(did);
+            ty_is_local_constructor(tcx, real_ty, in_crate)
+        }
 
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
@@ -518,8 +527,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
         ty::UnnormalizedProjection(..) |
         ty::Closure(..) |
         ty::Generator(..) |
-        ty::GeneratorWitness(..) |
-        ty::Opaque(..) => {
+        ty::GeneratorWitness(..) => {
             bug!("ty_is_local invoked on unexpected type: {:?}", ty)
         }
     }
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index b43881defdb..c9a40db41df 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -395,7 +395,7 @@ impl<'tcx> Graph {
     /// The parent of a given impl, which is the `DefId` of the trait when the
     /// impl is a "specialization root".
     pub fn parent(&self, child: DefId) -> DefId {
-        *self.parent.get(&child).unwrap()
+        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
     }
 }
 
diff --git a/src/librustc_ast_borrowck/Cargo.toml b/src/librustc_ast_borrowck/Cargo.toml
index 024b2640e1e..40c4c1fc3fe 100644
--- a/src/librustc_ast_borrowck/Cargo.toml
+++ b/src/librustc_ast_borrowck/Cargo.toml
@@ -12,11 +12,9 @@ doctest = false
 
 [dependencies]
 log = "0.4"
-syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 # for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
 # refers to the borrowck-specific graphviz adapter traits.
 dot = { path = "../libgraphviz", package = "graphviz" }
 rustc = { path = "../librustc" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index bc028d66242..2e3666e6096 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -17,7 +17,6 @@ memmap = "0.6"
 log = "0.4.5"
 libc = "0.2.44"
 jobserver = "0.1.11"
-parking_lot = "0.9"
 tempfile = "3.1"
 
 rustc_serialize = { path = "../libserialize", package = "serialize" }
diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml
index 89b50c5dacc..c8c219d039a 100644
--- a/src/librustc_codegen_utils/Cargo.toml
+++ b/src/librustc_codegen_utils/Cargo.toml
@@ -10,7 +10,6 @@ path = "lib.rs"
 test = false
 
 [dependencies]
-flate2 = "1.0"
 log = "0.4"
 punycode = "0.4.0"
 rustc-demangle = "0.1.16"
diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs
index c4185fc7cd9..cbf6a0a3c03 100644
--- a/src/librustc_data_structures/graph/iterate/mod.rs
+++ b/src/librustc_data_structures/graph/iterate/mod.rs
@@ -1,5 +1,5 @@
 use super::super::indexed_vec::IndexVec;
-use super::{DirectedGraph, WithNumNodes, WithSuccessors};
+use super::{DirectedGraph, WithNumNodes, WithSuccessors, WithStartNode};
 use crate::bit_set::BitSet;
 
 #[cfg(test)]
@@ -85,3 +85,205 @@ where
         Some(n)
     }
 }
+
+/// Allows searches to terminate early with a value.
+#[derive(Clone, Copy, Debug)]
+pub enum ControlFlow<T> {
+    Break(T),
+    Continue,
+}
+
+/// The status of a node in the depth-first search.
+///
+/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
+/// during DFS.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum NodeStatus {
+    /// This node has been examined by the depth-first search but is not yet `Settled`.
+    ///
+    /// Also referred to as "gray" or "discovered" nodes in [CLR][].
+    ///
+    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
+    Visited,
+
+    /// This node and all nodes reachable from it have been examined by the depth-first search.
+    ///
+    /// Also referred to as "black" or "finished" nodes in [CLR][].
+    ///
+    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
+    Settled,
+}
+
+struct Event<N> {
+    node: N,
+    becomes: NodeStatus,
+}
+
+/// A depth-first search that also tracks when all successors of a node have been examined.
+///
+/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
+/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`][] above instead of
+/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
+/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
+/// reachable from it have been examined. This allows us to differentiate between "tree", "back"
+/// and "forward" edges (see [`TriColorVisitor::node_examined`]).
+///
+/// Unlike the pseudocode in [CLR][], this implementation is iterative and does not use timestamps.
+/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
+/// for each node. A `Visited` event signifies that we should examine this node if it has not yet
+/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
+/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
+/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
+/// may exist on the stack simultaneously if a node has multiple predecessors, but only one
+/// `Settled` event will ever be created for each node. After all `Visited` events for a node's
+/// successors have been popped off the stack (as well as any new events triggered by visiting
+/// those successors), we will pop off that node's `Settled` event.
+///
+/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
+/// [`NodeStatus`]: ./enum.NodeStatus.html
+/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
+pub struct TriColorDepthFirstSearch<'graph, G>
+where
+    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+{
+    graph: &'graph G,
+    stack: Vec<Event<G::Node>>,
+    visited: BitSet<G::Node>,
+    settled: BitSet<G::Node>,
+}
+
+impl<G> TriColorDepthFirstSearch<'graph, G>
+where
+    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+{
+    pub fn new(graph: &'graph G) -> Self {
+        TriColorDepthFirstSearch {
+            graph,
+            stack: vec![],
+            visited: BitSet::new_empty(graph.num_nodes()),
+            settled: BitSet::new_empty(graph.num_nodes()),
+        }
+    }
+
+    /// Performs a depth-first search, starting from the given `root`.
+    ///
+    /// This won't visit nodes that are not reachable from `root`.
+    pub fn run_from<V>(mut self, root: G::Node, visitor: &mut V) -> Option<V::BreakVal>
+    where
+        V: TriColorVisitor<G>,
+    {
+        use NodeStatus::{Visited, Settled};
+
+        self.stack.push(Event { node: root, becomes: Visited });
+
+        loop {
+            match self.stack.pop()? {
+                Event { node, becomes: Settled } => {
+                    let not_previously_settled = self.settled.insert(node);
+                    assert!(not_previously_settled, "A node should be settled exactly once");
+                    if let ControlFlow::Break(val) = visitor.node_settled(node) {
+                        return Some(val);
+                    }
+                }
+
+                Event { node, becomes: Visited } => {
+                    let not_previously_visited = self.visited.insert(node);
+                    let prior_status = if not_previously_visited {
+                        None
+                    } else if self.settled.contains(node) {
+                        Some(Settled)
+                    } else {
+                        Some(Visited)
+                    };
+
+                    if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) {
+                        return Some(val);
+                    }
+
+                    // If this node has already been examined, we are done.
+                    if prior_status.is_some() {
+                        continue;
+                    }
+
+                    // Otherwise, push a `Settled` event for this node onto the stack, then
+                    // schedule its successors for examination.
+                    self.stack.push(Event { node, becomes: Settled });
+                    for succ in self.graph.successors(node) {
+                        self.stack.push(Event { node: succ, becomes: Visited });
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<G> TriColorDepthFirstSearch<'graph, G>
+where
+    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
+{
+    /// Performs a depth-first search, starting from `G::start_node()`.
+    ///
+    /// This won't visit nodes that are not reachable from the start node.
+    pub fn run_from_start<V>(self, visitor: &mut V) -> Option<V::BreakVal>
+    where
+        V: TriColorVisitor<G>,
+    {
+        let root = self.graph.start_node();
+        self.run_from(root, visitor)
+    }
+}
+
+/// What to do when a node is examined or becomes `Settled` during DFS.
+pub trait TriColorVisitor<G>
+where
+    G: ?Sized + DirectedGraph,
+{
+    /// The value returned by this search.
+    type BreakVal;
+
+    /// Called when a node is examined by the depth-first search.
+    ///
+    /// By checking the value of `prior_status`, this visitor can determine whether the edge
+    /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
+    /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
+    /// chapter in [CLR][] or [wikipedia][].
+    ///
+    /// If you want to know *both* nodes linked by each edge, you'll need to modify
+    /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
+    ///
+    /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
+    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
+    fn node_examined(
+        &mut self,
+        _target: G::Node,
+        _prior_status: Option<NodeStatus>,
+    ) -> ControlFlow<Self::BreakVal> {
+        ControlFlow::Continue
+    }
+
+    /// Called after all nodes reachable from this one have been examined.
+    fn node_settled(&mut self, _target: G::Node) -> ControlFlow<Self::BreakVal> {
+        ControlFlow::Continue
+    }
+}
+
+/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
+pub struct CycleDetector;
+
+impl<G> TriColorVisitor<G> for CycleDetector
+where
+    G: ?Sized + DirectedGraph,
+{
+    type BreakVal = ();
+
+    fn node_examined(
+        &mut self,
+        _node: G::Node,
+        prior_status: Option<NodeStatus>,
+    ) -> ControlFlow<Self::BreakVal> {
+        match prior_status {
+            Some(NodeStatus::Visited) => ControlFlow::Break(()),
+            _ => ControlFlow::Continue,
+        }
+    }
+}
diff --git a/src/librustc_data_structures/graph/iterate/tests.rs b/src/librustc_data_structures/graph/iterate/tests.rs
index 6c7cfd6d8a7..0e038e88b22 100644
--- a/src/librustc_data_structures/graph/iterate/tests.rs
+++ b/src/librustc_data_structures/graph/iterate/tests.rs
@@ -9,3 +9,14 @@ fn diamond_post_order() {
     let result = post_order_from(&graph, 0);
     assert_eq!(result, vec![3, 1, 2, 0]);
 }
+
+#[test]
+fn is_cyclic() {
+    use super::super::is_cyclic;
+
+    let diamond_acyclic = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
+    let diamond_cyclic = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 0)]);
+
+    assert!(!is_cyclic(&diamond_acyclic));
+    assert!(is_cyclic(&diamond_cyclic));
+}
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index 662581ca1e4..0a607659f3e 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -81,3 +81,13 @@ where
         + WithNumNodes,
 {
 }
+
+/// Returns `true` if the graph has a cycle that is reachable from the start node.
+pub fn is_cyclic<G>(graph: &G) -> bool
+where
+    G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+{
+    iterate::TriColorDepthFirstSearch::new(graph)
+        .run_from_start(&mut iterate::CycleDetector)
+        .is_some()
+}
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f99e65b4494..4a868136741 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -296,7 +296,6 @@ pub fn run_compiler(
                     );
                     Ok(())
                 })?;
-                return sess.compile_status();
             } else {
                 let mut krate = compiler.parse()?.take();
                 pretty::visit_crate(sess, &mut krate, ppm);
@@ -307,8 +306,8 @@ pub fn run_compiler(
                     ppm,
                     compiler.output_file().as_ref().map(|p| &**p),
                 );
-                return sess.compile_status();
             }
+            return sess.compile_status();
         }
 
         if callbacks.after_parsing(compiler) == Compilation::Stop {
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index e85388bfea2..cc60bf89c7e 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -1,10 +1,6 @@
-use crate::Diagnostic;
-use crate::DiagnosticId;
-use crate::DiagnosticStyledString;
-use crate::Applicability;
+use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};
+use crate::{Applicability, Level, Handler, StashKey};
 
-use crate::Level;
-use crate::Handler;
 use std::fmt::{self, Debug};
 use std::ops::{Deref, DerefMut};
 use std::thread::panicking;
@@ -117,18 +113,30 @@ impl<'a> DiagnosticBuilder<'a> {
         }
     }
 
-    /// Buffers the diagnostic for later emission, unless handler
-    /// has disabled such buffering.
-    pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
+    /// Stashes diagnostic for possible later improvement in a different,
+    /// later stage of the compiler. The diagnostic can be accessed with
+    /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`.
+    ///
+    /// As with `buffer`, this is unless the handler has disabled such buffering.
+    pub fn stash(self, span: Span, key: StashKey) {
+        if let Some((diag, handler)) = self.into_diagnostic() {
+            handler.stash_diagnostic(span, key, diag);
+        }
+    }
+
+    /// Converts the builder to a `Diagnostic` for later emission,
+    /// unless handler has disabled such buffering.
+    pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
         if self.0.handler.flags.dont_buffer_diagnostics ||
             self.0.handler.flags.treat_err_as_bug.is_some()
         {
             self.emit();
-            return;
+            return None;
         }
 
-        // We need to use `ptr::read` because `DiagnosticBuilder`
-        // implements `Drop`.
+        let handler = self.0.handler;
+
+        // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`.
         let diagnostic;
         unsafe {
             diagnostic = std::ptr::read(&self.0.diagnostic);
@@ -137,7 +145,14 @@ impl<'a> DiagnosticBuilder<'a> {
         // Logging here is useful to help track down where in logs an error was
         // actually emitted.
         debug!("buffer: diagnostic={:?}", diagnostic);
-        buffered_diagnostics.push(diagnostic);
+
+        Some((diagnostic, handler))
+    }
+
+    /// Buffers the diagnostic for later emission,
+    /// unless handler has disabled such buffering.
+    pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
+        buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
     }
 
     /// Convenience function for internal use, clients should use one of the
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index fc441320e00..2a89c94652a 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -1043,14 +1043,13 @@ impl EmitterWriter {
     }
 
     fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize {
-        let mut max = 0;
 
         let primary = self.get_multispan_max_line_num(span);
-        max = if primary > max { primary } else { max };
+        let mut max = primary;
 
         for sub in children {
             let sub_result = self.get_multispan_max_line_num(&sub.span);
-            max = if sub_result > max { primary } else { max };
+            max = std::cmp::max(sub_result, max);
         }
         max
     }
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 1fe5b71d7b1..c01dcd94c72 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter};
 use registry::Registry;
 
 use rustc_data_structures::sync::{self, Lrc, Lock};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::StableHasher;
 
 use std::borrow::Cow;
@@ -302,6 +302,9 @@ pub struct Handler {
     inner: Lock<HandlerInner>,
 }
 
+/// This inner struct exists to keep it all behind a single lock;
+/// this is done to prevent possible deadlocks in a multi-threaded compiler,
+/// as well as inconsistent state observation.
 struct HandlerInner {
     flags: HandlerFlags,
     /// The number of errors that have been emitted, including duplicates.
@@ -326,6 +329,18 @@ struct HandlerInner {
     /// this handler. These hashes is used to avoid emitting the same error
     /// twice.
     emitted_diagnostics: FxHashSet<u128>,
+
+    /// Stashed diagnostics emitted in one stage of the compiler that may be
+    /// stolen by other stages (e.g. to improve them and add more information).
+    /// The stashed diagnostics count towards the total error count.
+    /// When `.abort_if_errors()` is called, these are also emitted.
+    stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
+}
+
+/// A key denoting where from a diagnostic was stashed.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum StashKey {
+    ItemNoType,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
@@ -354,7 +369,9 @@ pub struct HandlerFlags {
 
 impl Drop for HandlerInner {
     fn drop(&mut self) {
-        if self.err_count == 0 {
+        self.emit_stashed_diagnostics();
+
+        if !self.has_errors() {
             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
             let has_bugs = !bugs.is_empty();
             for bug in bugs {
@@ -368,57 +385,71 @@ impl Drop for HandlerInner {
 }
 
 impl Handler {
-    pub fn with_tty_emitter(color_config: ColorConfig,
-                            can_emit_warnings: bool,
-                            treat_err_as_bug: Option<usize>,
-                            cm: Option<Lrc<SourceMapperDyn>>)
-                            -> Handler {
-        Handler::with_tty_emitter_and_flags(
+    pub fn with_tty_emitter(
+        color_config: ColorConfig,
+        can_emit_warnings: bool,
+        treat_err_as_bug: Option<usize>,
+        cm: Option<Lrc<SourceMapperDyn>>,
+    ) -> Self {
+        Self::with_tty_emitter_and_flags(
             color_config,
             cm,
             HandlerFlags {
                 can_emit_warnings,
                 treat_err_as_bug,
                 .. Default::default()
-            })
+            },
+        )
     }
 
-    pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
-                                      cm: Option<Lrc<SourceMapperDyn>>,
-                                      flags: HandlerFlags)
-                                      -> Handler {
+    pub fn with_tty_emitter_and_flags(
+        color_config: ColorConfig,
+        cm: Option<Lrc<SourceMapperDyn>>,
+        flags: HandlerFlags,
+    ) -> Self {
         let emitter = Box::new(EmitterWriter::stderr(
-            color_config, cm, false, false, None, flags.external_macro_backtrace));
-        Handler::with_emitter_and_flags(emitter, flags)
-    }
-
-    pub fn with_emitter(can_emit_warnings: bool,
-                        treat_err_as_bug: Option<usize>,
-                        e: Box<dyn Emitter + sync::Send>)
-                        -> Handler {
+            color_config,
+            cm,
+            false,
+            false,
+            None,
+            flags.external_macro_backtrace,
+        ));
+        Self::with_emitter_and_flags(emitter, flags)
+    }
+
+    pub fn with_emitter(
+        can_emit_warnings: bool,
+        treat_err_as_bug: Option<usize>,
+        emitter: Box<dyn Emitter + sync::Send>,
+    ) -> Self {
         Handler::with_emitter_and_flags(
-            e,
+            emitter,
             HandlerFlags {
                 can_emit_warnings,
                 treat_err_as_bug,
                 .. Default::default()
-            })
+            },
+        )
     }
 
-    pub fn with_emitter_and_flags(e: Box<dyn Emitter + sync::Send>, flags: HandlerFlags) -> Handler
-    {
-        Handler {
+    pub fn with_emitter_and_flags(
+        emitter: Box<dyn Emitter + sync::Send>,
+        flags: HandlerFlags
+    ) -> Self {
+        Self {
             flags,
             inner: Lock::new(HandlerInner {
                 flags,
                 err_count: 0,
                 deduplicated_err_count: 0,
-                emitter: e,
+                emitter,
                 continue_after_error: true,
                 delayed_span_bugs: Vec::new(),
                 taught_diagnostics: Default::default(),
                 emitted_diagnostic_codes: Default::default(),
                 emitted_diagnostics: Default::default(),
+                stashed_diagnostics: Default::default(),
             }),
         }
     }
@@ -445,36 +476,68 @@ impl Handler {
         inner.emitted_diagnostics = Default::default();
         inner.deduplicated_err_count = 0;
         inner.err_count = 0;
+        inner.stashed_diagnostics.clear();
+    }
+
+    /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
+    /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE.
+    pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
+        let mut inner = self.inner.borrow_mut();
+        if let Some(mut old_diag) = inner.stashed_diagnostics.insert((span, key), diag) {
+            // We are removing a previously stashed diagnostic which should not happen.
+            old_diag.level = Bug;
+            old_diag.note(&format!(
+                "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})",
+                file!(), line!(), span, key
+            ));
+            inner.emit_diag_at_span(old_diag, span);
+            panic!(ExplicitBug);
+        }
+    }
+
+    /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
+    pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
+        self.inner
+            .borrow_mut()
+            .stashed_diagnostics
+            .remove(&(span, key))
+            .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+    }
+
+    /// Emit all stashed diagnostics.
+    pub fn emit_stashed_diagnostics(&self) {
+        self.inner.borrow_mut().emit_stashed_diagnostics();
     }
 
+    /// Construct a dummy builder with `Level::Cancelled`.
+    ///
+    /// Using this will neither report anything to the user (e.g. a warning),
+    /// nor will compilation cancel as a result.
     pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
         DiagnosticBuilder::new(self, Level::Cancelled, "")
     }
 
-    pub fn struct_span_warn<S: Into<MultiSpan>>(&self,
-                                                sp: S,
-                                                msg: &str)
-                                                -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
-        result.set_span(sp);
-        if !self.flags.can_emit_warnings {
-            result.cancel();
-        }
+    /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
+    pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_warn(msg);
+        result.set_span(span);
         result
     }
-    pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(&self,
-                                                          sp: S,
-                                                          msg: &str,
-                                                          code: DiagnosticId)
-                                                          -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
-        result.set_span(sp);
+
+    /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
+    /// Also include a code.
+    pub fn struct_span_warn_with_code(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_span_warn(span, msg);
         result.code(code);
-        if !self.flags.can_emit_warnings {
-            result.cancel();
-        }
         result
     }
+
+    /// Construct a builder at the `Warning` level with the `msg`.
     pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
         if !self.flags.can_emit_warnings {
@@ -482,146 +545,151 @@ impl Handler {
         }
         result
     }
-    pub fn struct_span_err<S: Into<MultiSpan>>(&self,
-                                               sp: S,
-                                               msg: &str)
-                                               -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
-        result.set_span(sp);
+
+    /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
+    pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_err(msg);
+        result.set_span(span);
         result
     }
-    pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
-                                                         sp: S,
-                                                         msg: &str,
-                                                         code: DiagnosticId)
-                                                         -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
-        result.set_span(sp);
+
+    /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
+    pub fn struct_span_err_with_code(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_span_err(span, msg);
         result.code(code);
         result
     }
+
+    /// Construct a builder at the `Error` level with the `msg`.
     // FIXME: This method should be removed (every error should have an associated error code).
     pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
         DiagnosticBuilder::new(self, Level::Error, msg)
     }
-    pub fn struct_err_with_code(
-        &self,
-        msg: &str,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
+
+    /// Construct a builder at the `Error` level with the `msg` and the `code`.
+    pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_err(msg);
         result.code(code);
         result
     }
-    pub fn struct_span_fatal<S: Into<MultiSpan>>(&self,
-                                                 sp: S,
-                                                 msg: &str)
-                                                 -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
-        result.set_span(sp);
+
+    /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
+    pub fn struct_span_fatal(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: &str,
+    ) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_fatal(msg);
+        result.set_span(span);
         result
     }
-    pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(&self,
-                                                           sp: S,
-                                                           msg: &str,
-                                                           code: DiagnosticId)
-                                                           -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
-        result.set_span(sp);
+
+    /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
+    pub fn struct_span_fatal_with_code(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> DiagnosticBuilder<'_> {
+        let mut result = self.struct_span_fatal(span, msg);
         result.code(code);
         result
     }
+
+    /// Construct a builder at the `Error` level with the `msg`.
     pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
         DiagnosticBuilder::new(self, Level::Fatal, msg)
     }
 
-    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
-        self.emit_diagnostic(Diagnostic::new(Fatal, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+    pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> FatalError {
+        self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
         FatalError
     }
-    pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
-                                                    sp: S,
-                                                    msg: &str,
-                                                    code: DiagnosticId)
-                                                    -> FatalError {
-        self.emit_diagnostic(Diagnostic::new_with_code(Fatal, Some(code), msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_fatal_with_code(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> FatalError {
+        self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
         FatalError
     }
-    pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.emit_diagnostic(Diagnostic::new(Error, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
-    }
-    pub fn mut_span_err<S: Into<MultiSpan>>(&self,
-                                            sp: S,
-                                            msg: &str)
-                                            -> DiagnosticBuilder<'_> {
-        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
-        result.set_span(sp);
-        result
+
+    pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
+        self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
     }
-    pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
-        self.emit_diagnostic(Diagnostic::new_with_code(Error, Some(code), msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
+        self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
     }
-    pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.emit_diagnostic(Diagnostic::new(Warning, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
+        self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
     }
-    pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
-        self.emit_diagnostic(Diagnostic::new_with_code(Warning, Some(code), msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
+        self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
     }
-    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
-        self.inner.borrow_mut().span_bug(sp, msg)
+
+    pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
+        self.inner.borrow_mut().span_bug(span, msg)
     }
-    pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.inner.borrow_mut().delay_span_bug(sp, msg)
+
+    pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
+        self.inner.borrow_mut().delay_span_bug(span, msg)
     }
-    pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
+        self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
     }
-    pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.emit_diagnostic(Diagnostic::new(Note, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+
+    pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
+        self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
     }
-    pub fn span_note_diag(&self,
-                          sp: Span,
-                          msg: &str)
-                          -> DiagnosticBuilder<'_> {
+
+    pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
         let mut db = DiagnosticBuilder::new(self, Note, msg);
-        db.set_span(sp);
+        db.set_span(span);
         db
     }
+
     pub fn failure(&self, msg: &str) {
         self.inner.borrow_mut().failure(msg);
     }
+
     pub fn fatal(&self, msg: &str) -> FatalError {
         self.inner.borrow_mut().fatal(msg)
     }
+
     pub fn err(&self, msg: &str) {
         self.inner.borrow_mut().err(msg);
     }
+
     pub fn warn(&self, msg: &str) {
         let mut db = DiagnosticBuilder::new(self, Warning, msg);
         db.emit();
     }
+
     pub fn note_without_error(&self, msg: &str) {
-        let mut db = DiagnosticBuilder::new(self, Note, msg);
-        db.emit();
+        DiagnosticBuilder::new(self, Note, msg).emit();
     }
+
     pub fn bug(&self, msg: &str) -> ! {
         self.inner.borrow_mut().bug(msg)
     }
 
     pub fn err_count(&self) -> usize {
-        self.inner.borrow().err_count
+        self.inner.borrow().err_count()
     }
 
     pub fn has_errors(&self) -> bool {
-        self.err_count() > 0
+        self.inner.borrow().has_errors()
     }
 
     pub fn print_error_count(&self, registry: &Registry) {
@@ -629,13 +697,18 @@ impl Handler {
     }
 
     pub fn abort_if_errors(&self) {
-        self.inner.borrow().abort_if_errors()
+        self.inner.borrow_mut().abort_if_errors()
     }
 
     pub fn abort_if_errors_and_should_abort(&self) {
-        self.inner.borrow().abort_if_errors_and_should_abort()
+        self.inner.borrow_mut().abort_if_errors_and_should_abort()
     }
 
+    /// `true` if we haven't taught a diagnostic with this code already.
+    /// The caller must then teach the user about such a diagnostic.
+    ///
+    /// Used to suppress emitting the same error multiple times with extended explanation when
+    /// calling `-Zteach`.
     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
         self.inner.borrow_mut().must_teach(code)
     }
@@ -648,6 +721,12 @@ impl Handler {
         self.inner.borrow_mut().emit_diagnostic(diagnostic)
     }
 
+    fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
+        let mut inner = self.inner.borrow_mut();
+        inner.emit_diagnostic(diag.set_span(sp));
+        inner.abort_if_errors_and_should_abort();
+    }
+
     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
         self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
     }
@@ -658,11 +737,6 @@ impl Handler {
 }
 
 impl HandlerInner {
-    /// `true` if we haven't taught a diagnostic with this code already.
-    /// The caller must then teach the user about such a diagnostic.
-    ///
-    /// Used to suppress emitting the same error multiple times with extended explanation when
-    /// calling `-Zteach`.
     fn must_teach(&mut self, code: &DiagnosticId) -> bool {
         self.taught_diagnostics.insert(code.clone())
     }
@@ -671,6 +745,12 @@ impl HandlerInner {
         self.emitter.emit_diagnostic(&db);
     }
 
+    /// Emit all stashed diagnostics.
+    fn emit_stashed_diagnostics(&mut self) {
+        let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
+        diags.iter().for_each(|diag| self.emit_diagnostic(diag));
+    }
+
     fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
         if diagnostic.cancelled() {
             return;
@@ -713,10 +793,12 @@ impl HandlerInner {
     }
 
     fn treat_err_as_bug(&self) -> bool {
-        self.flags.treat_err_as_bug.map(|c| self.err_count >= c).unwrap_or(false)
+        self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false)
     }
 
     fn print_error_count(&mut self, registry: &Registry) {
+        self.emit_stashed_diagnostics();
+
         let s = match self.deduplicated_err_count {
             0 => return,
             1 => "aborting due to previous error".to_string(),
@@ -760,25 +842,41 @@ impl HandlerInner {
         }
     }
 
-    fn abort_if_errors_and_should_abort(&self) {
-        if self.err_count > 0 && !self.continue_after_error {
+    fn err_count(&self) -> usize {
+        self.err_count + self.stashed_diagnostics.len()
+    }
+
+    fn has_errors(&self) -> bool {
+        self.err_count() > 0
+    }
+
+    fn abort_if_errors_and_should_abort(&mut self) {
+        self.emit_stashed_diagnostics();
+
+        if self.has_errors() && !self.continue_after_error {
             FatalError.raise();
         }
     }
 
-    fn abort_if_errors(&self) {
-        if self.err_count > 0 {
+    fn abort_if_errors(&mut self) {
+        self.emit_stashed_diagnostics();
+
+        if self.has_errors() {
             FatalError.raise();
         }
     }
 
-    fn span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> ! {
-        self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
-        self.abort_if_errors_and_should_abort();
+    fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
+        self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
         panic!(ExplicitBug);
     }
 
-    fn delay_span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) {
+    fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
+        self.emit_diagnostic(diag.set_span(sp));
+        self.abort_if_errors_and_should_abort();
+    }
+
+    fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
         if self.treat_err_as_bug() {
             // FIXME: don't abort here if report_delayed_bugs is off
             self.span_bug(sp, msg);
@@ -793,18 +891,20 @@ impl HandlerInner {
     }
 
     fn fatal(&mut self, msg: &str) -> FatalError {
-        if self.treat_err_as_bug() {
-            self.bug(msg);
-        }
-        self.emit_diagnostic(&Diagnostic::new(Fatal, msg));
+        self.emit_error(Fatal, msg);
         FatalError
     }
 
     fn err(&mut self, msg: &str) {
+        self.emit_error(Error, msg);
+    }
+
+    /// Emit an error; level should be `Error` or `Fatal`.
+    fn emit_error(&mut self, level: Level, msg: &str,) {
         if self.treat_err_as_bug() {
             self.bug(msg);
         }
-        self.emit_diagnostic(&Diagnostic::new(Error, msg));
+        self.emit_diagnostic(&Diagnostic::new(level, msg));
     }
 
     fn bug(&mut self, msg: &str) -> ! {
@@ -826,7 +926,7 @@ impl HandlerInner {
 
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
-            let s = match (self.err_count, self.flags.treat_err_as_bug.unwrap_or(0)) {
+            let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
                 (0, _) => return,
                 (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
                 (1, _) => return,
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index e8e8da67334..33de518c596 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -221,7 +221,6 @@ pub struct PluginInfo {
 }
 
 pub fn register_plugins<'a>(
-    compiler: &Compiler,
     sess: &'a Session,
     cstore: &'a CStore,
     mut krate: ast::Crate,
@@ -261,9 +260,6 @@ pub fn register_plugins<'a>(
         });
     }
 
-    // If necessary, compute the dependency graph (in the background).
-    compiler.dep_graph_future().ok();
-
     time(sess, "recursion limit", || {
         middle::recursion_limit::update_limits(sess, &krate);
     });
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index ed50dadb600..ff5cd8b8c69 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -114,29 +114,38 @@ impl Compiler {
             let crate_name = self.crate_name()?.peek().clone();
             let krate = self.parse()?.take();
 
-            passes::register_plugins(
-                self,
+            let result = passes::register_plugins(
                 self.session(),
                 self.cstore(),
                 krate,
                 &crate_name,
-            )
+            );
+
+            // Compute the dependency graph (in the background). We want to do
+            // this as early as possible, to give the DepGraph maximum time to
+            // load before dep_graph() is called, but it also can't happen
+            // until after rustc_incremental::prepare_session_directory() is
+            // called, which happens within passes::register_plugins().
+            self.dep_graph_future().ok();
+
+            result
         })
     }
 
     pub fn crate_name(&self) -> Result<&Query<String>> {
         self.queries.crate_name.compute(|| {
-            let parse_result = self.parse()?;
-            let krate = parse_result.peek();
-            let result = match self.crate_name {
+            Ok(match self.crate_name {
                 Some(ref crate_name) => crate_name.clone(),
-                None => rustc_codegen_utils::link::find_crate_name(
-                    Some(self.session()),
-                    &krate.attrs,
-                    &self.input
-                ),
-            };
-            Ok(result)
+                None => {
+                    let parse_result = self.parse()?;
+                    let krate = parse_result.peek();
+                    rustc_codegen_utils::link::find_crate_name(
+                        Some(self.session()),
+                        &krate.attrs,
+                        &self.input
+                    )
+                }
+            })
         })
     }
 
@@ -194,7 +203,6 @@ impl Compiler {
 
     pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
         self.queries.prepare_outputs.compute(|| {
-            self.lower_to_hir()?;
             let krate = self.expansion()?;
             let krate = krate.peek();
             let crate_name = self.crate_name()?;
@@ -267,6 +275,11 @@ impl Compiler {
         })
     }
 
+    // This method is different to all the other methods in `Compiler` because
+    // it lacks a `Queries` entry. It's also not currently used. It does serve
+    // as an example of how `Compiler` can be used, with additional steps added
+    // between some passes. And see `rustc_driver::run_compiler` for a more
+    // complex example.
     pub fn compile(&self) -> Result<()> {
         self.prepare_outputs()?;
 
@@ -278,12 +291,12 @@ impl Compiler {
 
         self.global_ctxt()?;
 
-        // Drop AST after creating GlobalCtxt to free memory
+        // Drop AST after creating GlobalCtxt to free memory.
         mem::drop(self.expansion()?.take());
 
         self.ongoing_codegen()?;
 
-        // Drop GlobalCtxt after starting codegen to free memory
+        // Drop GlobalCtxt after starting codegen to free memory.
         mem::drop(self.global_ctxt()?.take());
 
         self.link().map(|_| ())
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 0691390bead..f296753a030 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -24,6 +24,5 @@ rustc_lexer = { path = "../librustc_lexer" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-byteorder = { version = "1.3" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml
index 84a743ed1ad..3f11430dc82 100644
--- a/src/librustc_plugin/Cargo.toml
+++ b/src/librustc_plugin/Cargo.toml
@@ -15,4 +15,3 @@ rustc = { path = "../librustc" }
 rustc_metadata = { path = "../librustc_metadata" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml
index 548f982fe3b..936e72ef2c5 100644
--- a/src/librustc_resolve/Cargo.toml
+++ b/src/librustc_resolve/Cargo.toml
@@ -12,7 +12,6 @@ doctest = false
 
 [dependencies]
 bitflags = "1.0"
-indexmap = "1"
 log = "0.4"
 syntax = { path = "../libsyntax" }
 rustc = { path = "../librustc" }
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3900a3dbb38..73ad0670659 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -18,7 +18,7 @@ use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
 use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind};
-use syntax::ext::tt::macro_rules;
+use syntax::ext::compile_declarative_macro;
 use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
 use syntax::feature_gate::GateIssue;
 use syntax::symbol::{Symbol, kw, sym};
@@ -843,7 +843,7 @@ impl<'a> Resolver<'a> {
     /// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
     /// extension partially or entirely for built-in macros and legacy plugin macros.
     crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
-        let mut result = macro_rules::compile(
+        let mut result = compile_declarative_macro(
             &self.session.parse_sess, self.session.features_untracked(), item, edition
         );
 
diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml
index 88bb76d2aba..b89c83d630b 100644
--- a/src/librustc_save_analysis/Cargo.toml
+++ b/src/librustc_save_analysis/Cargo.toml
@@ -14,7 +14,6 @@ rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_target = { path = "../librustc_target" }
-rustc_typeck = { path = "../librustc_typeck" }
 serde_json = "1"
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml
index bb28ac839a5..b86a3a5e963 100644
--- a/src/librustc_traits/Cargo.toml
+++ b/src/librustc_traits/Cargo.toml
@@ -9,8 +9,6 @@ name = "rustc_traits"
 path = "lib.rs"
 
 [dependencies]
-bitflags = "1.0"
-graphviz = { path = "../libgraphviz" }
 log = { version = "0.4" }
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 74e4f28255b..4c681544978 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -232,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
                 let mut err = if !actual.references_error() {
                     // Suggest clamping down the type if the method that is being attempted to
-                    // be used exists at all, and the type is an ambiuous numeric type
+                    // be used exists at all, and the type is an ambiguous numeric type
                     // ({integer}/{float}).
                     let mut candidates = all_traits(self.tcx)
                         .into_iter()
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index d687a5084e2..2cd8507d753 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         } else {
             // Pattern has wrong number of fields.
-            self.e0023(pat.span, res, &subpats, &variant.fields, expected);
+            self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
             on_error();
             return tcx.types.err;
         }
@@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat_span: Span,
         res: Res,
+        qpath: &hir::QPath,
         subpats: &'tcx [P<Pat>],
         fields: &[ty::FieldDef],
         expected: Ty<'tcx>
     ) {
         let subpats_ending = pluralise!(subpats.len());
         let fields_ending = pluralise!(fields.len());
-        let missing_parenthesis = match expected.sty {
-            ty::Adt(_, substs) if fields.len() == 1 => {
-                let field_ty = fields[0].ty(self.tcx, substs);
-                match field_ty.sty {
-                    ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
-                    _ => false,
-                }
-            }
-            _ => false,
-        };
         let res_span = self.tcx.def_span(res.def_id());
         let mut err = struct_span_err!(
             self.tcx.sess,
@@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ))
             .span_label(res_span, format!("{} defined here", res.descr()));
 
+        // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
+        // More generally, the expected type wants a tuple variant with one field of an
+        // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
+        // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
+        let missing_parenthesis = match expected.sty {
+            ty::Adt(_, substs) if fields.len() == 1 => {
+                let field_ty = fields[0].ty(self.tcx, substs);
+                match field_ty.sty {
+                    ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
+                    _ => false,
+                }
+            }
+            _ => false,
+        };
         if missing_parenthesis {
+            let (left, right) = match subpats {
+                // This is the zero case; we aim to get the "hi" part of the `QPath`'s
+                // span as the "lo" and then the "hi" part of the pattern's span as the "hi".
+                // This looks like:
+                //
+                // help: missing parenthesis
+                //   |
+                // L |     let A(()) = A(());
+                //   |          ^  ^
+                [] => {
+                    let qpath_span = match qpath {
+                        hir::QPath::Resolved(_, path) => path.span,
+                        hir::QPath::TypeRelative(_, ps) => ps.ident.span,
+                    };
+                    (qpath_span.shrink_to_hi(), pat_span)
+                },
+                // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
+                // last sub-pattern. In the case of `A(x)` the first and last may coincide.
+                // This looks like:
+                //
+                // help: missing parenthesis
+                //   |
+                // L |     let A((x, y)) = A((1, 2));
+                //   |           ^    ^
+                [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
+            };
             err.multipart_suggestion(
                 "missing parenthesis",
-                vec![(subpats[0].span.shrink_to_lo(), "(".to_string()),
-                    (subpats[subpats.len()-1].span.shrink_to_hi(), ")".to_string())],
+                vec![
+                    (left, "(".to_string()),
+                    (right.shrink_to_hi(), ")".to_string()),
+                ],
                 Applicability::MachineApplicable,
             );
         }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b0e886a2aa2..f7e766bb84d 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -832,7 +832,7 @@ fn check_method_receiver<'fcx, 'tcx>(
 }
 
 fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) {
-    fcx.tcx.sess.diagnostic().mut_span_err(
+    fcx.tcx.sess.diagnostic().struct_span_err(
         span,
         &format!("invalid `self` parameter type: {:?}", receiver_ty)
     ).note("type of `self` must be `Self` or a type that dereferences to it")
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d2e9203779c..e6e0cb88fbd 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -46,7 +46,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::GenericParamKind;
 use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
 
-use errors::{Applicability, DiagnosticId};
+use errors::{Applicability, DiagnosticId, StashKey};
 
 struct OnlySelfBounds(bool);
 
@@ -1149,18 +1149,41 @@ fn infer_placeholder_type(
     def_id: DefId,
     body_id: hir::BodyId,
     span: Span,
+    item_ident: Ident,
 ) -> Ty<'_> {
     let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
-    let mut diag = bad_placeholder_type(tcx, span);
-    if ty != tcx.types.err {
-        diag.span_suggestion(
-            span,
-            "replace `_` with the correct type",
-            ty.to_string(),
-            Applicability::MaybeIncorrect,
-        );
+
+    // If this came from a free `const` or `static mut?` item,
+    // then the user may have written e.g. `const A = 42;`.
+    // In this case, the parser has stashed a diagnostic for
+    // us to improve in typeck so we do that now.
+    match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
+        Some(mut err) => {
+            // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
+            // We are typeck and have the real type, so remove that and suggest the actual type.
+            err.suggestions.clear();
+            err.span_suggestion(
+                span,
+                "provide a type for the item",
+                format!("{}: {}", item_ident, ty),
+                Applicability::MachineApplicable,
+            )
+            .emit();
+        }
+        None => {
+            let mut diag = bad_placeholder_type(tcx, span);
+            if ty != tcx.types.err {
+                diag.span_suggestion(
+                    span,
+                    "replace `_` with the correct type",
+                    ty.to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            diag.emit();
+        }
     }
-    diag.emit();
+
     ty
 }
 
@@ -1192,7 +1215,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
             TraitItemKind::Const(ref ty, body_id)  => {
                 body_id.and_then(|body_id| {
                     if let hir::TyKind::Infer = ty.node {
-                        Some(infer_placeholder_type(tcx, def_id, body_id, ty.span))
+                        Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
                     } else {
                         None
                     }
@@ -1214,7 +1237,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
             }
             ImplItemKind::Const(ref ty, body_id) => {
                 if let hir::TyKind::Infer = ty.node {
-                    infer_placeholder_type(tcx, def_id, body_id, ty.span)
+                    infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
                 } else {
                     icx.to_ty(ty)
                 }
@@ -1246,7 +1269,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                 ItemKind::Static(ref ty, .., body_id)
                 | ItemKind::Const(ref ty, body_id) => {
                     if let hir::TyKind::Infer = ty.node {
-                        infer_placeholder_type(tcx, def_id, body_id, ty.span)
+                        infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
                     } else {
                         icx.to_ty(ty)
                     }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 516be99ed6a..18a84cd0eeb 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -119,7 +119,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 source: Span::empty(),
                 name: None,
                 attrs: Default::default(),
-                visibility: None,
+                visibility: Inherited,
                 def_id: self.cx.next_def_id(param_env_def_id.krate),
                 stability: None,
                 deprecation: None,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 490d4107c51..4cd1cc1a1cf 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     source: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
                     name: None,
                     attrs: Default::default(),
-                    visibility: None,
+                    visibility: Inherited,
                     def_id: self.cx.next_def_id(impl_def_id.krate),
                     stability: None,
                     deprecation: None,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cb42ff1c805..031e77ff1db 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -131,7 +131,7 @@ pub fn try_inline(
         name: Some(name.clean(cx)),
         attrs,
         inner,
-        visibility: Some(clean::Public),
+        visibility: clean::Public,
         stability: cx.tcx.lookup_stability(did).clean(cx),
         deprecation: cx.tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
@@ -418,7 +418,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>,
         source: tcx.def_span(did).clean(cx),
         name: None,
         attrs,
-        visibility: Some(clean::Inherited),
+        visibility: clean::Inherited,
         stability: tcx.lookup_stability(did).clean(cx),
         deprecation: tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ae70fdc530b..197c09ba759 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -187,7 +187,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
                 source: Span::empty(),
                 name: Some(prim.to_url_str().to_string()),
                 attrs: attrs.clone(),
-                visibility: Some(Public),
+                visibility: Public,
                 stability: get_stability(cx, def_id),
                 deprecation: get_deprecation(cx, def_id),
                 def_id,
@@ -199,7 +199,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
                 source: Span::empty(),
                 name: Some(kw.clone()),
                 attrs: attrs,
-                visibility: Some(Public),
+                visibility: Public,
                 stability: get_stability(cx, def_id),
                 deprecation: get_deprecation(cx, def_id),
                 def_id,
@@ -361,7 +361,7 @@ pub struct Item {
     pub name: Option<String>,
     pub attrs: Attributes,
     pub inner: ItemEnum,
-    pub visibility: Option<Visibility>,
+    pub visibility: Visibility,
     pub def_id: DefId,
     pub stability: Option<Stability>,
     pub deprecation: Option<Deprecation>,
@@ -1849,7 +1849,7 @@ fn get_real_types(
     cx: &DocContext<'_>,
     recurse: i32,
 ) -> FxHashSet<Type> {
-    let arg_s = arg.to_string();
+    let arg_s = arg.print().to_string();
     let mut res = FxHashSet::default();
     if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
         return res;
@@ -2311,7 +2311,7 @@ impl Clean<Item> for hir::TraitItem {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             def_id: local_did,
-            visibility: None,
+            visibility: Visibility::Inherited,
             stability: get_stability(cx, local_did),
             deprecation: get_deprecation(cx, local_did),
             inner,
@@ -2496,7 +2496,7 @@ impl Clean<Item> for ty::AssocItem {
 
         let visibility = match self.container {
             ty::ImplContainer(_) => self.vis.clean(cx),
-            ty::TraitContainer(_) => None,
+            ty::TraitContainer(_) => Inherited,
         };
 
         Item {
@@ -3293,9 +3293,9 @@ pub enum Visibility {
     Restricted(DefId, Path),
 }
 
-impl Clean<Option<Visibility>> for hir::Visibility {
-    fn clean(&self, cx: &DocContext<'_>) -> Option<Visibility> {
-        Some(match self.node {
+impl Clean<Visibility> for hir::Visibility {
+    fn clean(&self, cx: &DocContext<'_>) -> Visibility {
+        match self.node {
             hir::VisibilityKind::Public => Visibility::Public,
             hir::VisibilityKind::Inherited => Visibility::Inherited,
             hir::VisibilityKind::Crate(_) => Visibility::Crate,
@@ -3304,13 +3304,13 @@ impl Clean<Option<Visibility>> for hir::Visibility {
                 let did = register_res(cx, path.res);
                 Visibility::Restricted(did, path)
             }
-        })
+        }
     }
 }
 
-impl Clean<Option<Visibility>> for ty::Visibility {
-    fn clean(&self, _: &DocContext<'_>) -> Option<Visibility> {
-        Some(if *self == ty::Visibility::Public { Public } else { Inherited })
+impl Clean<Visibility> for ty::Visibility {
+    fn clean(&self, _: &DocContext<'_>) -> Visibility {
+        if *self == ty::Visibility::Public { Public } else { Inherited }
     }
 }
 
@@ -3427,7 +3427,7 @@ impl Clean<Item> for doctree::Variant<'_> {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            visibility: None,
+            visibility: Inherited,
             stability: cx.stability(self.id).clean(cx),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id),
@@ -3470,7 +3470,7 @@ impl Clean<Item> for ty::VariantDef {
             name: Some(self.ident.clean(cx)),
             attrs: inline::load_attrs(cx, self.def_id).clean(cx),
             source: cx.tcx.def_span(self.def_id).clean(cx),
-            visibility: Some(Inherited),
+            visibility: Inherited,
             def_id: self.def_id,
             inner: VariantItem(Variant { kind }),
             stability: get_stability(cx, self.def_id),
@@ -3573,16 +3573,6 @@ pub enum GenericArg {
     Const(Constant),
 }
 
-impl fmt::Display for GenericArg {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            GenericArg::Lifetime(lt) => lt.fmt(f),
-            GenericArg::Type(ty) => ty.fmt(f),
-            GenericArg::Const(ct) => ct.fmt(f),
-        }
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum GenericArgs {
     AngleBracketed {
@@ -4274,7 +4264,7 @@ fn resolve_type(cx: &DocContext<'_>,
             return Generic(kw::SelfUpper.to_string());
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(format!("{:#}", path));
+            return Generic(format!("{:#}", path.print()));
         }
         Res::SelfTy(..)
         | Res::Def(DefKind::TyParam, _)
@@ -4343,7 +4333,7 @@ impl Clean<Item> for doctree::Macro<'_> {
             name: Some(name.clone()),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            visibility: Some(Public),
+            visibility: Public,
             stability: cx.stability(self.hid).clean(cx),
             deprecation: cx.deprecation(self.hid).clean(cx),
             def_id: self.def_id,
@@ -4371,7 +4361,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            visibility: Some(Public),
+            visibility: Public,
             stability: cx.stability(self.id).clean(cx),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index dcd32192ff3..fafd43cb60b 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -99,10 +99,6 @@ impl Buffer {
         self.into_inner()
     }
 
-    crate fn with_formatter<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result>(&mut self, t: T) {
-        self.from_display(display_fn(move |f| (t)(f)));
-    }
-
     crate fn from_display<T: std::fmt::Display>(&mut self, t: T) {
         if self.for_html {
             write!(self, "{}", t);
@@ -112,30 +108,6 @@ impl Buffer {
     }
 }
 
-/// Helper to render an optional visibility with a space after it (if the
-/// visibility is preset)
-#[derive(Copy, Clone)]
-pub struct VisSpace<'a>(pub &'a Option<clean::Visibility>);
-/// Similarly to VisSpace, this structure is used to render a function style with a
-/// space after it.
-#[derive(Copy, Clone)]
-pub struct UnsafetySpace(pub hir::Unsafety);
-/// Similarly to VisSpace, this structure is used to render a function constness
-/// with a space after it.
-#[derive(Copy, Clone)]
-pub struct ConstnessSpace(pub hir::Constness);
-/// Similarly to VisSpace, this structure is used to render a function asyncness
-/// with a space after it.
-#[derive(Copy, Clone)]
-pub struct AsyncSpace(pub hir::IsAsync);
-/// Similar to VisSpace, but used for mutability
-#[derive(Copy, Clone)]
-pub struct MutableSpace(pub clean::Mutability);
-/// Wrapper struct for emitting type parameter bounds.
-pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
-pub struct AbiSpace(pub Abi);
-pub struct DefaultSpace(pub bool);
-
 /// Wrapper struct for properly emitting a function or method declaration.
 pub struct Function<'a> {
     /// The declaration to emit.
@@ -161,102 +133,89 @@ pub struct WhereClause<'a>{
     pub end_newline: bool,
 }
 
-impl<'a> VisSpace<'a> {
-    pub fn get(self) -> &'a Option<clean::Visibility> {
-        let VisSpace(v) = self; v
-    }
-}
-
-impl UnsafetySpace {
-    pub fn get(&self) -> hir::Unsafety {
-        let UnsafetySpace(v) = *self; v
-    }
-}
-
-impl ConstnessSpace {
-    pub fn get(&self) -> hir::Constness {
-        let ConstnessSpace(v) = *self; v
-    }
-}
-
-fn comma_sep<T: fmt::Display>(items: &[T]) -> impl fmt::Display + '_ {
+fn comma_sep<T: fmt::Display>(items: impl Iterator<Item=T>) -> impl fmt::Display {
     display_fn(move |f| {
-        for (i, item) in items.iter().enumerate() {
+        for (i, item) in items.enumerate() {
             if i != 0 { write!(f, ", ")?; }
-            fmt::Display::fmt(item, f)?;
+            fmt::Display::fmt(&item, f)?;
         }
         Ok(())
     })
 }
 
-impl<'a> fmt::Display for GenericBounds<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+crate fn print_generic_bounds(bounds: &[clean::GenericBound]) -> impl fmt::Display + '_ {
+    display_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
-        let &GenericBounds(bounds) = self;
 
-        for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.to_string())).enumerate() {
+        for (i, bound) in bounds.iter().filter(|b| {
+            bounds_dup.insert(b.print().to_string())
+        }).enumerate() {
             if i > 0 {
                 f.write_str(" + ")?;
             }
-            fmt::Display::fmt(bound, f)?;
+            fmt::Display::fmt(&bound.print(), f)?;
         }
         Ok(())
-    }
+    })
 }
 
-impl fmt::Display for clean::GenericParamDef {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.kind {
-            clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
-            clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
-                f.write_str(&self.name)?;
+impl clean::GenericParamDef {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match self.kind {
+                clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
+                clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
+                    f.write_str(&self.name)?;
 
-                if !bounds.is_empty() {
-                    if f.alternate() {
-                        write!(f, ": {:#}", GenericBounds(bounds))?;
-                    } else {
-                        write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
+                    if !bounds.is_empty() {
+                        if f.alternate() {
+                            write!(f, ": {:#}", print_generic_bounds(bounds))?;
+                        } else {
+                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds))?;
+                        }
+                    }
+
+                    if let Some(ref ty) = default {
+                        if f.alternate() {
+                            write!(f, " = {:#}", ty.print())?;
+                        } else {
+                            write!(f, "&nbsp;=&nbsp;{}", ty.print())?;
+                        }
                     }
+
+                    Ok(())
                 }
+                clean::GenericParamDefKind::Const { ref ty, .. } => {
+                    f.write_str("const ")?;
+                    f.write_str(&self.name)?;
 
-                if let Some(ref ty) = default {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty)?;
+                        write!(f, ": {:#}", ty.print())
                     } else {
-                        write!(f, "&nbsp;=&nbsp;{}", ty)?;
+                        write!(f, ":&nbsp;{}", ty.print())
                     }
                 }
-
-                Ok(())
             }
-            clean::GenericParamDefKind::Const { ref ty, .. } => {
-                f.write_str("const ")?;
-                f.write_str(&self.name)?;
-
-                if f.alternate() {
-                    write!(f, ": {:#}", ty)
-                } else {
-                    write!(f, ":&nbsp;{}", ty)
-                }
-            }
-        }
+        })
     }
 }
 
-impl fmt::Display for clean::Generics {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let real_params = self.params
-            .iter()
-            .filter(|p| !p.is_synthetic_type_param())
-            .collect::<Vec<_>>();
-        if real_params.is_empty() {
-            return Ok(());
-        }
-        if f.alternate() {
-            write!(f, "<{:#}>", comma_sep(&real_params))
-        } else {
-            write!(f, "&lt;{}&gt;", comma_sep(&real_params))
-        }
+impl clean::Generics {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            let real_params = self.params
+                .iter()
+                .filter(|p| !p.is_synthetic_type_param())
+                .collect::<Vec<_>>();
+            if real_params.is_empty() {
+                return Ok(());
+            }
+            if f.alternate() {
+                write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print())))
+            } else {
+                write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print())))
+            }
+        })
     }
 }
 
@@ -287,24 +246,26 @@ impl<'a> fmt::Display for WhereClause<'a> {
                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
                     let bounds = bounds;
                     if f.alternate() {
-                        clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds)));
+                        clause.push_str(&format!("{:#}: {:#}",
+                                ty.print(), print_generic_bounds(bounds)));
                     } else {
-                        clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds)));
+                        clause.push_str(&format!("{}: {}",
+                                ty.print(), print_generic_bounds(bounds)));
                     }
                 }
                 &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => {
                     clause.push_str(&format!("{}: {}",
-                                                lifetime,
+                                                lifetime.print(),
                                                 bounds.iter()
-                                                    .map(|b| b.to_string())
+                                                    .map(|b| b.print().to_string())
                                                     .collect::<Vec<_>>()
                                                     .join(" + ")));
                 }
                 &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
                     if f.alternate() {
-                        clause.push_str(&format!("{:#} == {:#}", lhs, rhs));
+                        clause.push_str(&format!("{:#} == {:#}", lhs.print(), rhs.print()));
                     } else {
-                        clause.push_str(&format!("{} == {}", lhs, rhs));
+                        clause.push_str(&format!("{} == {}", lhs.print(), rhs.print()));
                     }
                 }
             }
@@ -336,153 +297,164 @@ impl<'a> fmt::Display for WhereClause<'a> {
     }
 }
 
-impl fmt::Display for clean::Lifetime {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(self.get_ref())?;
-        Ok(())
+impl clean::Lifetime {
+    crate fn print(&self) -> &str {
+        self.get_ref()
     }
 }
 
-impl fmt::Display for clean::Constant {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.expr, f)
+impl clean::Constant {
+    crate fn print(&self) -> &str {
+        &self.expr
     }
 }
 
-impl fmt::Display for clean::PolyTrait {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if !self.generic_params.is_empty() {
+impl clean::PolyTrait {
+    fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            if !self.generic_params.is_empty() {
+                if f.alternate() {
+                    write!(f, "for<{:#}> ",
+                        comma_sep(self.generic_params.iter().map(|g| g.print())))?;
+                } else {
+                    write!(f, "for&lt;{}&gt; ",
+                        comma_sep(self.generic_params.iter().map(|g| g.print())))?;
+                }
+            }
             if f.alternate() {
-                write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?;
+                write!(f, "{:#}", self.trait_.print())
             } else {
-                write!(f, "for&lt;{}&gt; ", comma_sep(&self.generic_params))?;
+                write!(f, "{}", self.trait_.print())
             }
-        }
-        if f.alternate() {
-            write!(f, "{:#}", self.trait_)
-        } else {
-            write!(f, "{}", self.trait_)
-        }
+        })
     }
 }
 
-impl fmt::Display for clean::GenericBound {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            clean::GenericBound::Outlives(ref lt) => {
-                write!(f, "{}", *lt)
-            }
-            clean::GenericBound::TraitBound(ref ty, modifier) => {
-                let modifier_str = match modifier {
-                    hir::TraitBoundModifier::None => "",
-                    hir::TraitBoundModifier::Maybe => "?",
-                };
-                if f.alternate() {
-                    write!(f, "{}{:#}", modifier_str, *ty)
-                } else {
-                    write!(f, "{}{}", modifier_str, *ty)
+impl clean::GenericBound {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match self {
+                clean::GenericBound::Outlives(lt) => {
+                    write!(f, "{}", lt.print())
+                }
+                clean::GenericBound::TraitBound(ty, modifier) => {
+                    let modifier_str = match modifier {
+                        hir::TraitBoundModifier::None => "",
+                        hir::TraitBoundModifier::Maybe => "?",
+                    };
+                    if f.alternate() {
+                        write!(f, "{}{:#}", modifier_str, ty.print())
+                    } else {
+                        write!(f, "{}{}", modifier_str, ty.print())
+                    }
                 }
             }
-        }
+        })
     }
 }
 
-impl fmt::Display for clean::GenericArgs {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            clean::GenericArgs::AngleBracketed { ref args, ref bindings } => {
-                if !args.is_empty() || !bindings.is_empty() {
-                    if f.alternate() {
-                        f.write_str("<")?;
-                    } else {
-                        f.write_str("&lt;")?;
-                    }
-                    let mut comma = false;
-                    for arg in args {
-                        if comma {
-                            f.write_str(", ")?;
+impl clean::GenericArgs {
+    fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match *self {
+                clean::GenericArgs::AngleBracketed { ref args, ref bindings } => {
+                    if !args.is_empty() || !bindings.is_empty() {
+                        if f.alternate() {
+                            f.write_str("<")?;
+                        } else {
+                            f.write_str("&lt;")?;
+                        }
+                        let mut comma = false;
+                        for arg in args {
+                            if comma {
+                                f.write_str(", ")?;
+                            }
+                            comma = true;
+                            if f.alternate() {
+                                write!(f, "{:#}", arg.print())?;
+                            } else {
+                                write!(f, "{}", arg.print())?;
+                            }
+                        }
+                        for binding in bindings {
+                            if comma {
+                                f.write_str(", ")?;
+                            }
+                            comma = true;
+                            if f.alternate() {
+                                write!(f, "{:#}", binding.print())?;
+                            } else {
+                                write!(f, "{}", binding.print())?;
+                            }
                         }
-                        comma = true;
                         if f.alternate() {
-                            write!(f, "{:#}", *arg)?;
+                            f.write_str(">")?;
                         } else {
-                            write!(f, "{}", *arg)?;
+                            f.write_str("&gt;")?;
                         }
                     }
-                    for binding in bindings {
+                }
+                clean::GenericArgs::Parenthesized { ref inputs, ref output } => {
+                    f.write_str("(")?;
+                    let mut comma = false;
+                    for ty in inputs {
                         if comma {
                             f.write_str(", ")?;
                         }
                         comma = true;
                         if f.alternate() {
-                            write!(f, "{:#}", *binding)?;
+                            write!(f, "{:#}", ty.print())?;
                         } else {
-                            write!(f, "{}", *binding)?;
+                            write!(f, "{}", ty.print())?;
                         }
                     }
-                    if f.alternate() {
-                        f.write_str(">")?;
-                    } else {
-                        f.write_str("&gt;")?;
-                    }
-                }
-            }
-            clean::GenericArgs::Parenthesized { ref inputs, ref output } => {
-                f.write_str("(")?;
-                let mut comma = false;
-                for ty in inputs {
-                    if comma {
-                        f.write_str(", ")?;
-                    }
-                    comma = true;
-                    if f.alternate() {
-                        write!(f, "{:#}", *ty)?;
-                    } else {
-                        write!(f, "{}", *ty)?;
-                    }
-                }
-                f.write_str(")")?;
-                if let Some(ref ty) = *output {
-                    if f.alternate() {
-                        write!(f, " -> {:#}", ty)?;
-                    } else {
-                        write!(f, " -&gt; {}", ty)?;
+                    f.write_str(")")?;
+                    if let Some(ref ty) = *output {
+                        if f.alternate() {
+                            write!(f, " -> {:#}", ty.print())?;
+                        } else {
+                            write!(f, " -&gt; {}", ty.print())?;
+                        }
                     }
                 }
             }
-        }
-        Ok(())
+            Ok(())
+        })
     }
 }
 
-impl fmt::Display for clean::PathSegment {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(&self.name)?;
-        if f.alternate() {
-            write!(f, "{:#}", self.args)
-        } else {
-            write!(f, "{}", self.args)
-        }
+impl clean::PathSegment {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            f.write_str(&self.name)?;
+            if f.alternate() {
+                write!(f, "{:#}", self.args.print())
+            } else {
+                write!(f, "{}", self.args.print())
+            }
+        })
     }
 }
 
-impl fmt::Display for clean::Path {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.global {
-            f.write_str("::")?
-        }
-
-        for (i, seg) in self.segments.iter().enumerate() {
-            if i > 0 {
+impl clean::Path {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            if self.global {
                 f.write_str("::")?
             }
-            if f.alternate() {
-                write!(f, "{:#}", seg)?;
-            } else {
-                write!(f, "{}", seg)?;
+
+            for (i, seg) in self.segments.iter().enumerate() {
+                if i > 0 {
+                    f.write_str("::")?
+                }
+                if f.alternate() {
+                    write!(f, "{:#}", seg.print())?;
+                } else {
+                    write!(f, "{}", seg.print())?;
+                }
             }
-        }
-        Ok(())
+            Ok(())
+        })
     }
 }
 
@@ -516,7 +488,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
             url.push_str("/index.html");
         }
         _ => {
-            url.push_str(shortty.css_class());
+            url.push_str(shortty.as_str());
             url.push_str(".");
             url.push_str(fqp.last().unwrap());
             url.push_str(".html");
@@ -537,7 +509,7 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path,
         }
     }
     if w.alternate() {
-        write!(w, "{}{:#}", &last.name, last.args)?;
+        write!(w, "{}{:#}", &last.name, last.args.print())?;
     } else {
         let path = if use_absolute {
             if let Some((_, _, fqp)) = href(did) {
@@ -550,7 +522,7 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path,
         } else {
             anchor(did, &last.name).to_string()
         };
-        write!(w, "{}{}", path, last.args)?;
+        write!(w, "{}{}", path, last.args.print())?;
     }
     Ok(())
 }
@@ -606,7 +578,7 @@ fn tybounds(param_names: &Option<Vec<clean::GenericBound>>) -> impl fmt::Display
             Some(ref params) => {
                 for param in params {
                     write!(f, " + ")?;
-                    fmt::Display::fmt(param, f)?;
+                    fmt::Display::fmt(&param.print(), f)?;
                 }
                 Ok(())
             }
@@ -644,14 +616,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
         clean::BareFunction(ref decl) => {
             if f.alternate() {
                 write!(f, "{}{:#}fn{:#}{:#}",
-                       UnsafetySpace(decl.unsafety),
-                       AbiSpace(decl.abi),
-                       comma_sep(&decl.generic_params),
-                       decl.decl)
+                       decl.unsafety.print_with_space(),
+                       print_abi_with_space(decl.abi),
+                       decl.print_generic_params(),
+                       decl.decl.print())
             } else {
-                write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
+                write!(f, "{}{}",
+                    decl.unsafety.print_with_space(), print_abi_with_space(decl.abi))?;
                 primitive_link(f, PrimitiveType::Fn, "fn")?;
-                write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl)
+                write!(f, "{}{}", decl.print_generic_params(), decl.decl.print())
             }
         }
         clean::Tuple(ref typs) => {
@@ -660,24 +633,27 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 &[ref one] => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
                     // Carry `f.alternate()` into this display w/o branching manually.
-                    fmt::Display::fmt(one, f)?;
+                    fmt::Display::fmt(&one.print(), f)?;
                     primitive_link(f, PrimitiveType::Tuple, ",)")
                 }
                 many => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
-                    fmt::Display::fmt(&comma_sep(many), f)?;
+                    for (i, item) in many.iter().enumerate() {
+                        if i != 0 { write!(f, ", ")?; }
+                        fmt::Display::fmt(&item.print(), f)?;
+                    }
                     primitive_link(f, PrimitiveType::Tuple, ")")
                 }
             }
         }
         clean::Slice(ref t) => {
             primitive_link(f, PrimitiveType::Slice, "[")?;
-            fmt::Display::fmt(t, f)?;
+            fmt::Display::fmt(&t.print(), f)?;
             primitive_link(f, PrimitiveType::Slice, "]")
         }
         clean::Array(ref t, ref n) => {
             primitive_link(f, PrimitiveType::Array, "[")?;
-            fmt::Display::fmt(t, f)?;
+            fmt::Display::fmt(&t.print(), f)?;
             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
         }
         clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
@@ -691,24 +667,24 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
                     if f.alternate() {
                         primitive_link(f, clean::PrimitiveType::RawPointer,
-                                       &format!("*{} {:#}", m, t))
+                                       &format!("*{} {:#}", m, t.print()))
                     } else {
                         primitive_link(f, clean::PrimitiveType::RawPointer,
-                                       &format!("*{} {}", m, t))
+                                       &format!("*{} {}", m, t.print()))
                     }
                 }
                 _ => {
                     primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?;
-                    fmt::Display::fmt(t, f)
+                    fmt::Display::fmt(&t.print(), f)
                 }
             }
         }
         clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
-            let lt = match *l {
-                Some(ref l) => format!("{} ", *l),
-                _ => String::new(),
+            let lt = match l {
+                Some(l) => format!("{} ", l.print()),
+                _ => String::new()
             };
-            let m = MutableSpace(mutability);
+            let m = mutability.print_with_space();
             let amp = if f.alternate() {
                 "&".to_string()
             } else {
@@ -720,19 +696,19 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                         clean::Generic(_) => {
                             if f.alternate() {
                                 primitive_link(f, PrimitiveType::Slice,
-                                    &format!("{}{}{}[{:#}]", amp, lt, m, **bt))
+                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print()))
                             } else {
                                 primitive_link(f, PrimitiveType::Slice,
-                                    &format!("{}{}{}[{}]", amp, lt, m, **bt))
+                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print()))
                             }
                         }
                         _ => {
                             primitive_link(f, PrimitiveType::Slice,
                                            &format!("{}{}{}[", amp, lt, m))?;
                             if f.alternate() {
-                                write!(f, "{:#}", **bt)?;
+                                write!(f, "{:#}", bt.print())?;
                             } else {
-                                write!(f, "{}", **bt)?;
+                                write!(f, "{}", bt.print())?;
                             }
                             primitive_link(f, PrimitiveType::Slice, "]")
                         }
@@ -756,9 +732,9 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
         }
         clean::ImplTrait(ref bounds) => {
             if f.alternate() {
-                write!(f, "impl {:#}", GenericBounds(bounds))
+                write!(f, "impl {:#}", print_generic_bounds(bounds))
             } else {
-                write!(f, "impl {}", GenericBounds(bounds))
+                write!(f, "impl {}", print_generic_bounds(bounds))
             }
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
@@ -770,15 +746,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
             };
             if f.alternate() {
                 if should_show_cast {
-                    write!(f, "<{:#} as {:#}>::", self_type, trait_)?
+                    write!(f, "<{:#} as {:#}>::", self_type.print(), trait_.print())?
                 } else {
-                    write!(f, "{:#}::", self_type)?
+                    write!(f, "{:#}::", self_type.print())?
                 }
             } else {
                 if should_show_cast {
-                    write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
+                    write!(f, "&lt;{} as {}&gt;::", self_type.print(), trait_.print())?
                 } else {
-                    write!(f, "{}::", self_type)?
+                    write!(f, "{}::", self_type.print())?
                 }
             };
             match *trait_ {
@@ -818,55 +794,64 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
     }
 }
 
-impl fmt::Display for clean::Type {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt_type(self, f, false)
+impl clean::Type {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            fmt_type(self, f, false)
+        })
     }
 }
 
-fn fmt_impl(i: &clean::Impl,
-            f: &mut fmt::Formatter<'_>,
-            link_trait: bool,
-            use_absolute: bool) -> fmt::Result {
-    if f.alternate() {
-        write!(f, "impl{:#} ", i.generics)?;
-    } else {
-        write!(f, "impl{} ", i.generics)?;
+impl clean::Impl {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        self.print_inner(true, false)
     }
 
-    if let Some(ref ty) = i.trait_ {
-        if i.polarity == Some(clean::ImplPolarity::Negative) {
-            write!(f, "!")?;
-        }
+    fn print_inner(
+        &self,
+        link_trait: bool,
+        use_absolute: bool,
+    ) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            if f.alternate() {
+                write!(f, "impl{:#} ", self.generics.print())?;
+            } else {
+                write!(f, "impl{} ", self.generics.print())?;
+            }
 
-        if link_trait {
-            fmt::Display::fmt(ty, f)?;
-        } else {
-            match *ty {
-                clean::ResolvedPath { param_names: None, ref path, is_generic: false, .. } => {
-                    let last = path.segments.last().unwrap();
-                    fmt::Display::fmt(&last.name, f)?;
-                    fmt::Display::fmt(&last.args, f)?;
+            if let Some(ref ty) = self.trait_ {
+                if self.polarity == Some(clean::ImplPolarity::Negative) {
+                    write!(f, "!")?;
                 }
-                _ => unreachable!(),
-            }
-        }
-        write!(f, " for ")?;
-    }
 
-    if let Some(ref ty) = i.blanket_impl {
-        fmt_type(ty, f, use_absolute)?;
-    } else {
-        fmt_type(&i.for_, f, use_absolute)?;
-    }
+                if link_trait {
+                    fmt::Display::fmt(&ty.print(), f)?;
+                } else {
+                    match ty {
+                        clean::ResolvedPath { param_names: None, path, is_generic: false, .. } => {
+                            let last = path.segments.last().unwrap();
+                            fmt::Display::fmt(&last.name, f)?;
+                            fmt::Display::fmt(&last.args.print(), f)?;
+                        }
+                        _ => unreachable!(),
+                    }
+                }
+                write!(f, " for ")?;
+            }
 
-    fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
-    Ok(())
-}
+            if let Some(ref ty) = self.blanket_impl {
+                fmt_type(ty, f, use_absolute)?;
+            } else {
+                fmt_type(&self.for_, f, use_absolute)?;
+            }
 
-impl fmt::Display for clean::Impl {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt_impl(self, f, true, false)
+            fmt::Display::fmt(&WhereClause {
+                gens: &self.generics,
+                indent: 0,
+                end_newline: true,
+            }, f)?;
+            Ok(())
+        })
     }
 }
 
@@ -874,275 +859,316 @@ impl fmt::Display for clean::Impl {
 pub fn fmt_impl_for_trait_page(i: &clean::Impl,
                                f: &mut Buffer,
                                use_absolute: bool) {
-    f.with_formatter(|f| fmt_impl(i, f, false, use_absolute))
+    f.from_display(i.print_inner(false, use_absolute))
 }
 
-impl fmt::Display for clean::Arguments {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        for (i, input) in self.values.iter().enumerate() {
-            if !input.name.is_empty() {
-                write!(f, "{}: ", input.name)?;
-            }
-            if f.alternate() {
-                write!(f, "{:#}", input.type_)?;
-            } else {
-                write!(f, "{}", input.type_)?;
+impl clean::Arguments {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            for (i, input) in self.values.iter().enumerate() {
+                if !input.name.is_empty() {
+                    write!(f, "{}: ", input.name)?;
+                }
+                if f.alternate() {
+                    write!(f, "{:#}", input.type_.print())?;
+                } else {
+                    write!(f, "{}", input.type_.print())?;
+                }
+                if i + 1 < self.values.len() { write!(f, ", ")?; }
             }
-            if i + 1 < self.values.len() { write!(f, ", ")?; }
-        }
-        Ok(())
+            Ok(())
+        })
     }
 }
 
-impl fmt::Display for clean::FunctionRetTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
-            clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
-            clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
-            clean::DefaultReturn => Ok(()),
-        }
+impl clean::FunctionRetTy {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match self {
+                clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()),
+                clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print()),
+                clean::Return(ty) => write!(f, " -&gt; {}", ty.print()),
+                clean::DefaultReturn => Ok(()),
+            }
+        })
     }
 }
 
-impl fmt::Display for clean::FnDecl {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
-        } else {
-            write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
-        }
+impl clean::BareFunctionDecl {
+    fn print_generic_params(&self) -> impl fmt::Display + '_ {
+        comma_sep(self.generic_params.iter().map(|g| g.print()))
     }
 }
 
-impl<'a> fmt::Display for Function<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let &Function { decl, header_len, indent, asyncness } = self;
-        let amp = if f.alternate() { "&" } else { "&amp;" };
-        let mut args = String::new();
-        let mut args_plain = String::new();
-        for (i, input) in decl.inputs.values.iter().enumerate() {
-            if i == 0 {
-                args.push_str("<br>");
+impl clean::FnDecl {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            if f.alternate() {
+                write!(f,
+                    "({args:#}){arrow:#}", args = self.inputs.print(), arrow = self.output.print())
+            } else {
+                write!(f,
+                    "({args}){arrow}", args = self.inputs.print(), arrow = self.output.print())
             }
+        })
+    }
+}
 
-            if let Some(selfty) = input.to_self() {
-                match selfty {
-                    clean::SelfValue => {
-                        args.push_str("self");
-                        args_plain.push_str("self");
+
+impl Function<'_> {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            let &Function { decl, header_len, indent, asyncness } = self;
+            let amp = if f.alternate() { "&" } else { "&amp;" };
+            let mut args = String::new();
+            let mut args_plain = String::new();
+            for (i, input) in decl.inputs.values.iter().enumerate() {
+                if i == 0 {
+                    args.push_str("<br>");
+                }
+
+                if let Some(selfty) = input.to_self() {
+                    match selfty {
+                        clean::SelfValue => {
+                            args.push_str("self");
+                            args_plain.push_str("self");
+                        }
+                        clean::SelfBorrowed(Some(ref lt), mtbl) => {
+                            args.push_str(
+                                &format!("{}{} {}self", amp, lt.print(), mtbl.print_with_space()));
+                            args_plain.push_str(
+                                &format!("&{} {}self", lt.print(), mtbl.print_with_space()));
+                        }
+                        clean::SelfBorrowed(None, mtbl) => {
+                            args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
+                            args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
+                        }
+                        clean::SelfExplicit(ref typ) => {
+                            if f.alternate() {
+                                args.push_str(&format!("self: {:#}", typ.print()));
+                            } else {
+                                args.push_str(&format!("self: {}", typ.print()));
+                            }
+                            args_plain.push_str(&format!("self: {:#}", typ.print()));
+                        }
                     }
-                    clean::SelfBorrowed(Some(ref lt), mtbl) => {
-                        args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
-                        args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
+                } else {
+                    if i > 0 {
+                        args.push_str(" <br>");
+                        args_plain.push_str(" ");
                     }
-                    clean::SelfBorrowed(None, mtbl) => {
-                        args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
-                        args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
+                    if !input.name.is_empty() {
+                        args.push_str(&format!("{}: ", input.name));
+                        args_plain.push_str(&format!("{}: ", input.name));
                     }
-                    clean::SelfExplicit(ref typ) => {
-                        if f.alternate() {
-                            args.push_str(&format!("self: {:#}", *typ));
-                        } else {
-                            args.push_str(&format!("self: {}", *typ));
-                        }
-                        args_plain.push_str(&format!("self: {:#}", *typ));
+
+                    if f.alternate() {
+                        args.push_str(&format!("{:#}", input.type_.print()));
+                    } else {
+                        args.push_str(&input.type_.print().to_string());
                     }
+                    args_plain.push_str(&format!("{:#}", input.type_.print()));
                 }
-            } else {
-                if i > 0 {
-                    args.push_str(" <br>");
-                    args_plain.push_str(" ");
-                }
-                if !input.name.is_empty() {
-                    args.push_str(&format!("{}: ", input.name));
-                    args_plain.push_str(&format!("{}: ", input.name));
-                }
-
-                if f.alternate() {
-                    args.push_str(&format!("{:#}", input.type_));
-                } else {
-                    args.push_str(&input.type_.to_string());
+                if i + 1 < decl.inputs.values.len() {
+                    args.push(',');
+                    args_plain.push(',');
                 }
-                args_plain.push_str(&format!("{:#}", input.type_));
-            }
-            if i + 1 < decl.inputs.values.len() {
-                args.push(',');
-                args_plain.push(',');
             }
-        }
 
-        let args_plain = format!("({})", args_plain);
+            let args_plain = format!("({})", args_plain);
 
-        let output = if let hir::IsAsync::Async = asyncness {
-            Cow::Owned(decl.sugared_async_return_type())
-        } else {
-            Cow::Borrowed(&decl.output)
-        };
+            let output = if let hir::IsAsync::Async = asyncness {
+                Cow::Owned(decl.sugared_async_return_type())
+            } else {
+                Cow::Borrowed(&decl.output)
+            };
 
-        let arrow_plain = format!("{:#}", &output);
-        let arrow = if f.alternate() {
-            format!("{:#}", &output)
-        } else {
-            output.to_string()
-        };
+            let arrow_plain = format!("{:#}", &output.print());
+            let arrow = if f.alternate() {
+                format!("{:#}", &output.print())
+            } else {
+                output.print().to_string()
+            };
 
-        let declaration_len = header_len + args_plain.len() + arrow_plain.len();
-        let output = if declaration_len > 80 {
-            let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
-            let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
-            format!("({args}{close}){arrow}",
-                    args = args.replace("<br>", &full_pad),
-                    close = close_pad,
-                    arrow = arrow)
-        } else {
-            format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
-        };
+            let declaration_len = header_len + args_plain.len() + arrow_plain.len();
+            let output = if declaration_len > 80 {
+                let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
+                let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
+                format!("({args}{close}){arrow}",
+                        args = args.replace("<br>", &full_pad),
+                        close = close_pad,
+                        arrow = arrow)
+            } else {
+                format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
+            };
 
-        if f.alternate() {
-            write!(f, "{}", output.replace("<br>", "\n"))
-        } else {
-            write!(f, "{}", output)
-        }
+            if f.alternate() {
+                write!(f, "{}", output.replace("<br>", "\n"))
+            } else {
+                write!(f, "{}", output)
+            }
+        })
     }
 }
 
-impl<'a> fmt::Display for VisSpace<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self.get() {
-            Some(clean::Public) => f.write_str("pub "),
-            Some(clean::Inherited) | None => Ok(()),
-            Some(clean::Visibility::Crate) => write!(f, "pub(crate) "),
-            Some(clean::Visibility::Restricted(did, ref path)) => {
-                f.write_str("pub(")?;
-                if path.segments.len() != 1
-                    || (path.segments[0].name != "self" && path.segments[0].name != "super")
-                {
-                    f.write_str("in ")?;
+impl clean::Visibility {
+    crate fn print_with_space(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match *self {
+                clean::Public => f.write_str("pub "),
+                clean::Inherited => Ok(()),
+                clean::Visibility::Crate => write!(f, "pub(crate) "),
+                clean::Visibility::Restricted(did, ref path) => {
+                    f.write_str("pub(")?;
+                    if path.segments.len() != 1
+                        || (path.segments[0].name != "self" && path.segments[0].name != "super")
+                    {
+                        f.write_str("in ")?;
+                    }
+                    resolved_path(f, did, path, true, false)?;
+                    f.write_str(") ")
                 }
-                resolved_path(f, did, path, true, false)?;
-                f.write_str(") ")
             }
-        }
+        })
     }
 }
 
-impl fmt::Display for UnsafetySpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.get() {
-            hir::Unsafety::Unsafe => write!(f, "unsafe "),
-            hir::Unsafety::Normal => Ok(())
+crate trait PrintWithSpace {
+    fn print_with_space(&self) -> &str;
+}
+
+impl PrintWithSpace for hir::Unsafety {
+    fn print_with_space(&self) -> &str {
+        match self {
+            hir::Unsafety::Unsafe => "unsafe ",
+            hir::Unsafety::Normal => ""
         }
     }
 }
 
-impl fmt::Display for ConstnessSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.get() {
-            hir::Constness::Const => write!(f, "const "),
-            hir::Constness::NotConst => Ok(())
+impl PrintWithSpace for hir::Constness {
+    fn print_with_space(&self) -> &str {
+        match self {
+            hir::Constness::Const => "const ",
+            hir::Constness::NotConst => ""
         }
     }
 }
 
-impl fmt::Display for AsyncSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {
-            hir::IsAsync::Async => write!(f, "async "),
-            hir::IsAsync::NotAsync => Ok(()),
+impl PrintWithSpace for hir::IsAsync {
+    fn print_with_space(&self) -> &str {
+        match self {
+            hir::IsAsync::Async => "async ",
+            hir::IsAsync::NotAsync => "",
         }
     }
 }
 
-impl fmt::Display for clean::Import {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            clean::Import::Simple(ref name, ref src) => {
-                if *name == src.path.last_name() {
-                    write!(f, "use {};", *src)
-                } else {
-                    write!(f, "use {} as {};", *src, *name)
+impl clean::Import {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match *self {
+                clean::Import::Simple(ref name, ref src) => {
+                    if *name == src.path.last_name() {
+                        write!(f, "use {};", src.print())
+                    } else {
+                        write!(f, "use {} as {};", src.print(), *name)
+                    }
                 }
-            }
-            clean::Import::Glob(ref src) => {
-                if src.path.segments.is_empty() {
-                    write!(f, "use *;")
-                } else {
-                    write!(f, "use {}::*;", *src)
+                clean::Import::Glob(ref src) => {
+                    if src.path.segments.is_empty() {
+                        write!(f, "use *;")
+                    } else {
+                        write!(f, "use {}::*;", src.print())
+                    }
                 }
             }
-        }
+        })
     }
 }
 
-impl fmt::Display for clean::ImportSource {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.did {
-            Some(did) => resolved_path(f, did, &self.path, true, false),
-            _ => {
-                for (i, seg) in self.path.segments.iter().enumerate() {
-                    if i > 0 {
-                        write!(f, "::")?
+impl clean::ImportSource {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match self.did {
+                Some(did) => resolved_path(f, did, &self.path, true, false),
+                _ => {
+                    for (i, seg) in self.path.segments.iter().enumerate() {
+                        if i > 0 {
+                            write!(f, "::")?
+                        }
+                        write!(f, "{}", seg.name)?;
                     }
-                    write!(f, "{}", seg.name)?;
+                    Ok(())
                 }
-                Ok(())
             }
-        }
+        })
     }
 }
 
-impl fmt::Display for clean::TypeBinding {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(&self.name)?;
-        match self.kind {
-            clean::TypeBindingKind::Equality { ref ty } => {
-                if f.alternate() {
-                    write!(f, " = {:#}", ty)?;
-                } else {
-                    write!(f, " = {}", ty)?;
-                }
-            }
-            clean::TypeBindingKind::Constraint { ref bounds } => {
-                if !bounds.is_empty() {
+impl clean::TypeBinding {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            f.write_str(&self.name)?;
+            match self.kind {
+                clean::TypeBindingKind::Equality { ref ty } => {
                     if f.alternate() {
-                        write!(f, ": {:#}", GenericBounds(bounds))?;
+                        write!(f, " = {:#}", ty.print())?;
                     } else {
-                        write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
+                        write!(f, " = {}", ty.print())?;
+                    }
+                }
+                clean::TypeBindingKind::Constraint { ref bounds } => {
+                    if !bounds.is_empty() {
+                        if f.alternate() {
+                            write!(f, ": {:#}", print_generic_bounds(bounds))?;
+                        } else {
+                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds))?;
+                        }
                     }
                 }
             }
-        }
-        Ok(())
+            Ok(())
+        })
     }
 }
 
-impl fmt::Display for MutableSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            MutableSpace(clean::Immutable) => Ok(()),
-            MutableSpace(clean::Mutable) => write!(f, "mut "),
+impl clean::Mutability {
+    crate fn print_with_space(&self) -> &str {
+        match self {
+            clean::Immutable => "",
+            clean::Mutable => "mut ",
         }
     }
 }
 
-impl fmt::Display for AbiSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+crate fn print_abi_with_space(abi: Abi) -> impl fmt::Display {
+    display_fn(move |f| {
         let quot = if f.alternate() { "\"" } else { "&quot;" };
-        match self.0 {
+        match abi {
             Abi::Rust => Ok(()),
             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
         }
+    })
+}
+
+crate fn print_default_space<'a>(v: bool) -> &'a str {
+    if v {
+        "default "
+    } else {
+        ""
     }
 }
 
-impl fmt::Display for DefaultSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.0 {
-            write!(f, "default ")
-        } else {
-            Ok(())
-        }
+impl clean::GenericArg {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        display_fn(move |f| {
+            match self {
+                clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
+                clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(), f),
+                clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f),
+            }
+        })
     }
 }
 
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index cf51a4eb5a5..5fb9afd6c49 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -46,14 +46,6 @@ pub enum ItemType {
 }
 
 
-#[derive(Copy, Eq, PartialEq, Clone)]
-pub enum NameSpace {
-    Type,
-    Value,
-    Macro,
-    Keyword,
-}
-
 impl<'a> From<&'a clean::Item> for ItemType {
     fn from(item: &'a clean::Item) -> ItemType {
         let inner = match item.inner {
@@ -120,7 +112,7 @@ impl From<clean::TypeKind> for ItemType {
 }
 
 impl ItemType {
-    pub fn css_class(&self) -> &'static str {
+    pub fn as_str(&self) -> &'static str {
         match *self {
             ItemType::Module          => "mod",
             ItemType::ExternCrate     => "externcrate",
@@ -151,7 +143,7 @@ impl ItemType {
         }
     }
 
-    pub fn name_space(&self) -> NameSpace {
+    pub fn name_space(&self) -> &'static str {
         match *self {
             ItemType::Struct |
             ItemType::Union |
@@ -163,7 +155,7 @@ impl ItemType {
             ItemType::AssocType |
             ItemType::OpaqueTy |
             ItemType::TraitAlias |
-            ItemType::ForeignType => NameSpace::Type,
+            ItemType::ForeignType => NAMESPACE_TYPE,
 
             ItemType::ExternCrate |
             ItemType::Import |
@@ -175,20 +167,20 @@ impl ItemType {
             ItemType::StructField |
             ItemType::Variant |
             ItemType::Constant |
-            ItemType::AssocConst => NameSpace::Value,
+            ItemType::AssocConst => NAMESPACE_VALUE,
 
             ItemType::Macro |
             ItemType::ProcAttribute |
-            ItemType::ProcDerive => NameSpace::Macro,
+            ItemType::ProcDerive => NAMESPACE_MACRO,
 
-            ItemType::Keyword => NameSpace::Keyword,
+            ItemType::Keyword => NAMESPACE_KEYWORD,
         }
     }
 }
 
 impl fmt::Display for ItemType {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.css_class().fmt(f)
+        write!(f, "{}", self.as_str())
     }
 }
 
@@ -196,20 +188,3 @@ pub const NAMESPACE_TYPE: &'static str = "t";
 pub const NAMESPACE_VALUE: &'static str = "v";
 pub const NAMESPACE_MACRO: &'static str = "m";
 pub const NAMESPACE_KEYWORD: &'static str = "k";
-
-impl NameSpace {
-    pub fn to_static_str(&self) -> &'static str {
-        match *self {
-            NameSpace::Type => NAMESPACE_TYPE,
-            NameSpace::Value => NAMESPACE_VALUE,
-            NameSpace::Macro => NAMESPACE_MACRO,
-            NameSpace::Keyword => NAMESPACE_KEYWORD,
-        }
-    }
-}
-
-impl fmt::Display for NameSpace {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.to_static_str().fmt(f)
-    }
-}
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 56074f4ab11..6414241727a 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 
 use crate::externalfiles::ExternalHtml;
-use crate::html::render::SlashChecker;
+use crate::html::render::ensure_trailing_slash;
 use crate::html::format::{Buffer, Print};
 
 #[derive(Clone)]
@@ -180,7 +180,7 @@ pub fn render<T: Print, S: Print>(
     css_class = page.css_class,
     logo      = {
         let p = format!("{}{}", page.root_path, layout.krate);
-        let p = SlashChecker(&p);
+        let p = ensure_trailing_slash(&p);
         if layout.logo.is_empty() {
             format!("<a href='{path}index.html'>\
                      <div class='logo-container'>\
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 1a4fa38ff8d..9ff1e1d3119 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -752,7 +752,7 @@ impl MarkdownWithToc<'_> {
             html::push_html(&mut s, p);
         }
 
-        format!("<nav id=\"TOC\">{}</nav>{}", toc.into_toc(), s)
+        format!("<nav id=\"TOC\">{}</nav>{}", toc.into_toc().print(), s)
     }
 }
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 9846073cad4..301dddbbfb9 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -25,20 +25,17 @@
 //! These threads are not parallelized (they haven't been a bottleneck yet), and
 //! both occur before the crate is rendered.
 
-pub use self::ExternalLocation::*;
-
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::cmp::Ordering;
 use std::collections::{BTreeMap, VecDeque};
 use std::default::Default;
 use std::error;
-use std::fmt::{self, Display, Formatter, Write as FmtWrite};
+use std::fmt::{self, Formatter, Write as FmtWrite};
 use std::ffi::OsStr;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
-use std::mem;
 use std::path::{PathBuf, Path, Component};
 use std::str;
 use std::sync::Arc;
@@ -52,7 +49,7 @@ use syntax::ext::base::MacroKind;
 use syntax::source_map::FileName;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::{Symbol, sym};
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::DefId;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc::hir;
@@ -63,11 +60,10 @@ use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutabilit
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, ErrorStorage, PathError};
 use crate::doctree;
-use crate::fold::DocFolder;
 use crate::html::escape::Escape;
-use crate::html::format::{Buffer, AsyncSpace, ConstnessSpace};
-use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace, DefaultSpace};
-use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace};
+use crate::html::format::{Buffer, PrintWithSpace, print_abi_with_space};
+use crate::html::format::{print_generic_bounds, WhereClause, href, print_default_space};
+use crate::html::format::{Function};
 use crate::html::format::fmt_impl_for_trait_page;
 use crate::html::item_type::ItemType;
 use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
@@ -79,19 +75,22 @@ use minifier;
 #[cfg(test)]
 mod tests;
 
+mod cache;
+
+use cache::Cache;
+crate use cache::ExternalLocation::{self, *};
+
 /// A pair of name and its optional document.
 pub type NameDoc = (String, Option<String>);
 
-pub struct SlashChecker<'a>(pub &'a str);
-
-impl<'a> Display for SlashChecker<'a> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        if !self.0.ends_with("/") && !self.0.is_empty() {
-            write!(f, "{}/", self.0)
+crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
+    crate::html::format::display_fn(move |f| {
+        if !v.ends_with("/") && !v.is_empty() {
+            write!(f, "{}/", v)
         } else {
-            write!(f, "{}", self.0)
+            write!(f, "{}", v)
         }
-    }
+    })
 }
 
 #[derive(Debug)]
@@ -106,7 +105,7 @@ impl error::Error for Error {
     }
 }
 
-impl Display for Error {
+impl std::fmt::Display for Error {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let file = self.file.display().to_string();
         if file.is_empty() {
@@ -165,13 +164,10 @@ struct Context {
     /// real location of an item. This is used to allow external links to
     /// publicly reused items to redirect to the right location.
     pub render_redirect_pages: bool,
-    pub codes: ErrorCodes,
-    /// The default edition used to parse doctests.
-    pub edition: Edition,
     /// The map used to ensure all generated 'id=' attributes are unique.
     id_map: Rc<RefCell<IdMap>>,
     pub shared: Arc<SharedContext>,
-    playground: Option<markdown::Playground>,
+    pub cache: Arc<Cache>,
 }
 
 crate struct SharedContext {
@@ -210,6 +206,30 @@ crate struct SharedContext {
     pub generate_redirect_pages: bool,
     /// The fs handle we are working with.
     pub fs: DocFS,
+    /// The default edition used to parse doctests.
+    pub edition: Edition,
+    pub codes: ErrorCodes,
+    playground: Option<markdown::Playground>,
+}
+
+impl Context {
+    fn path(&self, filename: &str) -> PathBuf {
+        // We use splitn vs Path::extension here because we might get a filename
+        // like `style.min.css` and we want to process that into
+        // `style-suffix.min.css`.  Path::extension would just return `css`
+        // which would result in `style.min-suffix.css` which isn't what we
+        // want.
+        let mut iter = filename.splitn(2, '.');
+        let base = iter.next().unwrap();
+        let ext = iter.next().unwrap();
+        let filename = format!(
+            "{}{}.{}",
+            base,
+            self.shared.resource_suffix,
+            ext,
+        );
+        self.dst.join(&filename)
+    }
 }
 
 impl SharedContext {
@@ -222,9 +242,7 @@ impl SharedContext {
 
         Ok(())
     }
-}
 
-impl SharedContext {
     /// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the
     /// `collapsed_doc_value` of the given item.
     pub fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<Cow<'a, str>> {
@@ -236,16 +254,6 @@ impl SharedContext {
     }
 }
 
-/// Indicates where an external crate can be found.
-pub enum ExternalLocation {
-    /// Remote URL root of the external crate
-    Remote(String),
-    /// This external crate can be found in the local doc/ folder
-    Local,
-    /// The external crate could not be found.
-    Unknown,
-}
-
 /// Metadata about implementations for a type or trait.
 #[derive(Clone, Debug)]
 pub struct Impl {
@@ -265,106 +273,6 @@ impl Impl {
     }
 }
 
-/// This cache is used to store information about the `clean::Crate` being
-/// rendered in order to provide more useful documentation. This contains
-/// information like all implementors of a trait, all traits a type implements,
-/// documentation for all known traits, etc.
-///
-/// This structure purposefully does not implement `Clone` because it's intended
-/// to be a fairly large and expensive structure to clone. Instead this adheres
-/// to `Send` so it may be stored in a `Arc` instance and shared among the various
-/// rendering threads.
-#[derive(Default)]
-pub struct Cache {
-    /// Maps a type ID to all known implementations for that type. This is only
-    /// recognized for intra-crate `ResolvedPath` types, and is used to print
-    /// out extra documentation on the page of an enum/struct.
-    ///
-    /// The values of the map are a list of implementations and documentation
-    /// found on that implementation.
-    pub impls: FxHashMap<DefId, Vec<Impl>>,
-
-    /// Maintains a mapping of local crate `NodeId`s to the fully qualified name
-    /// and "short type description" of that node. This is used when generating
-    /// URLs when a type is being linked to. External paths are not located in
-    /// this map because the `External` type itself has all the information
-    /// necessary.
-    pub paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
-
-    /// Similar to `paths`, but only holds external paths. This is only used for
-    /// generating explicit hyperlinks to other crates.
-    pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
-
-    /// Maps local `DefId`s of exported types to fully qualified paths.
-    /// Unlike 'paths', this mapping ignores any renames that occur
-    /// due to 'use' statements.
-    ///
-    /// This map is used when writing out the special 'implementors'
-    /// javascript file. By using the exact path that the type
-    /// is declared with, we ensure that each path will be identical
-    /// to the path used if the corresponding type is inlined. By
-    /// doing this, we can detect duplicate impls on a trait page, and only display
-    /// the impl for the inlined type.
-    pub exact_paths: FxHashMap<DefId, Vec<String>>,
-
-    /// This map contains information about all known traits of this crate.
-    /// Implementations of a crate should inherit the documentation of the
-    /// parent trait if no extra documentation is specified, and default methods
-    /// should show up in documentation about trait implementations.
-    pub traits: FxHashMap<DefId, clean::Trait>,
-
-    /// When rendering traits, it's often useful to be able to list all
-    /// implementors of the trait, and this mapping is exactly, that: a mapping
-    /// of trait ids to the list of known implementors of the trait
-    pub implementors: FxHashMap<DefId, Vec<Impl>>,
-
-    /// Cache of where external crate documentation can be found.
-    pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
-
-    /// Cache of where documentation for primitives can be found.
-    pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
-
-    // Note that external items for which `doc(hidden)` applies to are shown as
-    // non-reachable while local items aren't. This is because we're reusing
-    // the access levels from the privacy check pass.
-    pub access_levels: AccessLevels<DefId>,
-
-    /// The version of the crate being documented, if given from the `--crate-version` flag.
-    pub crate_version: Option<String>,
-
-    // Private fields only used when initially crawling a crate to build a cache
-
-    stack: Vec<String>,
-    parent_stack: Vec<DefId>,
-    parent_is_trait_impl: bool,
-    search_index: Vec<IndexItem>,
-    stripped_mod: bool,
-    deref_trait_did: Option<DefId>,
-    deref_mut_trait_did: Option<DefId>,
-    owned_box_did: Option<DefId>,
-    masked_crates: FxHashSet<CrateNum>,
-
-    // In rare case where a structure is defined in one module but implemented
-    // in another, if the implementing module is parsed before defining module,
-    // then the fully qualified name of the structure isn't presented in `paths`
-    // yet when its implementation methods are being indexed. Caches such methods
-    // and their parent id here and indexes them at the end of crate parsing.
-    orphan_impl_items: Vec<(DefId, clean::Item)>,
-
-    // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
-    // even though the trait itself is not exported. This can happen if a trait
-    // was defined in function/expression scope, since the impl will be picked
-    // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
-    // crawl. In order to prevent crashes when looking for spotlight traits or
-    // when gathering trait documentation on a type, hold impls here while
-    // folding and add them to the cache later on if we find the trait.
-    orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
-
-    /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
-    /// we need the alias element to have an array of items.
-    aliases: FxHashMap<String, Vec<IndexItem>>,
-}
-
 /// Temporary storage for data obtained during `RustdocVisitor::clean()`.
 /// Later on moved into `CACHE_KEY`.
 #[derive(Default)]
@@ -520,29 +428,6 @@ pub fn run(mut krate: clean::Crate,
         _ => PathBuf::new(),
     };
     let mut errors = Arc::new(ErrorStorage::new());
-    let mut scx = SharedContext {
-        collapsed: krate.collapsed,
-        src_root,
-        include_sources: true,
-        local_sources: Default::default(),
-        issue_tracker_base_url: None,
-        layout: layout::Layout {
-            logo: String::new(),
-            favicon: String::new(),
-            external_html,
-            krate: krate.name.clone(),
-            css_file_extension: extension_css,
-            generate_search_filter,
-        },
-        created_dirs: Default::default(),
-        sort_modules_alphabetically,
-        themes,
-        resource_suffix,
-        static_root_path,
-        generate_redirect_pages,
-        fs: DocFS::new(&errors),
-    };
-
     // If user passed in `--playground-url` arg, we fill in crate name here
     let mut playground = None;
     if let Some(url) = playground_url {
@@ -551,6 +436,16 @@ pub fn run(mut krate: clean::Crate,
             url,
         });
     }
+    let mut layout = layout::Layout {
+        logo: String::new(),
+        favicon: String::new(),
+        external_html,
+        krate: krate.name.clone(),
+        css_file_extension: extension_css,
+        generate_search_filter,
+    };
+    let mut issue_tracker_base_url = None;
+    let mut include_sources = true;
 
     // Crawl the crate attributes looking for attributes which control how we're
     // going to emit HTML
@@ -558,10 +453,10 @@ pub fn run(mut krate: clean::Crate,
         for attr in attrs.lists(sym::doc) {
             match (attr.name_or_empty(), attr.value_str()) {
                 (sym::html_favicon_url, Some(s)) => {
-                    scx.layout.favicon = s.to_string();
+                    layout.favicon = s.to_string();
                 }
                 (sym::html_logo_url, Some(s)) => {
-                    scx.layout.logo = s.to_string();
+                    layout.logo = s.to_string();
                 }
                 (sym::html_playground_url, Some(s)) => {
                     playground = Some(markdown::Playground {
@@ -570,122 +465,62 @@ pub fn run(mut krate: clean::Crate,
                     });
                 }
                 (sym::issue_tracker_base_url, Some(s)) => {
-                    scx.issue_tracker_base_url = Some(s.to_string());
+                    issue_tracker_base_url = Some(s.to_string());
                 }
                 (sym::html_no_source, None) if attr.is_word() => {
-                    scx.include_sources = false;
+                    include_sources = false;
                 }
                 _ => {}
             }
         }
     }
+    let mut scx = SharedContext {
+        collapsed: krate.collapsed,
+        src_root,
+        include_sources,
+        local_sources: Default::default(),
+        issue_tracker_base_url,
+        layout,
+        created_dirs: Default::default(),
+        sort_modules_alphabetically,
+        themes,
+        resource_suffix,
+        static_root_path,
+        generate_redirect_pages,
+        fs: DocFS::new(&errors),
+        edition,
+        codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
+        playground,
+    };
+
     let dst = output;
     scx.ensure_dir(&dst)?;
     krate = sources::render(&dst, &mut scx, krate)?;
+    let (new_crate, index, cache) = Cache::from_krate(
+        renderinfo,
+        &extern_html_root_urls,
+        &dst,
+        krate,
+    );
+    krate = new_crate;
+    let cache = Arc::new(cache);
     let mut cx = Context {
         current: Vec::new(),
         dst,
         render_redirect_pages: false,
-        codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
-        edition,
         id_map: Rc::new(RefCell::new(id_map)),
         shared: Arc::new(scx),
-        playground,
-    };
-
-    // Crawl the crate to build various caches used for the output
-    let RenderInfo {
-        inlined: _,
-        external_paths,
-        exact_paths,
-        access_levels,
-        deref_trait_did,
-        deref_mut_trait_did,
-        owned_box_did,
-    } = renderinfo;
-
-    let external_paths = external_paths.into_iter()
-        .map(|(k, (v, t))| (k, (v, ItemType::from(t))))
-        .collect();
-
-    let mut cache = Cache {
-        impls: Default::default(),
-        external_paths,
-        exact_paths,
-        paths: Default::default(),
-        implementors: Default::default(),
-        stack: Vec::new(),
-        parent_stack: Vec::new(),
-        search_index: Vec::new(),
-        parent_is_trait_impl: false,
-        extern_locations: Default::default(),
-        primitive_locations: Default::default(),
-        stripped_mod: false,
-        access_levels,
-        crate_version: krate.version.take(),
-        orphan_impl_items: Vec::new(),
-        orphan_trait_impls: Vec::new(),
-        traits: krate.external_traits.replace(Default::default()),
-        deref_trait_did,
-        deref_mut_trait_did,
-        owned_box_did,
-        masked_crates: mem::take(&mut krate.masked_crates),
-        aliases: Default::default(),
+        cache: cache.clone(),
     };
 
-    // Cache where all our extern crates are located
-    for &(n, ref e) in &krate.externs {
-        let src_root = match e.src {
-            FileName::Real(ref p) => match p.parent() {
-                Some(p) => p.to_path_buf(),
-                None => PathBuf::new(),
-            },
-            _ => PathBuf::new(),
-        };
-        let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
-        cache.extern_locations.insert(n, (e.name.clone(), src_root,
-                                          extern_location(e, extern_url, &cx.dst)));
-
-        let did = DefId { krate: n, index: CRATE_DEF_INDEX };
-        cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
-    }
-
-    // Cache where all known primitives have their documentation located.
-    //
-    // Favor linking to as local extern as possible, so iterate all crates in
-    // reverse topological order.
-    for &(_, ref e) in krate.externs.iter().rev() {
-        for &(def_id, prim, _) in &e.primitives {
-            cache.primitive_locations.insert(prim, def_id);
-        }
-    }
-    for &(def_id, prim, _) in &krate.primitives {
-        cache.primitive_locations.insert(prim, def_id);
-    }
-
-    cache.stack.push(krate.name.clone());
-    krate = cache.fold_crate(krate);
-
-    for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
-        if cache.traits.contains_key(&trait_did) {
-            for did in dids {
-                cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
-            }
-        }
-    }
-
-    // Build our search index
-    let index = build_index(&krate, &mut cache);
-
     // Freeze the cache now that the index has been built. Put an Arc into TLS
     // for future parallelization opportunities
-    let cache = Arc::new(cache);
     CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
     CURRENT_DEPTH.with(|s| s.set(0));
 
     // Write shared runs within a flock; disable thread dispatching of IO temporarily.
     Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
-    write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?;
+    write_shared(&cx, &krate, index, &md_opts, diag)?;
     Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
 
     // And finally render the whole crate's documentation
@@ -700,80 +535,9 @@ pub fn run(mut krate: clean::Crate,
     }
 }
 
-/// Builds the search index from the collected metadata
-fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
-    let mut nodeid_to_pathid = FxHashMap::default();
-    let mut crate_items = Vec::with_capacity(cache.search_index.len());
-    let mut crate_paths = Vec::<Json>::new();
-
-    let Cache { ref mut search_index,
-                ref orphan_impl_items,
-                ref mut paths, .. } = *cache;
-
-    // Attach all orphan items to the type's definition if the type
-    // has since been learned.
-    for &(did, ref item) in orphan_impl_items {
-        if let Some(&(ref fqp, _)) = paths.get(&did) {
-            search_index.push(IndexItem {
-                ty: item.type_(),
-                name: item.name.clone().unwrap(),
-                path: fqp[..fqp.len() - 1].join("::"),
-                desc: shorten(plain_summary_line(item.doc_value())),
-                parent: Some(did),
-                parent_idx: None,
-                search_type: get_index_search_type(&item),
-            });
-        }
-    }
-
-    // Reduce `NodeId` in paths into smaller sequential numbers,
-    // and prune the paths that do not appear in the index.
-    let mut lastpath = String::new();
-    let mut lastpathid = 0usize;
-
-    for item in search_index {
-        item.parent_idx = item.parent.map(|nodeid| {
-            if nodeid_to_pathid.contains_key(&nodeid) {
-                *nodeid_to_pathid.get(&nodeid).unwrap()
-            } else {
-                let pathid = lastpathid;
-                nodeid_to_pathid.insert(nodeid, pathid);
-                lastpathid += 1;
-
-                let &(ref fqp, short) = paths.get(&nodeid).unwrap();
-                crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
-                pathid
-            }
-        });
-
-        // Omit the parent path if it is same to that of the prior item.
-        if lastpath == item.path {
-            item.path.clear();
-        } else {
-            lastpath = item.path.clone();
-        }
-        crate_items.push(item.to_json());
-    }
-
-    let crate_doc = krate.module.as_ref().map(|module| {
-        shorten(plain_summary_line(module.doc_value()))
-    }).unwrap_or(String::new());
-
-    let mut crate_data = BTreeMap::new();
-    crate_data.insert("doc".to_owned(), Json::String(crate_doc));
-    crate_data.insert("i".to_owned(), Json::Array(crate_items));
-    crate_data.insert("p".to_owned(), Json::Array(crate_paths));
-
-    // Collect the index into a string
-    format!("searchIndex[{}] = {};",
-            as_json(&krate.name),
-            Json::Object(crate_data))
-}
-
 fn write_shared(
     cx: &Context,
     krate: &clean::Crate,
-    cache: &Cache,
     search_index: String,
     options: &RenderOptions,
     diag: &errors::Handler,
@@ -786,13 +550,13 @@ fn write_shared(
     // Add all the static files. These may already exist, but we just
     // overwrite them anyway to make sure that they're fresh and up-to-date.
 
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("rustdoc.css"),
                  static_files::RUSTDOC_CSS,
                  options.enable_minification)?;
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("settings.css"),
                  static_files::SETTINGS_CSS,
                  options.enable_minification)?;
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("noscript.css"),
                  static_files::NOSCRIPT_CSS,
                  options.enable_minification)?;
 
@@ -804,34 +568,25 @@ fn write_shared(
         let content = try_err!(fs::read(&entry), &entry);
         let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry);
         let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry);
-        cx.shared.fs.write(
-            cx.dst.join(format!("{}{}.{}", theme, cx.shared.resource_suffix, extension)),
-            content.as_slice())?;
+        cx.shared.fs.write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?;
         themes.insert(theme.to_owned());
     }
 
     let write = |p, c| { cx.shared.fs.write(p, c) };
     if (*cx.shared).layout.logo.is_empty() {
-        write(cx.dst.join(&format!("rust-logo{}.png", cx.shared.resource_suffix)),
-              static_files::RUST_LOGO)?;
+        write(cx.path("rust-log.png"), static_files::RUST_LOGO)?;
     }
     if (*cx.shared).layout.favicon.is_empty() {
-        write(cx.dst.join(&format!("favicon{}.ico", cx.shared.resource_suffix)),
-              static_files::RUST_FAVICON)?;
-    }
-    write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
-          static_files::BRUSH_SVG)?;
-    write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
-          static_files::WHEEL_SVG)?;
-    write(cx.dst.join(&format!("down-arrow{}.svg", cx.shared.resource_suffix)),
-          static_files::DOWN_ARROW_SVG)?;
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
-                 static_files::themes::LIGHT,
-                 options.enable_minification)?;
+        write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?;
+    }
+    write(cx.path("brush.svg"), static_files::BRUSH_SVG)?;
+    write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?;
+    write(cx.path("down-arrow.svg"), static_files::DOWN_ARROW_SVG)?;
+    write_minify(&cx.shared.fs,
+        cx.path("light.css"), static_files::themes::LIGHT, options.enable_minification)?;
     themes.insert("light".to_owned());
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)),
-                 static_files::themes::DARK,
-                 options.enable_minification)?;
+    write_minify(&cx.shared.fs,
+        cx.path("dark.css"), static_files::themes::DARK, options.enable_minification)?;
     themes.insert("dark".to_owned());
 
     let mut themes: Vec<&String> = themes.iter().collect();
@@ -894,16 +649,16 @@ themePicker.onblur = handleThemeButtonsBlur;
           theme_js.as_bytes()
     )?;
 
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("main.js"),
                  static_files::MAIN_JS,
                  options.enable_minification)?;
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("settings.js"),
                  static_files::SETTINGS_JS,
                  options.enable_minification)?;
     if cx.shared.include_sources {
         write_minify(
             &cx.shared.fs,
-            cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)),
+            cx.path("source-script.js"),
             static_files::sidebar::SOURCE_SCRIPT,
             options.enable_minification)?;
     }
@@ -911,7 +666,7 @@ themePicker.onblur = handleThemeButtonsBlur;
     {
         write_minify(
             &cx.shared.fs,
-            cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
+            cx.path("storage.js"),
             &format!("var resourcesSuffix = \"{}\";{}",
                      cx.shared.resource_suffix,
                      static_files::STORAGE_JS),
@@ -919,7 +674,7 @@ themePicker.onblur = handleThemeButtonsBlur;
     }
 
     if let Some(ref css) = cx.shared.layout.css_file_extension {
-        let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix));
+        let out = cx.path("theme.css");
         let buffer = try_err!(fs::read_to_string(css), css);
         if !options.enable_minification {
             cx.shared.fs.write(&out, &buffer)?;
@@ -927,7 +682,7 @@ themePicker.onblur = handleThemeButtonsBlur;
             write_minify(&cx.shared.fs, out, &buffer, options.enable_minification)?;
         }
     }
-    write_minify(&cx.shared.fs, cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)),
+    write_minify(&cx.shared.fs, cx.path("normalize.css"),
                  static_files::NORMALIZE_CSS,
                  options.enable_minification)?;
     write(cx.dst.join("FiraSans-Regular.woff"),
@@ -1004,7 +759,7 @@ themePicker.onblur = handleThemeButtonsBlur;
     {
         let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst);
         let mut output = String::with_capacity(100);
-        for (alias, items) in &cache.aliases {
+        for (alias, items) in &cx.cache.aliases {
             if items.is_empty() {
                 continue
             }
@@ -1136,7 +891,7 @@ themePicker.onblur = handleThemeButtonsBlur;
             md_opts.output = cx.dst.clone();
             md_opts.external_html = (*cx.shared).layout.external_html.clone();
 
-            crate::markdown::render(index_page, md_opts, diag, cx.edition);
+            crate::markdown::render(index_page, md_opts, diag, cx.shared.edition);
         } else {
             let dst = cx.dst.join("index.html");
             let page = layout::Page {
@@ -1162,7 +917,7 @@ themePicker.onblur = handleThemeButtonsBlur;
                                     .iter()
                                     .map(|s| {
                                         format!("<li><a href=\"{}index.html\">{}</li>",
-                                                SlashChecker(s), s)
+                                                ensure_trailing_slash(s), s)
                                     })
                                     .collect::<String>());
             let v = layout::render(&cx.shared.layout,
@@ -1174,7 +929,7 @@ themePicker.onblur = handleThemeButtonsBlur;
 
     // Update the list of all implementors for traits
     let dst = cx.dst.join("implementors");
-    for (&did, imps) in &cache.implementors {
+    for (&did, imps) in &cx.cache.implementors {
         // Private modules can leak through to this phase of rustdoc, which
         // could contain implementations for otherwise private types. In some
         // rare cases we could find an implementation for an item which wasn't
@@ -1182,9 +937,9 @@ themePicker.onblur = handleThemeButtonsBlur;
         //
         // FIXME: this is a vague explanation for why this can't be a `get`, in
         //        theory it should be...
-        let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
+        let &(ref remote_path, remote_item_type) = match cx.cache.paths.get(&did) {
             Some(p) => p,
-            None => match cache.external_paths.get(&did) {
+            None => match cx.cache.external_paths.get(&did) {
                 Some(p) => p,
                 None => continue,
             }
@@ -1203,7 +958,7 @@ themePicker.onblur = handleThemeButtonsBlur;
             if !imp.impl_item.def_id.is_local() { continue }
             have_impls = true;
             write!(implementors, "{{text:{},synthetic:{},types:{}}},",
-                   as_json(&imp.inner_impl().to_string()),
+                   as_json(&imp.inner_impl().print().to_string()),
                    imp.inner_impl().synthetic,
                    as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap();
         }
@@ -1212,7 +967,7 @@ themePicker.onblur = handleThemeButtonsBlur;
         // Only create a js file if we have impls to add to it. If the trait is
         // documented locally though we always create the file to avoid dead
         // links.
-        if !have_impls && !cache.paths.contains_key(&did) {
+        if !have_impls && !cx.cache.paths.contains_key(&did) {
             continue;
         }
 
@@ -1222,7 +977,7 @@ themePicker.onblur = handleThemeButtonsBlur;
         }
         cx.shared.ensure_dir(&mydst)?;
         mydst.push(&format!("{}.{}.js",
-                            remote_item_type.css_class(),
+                            remote_item_type,
                             remote_path[remote_path.len() - 1]));
 
         let (mut all_implementors, _, _) = try_err!(collect(&mydst, &krate.name, "implementors",
@@ -1326,327 +1081,6 @@ fn minify_replacer(
     }
 }
 
-/// Attempts to find where an external crate is located, given that we're
-/// rendering in to the specified source destination.
-fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
-    -> ExternalLocation
-{
-    // See if there's documentation generated into the local directory
-    let local_location = dst.join(&e.name);
-    if local_location.is_dir() {
-        return Local;
-    }
-
-    if let Some(url) = extern_url {
-        let mut url = url.to_string();
-        if !url.ends_with("/") {
-            url.push('/');
-        }
-        return Remote(url);
-    }
-
-    // Failing that, see if there's an attribute specifying where to find this
-    // external crate
-    e.attrs.lists(sym::doc)
-     .filter(|a| a.check_name(sym::html_root_url))
-     .filter_map(|a| a.value_str())
-     .map(|url| {
-        let mut url = url.to_string();
-        if !url.ends_with("/") {
-            url.push('/')
-        }
-        Remote(url)
-    }).next().unwrap_or(Unknown) // Well, at least we tried.
-}
-
-impl DocFolder for Cache {
-    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
-        if item.def_id.is_local() {
-            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
-        }
-
-        // If this is a stripped module,
-        // we don't want it or its children in the search index.
-        let orig_stripped_mod = match item.inner {
-            clean::StrippedItem(box clean::ModuleItem(..)) => {
-                mem::replace(&mut self.stripped_mod, true)
-            }
-            _ => self.stripped_mod,
-        };
-
-        // If the impl is from a masked crate or references something from a
-        // masked crate then remove it completely.
-        if let clean::ImplItem(ref i) = item.inner {
-            if self.masked_crates.contains(&item.def_id.krate) ||
-               i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) ||
-               i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) {
-                return None;
-            }
-        }
-
-        // Propagate a trait method's documentation to all implementors of the
-        // trait.
-        if let clean::TraitItem(ref t) = item.inner {
-            self.traits.entry(item.def_id).or_insert_with(|| t.clone());
-        }
-
-        // Collect all the implementors of traits.
-        if let clean::ImplItem(ref i) = item.inner {
-            if let Some(did) = i.trait_.def_id() {
-                if i.blanket_impl.is_none() {
-                    self.implementors.entry(did).or_default().push(Impl {
-                        impl_item: item.clone(),
-                    });
-                }
-            }
-        }
-
-        // Index this method for searching later on.
-        if let Some(ref s) = item.name {
-            let (parent, is_inherent_impl_item) = match item.inner {
-                clean::StrippedItem(..) => ((None, None), false),
-                clean::AssocConstItem(..) |
-                clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
-                    // skip associated items in trait impls
-                    ((None, None), false)
-                }
-                clean::AssocTypeItem(..) |
-                clean::TyMethodItem(..) |
-                clean::StructFieldItem(..) |
-                clean::VariantItem(..) => {
-                    ((Some(*self.parent_stack.last().unwrap()),
-                      Some(&self.stack[..self.stack.len() - 1])),
-                     false)
-                }
-                clean::MethodItem(..) | clean::AssocConstItem(..) => {
-                    if self.parent_stack.is_empty() {
-                        ((None, None), false)
-                    } else {
-                        let last = self.parent_stack.last().unwrap();
-                        let did = *last;
-                        let path = match self.paths.get(&did) {
-                            // The current stack not necessarily has correlation
-                            // for where the type was defined. On the other
-                            // hand, `paths` always has the right
-                            // information if present.
-                            Some(&(ref fqp, ItemType::Trait)) |
-                            Some(&(ref fqp, ItemType::Struct)) |
-                            Some(&(ref fqp, ItemType::Union)) |
-                            Some(&(ref fqp, ItemType::Enum)) =>
-                                Some(&fqp[..fqp.len() - 1]),
-                            Some(..) => Some(&*self.stack),
-                            None => None
-                        };
-                        ((Some(*last), path), true)
-                    }
-                }
-                _ => ((None, Some(&*self.stack)), false)
-            };
-
-            match parent {
-                (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
-                    debug_assert!(!item.is_stripped());
-
-                    // A crate has a module at its root, containing all items,
-                    // which should not be indexed. The crate-item itself is
-                    // inserted later on when serializing the search-index.
-                    if item.def_id.index != CRATE_DEF_INDEX {
-                        self.search_index.push(IndexItem {
-                            ty: item.type_(),
-                            name: s.to_string(),
-                            path: path.join("::"),
-                            desc: shorten(plain_summary_line(item.doc_value())),
-                            parent,
-                            parent_idx: None,
-                            search_type: get_index_search_type(&item),
-                        });
-                    }
-                }
-                (Some(parent), None) if is_inherent_impl_item => {
-                    // We have a parent, but we don't know where they're
-                    // defined yet. Wait for later to index this item.
-                    self.orphan_impl_items.push((parent, item.clone()));
-                }
-                _ => {}
-            }
-        }
-
-        // Keep track of the fully qualified path for this item.
-        let pushed = match item.name {
-            Some(ref n) if !n.is_empty() => {
-                self.stack.push(n.to_string());
-                true
-            }
-            _ => false,
-        };
-
-        match item.inner {
-            clean::StructItem(..) | clean::EnumItem(..) |
-            clean::TypedefItem(..) | clean::TraitItem(..) |
-            clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
-            clean::ConstantItem(..) | clean::StaticItem(..) |
-            clean::UnionItem(..) | clean::ForeignTypeItem |
-            clean::MacroItem(..) | clean::ProcMacroItem(..)
-            if !self.stripped_mod => {
-                // Re-exported items mean that the same id can show up twice
-                // in the rustdoc ast that we're looking at. We know,
-                // however, that a re-exported item doesn't show up in the
-                // `public_items` map, so we can skip inserting into the
-                // paths map if there was already an entry present and we're
-                // not a public item.
-                if !self.paths.contains_key(&item.def_id) ||
-                   self.access_levels.is_public(item.def_id)
-                {
-                    self.paths.insert(item.def_id,
-                                      (self.stack.clone(), item.type_()));
-                }
-                self.add_aliases(&item);
-            }
-            // Link variants to their parent enum because pages aren't emitted
-            // for each variant.
-            clean::VariantItem(..) if !self.stripped_mod => {
-                let mut stack = self.stack.clone();
-                stack.pop();
-                self.paths.insert(item.def_id, (stack, ItemType::Enum));
-            }
-
-            clean::PrimitiveItem(..) if item.visibility.is_some() => {
-                self.add_aliases(&item);
-                self.paths.insert(item.def_id, (self.stack.clone(),
-                                                item.type_()));
-            }
-
-            _ => {}
-        }
-
-        // Maintain the parent stack
-        let orig_parent_is_trait_impl = self.parent_is_trait_impl;
-        let parent_pushed = match item.inner {
-            clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem |
-            clean::StructItem(..) | clean::UnionItem(..) => {
-                self.parent_stack.push(item.def_id);
-                self.parent_is_trait_impl = false;
-                true
-            }
-            clean::ImplItem(ref i) => {
-                self.parent_is_trait_impl = i.trait_.is_some();
-                match i.for_ {
-                    clean::ResolvedPath{ did, .. } => {
-                        self.parent_stack.push(did);
-                        true
-                    }
-                    ref t => {
-                        let prim_did = t.primitive_type().and_then(|t| {
-                            self.primitive_locations.get(&t).cloned()
-                        });
-                        match prim_did {
-                            Some(did) => {
-                                self.parent_stack.push(did);
-                                true
-                            }
-                            None => false,
-                        }
-                    }
-                }
-            }
-            _ => false
-        };
-
-        // Once we've recursively found all the generics, hoard off all the
-        // implementations elsewhere.
-        let ret = self.fold_item_recur(item).and_then(|item| {
-            if let clean::Item { inner: clean::ImplItem(_), .. } = item {
-                // Figure out the id of this impl. This may map to a
-                // primitive rather than always to a struct/enum.
-                // Note: matching twice to restrict the lifetime of the `i` borrow.
-                let mut dids = FxHashSet::default();
-                if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
-                    match i.for_ {
-                        clean::ResolvedPath { did, .. } |
-                        clean::BorrowedRef {
-                            type_: box clean::ResolvedPath { did, .. }, ..
-                        } => {
-                            dids.insert(did);
-                        }
-                        ref t => {
-                            let did = t.primitive_type().and_then(|t| {
-                                self.primitive_locations.get(&t).cloned()
-                            });
-
-                            if let Some(did) = did {
-                                dids.insert(did);
-                            }
-                        }
-                    }
-
-                    if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
-                        for bound in generics {
-                            if let Some(did) = bound.def_id() {
-                                dids.insert(did);
-                            }
-                        }
-                    }
-                } else {
-                    unreachable!()
-                };
-                let impl_item = Impl {
-                    impl_item: item,
-                };
-                if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
-                    for did in dids {
-                        self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
-                    }
-                } else {
-                    let trait_did = impl_item.trait_did().unwrap();
-                    self.orphan_trait_impls.push((trait_did, dids, impl_item));
-                }
-                None
-            } else {
-                Some(item)
-            }
-        });
-
-        if pushed { self.stack.pop().unwrap(); }
-        if parent_pushed { self.parent_stack.pop().unwrap(); }
-        self.stripped_mod = orig_stripped_mod;
-        self.parent_is_trait_impl = orig_parent_is_trait_impl;
-        ret
-    }
-}
-
-impl Cache {
-    fn add_aliases(&mut self, item: &clean::Item) {
-        if item.def_id.index == CRATE_DEF_INDEX {
-            return
-        }
-        if let Some(ref item_name) = item.name {
-            let path = self.paths.get(&item.def_id)
-                                 .map(|p| p.0[..p.0.len() - 1].join("::"))
-                                 .unwrap_or("std".to_owned());
-            for alias in item.attrs.lists(sym::doc)
-                                   .filter(|a| a.check_name(sym::alias))
-                                   .filter_map(|a| a.value_str()
-                                                    .map(|s| s.to_string().replace("\"", "")))
-                                   .filter(|v| !v.is_empty())
-                                   .collect::<FxHashSet<_>>()
-                                   .into_iter() {
-                self.aliases.entry(alias)
-                            .or_insert(Vec::with_capacity(1))
-                            .push(IndexItem {
-                                ty: item.type_(),
-                                name: item_name.to_string(),
-                                path: path.clone(),
-                                desc: shorten(plain_summary_line(item.doc_value())),
-                                parent: None,
-                                parent_idx: None,
-                                search_type: get_index_search_type(&item),
-                            });
-            }
-        }
-    }
-}
-
 #[derive(Debug, Eq, PartialEq, Hash)]
 struct ItemEntry {
     url: String,
@@ -1665,9 +1099,11 @@ impl ItemEntry {
     }
 }
 
-impl fmt::Display for ItemEntry {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
+impl ItemEntry {
+    crate fn print(&self) -> impl fmt::Display + '_ {
+        crate::html::format::display_fn(move |f| {
+            write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
+        })
     }
 }
 
@@ -1759,7 +1195,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
                title,
                Escape(title),
                class,
-               e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>());
+               e.iter().map(|s| format!("<li>{}</li>", s.print())).collect::<String>());
     }
 }
 
@@ -1882,7 +1318,7 @@ impl Context {
             extra_scripts: &[],
             static_extra_scripts: &[],
         };
-        let sidebar = if let Some(ref version) = cache().crate_version {
+        let sidebar = if let Some(ref version) = self.cache.crate_version {
             format!("<p class='location'>Crate {}</p>\
                      <div class='block version'>\
                          <p>Version {}</p>\
@@ -1939,7 +1375,7 @@ impl Context {
             title.push_str(it.name.as_ref().unwrap());
         }
         title.push_str(" - Rust");
-        let tyname = it.type_().css_class();
+        let tyname = it.type_();
         let desc = if it.is_crate() {
             format!("API documentation for the Rust `{}` crate.",
                     self.shared.layout.krate)
@@ -1949,7 +1385,7 @@ impl Context {
         };
         let keywords = make_item_keywords(it);
         let page = layout::Page {
-            css_class: tyname,
+            css_class: tyname.as_str(),
             root_path: &self.root_path(),
             static_root_path: self.shared.static_root_path.as_deref(),
             title: &title,
@@ -1972,7 +1408,7 @@ impl Context {
                            &self.shared.themes)
         } else {
             let mut url = self.root_path();
-            if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
+            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
                 for name in &names[..names.len() - 1] {
                     url.push_str(name);
                     url.push_str("/");
@@ -2090,7 +1526,7 @@ impl Context {
         for item in &m.items {
             if item.is_stripped() { continue }
 
-            let short = item.type_().css_class();
+            let short = item.type_();
             let myname = match item.name {
                 None => continue,
                 Some(ref s) => s.to_string(),
@@ -2122,7 +1558,6 @@ impl Context {
     fn src_href(&self, item: &clean::Item) -> Option<String> {
         let mut root = self.root_path();
 
-        let cache = cache();
         let mut path = String::new();
 
         // We can safely ignore macros from other libraries
@@ -2138,7 +1573,7 @@ impl Context {
                 return None;
             }
         } else {
-            let (krate, src_root) = match *cache.extern_locations.get(&item.def_id.krate)? {
+            let (krate, src_root) = match *self.cache.extern_locations.get(&item.def_id.krate)? {
                 (ref name, ref src, Local) => (name, src),
                 (ref name, ref src, Remote(ref s)) => {
                     root = s.to_string();
@@ -2267,12 +1702,12 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) {
         clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t),
         clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
         clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
-        clean::PrimitiveItem(ref p) => item_primitive(buf, cx, item, p),
+        clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
         clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
             item_static(buf, cx, item, i),
         clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
-        clean::KeywordItem(ref k) => item_keyword(buf, cx, item, k),
+        clean::KeywordItem(_) => item_keyword(buf, cx, item),
         clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e),
         clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
         _ => {
@@ -2284,8 +1719,8 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) {
 
 fn item_path(ty: ItemType, name: &str) -> String {
     match ty {
-        ItemType::Module => format!("{}index.html", SlashChecker(name)),
-        _ => format!("{}.{}.html", ty.css_class(), name),
+        ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)),
+        _ => format!("{}.{}.html", ty, name),
     }
 }
 
@@ -2353,7 +1788,7 @@ fn render_markdown(
            if is_hidden { " hidden" } else { "" },
            prefix,
            Markdown(md_text, &links, &mut ids,
-           cx.codes, cx.edition, &cx.playground).to_string())
+           cx.shared.codes, cx.shared.edition, &cx.shared.playground).to_string())
 }
 
 fn document_short(
@@ -2571,13 +2006,13 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
                 match *src {
                     Some(ref src) => {
                         write!(w, "<tr><td><code>{}extern crate {} as {};",
-                               VisSpace(&myitem.visibility),
+                               myitem.visibility.print_with_space(),
                                anchor(myitem.def_id, src),
                                name)
                     }
                     None => {
                         write!(w, "<tr><td><code>{}extern crate {};",
-                               VisSpace(&myitem.visibility),
+                               myitem.visibility.print_with_space(),
                                anchor(myitem.def_id, name))
                     }
                 }
@@ -2586,7 +2021,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
 
             clean::ImportItem(ref import) => {
                 write!(w, "<tr><td><code>{}{}</code></td></tr>",
-                       VisSpace(&myitem.visibility), *import);
+                       myitem.visibility.print_with_space(), import.print());
             }
 
             _ => {
@@ -2688,7 +2123,7 @@ fn stability_tags(item: &clean::Item) -> String {
 /// documentation.
 fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
     let mut stability = vec![];
-    let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
+    let error_codes = cx.shared.codes;
 
     if let Some(Deprecation { note, since }) = &item.deprecation() {
         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
@@ -2710,7 +2145,8 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
-            let html = MarkdownHtml(&note, &mut ids, error_codes, cx.edition, &cx.playground);
+            let html = MarkdownHtml(
+                &note, &mut ids, error_codes, cx.shared.edition, &cx.shared.playground);
             message.push_str(&format!(": {}", html.to_string()));
         }
         stability.push(format!("<div class='stab deprecated'>{}</div>", message));
@@ -2763,8 +2199,8 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
                     &unstable_reason,
                     &mut ids,
                     error_codes,
-                    cx.edition,
-                    &cx.playground,
+                    cx.shared.edition,
+                    &cx.shared.playground,
                 ).to_string()
             );
         }
@@ -2792,9 +2228,9 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons
     render_attributes(w, it, false);
     write!(w, "{vis}const \
                {name}: {typ}</pre>",
-           vis = VisSpace(&it.visibility),
+           vis = it.visibility.print_with_space(),
            name = it.name.as_ref().unwrap(),
-           typ = c.type_);
+           typ = c.type_.print());
     document(w, cx, it)
 }
 
@@ -2803,43 +2239,43 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static
     render_attributes(w, it, false);
     write!(w, "{vis}static {mutability}\
                {name}: {typ}</pre>",
-           vis = VisSpace(&it.visibility),
-           mutability = MutableSpace(s.mutability),
+           vis = it.visibility.print_with_space(),
+           mutability = s.mutability.print_with_space(),
            name = it.name.as_ref().unwrap(),
-           typ = s.type_);
+           typ = s.type_.print());
     document(w, cx, it)
 }
 
 fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) {
     let header_len = format!(
         "{}{}{}{}{:#}fn {}{:#}",
-        VisSpace(&it.visibility),
-        ConstnessSpace(f.header.constness),
-        UnsafetySpace(f.header.unsafety),
-        AsyncSpace(f.header.asyncness),
-        AbiSpace(f.header.abi),
+        it.visibility.print_with_space(),
+        f.header.constness.print_with_space(),
+        f.header.unsafety.print_with_space(),
+        f.header.asyncness.print_with_space(),
+        print_abi_with_space(f.header.abi),
         it.name.as_ref().unwrap(),
-        f.generics
+        f.generics.print()
     ).len();
     write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it));
     render_attributes(w, it, false);
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}</pre>",
-           vis = VisSpace(&it.visibility),
-           constness = ConstnessSpace(f.header.constness),
-           unsafety = UnsafetySpace(f.header.unsafety),
-           asyncness = AsyncSpace(f.header.asyncness),
-           abi = AbiSpace(f.header.abi),
+           vis = it.visibility.print_with_space(),
+           constness = f.header.constness.print_with_space(),
+           unsafety = f.header.unsafety.print_with_space(),
+           asyncness = f.header.asyncness.print_with_space(),
+           abi = print_abi_with_space(f.header.abi),
            name = it.name.as_ref().unwrap(),
-           generics = f.generics,
+           generics = f.generics.print(),
            where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
            decl = Function {
               decl: &f.decl,
               header_len,
               indent: 0,
               asyncness: f.header.asyncness,
-           });
+           }.print());
     document(w, cx, it)
 }
 
@@ -2880,15 +2316,15 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
             if i > 0 {
                 bounds.push_str(" + ");
             }
-            bounds.push_str(&(*p).to_string());
+            bounds.push_str(&p.print().to_string());
         }
     }
     bounds
 }
 
 fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
-    let lhs = format!("{}", lhs.inner_impl());
-    let rhs = format!("{}", rhs.inner_impl());
+    let lhs = format!("{}", lhs.inner_impl().print());
+    let rhs = format!("{}", rhs.inner_impl().print());
 
     // lhs and rhs are formatted as HTML, which may be unnecessary
     name_key(&lhs).cmp(&name_key(&rhs))
@@ -2911,11 +2347,11 @@ fn item_trait(
         write!(w, "<pre class='rust trait'>");
         render_attributes(w, it, true);
         write!(w, "{}{}{}trait {}{}{}",
-               VisSpace(&it.visibility),
-               UnsafetySpace(t.unsafety),
+               it.visibility.print_with_space(),
+               t.unsafety.print_with_space(),
                if t.is_auto { "auto " } else { "" },
                it.name.as_ref().unwrap(),
-               t.generics,
+               t.generics.print(),
                bounds);
 
         if !t.generics.where_predicates.is_empty() {
@@ -3047,11 +2483,9 @@ fn item_trait(
     // If there are methods directly on this trait object, render them here.
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All);
 
-    let cache = cache();
-
     let mut synthetic_types = Vec::new();
 
-    if let Some(implementors) = cache.implementors.get(&it.def_id) {
+    if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
         // if any Types with the same name but different DefId have been found.
         let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap::default();
@@ -3074,7 +2508,7 @@ fn item_trait(
 
         let (local, foreign) = implementors.iter()
             .partition::<Vec<_>, _>(|i| i.inner_impl().for_.def_id()
-                                         .map_or(true, |d| cache.paths.contains_key(&d)));
+                                         .map_or(true, |d| cx.cache.paths.contains_key(&d)));
 
 
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
@@ -3139,10 +2573,10 @@ fn item_trait(
            path = if it.def_id.is_local() {
                cx.current.join("/")
            } else {
-               let (ref path, _) = cache.external_paths[&it.def_id];
+               let (ref path, _) = cx.cache.external_paths[&it.def_id];
                path[..path.len() - 1].join("/")
            },
-           ty = it.type_().css_class(),
+           ty = it.type_(),
            name = *it.name.as_ref().unwrap());
 }
 
@@ -3173,10 +2607,10 @@ fn assoc_const(w: &mut Buffer,
                extra: &str) {
     write!(w, "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
            extra,
-           VisSpace(&it.visibility),
+           it.visibility.print_with_space(),
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap(),
-           ty);
+           ty.print());
 }
 
 fn assoc_type(w: &mut Buffer, it: &clean::Item,
@@ -3189,10 +2623,10 @@ fn assoc_type(w: &mut Buffer, it: &clean::Item,
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap());
     if !bounds.is_empty() {
-        write!(w, ": {}", GenericBounds(bounds))
+        write!(w, ": {}", print_generic_bounds(bounds))
     }
     if let Some(default) = default {
-        write!(w, " = {}", default)
+        write!(w, " = {}", default.print())
     }
 }
 
@@ -3238,14 +2672,14 @@ fn render_assoc_item(w: &mut Buffer,
         };
         let mut header_len = format!(
             "{}{}{}{}{}{:#}fn {}{:#}",
-            VisSpace(&meth.visibility),
-            ConstnessSpace(header.constness),
-            UnsafetySpace(header.unsafety),
-            AsyncSpace(header.asyncness),
-            DefaultSpace(meth.is_default()),
-            AbiSpace(header.abi),
+            meth.visibility.print_with_space(),
+            header.constness.print_with_space(),
+            header.unsafety.print_with_space(),
+            header.asyncness.print_with_space(),
+            print_default_space(meth.is_default()),
+            print_abi_with_space(header.abi),
             name,
-            *g
+            g.print()
         ).len();
         let (indent, end_newline) = if parent == ItemType::Trait {
             header_len += 4;
@@ -3257,21 +2691,21 @@ fn render_assoc_item(w: &mut Buffer,
         write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
                if parent == ItemType::Trait { "    " } else { "" },
-               VisSpace(&meth.visibility),
-               ConstnessSpace(header.constness),
-               UnsafetySpace(header.unsafety),
-               AsyncSpace(header.asyncness),
-               DefaultSpace(meth.is_default()),
-               AbiSpace(header.abi),
+               meth.visibility.print_with_space(),
+               header.constness.print_with_space(),
+               header.unsafety.print_with_space(),
+               header.asyncness.print_with_space(),
+               print_default_space(meth.is_default()),
+               print_abi_with_space(header.abi),
                href = href,
                name = name,
-               generics = *g,
+               generics = g.print(),
                decl = Function {
                    decl: d,
                    header_len,
                    indent,
                    asyncness: header.asyncness,
-               },
+               }.print(),
                where_clause = WhereClause {
                    gens: g,
                    indent,
@@ -3340,7 +2774,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
                        id = id,
                        ns_id = ns_id,
                        name = field.name.as_ref().unwrap(),
-                       ty = ty);
+                       ty = ty.print());
                 document(w, cx, field);
             }
         }
@@ -3381,7 +2815,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union)
                    id = id,
                    name = name,
                    shortty = ItemType::StructField,
-                   ty = ty);
+                   ty = ty.print());
             if let Some(stability_class) = field.stability_class() {
                 write!(w, "<span class='stab {stab}'></span>",
                     stab = stability_class);
@@ -3397,9 +2831,9 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
         write!(w, "<pre class='rust enum'>");
         render_attributes(w, it, true);
         write!(w, "{}enum {}{}{}",
-               VisSpace(&it.visibility),
+               it.visibility.print_with_space(),
                it.name.as_ref().unwrap(),
-               e.generics,
+               e.generics.print(),
                WhereClause { gens: &e.generics, indent: 0, end_newline: true });
         if e.variants.is_empty() && !e.variants_stripped {
             write!(w, " {{}}");
@@ -3418,7 +2852,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                                     if i > 0 {
                                         write!(w, ",&nbsp;")
                                     }
-                                    write!(w, "{}", *ty);
+                                    write!(w, "{}", ty.print());
                                 }
                                 write!(w, ")");
                             }
@@ -3472,7 +2906,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                         if i > 0 {
                             write!(w, ",&nbsp;");
                         }
-                        write!(w, "{}", *ty);
+                        write!(w, "{}", ty.print());
                     }
                     write!(w, ")");
                 }
@@ -3510,7 +2944,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                                id = id,
                                ns_id = ns_id,
                                f = field.name.as_ref().unwrap(),
-                               t = *ty);
+                               t = ty.print());
                         document(w, cx, field);
                     }
                 }
@@ -3586,11 +3020,11 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                  tab: &str,
                  structhead: bool) {
     write!(w, "{}{}{}",
-           VisSpace(&it.visibility),
+           it.visibility.print_with_space(),
            if structhead {"struct "} else {""},
            it.name.as_ref().unwrap());
     if let Some(g) = g {
-        write!(w, "{}", g)
+        write!(w, "{}", g.print())
     }
     match ty {
         doctree::Plain => {
@@ -3603,9 +3037,9 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                 if let clean::StructFieldItem(ref ty) = field.inner {
                     write!(w, "\n{}    {}{}: {},",
                            tab,
-                           VisSpace(&field.visibility),
+                           field.visibility.print_with_space(),
                            field.name.as_ref().unwrap(),
-                           *ty);
+                           ty.print());
                     has_visible_fields = true;
                 }
             }
@@ -3633,7 +3067,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                         write!(w, "_")
                     }
                     clean::StructFieldItem(ref ty) => {
-                        write!(w, "{}{}", VisSpace(&field.visibility), *ty)
+                        write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
                     }
                     _ => unreachable!()
                 }
@@ -3660,11 +3094,11 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
                 tab: &str,
                 structhead: bool) {
     write!(w, "{}{}{}",
-           VisSpace(&it.visibility),
+           it.visibility.print_with_space(),
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap());
     if let Some(g) = g {
-        write!(w, "{}", g);
+        write!(w, "{}", g.print());
         write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true });
     }
 
@@ -3672,9 +3106,9 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
     for field in fields {
         if let clean::StructFieldItem(ref ty) = field.inner {
             write!(w, "    {}{}: {},\n{}",
-                   VisSpace(&field.visibility),
+                   field.visibility.print_with_space(),
                    field.name.as_ref().unwrap(),
-                   *ty,
+                   ty.print(),
                    tab);
         }
     }
@@ -3716,7 +3150,7 @@ fn render_assoc_items(w: &mut Buffer,
                       containing_item: &clean::Item,
                       it: DefId,
                       what: AssocItemRender<'_>) {
-    let c = cache();
+    let c = &cx.cache;
     let v = match c.impls.get(&it) {
         Some(v) => v,
         None => return,
@@ -3740,7 +3174,7 @@ fn render_assoc_items(w: &mut Buffer,
                       Methods from {}&lt;Target = {}&gt;\
                       <a href='#deref-methods' class='anchor'></a>\
                     </h2>\
-                ", trait_, type_);
+                ", trait_.print(), type_.print());
                 RenderMode::ForDeref { mut_: deref_mut_ }
             }
         };
@@ -3822,7 +3256,7 @@ fn render_deref_methods(w: &mut Buffer, cx: &Context, impl_: &Impl,
         render_assoc_items(w, cx, container_item, did, what)
     } else {
         if let Some(prim) = target.primitive_type() {
-            if let Some(&did) = cache().primitive_locations.get(&prim) {
+            if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
                 render_assoc_items(w, cx, container_item, did, what);
             }
         }
@@ -3856,19 +3290,15 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
 }
 
 fn render_spotlight_traits(item: &clean::Item) -> String {
-    let mut out = String::new();
-
     match item.inner {
         clean::FunctionItem(clean::Function { ref decl, .. }) |
         clean::TyMethodItem(clean::TyMethod { ref decl, .. }) |
         clean::MethodItem(clean::Method { ref decl, .. }) |
         clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => {
-            out = spotlight_decl(decl);
+            spotlight_decl(decl)
         }
-        _ => {}
+        _ => String::new()
     }
-
-    out
 }
 
 fn spotlight_decl(decl: &clean::FnDecl) -> String {
@@ -3885,12 +3315,13 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
                         out.push_str(
                             &format!("<h3 class=\"important\">Important traits for {}</h3>\
                                       <code class=\"content\">",
-                                     impl_.for_));
-                        trait_.push_str(&impl_.for_.to_string());
+                                     impl_.for_.print()));
+                        trait_.push_str(&impl_.for_.print().to_string());
                     }
 
                     //use the "where" class here to make it small
-                    out.push_str(&format!("<span class=\"where fmt-newline\">{}</span>", impl_));
+                    out.push_str(
+                        &format!("<span class=\"where fmt-newline\">{}</span>", impl_.print()));
                     let t_did = impl_.trait_.def_id().unwrap();
                     for it in &impl_.items {
                         if let clean::TypedefItem(ref tydef, _) = it.inner {
@@ -3927,7 +3358,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
             Some(ref t) => if is_on_foreign_type {
                 get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t)
             } else {
-                format!("impl-{}", small_url_encode(&format!("{:#}", t)))
+                format!("impl-{}", small_url_encode(&format!("{:#}", t.print())))
             },
             None => "impl".to_string(),
         });
@@ -3948,7 +3379,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
             write!(w, "</code>");
         } else {
             write!(w, "<h3 id='{}' class='impl'><code class='in-band'>{}</code>",
-                id, i.inner_impl()
+                id, i.inner_impl().print()
             );
         }
         write!(w, "<a href='#{}' class='anchor'></a>", id);
@@ -3963,7 +3394,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
             let mut ids = cx.id_map.borrow_mut();
             write!(w, "<div class='docblock'>{}</div>",
                    Markdown(&*dox, &i.impl_item.links(), &mut ids,
-                            cx.codes, cx.edition, &cx.playground).to_string());
+                            cx.shared.codes, cx.shared.edition, &cx.shared.playground).to_string());
         }
     }
 
@@ -3974,7 +3405,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
         let item_type = item.type_();
         let name = item.name.as_ref().unwrap();
 
-        let render_method_item: bool = match render_mode {
+        let render_method_item = match render_mode {
             RenderMode::Normal => true,
             RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
         };
@@ -3993,8 +3424,10 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
                     let id = cx.derive_id(format!("{}.{}", item_type, name));
-                    let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-                    write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class);
+                    let ns_id = cx.derive_id(format!("{}.{}",
+                            name, item_type.name_space()));
+                    write!(w, "<h4 id='{}' class=\"{}{}\">",
+                        id, item_type, extra_class);
                     write!(w, "{}", spotlight_decl(decl));
                     write!(w, "<code id='{}'>", ns_id);
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
@@ -4041,7 +3474,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
             _ => panic!("can't make docs for trait item with name {:?}", item.name)
         }
 
-        if render_method_item || render_mode == RenderMode::Normal {
+        if render_method_item {
             if !is_default_item {
                 if let Some(t) = trait_ {
                     // The trait item may have been stripped so we might not
@@ -4073,7 +3506,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
         }
     }
 
-    let traits = &cache().traits;
+    let traits = &cx.cache.traits;
     let trait_ = i.trait_did().map(|did| &traits[&did]);
 
     write!(w, "<div class='impl-items'>");
@@ -4125,7 +3558,7 @@ fn item_opaque_ty(
     render_attributes(w, it, false);
     write!(w, "type {}{}{where_clause} = impl {bounds};</pre>",
            it.name.as_ref().unwrap(),
-           t.generics,
+           t.generics.print(),
            where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
            bounds = bounds(&t.bounds, false));
 
@@ -4144,7 +3577,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context, it: &clean::Item,
     render_attributes(w, it, false);
     write!(w, "trait {}{}{} = {};</pre>",
            it.name.as_ref().unwrap(),
-           t.generics,
+           t.generics.print(),
            WhereClause { gens: &t.generics, indent: 0, end_newline: true },
            bounds(&t.bounds, true));
 
@@ -4162,9 +3595,9 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed
     render_attributes(w, it, false);
     write!(w, "type {}{}{where_clause} = {type_};</pre>",
            it.name.as_ref().unwrap(),
-           t.generics,
+           t.generics.print(),
            where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
-           type_ = t.type_);
+           type_ = t.type_.print());
 
     document(w, cx, it);
 
@@ -4181,7 +3614,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item) {
     write!(
         w,
         "    {}type {};\n}}</pre>",
-        VisSpace(&it.visibility),
+        it.visibility.print_with_space(),
         it.name.as_ref().unwrap(),
     );
 
@@ -4215,7 +3648,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) {
     }
 
     if it.is_crate() {
-        if let Some(ref version) = cache().crate_version {
+        if let Some(ref version) = cx.cache.crate_version {
             write!(buffer,
                     "<div class='block version'>\
                     <p>Version {}</p>\
@@ -4232,11 +3665,11 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) {
     match it.inner {
         clean::StructItem(ref s) => sidebar_struct(buffer, it, s),
         clean::TraitItem(ref t) => sidebar_trait(buffer, it, t),
-        clean::PrimitiveItem(ref p) => sidebar_primitive(buffer, it, p),
+        clean::PrimitiveItem(_) => sidebar_primitive(buffer, it),
         clean::UnionItem(ref u) => sidebar_union(buffer, it, u),
         clean::EnumItem(ref e) => sidebar_enum(buffer, it, e),
-        clean::TypedefItem(ref t, _) => sidebar_typedef(buffer, it, t),
-        clean::ModuleItem(ref m) => sidebar_module(buffer, it, &m.items),
+        clean::TypedefItem(_, _) => sidebar_typedef(buffer, it),
+        clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
         clean::ForeignTypeItem => sidebar_foreign_type(buffer, it),
         _ => (),
     }
@@ -4269,7 +3702,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) {
                 relpath: '{path}'\
             }};</script>",
             name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
-            ty = it.type_().css_class(),
+            ty = it.type_(),
             path = relpath);
     if parentlen == 0 {
         // There is no sidebar-items.js beyond the crate root path
@@ -4301,8 +3734,7 @@ fn get_methods(
 ) -> Vec<String> {
     i.items.iter().filter_map(|item| {
         match item.name {
-            // Maybe check with clean::Visibility::Public as well?
-            Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => {
+            Some(ref name) if !name.is_empty() && item.is_method() => {
                 if !for_deref || should_render_item(item, deref_mut) {
                     Some(format!("<a href=\"#{}\">{}</a>",
                                  get_next_url(used_links, format!("method.{}", name)),
@@ -4339,12 +3771,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
         let mut used_links = FxHashSet::default();
 
         {
-            let used_links_bor = Rc::new(RefCell::new(&mut used_links));
+            let used_links_bor = &mut used_links;
             let mut ret = v.iter()
                            .filter(|i| i.inner_impl().trait_.is_none())
                            .flat_map(move |i| get_methods(i.inner_impl(),
                                                           false,
-                                                          &mut used_links_bor.borrow_mut(), false))
+                                                          used_links_bor, false))
                            .collect::<Vec<_>>();
             // We want links' order to be reproducible so we don't use unstable sort.
             ret.sort();
@@ -4370,9 +3802,10 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
                     if let Some(impls) = inner_impl {
                         out.push_str("<a class=\"sidebar-title\" href=\"#deref-methods\">");
                         out.push_str(&format!("Methods from {}&lt;Target={}&gt;",
-                                              Escape(&format!("{:#}",
-                                                     impl_.inner_impl().trait_.as_ref().unwrap())),
-                                              Escape(&format!("{:#}", target))));
+                            Escape(&format!(
+                                "{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print()
+                            )),
+                            Escape(&format!("{:#}", target.print()))));
                         out.push_str("</a>");
                         let mut ret = impls.iter()
                                            .filter(|i| i.inner_impl().trait_.is_none())
@@ -4397,9 +3830,9 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
                     .filter_map(|i| {
                         let is_negative_impl = is_negative_impl(i.inner_impl());
                         if let Some(ref i) = i.inner_impl().trait_ {
-                            let i_display = format!("{:#}", i);
+                            let i_display = format!("{:#}", i.print());
                             let out = Escape(&i_display);
-                            let encoded = small_url_encode(&format!("{:#}", i));
+                            let encoded = small_url_encode(&format!("{:#}", i.print()));
                             let generated = format!("<a href=\"#impl-{}\">{}{}</a>",
                                                     encoded,
                                                     if is_negative_impl { "!" } else { "" },
@@ -4471,14 +3904,17 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
 }
 
 fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String {
-    small_url_encode(&format!("impl-{:#}-for-{:#}", trait_, for_))
+    small_url_encode(&format!("impl-{:#}-for-{:#}", trait_.print(), for_.print()))
 }
 
 fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
     match item.inner {
         clean::ItemEnum::ImplItem(ref i) => {
             if let Some(ref trait_) = i.trait_ {
-                Some((format!("{:#}", i.for_), get_id_for_impl_on_foreign_type(&i.for_, trait_)))
+                Some((
+                    format!("{:#}", i.for_.print()),
+                    get_id_for_impl_on_foreign_type(&i.for_, trait_),
+                ))
             } else {
                 None
             }
@@ -4602,7 +4038,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
     write!(buf, "<div class=\"block items\">{}</div>", sidebar)
 }
 
-fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveType) {
+fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item) {
     let sidebar = sidebar_assoc_items(it);
 
     if !sidebar.is_empty() {
@@ -4610,7 +4046,7 @@ fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveTy
     }
 }
 
-fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item, _t: &clean::Typedef) {
+fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) {
     let sidebar = sidebar_assoc_items(it);
 
     if !sidebar.is_empty() {
@@ -4702,7 +4138,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
     }
 }
 
-fn sidebar_module(buf: &mut Buffer, _it: &clean::Item, items: &[clean::Item]) {
+fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
     if items.iter().any(|it| it.type_() == ItemType::ExternCrate ||
@@ -4780,16 +4216,12 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr
     document(w, cx, it)
 }
 
-fn item_primitive(w: &mut Buffer, cx: &Context,
-                  it: &clean::Item,
-                  _p: &clean::PrimitiveType) {
+fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item) {
     document(w, cx, it);
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_keyword(w: &mut Buffer, cx: &Context,
-                it: &clean::Item,
-                _p: &str) {
+fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) {
     document(w, cx, it)
 }
 
@@ -4799,37 +4231,6 @@ fn make_item_keywords(it: &clean::Item) -> String {
     format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
 }
 
-fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
-    let (all_types, ret_types) = match item.inner {
-        clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
-        clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
-        clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
-        _ => return None,
-    };
-
-    let inputs = all_types.iter().map(|arg| {
-        get_index_type(&arg)
-    }).filter(|a| a.name.is_some()).collect();
-    let output = ret_types.iter().map(|arg| {
-        get_index_type(&arg)
-    }).filter(|a| a.name.is_some()).collect::<Vec<_>>();
-    let output = if output.is_empty() {
-        None
-    } else {
-        Some(output)
-    };
-
-    Some(IndexItemFunctionType { inputs, output })
-}
-
-fn get_index_type(clean_type: &clean::Type) -> Type {
-    let t = Type {
-        name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
-        generics: get_generics(clean_type),
-    };
-    t
-}
-
 /// Returns a list of all paths used in the type.
 /// This is used to help deduplicate imported impls
 /// for reexported types. If any of the contained
@@ -4887,39 +4288,6 @@ fn collect_paths_for_type(first_ty: clean::Type) -> Vec<String> {
     out
 }
 
-fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<String> {
-    match *clean_type {
-        clean::ResolvedPath { ref path, .. } => {
-            let segments = &path.segments;
-            let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!(
-                "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
-                clean_type, accept_generic
-            ));
-            Some(path_segment.name.clone())
-        }
-        clean::Generic(ref s) if accept_generic => Some(s.clone()),
-        clean::Primitive(ref p) => Some(format!("{:?}", p)),
-        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
-        // FIXME: add all from clean::Type.
-        _ => None
-    }
-}
-
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
-    clean_type.generics()
-              .and_then(|types| {
-                  let r = types.iter()
-                               .filter_map(|t| get_index_type_name(t, false))
-                               .map(|s| s.to_ascii_lowercase())
-                               .collect::<Vec<_>>();
-                  if r.is_empty() {
-                      None
-                  } else {
-                      Some(r)
-                  }
-              })
-}
-
-pub fn cache() -> Arc<Cache> {
+crate fn cache() -> Arc<Cache> {
     CACHE_KEY.with(|c| c.borrow().clone())
 }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
new file mode 100644
index 00000000000..65dd119c27c
--- /dev/null
+++ b/src/librustdoc/html/render/cache.rs
@@ -0,0 +1,675 @@
+use crate::clean::{self, GetDefId, AttributesExt};
+use crate::fold::DocFolder;
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
+use rustc::middle::privacy::AccessLevels;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use std::mem;
+use std::path::{Path, PathBuf};
+use std::collections::BTreeMap;
+use syntax::source_map::FileName;
+use syntax::symbol::sym;
+use serialize::json::{ToJson, Json, as_json};
+
+use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line};
+use super::{Type, RenderInfo};
+
+/// Indicates where an external crate can be found.
+pub enum ExternalLocation {
+    /// Remote URL root of the external crate
+    Remote(String),
+    /// This external crate can be found in the local doc/ folder
+    Local,
+    /// The external crate could not be found.
+    Unknown,
+}
+
+/// This cache is used to store information about the `clean::Crate` being
+/// rendered in order to provide more useful documentation. This contains
+/// information like all implementors of a trait, all traits a type implements,
+/// documentation for all known traits, etc.
+///
+/// This structure purposefully does not implement `Clone` because it's intended
+/// to be a fairly large and expensive structure to clone. Instead this adheres
+/// to `Send` so it may be stored in a `Arc` instance and shared among the various
+/// rendering threads.
+#[derive(Default)]
+crate struct Cache {
+    /// Maps a type ID to all known implementations for that type. This is only
+    /// recognized for intra-crate `ResolvedPath` types, and is used to print
+    /// out extra documentation on the page of an enum/struct.
+    ///
+    /// The values of the map are a list of implementations and documentation
+    /// found on that implementation.
+    pub impls: FxHashMap<DefId, Vec<Impl>>,
+
+    /// Maintains a mapping of local crate `NodeId`s to the fully qualified name
+    /// and "short type description" of that node. This is used when generating
+    /// URLs when a type is being linked to. External paths are not located in
+    /// this map because the `External` type itself has all the information
+    /// necessary.
+    pub paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
+
+    /// Similar to `paths`, but only holds external paths. This is only used for
+    /// generating explicit hyperlinks to other crates.
+    pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
+
+    /// Maps local `DefId`s of exported types to fully qualified paths.
+    /// Unlike 'paths', this mapping ignores any renames that occur
+    /// due to 'use' statements.
+    ///
+    /// This map is used when writing out the special 'implementors'
+    /// javascript file. By using the exact path that the type
+    /// is declared with, we ensure that each path will be identical
+    /// to the path used if the corresponding type is inlined. By
+    /// doing this, we can detect duplicate impls on a trait page, and only display
+    /// the impl for the inlined type.
+    pub exact_paths: FxHashMap<DefId, Vec<String>>,
+
+    /// This map contains information about all known traits of this crate.
+    /// Implementations of a crate should inherit the documentation of the
+    /// parent trait if no extra documentation is specified, and default methods
+    /// should show up in documentation about trait implementations.
+    pub traits: FxHashMap<DefId, clean::Trait>,
+
+    /// When rendering traits, it's often useful to be able to list all
+    /// implementors of the trait, and this mapping is exactly, that: a mapping
+    /// of trait ids to the list of known implementors of the trait
+    pub implementors: FxHashMap<DefId, Vec<Impl>>,
+
+    /// Cache of where external crate documentation can be found.
+    pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
+
+    /// Cache of where documentation for primitives can be found.
+    pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
+
+    // Note that external items for which `doc(hidden)` applies to are shown as
+    // non-reachable while local items aren't. This is because we're reusing
+    // the access levels from the privacy check pass.
+    pub access_levels: AccessLevels<DefId>,
+
+    /// The version of the crate being documented, if given from the `--crate-version` flag.
+    pub crate_version: Option<String>,
+
+    // Private fields only used when initially crawling a crate to build a cache
+
+    stack: Vec<String>,
+    parent_stack: Vec<DefId>,
+    parent_is_trait_impl: bool,
+    search_index: Vec<IndexItem>,
+    stripped_mod: bool,
+    pub deref_trait_did: Option<DefId>,
+    pub deref_mut_trait_did: Option<DefId>,
+    pub owned_box_did: Option<DefId>,
+    masked_crates: FxHashSet<CrateNum>,
+
+    // In rare case where a structure is defined in one module but implemented
+    // in another, if the implementing module is parsed before defining module,
+    // then the fully qualified name of the structure isn't presented in `paths`
+    // yet when its implementation methods are being indexed. Caches such methods
+    // and their parent id here and indexes them at the end of crate parsing.
+    orphan_impl_items: Vec<(DefId, clean::Item)>,
+
+    // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
+    // even though the trait itself is not exported. This can happen if a trait
+    // was defined in function/expression scope, since the impl will be picked
+    // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
+    // crawl. In order to prevent crashes when looking for spotlight traits or
+    // when gathering trait documentation on a type, hold impls here while
+    // folding and add them to the cache later on if we find the trait.
+    orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
+
+    /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
+    /// we need the alias element to have an array of items.
+    pub(super) aliases: FxHashMap<String, Vec<IndexItem>>,
+}
+
+impl Cache {
+    pub fn from_krate(
+        renderinfo: RenderInfo,
+        extern_html_root_urls: &BTreeMap<String, String>,
+        dst: &Path,
+        mut krate: clean::Crate,
+    ) -> (clean::Crate, String, Cache) {
+        // Crawl the crate to build various caches used for the output
+        let RenderInfo {
+            inlined: _,
+            external_paths,
+            exact_paths,
+            access_levels,
+            deref_trait_did,
+            deref_mut_trait_did,
+            owned_box_did,
+        } = renderinfo;
+
+        let external_paths = external_paths.into_iter()
+            .map(|(k, (v, t))| (k, (v, ItemType::from(t))))
+            .collect();
+
+        let mut cache = Cache {
+            impls: Default::default(),
+            external_paths,
+            exact_paths,
+            paths: Default::default(),
+            implementors: Default::default(),
+            stack: Vec::new(),
+            parent_stack: Vec::new(),
+            search_index: Vec::new(),
+            parent_is_trait_impl: false,
+            extern_locations: Default::default(),
+            primitive_locations: Default::default(),
+            stripped_mod: false,
+            access_levels,
+            crate_version: krate.version.take(),
+            orphan_impl_items: Vec::new(),
+            orphan_trait_impls: Vec::new(),
+            traits: krate.external_traits.replace(Default::default()),
+            deref_trait_did,
+            deref_mut_trait_did,
+            owned_box_did,
+            masked_crates: mem::take(&mut krate.masked_crates),
+            aliases: Default::default(),
+        };
+
+        // Cache where all our extern crates are located
+        for &(n, ref e) in &krate.externs {
+            let src_root = match e.src {
+                FileName::Real(ref p) => match p.parent() {
+                    Some(p) => p.to_path_buf(),
+                    None => PathBuf::new(),
+                },
+                _ => PathBuf::new(),
+            };
+            let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
+            cache.extern_locations.insert(n, (e.name.clone(), src_root,
+                                            extern_location(e, extern_url, &dst)));
+
+            let did = DefId { krate: n, index: CRATE_DEF_INDEX };
+            cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
+        }
+
+        // Cache where all known primitives have their documentation located.
+        //
+        // Favor linking to as local extern as possible, so iterate all crates in
+        // reverse topological order.
+        for &(_, ref e) in krate.externs.iter().rev() {
+            for &(def_id, prim, _) in &e.primitives {
+                cache.primitive_locations.insert(prim, def_id);
+            }
+        }
+        for &(def_id, prim, _) in &krate.primitives {
+            cache.primitive_locations.insert(prim, def_id);
+        }
+
+        cache.stack.push(krate.name.clone());
+        krate = cache.fold_crate(krate);
+
+        for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
+            if cache.traits.contains_key(&trait_did) {
+                for did in dids {
+                    cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
+                }
+            }
+        }
+
+        // Build our search index
+        let index = build_index(&krate, &mut cache);
+
+        (krate, index, cache)
+    }
+}
+
+impl DocFolder for Cache {
+    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+        if item.def_id.is_local() {
+            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
+        }
+
+        // If this is a stripped module,
+        // we don't want it or its children in the search index.
+        let orig_stripped_mod = match item.inner {
+            clean::StrippedItem(box clean::ModuleItem(..)) => {
+                mem::replace(&mut self.stripped_mod, true)
+            }
+            _ => self.stripped_mod,
+        };
+
+        // If the impl is from a masked crate or references something from a
+        // masked crate then remove it completely.
+        if let clean::ImplItem(ref i) = item.inner {
+            if self.masked_crates.contains(&item.def_id.krate) ||
+               i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) ||
+               i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) {
+                return None;
+            }
+        }
+
+        // Propagate a trait method's documentation to all implementors of the
+        // trait.
+        if let clean::TraitItem(ref t) = item.inner {
+            self.traits.entry(item.def_id).or_insert_with(|| t.clone());
+        }
+
+        // Collect all the implementors of traits.
+        if let clean::ImplItem(ref i) = item.inner {
+            if let Some(did) = i.trait_.def_id() {
+                if i.blanket_impl.is_none() {
+                    self.implementors.entry(did).or_default().push(Impl {
+                        impl_item: item.clone(),
+                    });
+                }
+            }
+        }
+
+        // Index this method for searching later on.
+        if let Some(ref s) = item.name {
+            let (parent, is_inherent_impl_item) = match item.inner {
+                clean::StrippedItem(..) => ((None, None), false),
+                clean::AssocConstItem(..) |
+                clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
+                    // skip associated items in trait impls
+                    ((None, None), false)
+                }
+                clean::AssocTypeItem(..) |
+                clean::TyMethodItem(..) |
+                clean::StructFieldItem(..) |
+                clean::VariantItem(..) => {
+                    ((Some(*self.parent_stack.last().unwrap()),
+                      Some(&self.stack[..self.stack.len() - 1])),
+                     false)
+                }
+                clean::MethodItem(..) | clean::AssocConstItem(..) => {
+                    if self.parent_stack.is_empty() {
+                        ((None, None), false)
+                    } else {
+                        let last = self.parent_stack.last().unwrap();
+                        let did = *last;
+                        let path = match self.paths.get(&did) {
+                            // The current stack not necessarily has correlation
+                            // for where the type was defined. On the other
+                            // hand, `paths` always has the right
+                            // information if present.
+                            Some(&(ref fqp, ItemType::Trait)) |
+                            Some(&(ref fqp, ItemType::Struct)) |
+                            Some(&(ref fqp, ItemType::Union)) |
+                            Some(&(ref fqp, ItemType::Enum)) =>
+                                Some(&fqp[..fqp.len() - 1]),
+                            Some(..) => Some(&*self.stack),
+                            None => None
+                        };
+                        ((Some(*last), path), true)
+                    }
+                }
+                _ => ((None, Some(&*self.stack)), false)
+            };
+
+            match parent {
+                (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
+                    debug_assert!(!item.is_stripped());
+
+                    // A crate has a module at its root, containing all items,
+                    // which should not be indexed. The crate-item itself is
+                    // inserted later on when serializing the search-index.
+                    if item.def_id.index != CRATE_DEF_INDEX {
+                        self.search_index.push(IndexItem {
+                            ty: item.type_(),
+                            name: s.to_string(),
+                            path: path.join("::"),
+                            desc: shorten(plain_summary_line(item.doc_value())),
+                            parent,
+                            parent_idx: None,
+                            search_type: get_index_search_type(&item),
+                        });
+                    }
+                }
+                (Some(parent), None) if is_inherent_impl_item => {
+                    // We have a parent, but we don't know where they're
+                    // defined yet. Wait for later to index this item.
+                    self.orphan_impl_items.push((parent, item.clone()));
+                }
+                _ => {}
+            }
+        }
+
+        // Keep track of the fully qualified path for this item.
+        let pushed = match item.name {
+            Some(ref n) if !n.is_empty() => {
+                self.stack.push(n.to_string());
+                true
+            }
+            _ => false,
+        };
+
+        match item.inner {
+            clean::StructItem(..) | clean::EnumItem(..) |
+            clean::TypedefItem(..) | clean::TraitItem(..) |
+            clean::FunctionItem(..) | clean::ModuleItem(..) |
+            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
+            clean::ConstantItem(..) | clean::StaticItem(..) |
+            clean::UnionItem(..) | clean::ForeignTypeItem |
+            clean::MacroItem(..) | clean::ProcMacroItem(..)
+            if !self.stripped_mod => {
+                // Re-exported items mean that the same id can show up twice
+                // in the rustdoc ast that we're looking at. We know,
+                // however, that a re-exported item doesn't show up in the
+                // `public_items` map, so we can skip inserting into the
+                // paths map if there was already an entry present and we're
+                // not a public item.
+                if !self.paths.contains_key(&item.def_id) ||
+                   self.access_levels.is_public(item.def_id)
+                {
+                    self.paths.insert(item.def_id,
+                                      (self.stack.clone(), item.type_()));
+                }
+                self.add_aliases(&item);
+            }
+            // Link variants to their parent enum because pages aren't emitted
+            // for each variant.
+            clean::VariantItem(..) if !self.stripped_mod => {
+                let mut stack = self.stack.clone();
+                stack.pop();
+                self.paths.insert(item.def_id, (stack, ItemType::Enum));
+            }
+
+            clean::PrimitiveItem(..) => {
+                self.add_aliases(&item);
+                self.paths.insert(item.def_id, (self.stack.clone(),
+                                                item.type_()));
+            }
+
+            _ => {}
+        }
+
+        // Maintain the parent stack
+        let orig_parent_is_trait_impl = self.parent_is_trait_impl;
+        let parent_pushed = match item.inner {
+            clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem |
+            clean::StructItem(..) | clean::UnionItem(..) => {
+                self.parent_stack.push(item.def_id);
+                self.parent_is_trait_impl = false;
+                true
+            }
+            clean::ImplItem(ref i) => {
+                self.parent_is_trait_impl = i.trait_.is_some();
+                match i.for_ {
+                    clean::ResolvedPath{ did, .. } => {
+                        self.parent_stack.push(did);
+                        true
+                    }
+                    ref t => {
+                        let prim_did = t.primitive_type().and_then(|t| {
+                            self.primitive_locations.get(&t).cloned()
+                        });
+                        match prim_did {
+                            Some(did) => {
+                                self.parent_stack.push(did);
+                                true
+                            }
+                            None => false,
+                        }
+                    }
+                }
+            }
+            _ => false
+        };
+
+        // Once we've recursively found all the generics, hoard off all the
+        // implementations elsewhere.
+        let ret = self.fold_item_recur(item).and_then(|item| {
+            if let clean::Item { inner: clean::ImplItem(_), .. } = item {
+                // Figure out the id of this impl. This may map to a
+                // primitive rather than always to a struct/enum.
+                // Note: matching twice to restrict the lifetime of the `i` borrow.
+                let mut dids = FxHashSet::default();
+                if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
+                    match i.for_ {
+                        clean::ResolvedPath { did, .. } |
+                        clean::BorrowedRef {
+                            type_: box clean::ResolvedPath { did, .. }, ..
+                        } => {
+                            dids.insert(did);
+                        }
+                        ref t => {
+                            let did = t.primitive_type().and_then(|t| {
+                                self.primitive_locations.get(&t).cloned()
+                            });
+
+                            if let Some(did) = did {
+                                dids.insert(did);
+                            }
+                        }
+                    }
+
+                    if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+                        for bound in generics {
+                            if let Some(did) = bound.def_id() {
+                                dids.insert(did);
+                            }
+                        }
+                    }
+                } else {
+                    unreachable!()
+                };
+                let impl_item = Impl {
+                    impl_item: item,
+                };
+                if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
+                    for did in dids {
+                        self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+                    }
+                } else {
+                    let trait_did = impl_item.trait_did().unwrap();
+                    self.orphan_trait_impls.push((trait_did, dids, impl_item));
+                }
+                None
+            } else {
+                Some(item)
+            }
+        });
+
+        if pushed { self.stack.pop().unwrap(); }
+        if parent_pushed { self.parent_stack.pop().unwrap(); }
+        self.stripped_mod = orig_stripped_mod;
+        self.parent_is_trait_impl = orig_parent_is_trait_impl;
+        ret
+    }
+}
+
+impl Cache {
+    fn add_aliases(&mut self, item: &clean::Item) {
+        if item.def_id.index == CRATE_DEF_INDEX {
+            return
+        }
+        if let Some(ref item_name) = item.name {
+            let path = self.paths.get(&item.def_id)
+                                 .map(|p| p.0[..p.0.len() - 1].join("::"))
+                                 .unwrap_or("std".to_owned());
+            for alias in item.attrs.lists(sym::doc)
+                                   .filter(|a| a.check_name(sym::alias))
+                                   .filter_map(|a| a.value_str()
+                                                    .map(|s| s.to_string().replace("\"", "")))
+                                   .filter(|v| !v.is_empty())
+                                   .collect::<FxHashSet<_>>()
+                                   .into_iter() {
+                self.aliases.entry(alias)
+                            .or_insert(Vec::with_capacity(1))
+                            .push(IndexItem {
+                                ty: item.type_(),
+                                name: item_name.to_string(),
+                                path: path.clone(),
+                                desc: shorten(plain_summary_line(item.doc_value())),
+                                parent: None,
+                                parent_idx: None,
+                                search_type: get_index_search_type(&item),
+                            });
+            }
+        }
+    }
+}
+
+/// Attempts to find where an external crate is located, given that we're
+/// rendering in to the specified source destination.
+fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
+    -> ExternalLocation
+{
+    use ExternalLocation::*;
+    // See if there's documentation generated into the local directory
+    let local_location = dst.join(&e.name);
+    if local_location.is_dir() {
+        return Local;
+    }
+
+    if let Some(url) = extern_url {
+        let mut url = url.to_string();
+        if !url.ends_with("/") {
+            url.push('/');
+        }
+        return Remote(url);
+    }
+
+    // Failing that, see if there's an attribute specifying where to find this
+    // external crate
+    e.attrs.lists(sym::doc)
+     .filter(|a| a.check_name(sym::html_root_url))
+     .filter_map(|a| a.value_str())
+     .map(|url| {
+        let mut url = url.to_string();
+        if !url.ends_with("/") {
+            url.push('/')
+        }
+        Remote(url)
+    }).next().unwrap_or(Unknown) // Well, at least we tried.
+}
+
+/// Builds the search index from the collected metadata
+fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
+    let mut nodeid_to_pathid = FxHashMap::default();
+    let mut crate_items = Vec::with_capacity(cache.search_index.len());
+    let mut crate_paths = Vec::<Json>::new();
+
+    let Cache { ref mut search_index,
+                ref orphan_impl_items,
+                ref paths, .. } = *cache;
+
+    // Attach all orphan items to the type's definition if the type
+    // has since been learned.
+    for &(did, ref item) in orphan_impl_items {
+        if let Some(&(ref fqp, _)) = paths.get(&did) {
+            search_index.push(IndexItem {
+                ty: item.type_(),
+                name: item.name.clone().unwrap(),
+                path: fqp[..fqp.len() - 1].join("::"),
+                desc: shorten(plain_summary_line(item.doc_value())),
+                parent: Some(did),
+                parent_idx: None,
+                search_type: get_index_search_type(&item),
+            });
+        }
+    }
+
+    // Reduce `NodeId` in paths into smaller sequential numbers,
+    // and prune the paths that do not appear in the index.
+    let mut lastpath = String::new();
+    let mut lastpathid = 0usize;
+
+    for item in search_index {
+        item.parent_idx = item.parent.map(|nodeid| {
+            if nodeid_to_pathid.contains_key(&nodeid) {
+                *nodeid_to_pathid.get(&nodeid).unwrap()
+            } else {
+                let pathid = lastpathid;
+                nodeid_to_pathid.insert(nodeid, pathid);
+                lastpathid += 1;
+
+                let &(ref fqp, short) = paths.get(&nodeid).unwrap();
+                crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
+                pathid
+            }
+        });
+
+        // Omit the parent path if it is same to that of the prior item.
+        if lastpath == item.path {
+            item.path.clear();
+        } else {
+            lastpath = item.path.clone();
+        }
+        crate_items.push(item.to_json());
+    }
+
+    let crate_doc = krate.module.as_ref().map(|module| {
+        shorten(plain_summary_line(module.doc_value()))
+    }).unwrap_or(String::new());
+
+    let mut crate_data = BTreeMap::new();
+    crate_data.insert("doc".to_owned(), Json::String(crate_doc));
+    crate_data.insert("i".to_owned(), Json::Array(crate_items));
+    crate_data.insert("p".to_owned(), Json::Array(crate_paths));
+
+    // Collect the index into a string
+    format!("searchIndex[{}] = {};",
+            as_json(&krate.name),
+            Json::Object(crate_data))
+}
+
+fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
+    let (all_types, ret_types) = match item.inner {
+        clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
+        clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
+        clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
+        _ => return None,
+    };
+
+    let inputs = all_types.iter().map(|arg| {
+        get_index_type(&arg)
+    }).filter(|a| a.name.is_some()).collect();
+    let output = ret_types.iter().map(|arg| {
+        get_index_type(&arg)
+    }).filter(|a| a.name.is_some()).collect::<Vec<_>>();
+    let output = if output.is_empty() {
+        None
+    } else {
+        Some(output)
+    };
+
+    Some(IndexItemFunctionType { inputs, output })
+}
+
+fn get_index_type(clean_type: &clean::Type) -> Type {
+    let t = Type {
+        name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
+        generics: get_generics(clean_type),
+    };
+    t
+}
+
+fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<String> {
+    match *clean_type {
+        clean::ResolvedPath { ref path, .. } => {
+            let segments = &path.segments;
+            let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!(
+                "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
+                clean_type, accept_generic
+            ));
+            Some(path_segment.name.clone())
+        }
+        clean::Generic(ref s) if accept_generic => Some(s.clone()),
+        clean::Primitive(ref p) => Some(format!("{:?}", p)),
+        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
+        // FIXME: add all from clean::Type.
+        _ => None
+    }
+}
+
+fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
+    clean_type.generics()
+              .and_then(|types| {
+                  let r = types.iter()
+                               .filter_map(|t| get_index_type_name(t, false))
+                               .map(|s| s.to_ascii_lowercase())
+                               .collect::<Vec<_>>();
+                  if r.is_empty() {
+                      None
+                  } else {
+                      Some(r)
+                  }
+              })
+}
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index 2da7aceae8b..0fb2f8dd796 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -1,10 +1,7 @@
 //! Table-of-contents creation.
 
-use std::fmt;
-use std::string::String;
-
 /// A (recursive) table of contents
-#[derive(PartialEq)]
+#[derive(Debug, PartialEq)]
 pub struct Toc {
     /// The levels are strictly decreasing, i.e.
     ///
@@ -28,7 +25,7 @@ impl Toc {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(Debug, PartialEq)]
 pub struct TocEntry {
     level: u32,
     sec_number: String,
@@ -165,25 +162,23 @@ impl TocBuilder {
     }
 }
 
-impl fmt::Debug for Toc {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, f)
-    }
-}
-
-impl fmt::Display for Toc {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "<ul>")?;
+impl Toc {
+    fn print_inner(&self, v: &mut String) {
+        v.push_str("<ul>");
         for entry in &self.entries {
-            // recursively format this table of contents (the
-            // `{children}` is the key).
-            write!(fmt,
-                   "\n<li><a href=\"#{id}\">{num} {name}</a>{children}</li>",
+            // recursively format this table of contents
+            v.push_str(&format!("\n<li><a href=\"#{id}\">{num} {name}</a>",
                    id = entry.id,
-                   num = entry.sec_number, name = entry.name,
-                   children = entry.children)?
+                   num = entry.sec_number, name = entry.name));
+            entry.children.print_inner(&mut *v);
+            v.push_str("</li>");
         }
-        write!(fmt, "</ul>")
+        v.push_str("</ul>");
+    }
+    crate fn print(&self) -> String {
+        let mut v = String::new();
+        self.print_inner(&mut v);
+        v
     }
 }
 
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 4ee09f7096b..dc1ca8d7668 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -142,7 +142,8 @@ impl fold::DocFolder for CoverageCalculator {
             }
             clean::ImplItem(ref impl_) => {
                 if let Some(ref tr) = impl_.trait_ {
-                    debug!("impl {:#} for {:#} in {}", tr, impl_.for_, i.source.filename);
+                    debug!("impl {:#} for {:#} in {}",
+                        tr.print(), impl_.for_.print(), i.source.filename);
 
                     // don't count trait impls, the missing-docs lint doesn't so we shouldn't
                     // either
@@ -151,11 +152,11 @@ impl fold::DocFolder for CoverageCalculator {
                     // inherent impls *can* be documented, and those docs show up, but in most
                     // cases it doesn't make sense, as all methods on a type are in one single
                     // impl block
-                    debug!("impl {:#} in {}", impl_.for_, i.source.filename);
+                    debug!("impl {:#} in {}", impl_.for_.print(), i.source.filename);
                 }
             }
             _ => {
-                debug!("counting {} {:?} in {}", i.type_(), i.name, i.source.filename);
+                debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
                 self.items.entry(i.source.filename.clone())
                           .or_default()
                           .count_item(has_docs);
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index d6073cdc1e1..b67f39d3280 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -237,7 +237,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         });
 
         if parent_node.is_some() {
-            debug!("got parent node for {} {:?}, id {:?}", item.type_(), item.name, item.def_id);
+            debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
         }
 
         let current_item = match item.inner {
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 14f8b16dc30..f6560218a78 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -153,7 +153,7 @@ impl<'a> DocFolder for Stripper<'a> {
                 // We need to recurse into stripped modules to strip things
                 // like impl methods but when doing so we must not add any
                 // items to the `retained` set.
-                debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name);
+                debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
                 let old = mem::replace(&mut self.update_retained, false);
                 let ret = self.fold_item_recur(i);
                 self.update_retained = old;
@@ -178,20 +178,20 @@ impl<'a> DocFolder for Stripper<'a> {
             | clean::ForeignTypeItem => {
                 if i.def_id.is_local() {
                     if !self.access_levels.is_exported(i.def_id) {
-                        debug!("Stripper: stripping {} {:?}", i.type_(), i.name);
+                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                         return None;
                     }
                 }
             }
 
             clean::StructFieldItem(..) => {
-                if i.visibility != Some(clean::Public) {
+                if i.visibility != clean::Public {
                     return StripItem(i).strip();
                 }
             }
 
             clean::ModuleItem(..) => {
-                if i.def_id.is_local() && i.visibility != Some(clean::Public) {
+                if i.def_id.is_local() && i.visibility != clean::Public {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
@@ -299,7 +299,7 @@ impl DocFolder for ImportStripper {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match i.inner {
             clean::ExternCrateItem(..) | clean::ImportItem(..)
-                if i.visibility != Some(clean::Public) =>
+                if i.visibility != clean::Public =>
             {
                 None
             }
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index da8977544f6..0159e03f6f2 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -39,7 +39,7 @@ struct Stripper<'a> {
 impl<'a> DocFolder for Stripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.attrs.lists(sym::doc).has_word(sym::hidden) {
-            debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name);
+            debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
             // use a dedicated hidden item for given item type if any
             match i.inner {
                 clean::StructFieldItem(..) | clean::ModuleItem(..) => {
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index af1d2402f88..ee4b367b5c5 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -53,9 +53,6 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] }
 
-[build-dependencies]
-cc = "1.0"
-
 [features]
 default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]
 
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index b5265fe369e..8933f027a06 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -114,6 +114,9 @@ pub struct Metadata(fs_imp::FileAttr);
 /// information like the entry's path and possibly other metadata can be
 /// learned.
 ///
+/// The order in which this iterator returns entries is platform and filesystem
+/// dependent.
+///
 /// # Errors
 ///
 /// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
@@ -1962,6 +1965,9 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
+/// The order in which this iterator returns entries is platform and filesystem
+/// dependent.
+///
 /// # Errors
 ///
 /// This function will return an error in the following situations, but is not
@@ -1994,6 +2000,25 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///     Ok(())
 /// }
 /// ```
+///
+/// ```rust,no_run
+/// use std::{fs, io};
+///
+/// fn main() -> io::Result<()> {
+///     let mut entries = fs::read_dir(".")?
+///         .map(|res| res.map(|e| e.path()))
+///         .collect::<Result<Vec<_>, io::Error>>()?;
+///
+///     // The order in which `read_dir` returns entries is not guaranteed. If reproducible
+///     // ordering is required the entries should be explicitly sorted.
+///
+///     entries.sort();
+///
+///     // The entries have now been sorted by their path.
+///
+///     Ok(())
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
     fs_imp::readdir(path.as_ref()).map(ReadDir)
diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs
index 1fc88fbde74..3ecbe4e3b28 100644
--- a/src/libstd/sys/vxworks/process/mod.rs
+++ b/src/libstd/sys/vxworks/process/mod.rs
@@ -5,4 +5,3 @@ pub use crate::ffi::OsString as EnvKey;
 mod process_common;
 #[path = "process_vxworks.rs"]
 mod process_inner;
-mod rtp;
diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
index 8780df17a1c..beb20aa4816 100644
--- a/src/libstd/sys/vxworks/process/process_vxworks.rs
+++ b/src/libstd/sys/vxworks/process/process_vxworks.rs
@@ -3,7 +3,6 @@ use libc::{self, c_int, c_char};
 use libc::{RTP_ID};
 use crate::sys;
 use crate::sys::cvt;
-use crate::sys::process::rtp;
 use crate::sys::process::process_common::*;
 use crate::sys_common::thread;
 
@@ -53,7 +52,7 @@ impl Command {
                 t!(cvt(libc::chdir(cwd.as_ptr())));
             }
 
-            let ret = rtp::rtpSpawn(
+            let ret = libc::rtpSpawn(
                 self.get_argv()[0],                   // executing program
                 self.get_argv().as_ptr() as *const _, // argv
                 *sys::os::environ() as *const *const c_char,
@@ -78,7 +77,7 @@ impl Command {
                 libc::close(orig_stderr);
             }
 
-            if ret != rtp::RTP_ID_ERROR {
+            if ret != libc::RTP_ID_ERROR {
                 p.pid = ret;
                 Ok((p, ours))
             } else {
diff --git a/src/libstd/sys/vxworks/process/rtp.rs b/src/libstd/sys/vxworks/process/rtp.rs
deleted file mode 100644
index 3e6e0017abc..00000000000
--- a/src/libstd/sys/vxworks/process/rtp.rs
+++ /dev/null
@@ -1,298 +0,0 @@
-#![allow(non_camel_case_types, unused)]
-
-use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID};
-
-
-// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options)
-
-// ****     definitions for rtpLibCommon.h    ****
-
-pub const RTP_GLOBAL_SYMBOLS     : c_int = 0x01; // register global symbols for RTP
-pub const RTP_LOCAL_SYMBOLS      : c_int = 0x02; // idem for local symbols
-pub const RTP_ALL_SYMBOLS        : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS);
-pub const RTP_DEBUG              : c_int = 0x10; // set RTP in debug mode when created
-pub const RTP_BUFFER_VAL_OFF     : c_int = 0x20; // disable buffer validation for all
-                                                 // system calls issued from the RTP
-pub const RTP_LOADED_WAIT        : c_int = 0x40; // Wait until the RTP is loaded
-pub const RTP_CPU_AFFINITY_NONE  : c_int = 0x80; // Remove any CPU affinity (SMP)
-
-// Error Status codes
-
-pub const M_rtpLib : c_int = 178 << 16;
-
-pub const S_rtpLib_INVALID_FILE                   : c_int = (M_rtpLib | 1);
-pub const S_rtpLib_INVALID_OPTION                 : c_int = (M_rtpLib | 2);
-pub const S_rtpLib_ACCESS_DENIED                  : c_int = (M_rtpLib | 3);
-pub const S_rtpLib_INVALID_RTP_ID                 : c_int = (M_rtpLib | 4);
-pub const S_rtpLib_NO_SYMBOL_TABLE                : c_int = (M_rtpLib | 5);
-pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS  : c_int = (M_rtpLib | 6);
-pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY  : c_int = (M_rtpLib | 7);
-pub const S_rtpLib_INSTANTIATE_FAILED             : c_int = (M_rtpLib | 8);
-pub const S_rtpLib_INVALID_TASK_OPTION            : c_int = (M_rtpLib | 9);
-pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED       : c_int = (M_rtpLib | 10);    // rtpInfoGet
-
-pub const VX_RTP_NAME_LENGTH                      : c_int  = 255;    // max name length for diplay
-
-
-// The 'status' field (32 bit integer) of a RTP holds the RTP state and status.
-//
-// NOTE: RTP_STATE_GET()    : read the RTP state(s)
-//       RTP_STATE_PUT()    : write the RTP state(s)
-//       RTP_STATE_SET()    : set a RTP state
-//       RTP_STATE_UNSET()  : unset a RTP state
-//
-//       RTP_STATUS_GET()   : read the RTP status
-//       RTP_STATUS_PUT()   : write the RTP status
-//       RTP_STATUS_SET()   : set a RTP status
-//       RTP_STATUS_UNSET() : unset a RTP status
-//
-// The PUT/SET/UNSET macros are available only in the kernel headers.
-
-
-// RTP states
-
-pub const RTP_STATE_CREATE           : c_int  = 0x0001; // RrtpStructTP is under construction
-pub const RTP_STATE_NORMAL           : c_int  = 0x0002; // RrtpStructTP is ready
-pub const RTP_STATE_DELETE           : c_int  = 0x0004; // RrtpStructTP is being deleted
-
-pub const RTP_STATUS_STOP            : c_int  = 0x0100; // RTP hrtpStructas recieved stopped signal
-pub const RTP_STATUS_ELECTED_DELETER : c_int  = 0x0200; // RTP drtpStructelete has started
-
-pub const RTP_STATE_MASK             : c_int  = (RTP_STATE_CREATE | RTP_STATE_NORMAL |
-                                                 RTP_STATE_DELETE);
-pub const RTP_STATUS_MASK            : c_int  = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER);
-
-pub fn RTP_STATE_GET  (value : c_int) -> c_int {
-    value & RTP_STATE_MASK
-}
-pub fn RTP_STATUS_GET (value : c_int) -> c_int {
-    value & RTP_STATUS_MASK
-}
-
-// Indicates that the RTP_ID returned is not valid.
-
-// RTP_ID_ERROR is supposed to be set to -1, but you can't set
-// an unsigned value to a negative without casting, and you
-// can't cast unless the size of the integer types are the same,
-// but the size of RTP_ID may differ between kernel and user space.
-// Bitwise or-ing min and max should get the same result.
-pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value();
-
-// IS_RTP_ C macros
-
-pub fn IS_RTP_STATE_NORMAL           (value : c_int) -> bool {
-    (RTP_STATE_GET(value)  & RTP_STATE_NORMAL) == RTP_STATE_NORMAL
-}
-pub fn IS_RTP_STATE_CREATE           (value : c_int) -> bool {
-    (RTP_STATE_GET(value)  & RTP_STATE_CREATE) == RTP_STATE_CREATE
-}
-pub fn IS_RTP_STATE_DELETE           (value : c_int) -> bool {
-    (RTP_STATE_GET(value)  & RTP_STATE_DELETE) == RTP_STATE_DELETE
-}
-pub fn IS_RTP_STATUS_STOP            (value : c_int) -> bool {
-    (RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP
-}
-pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool {
-    (RTP_STATUS_GET(value) &  RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER
-}
-
-// **** end of definitions for rtpLibCommon.h ****
-
-
-
-
-// ****    definitions for rtpLib.h     ****
-
-pub fn rtpExit(exitCode : c_int) -> ! {
-    unsafe{ libc::exit (exitCode) }
-}
-
-/* rtpLib.h in the kernel
-pub const RTP_DEL_VIA_TASK_DELETE : c_int  = 0x1;          // rtpDelete() via taskDestroy()
-pub const RTP_DEL_FORCE           : c_int  = 0x2;          // Forceful  rtpDelete()
-pub const RTP_ID_ANY              : RTP_ID = 0;            // used for when a kernel task
-                                                           // wants to wait for the next
-                                                           // RTP to finish
-
-
-// Function pointers
-
-pub type RTP_PRE_CREATE_HOOK    = size_t;
-pub type RTP_POST_CREATE_HOOK   = size_t;
-pub type RTP_INIT_COMPLETE_HOOK = size_t;
-pub type RTP_DELETE_HOOK        = size_t;
-*/
-
-// **** end of definitions for rtpLib.h ****
-
-
-
-
-
-// ****     definitions for signal.h    ****
-pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int {
-    unsafe{ libc::kill(rtpId as c_int, signo) }
-}
-
-pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int {
-    unsafe{ libc::sigqueue(rtpId as c_int, signo, value) }
-}
-
-pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int {
-    unsafe{ libc::_sigqueue(rtpId, signo, value, code) }
-}
-
-pub fn taskRaise(signo : c_int) -> c_int {
-    unsafe{ libc::taskKill(libc::taskIdSelf(), signo) }
-}
-pub fn rtpRaise(signo : c_int) -> c_int {
-    unsafe{ libc::raise(signo) }
-}
-
-// **** end of definitions for signal.h ****
-
-
-
-// ****     definitions for taskLibCommon.h    ****
-pub const VX_PRIVATE_ENV      : c_int = 0x0080;  // 1 = private environment variables
-pub const VX_NO_STACK_FILL    : c_int = 0x0100;  // 1 = avoid stack fill of 0xee
-pub const VX_PRIVATE_UMASK    : c_int = 0x0400;  // 1 = private file creation mode mask
-pub const VX_TASK_NOACTIVATE  : c_int = 0x2000;  // taskOpen() does not taskActivate()
-pub const VX_NO_STACK_PROTECT : c_int = 0x4000;  // no over/underflow stack protection,
-                                                 // stack space remains executable
-
-// define for all valid user task options
-
-pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV      |
-                                             VX_NO_STACK_FILL    |
-                                             VX_TASK_NOACTIVATE  |
-                                             VX_NO_STACK_PROTECT |
-                                             VX_PRIVATE_UMASK);
-
-// **** end of definitions for taskLibCommon.h ****
-
-
-
-extern "C" {
-// functions in rtpLibCommon.h
-
-// forward declarations
-    pub fn rtpSpawn (
-        pubrtpFileName : *const c_char,
-        argv           : *const *const c_char,
-        envp           : *const *const c_char,
-        priority       : c_int,
-        uStackSize     : size_t,
-        options        : c_int,
-        taskOptions    : c_int,
-    ) -> RTP_ID;
-
-    pub fn rtpInfoGet (
-        rtpId     : RTP_ID,
-        rtpStruct : *mut RTP_DESC,
-    ) -> c_int;
-
-/* functions in rtpLib.h for kernel
-
-
-    // function declarations
-
-    pub fn rtpDelete (
-        id      : RTP_ID,
-        options : c_int,
-        status  : c_int,
-    ) -> c_int;
-
-    pub fn rtpDeleteForce (
-        rtpId : RTP_ID
-    ) -> c_int;
-
-    pub fn rtpShow (
-        rtpNameOrId : *mut c_char,
-        level       : c_int,
-    ) -> BOOL;
-
-    // RTP signals are always present when RTPs are included.  The public RTP
-    // signal APIs are declared here.
-
-
-    pub fn rtpKill (
-        rtpId : RTP_ID,
-        signo : c_int,
-    ) -> c_int;
-
-    pub fn rtpSigqueue (
-        rtpId : RTP_ID,
-        signo : c_int,
-        value : size_t, // Actual type is const union sigval value,
-                        // which is a union of int and void *
-    ) -> c_int;
-
-    pub fn rtpTaskKill (
-        tid   : TASK_ID,
-        signo : c_int,
-    ) -> c_int;
-
-    pub fn rtpTaskSigqueue (
-        tid   : TASK_ID,
-        signo : c_int,
-        value : const size_t, // Actual type is const union sigval,
-                        // which is a union of int and void *
-    ) -> c_int;
-
-    pub fn rtpWait (
-        rtpWaitId : RTP_ID,
-        timeout   : libc::alloc_jemalloc_Vx_ticks_t,
-        pRtpId    : *mut RTP_ID,
-        pStatus   : *mut c_int,
-    ) -> c_int;
-
-                             // Other public functions
-
-
-    pub fn rtpPreCreateHookAdd     (
-        hook      : RTP_PRE_CREATE_HOOK,
-        addToHead : BOOL,
-    ) -> c_int;
-
-    pub fn rtpPreCreateHookDelete  (
-        hook      : RTP_POST_CREATE_HOOK,
-    ) -> c_int;
-
-    pub fn rtpPostCreateHookAdd    (
-        hook      : RTP_POST_CREATE_HOOK,
-        addToHead : BOOL,
-    ) -> c_int;
-
-    pub fn rtpPostCreateHookDelete (
-        hook      : RTP_POST_CREATE_HOOK,
-    ) -> c_int;
-
-    pub fn rtpInitCompleteHookAdd  (
-        hook      : RTP_INIT_COMPLETE_HOOK,
-        addToHead : BOOL,
-    ) -> c_int;
-
-    pub fn rtpInitCompleteHookDelete (
-        hook      : RTP_INIT_COMPLETE_HOOK,
-    ) -> c_int;
-
-    pub fn rtpDeleteHookAdd        (
-        hook      : RTP_DELETE_HOOK,
-        addToHead : BOOL,
-    ) -> c_int;
-
-    pub fn rtpDeleteHookDelete     (
-        hook      : RTP_DELETE_HOOK,
-    ) -> c_int;
-
-    pub fn rtpMemShow              (
-        rtpNameOrId : *mut c_char,
-        level       : c_int,
-    ) -> c_int;
-
-    pub fn rtpHookShow             (
-
-    );
-*/
-}
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index d4a9acc1569..196cf4d9dfa 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -19,6 +19,5 @@ syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_lexer = { path = "../librustc_lexer" }
-rustc_macros = { path = "../librustc_macros" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index e189d8f8636..aa76667c2e9 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1017,10 +1017,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
         self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code);
     }
-    pub fn mut_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
-                        -> DiagnosticBuilder<'a> {
-        self.parse_sess.span_diagnostic.mut_span_err(sp, msg)
-    }
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.parse_sess.span_diagnostic.span_warn(sp, msg);
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b80c530731d..c8078d2bb71 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -6,7 +6,7 @@ use crate::config::StripUnconfigured;
 use crate::ext::base::*;
 use crate::ext::proc_macro::{collect_derives, MarkAttrs};
 use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
-use crate::ext::tt::macro_rules::annotate_err_with_kind;
+use crate::ext::mbe::macro_rules::annotate_err_with_kind;
 use crate::ext::placeholders::{placeholder, PlaceholderExpander};
 use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
 use crate::mut_visit::*;
@@ -115,8 +115,8 @@ macro_rules! ast_fragments {
             }
         }
 
-        impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> {
-            $(fn $make_ast(self: Box<crate::ext::tt::macro_rules::ParserAnyMacro<'a>>)
+        impl<'a> MacResult for crate::ext::mbe::macro_rules::ParserAnyMacro<'a> {
+            $(fn $make_ast(self: Box<crate::ext::mbe::macro_rules::ParserAnyMacro<'a>>)
                            -> Option<$AstTy> {
                 Some(self.make(AstFragmentKind::$Kind).$make_ast())
             })*
@@ -384,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         let attr = attr::find_by_name(item.attrs(), sym::derive)
                             .expect("`derive` attribute should exist");
                         let span = attr.span;
-                        let mut err = self.cx.mut_span_err(span,
+                        let mut err = self.cx.struct_span_err(span,
                             "`derive` may only be applied to structs, enums and unions");
                         if let ast::AttrStyle::Inner = attr.style {
                             let trait_list = derives.iter()
diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs
new file mode 100644
index 00000000000..a87da791c9b
--- /dev/null
+++ b/src/libsyntax/ext/mbe.rs
@@ -0,0 +1,166 @@
+//! This module implements declarative macros: old `macro_rules` and the newer
+//! `macro`. Declarative macros are also known as "macro by example", and that's
+//! why we call this module `mbe`. For external documentation, prefer the
+//! official terminology: "declarative macros".
+
+crate mod transcribe;
+crate mod macro_check;
+crate mod macro_parser;
+crate mod macro_rules;
+crate mod quoted;
+
+use crate::ast;
+use crate::parse::token::{self, Token, TokenKind};
+use crate::tokenstream::{DelimSpan};
+
+use syntax_pos::{BytePos, Span};
+
+use rustc_data_structures::sync::Lrc;
+
+/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
+/// that the delimiter itself might be `NoDelim`.
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+struct Delimited {
+    delim: token::DelimToken,
+    tts: Vec<TokenTree>,
+}
+
+impl Delimited {
+    /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
+    fn open_tt(&self, span: Span) -> TokenTree {
+        let open_span = if span.is_dummy() {
+            span
+        } else {
+            span.with_hi(span.lo() + BytePos(self.delim.len() as u32))
+        };
+        TokenTree::token(token::OpenDelim(self.delim), open_span)
+    }
+
+    /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
+    fn close_tt(&self, span: Span) -> TokenTree {
+        let close_span = if span.is_dummy() {
+            span
+        } else {
+            span.with_lo(span.hi() - BytePos(self.delim.len() as u32))
+        };
+        TokenTree::token(token::CloseDelim(self.delim), close_span)
+    }
+}
+
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+struct SequenceRepetition {
+    /// The sequence of token trees
+    tts: Vec<TokenTree>,
+    /// The optional separator
+    separator: Option<Token>,
+    /// Whether the sequence can be repeated zero (*), or one or more times (+)
+    kleene: KleeneToken,
+    /// The number of `Match`s that appear in the sequence (and subsequences)
+    num_captures: usize,
+}
+
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+struct KleeneToken {
+    span: Span,
+    op: KleeneOp,
+}
+
+impl KleeneToken {
+    fn new(op: KleeneOp, span: Span) -> KleeneToken {
+        KleeneToken { span, op }
+    }
+}
+
+/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
+/// for token sequences.
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+enum KleeneOp {
+    /// Kleene star (`*`) for zero or more repetitions
+    ZeroOrMore,
+    /// Kleene plus (`+`) for one or more repetitions
+    OneOrMore,
+    /// Kleene optional (`?`) for zero or one reptitions
+    ZeroOrOne,
+}
+
+/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
+/// are "first-class" token trees. Useful for parsing macros.
+#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
+enum TokenTree {
+    Token(Token),
+    Delimited(DelimSpan, Lrc<Delimited>),
+    /// A kleene-style repetition sequence
+    Sequence(DelimSpan, Lrc<SequenceRepetition>),
+    /// e.g., `$var`
+    MetaVar(Span, ast::Ident),
+    /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
+    MetaVarDecl(
+        Span,
+        ast::Ident, /* name to bind */
+        ast::Ident, /* kind of nonterminal */
+    ),
+}
+
+impl TokenTree {
+    /// Return the number of tokens in the tree.
+    fn len(&self) -> usize {
+        match *self {
+            TokenTree::Delimited(_, ref delimed) => match delimed.delim {
+                token::NoDelim => delimed.tts.len(),
+                _ => delimed.tts.len() + 2,
+            },
+            TokenTree::Sequence(_, ref seq) => seq.tts.len(),
+            _ => 0,
+        }
+    }
+
+    /// Returns `true` if the given token tree is delimited.
+    fn is_delimited(&self) -> bool {
+        match *self {
+            TokenTree::Delimited(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if the given token tree is a token of the given kind.
+    fn is_token(&self, expected_kind: &TokenKind) -> bool {
+        match self {
+            TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind,
+            _ => false,
+        }
+    }
+
+    /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences.
+    fn get_tt(&self, index: usize) -> TokenTree {
+        match (self, index) {
+            (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
+                delimed.tts[index].clone()
+            }
+            (&TokenTree::Delimited(span, ref delimed), _) => {
+                if index == 0 {
+                    return delimed.open_tt(span.open);
+                }
+                if index == delimed.tts.len() + 1 {
+                    return delimed.close_tt(span.close);
+                }
+                delimed.tts[index - 1].clone()
+            }
+            (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
+            _ => panic!("Cannot expand a token tree"),
+        }
+    }
+
+    /// Retrieves the `TokenTree`'s span.
+    fn span(&self) -> Span {
+        match *self {
+            TokenTree::Token(Token { span, .. })
+            | TokenTree::MetaVar(span, _)
+            | TokenTree::MetaVarDecl(span, _, _) => span,
+            TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
+        }
+    }
+
+    fn token(kind: TokenKind, span: Span) -> TokenTree {
+        TokenTree::Token(Token::new(kind, span))
+    }
+}
diff --git a/src/libsyntax/ext/tt/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs
index 5af97199902..97074f5cbe4 100644
--- a/src/libsyntax/ext/tt/macro_check.rs
+++ b/src/libsyntax/ext/mbe/macro_check.rs
@@ -106,7 +106,7 @@
 //! bound.
 use crate::ast::NodeId;
 use crate::early_buffered_lints::BufferedEarlyLintId;
-use crate::ext::tt::quoted::{KleeneToken, TokenTree};
+use crate::ext::mbe::{KleeneToken, TokenTree};
 use crate::parse::token::TokenKind;
 use crate::parse::token::{DelimToken, Token};
 use crate::parse::ParseSess;
@@ -196,7 +196,7 @@ struct MacroState<'a> {
 /// - `node_id` is used to emit lints
 /// - `span` is used when no spans are available
 /// - `lhses` and `rhses` should have the same length and represent the macro definition
-pub fn check_meta_variables(
+pub(super) fn check_meta_variables(
     sess: &ParseSess,
     node_id: NodeId,
     span: Span,
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs
index dbf14daa30e..b51384d3b15 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/mbe/macro_parser.rs
@@ -70,12 +70,12 @@
 //! eof: [a $( a )* a b ·]
 //! ```
 
-pub use NamedMatch::*;
-pub use ParseResult::*;
+crate use NamedMatch::*;
+crate use ParseResult::*;
 use TokenTreeOrTokenTreeSlice::*;
 
 use crate::ast::{Ident, Name};
-use crate::ext::tt::quoted::{self, TokenTree};
+use crate::ext::mbe::{self, TokenTree};
 use crate::parse::{Directory, ParseSess};
 use crate::parse::parser::{Parser, PathStyle};
 use crate::parse::token::{self, DocComment, Nonterminal, Token};
@@ -195,7 +195,7 @@ struct MatcherPos<'root, 'tt> {
     // `None`.
 
     /// The KleeneOp of this sequence if we are in a repetition.
-    seq_op: Option<quoted::KleeneOp>,
+    seq_op: Option<mbe::KleeneOp>,
 
     /// The separator if we are in a repetition.
     sep: Option<Token>,
@@ -267,7 +267,7 @@ impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> {
 }
 
 /// Represents the possible results of an attempted parse.
-pub enum ParseResult<T> {
+crate enum ParseResult<T> {
     /// Parsed successfully.
     Success(T),
     /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
@@ -279,10 +279,10 @@ pub enum ParseResult<T> {
 
 /// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es.
 /// This represents the mapping of metavars to the token trees they bind to.
-pub type NamedParseResult = ParseResult<FxHashMap<Ident, NamedMatch>>;
+crate type NamedParseResult = ParseResult<FxHashMap<Ident, NamedMatch>>;
 
 /// Count how many metavars are named in the given matcher `ms`.
-pub fn count_names(ms: &[TokenTree]) -> usize {
+pub(super) fn count_names(ms: &[TokenTree]) -> usize {
     ms.iter().fold(0, |count, elt| {
         count + match *elt {
             TokenTree::Sequence(_, ref seq) => seq.num_captures,
@@ -352,7 +352,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
 /// only on the nesting depth of `ast::TTSeq`s in the originating
 /// token tree it was derived from.
 #[derive(Debug, Clone)]
-pub enum NamedMatch {
+crate enum NamedMatch {
     MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
     MatchedNonterminal(Lrc<Nonterminal>),
 }
@@ -415,7 +415,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
 
 /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
 /// other tokens, this is "unexpected token...".
-pub fn parse_failure_msg(tok: &Token) -> String {
+crate fn parse_failure_msg(tok: &Token) -> String {
     match tok.kind {
         token::Eof => "unexpected end of macro invocation".to_string(),
         _ => format!(
@@ -532,7 +532,7 @@ fn inner_parse_loop<'root, 'tt>(
                 }
                 // We don't need a separator. Move the "dot" back to the beginning of the matcher
                 // and try to match again UNLESS we are only allowed to have _one_ repetition.
-                else if item.seq_op != Some(quoted::KleeneOp::ZeroOrOne) {
+                else if item.seq_op != Some(mbe::KleeneOp::ZeroOrOne) {
                     item.match_cur = item.match_lo;
                     item.idx = 0;
                     cur_items.push(item);
@@ -555,8 +555,8 @@ fn inner_parse_loop<'root, 'tt>(
                     // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will
                     // result in a "no rules expected token" error by virtue of this matcher not
                     // working.
-                    if seq.kleene.op == quoted::KleeneOp::ZeroOrMore
-                        || seq.kleene.op == quoted::KleeneOp::ZeroOrOne
+                    if seq.kleene.op == mbe::KleeneOp::ZeroOrMore
+                        || seq.kleene.op == mbe::KleeneOp::ZeroOrOne
                     {
                         let mut new_item = item.clone();
                         new_item.match_cur += seq.num_captures;
@@ -648,7 +648,7 @@ fn inner_parse_loop<'root, 'tt>(
 /// - `directory`: Information about the file locations (needed for the black-box parser)
 /// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box
 ///   parser)
-pub fn parse(
+pub(super) fn parse(
     sess: &ParseSess,
     tts: TokenStream,
     ms: &[TokenTree],
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs
index b27e9c54337..816baadb12f 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/mbe/macro_rules.rs
@@ -4,12 +4,12 @@ use crate::edition::Edition;
 use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
 use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
 use crate::ext::expand::{AstFragment, AstFragmentKind};
-use crate::ext::tt::macro_check;
-use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
-use crate::ext::tt::macro_parser::{Error, Failure, Success};
-use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq};
-use crate::ext::tt::quoted;
-use crate::ext::tt::transcribe::transcribe;
+use crate::ext::mbe;
+use crate::ext::mbe::macro_check;
+use crate::ext::mbe::macro_parser::{parse, parse_failure_msg};
+use crate::ext::mbe::macro_parser::{Error, Failure, Success};
+use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
+use crate::ext::mbe::transcribe::transcribe;
 use crate::feature_gate::Features;
 use crate::parse::parser::Parser;
 use crate::parse::token::TokenKind::*;
@@ -35,7 +35,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
                                         `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
                                         `literal`, `path`, `meta`, `tt`, `item` and `vis`";
 
-pub struct ParserAnyMacro<'a> {
+crate struct ParserAnyMacro<'a> {
     parser: Parser<'a>,
 
     /// Span of the expansion site of the macro this parser is for
@@ -45,7 +45,11 @@ pub struct ParserAnyMacro<'a> {
     arm_span: Span,
 }
 
-pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragmentKind, span: Span) {
+crate fn annotate_err_with_kind(
+    err: &mut DiagnosticBuilder<'_>,
+    kind: AstFragmentKind,
+    span: Span,
+) {
     match kind {
         AstFragmentKind::Ty => {
             err.span_label(span, "this macro call doesn't expand to a type");
@@ -58,7 +62,7 @@ pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragment
 }
 
 impl<'a> ParserAnyMacro<'a> {
-    pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
+    crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
         let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
         let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
             if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
@@ -131,8 +135,8 @@ struct MacroRulesMacroExpander {
     name: ast::Ident,
     span: Span,
     transparency: Transparency,
-    lhses: Vec<quoted::TokenTree>,
-    rhses: Vec<quoted::TokenTree>,
+    lhses: Vec<mbe::TokenTree>,
+    rhses: Vec<mbe::TokenTree>,
     valid: bool,
 }
 
@@ -165,8 +169,8 @@ fn generic_extension<'cx>(
     name: ast::Ident,
     transparency: Transparency,
     arg: TokenStream,
-    lhses: &[quoted::TokenTree],
-    rhses: &[quoted::TokenTree],
+    lhses: &[mbe::TokenTree],
+    rhses: &[mbe::TokenTree],
 ) -> Box<dyn MacResult + 'cx> {
     if cx.trace_macros() {
         trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg));
@@ -178,7 +182,7 @@ fn generic_extension<'cx>(
     for (i, lhs) in lhses.iter().enumerate() {
         // try each arm's matchers
         let lhs_tt = match *lhs {
-            quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+            mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
             _ => cx.span_bug(sp, "malformed macro lhs"),
         };
 
@@ -186,7 +190,7 @@ fn generic_extension<'cx>(
             Success(named_matches) => {
                 let rhs = match rhses[i] {
                     // ignore delimiters
-                    quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
+                    mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
                 let arm_span = rhses[i].span();
@@ -254,7 +258,7 @@ fn generic_extension<'cx>(
         for lhs in lhses {
             // try each arm's matchers
             let lhs_tt = match *lhs {
-                quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+                mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
                 _ => continue,
             };
             match TokenTree::parse(cx, lhs_tt, arg.clone()) {
@@ -284,8 +288,8 @@ fn generic_extension<'cx>(
 //
 // Holy self-referential!
 
-/// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile(
+/// Converts a macro item into a syntax extension.
+pub fn compile_declarative_macro(
     sess: &ParseSess,
     features: &Features,
     def: &ast::Item,
@@ -308,32 +312,32 @@ pub fn compile(
     // ...quasiquoting this would be nice.
     // These spans won't matter, anyways
     let argument_gram = vec![
-        quoted::TokenTree::Sequence(
+        mbe::TokenTree::Sequence(
             DelimSpan::dummy(),
-            Lrc::new(quoted::SequenceRepetition {
+            Lrc::new(mbe::SequenceRepetition {
                 tts: vec![
-                    quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
-                    quoted::TokenTree::token(token::FatArrow, def.span),
-                    quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
+                    mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
+                    mbe::TokenTree::token(token::FatArrow, def.span),
+                    mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
                 ],
                 separator: Some(Token::new(
                     if body.legacy { token::Semi } else { token::Comma },
                     def.span,
                 )),
-                kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
+                kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
                 num_captures: 2,
             }),
         ),
         // to phase into semicolon-termination instead of semicolon-separation
-        quoted::TokenTree::Sequence(
+        mbe::TokenTree::Sequence(
             DelimSpan::dummy(),
-            Lrc::new(quoted::SequenceRepetition {
-                tts: vec![quoted::TokenTree::token(
+            Lrc::new(mbe::SequenceRepetition {
+                tts: vec![mbe::TokenTree::token(
                     if body.legacy { token::Semi } else { token::Comma },
                     def.span,
                 )],
                 separator: None,
-                kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
+                kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span),
                 num_captures: 0,
             }),
         ),
@@ -363,7 +367,7 @@ pub fn compile(
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
                     if let NtTT(ref tt) = **nt {
-                        let tt = quoted::parse(
+                        let tt = mbe::quoted::parse(
                             tt.clone().into(),
                             true,
                             sess,
@@ -380,7 +384,7 @@ pub fn compile(
                 }
                 sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
             })
-            .collect::<Vec<quoted::TokenTree>>(),
+            .collect::<Vec<mbe::TokenTree>>(),
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
     };
 
@@ -390,7 +394,7 @@ pub fn compile(
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
                     if let NtTT(ref tt) = **nt {
-                        return quoted::parse(
+                        return mbe::quoted::parse(
                             tt.clone().into(),
                             false,
                             sess,
@@ -405,7 +409,7 @@ pub fn compile(
                 }
                 sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
             })
-            .collect::<Vec<quoted::TokenTree>>(),
+            .collect::<Vec<mbe::TokenTree>>(),
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
     };
 
@@ -450,11 +454,11 @@ fn check_lhs_nt_follows(
     sess: &ParseSess,
     features: &Features,
     attrs: &[ast::Attribute],
-    lhs: &quoted::TokenTree,
+    lhs: &mbe::TokenTree,
 ) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
-    if let quoted::TokenTree::Delimited(_, ref tts) = *lhs {
+    if let mbe::TokenTree::Delimited(_, ref tts) = *lhs {
         check_matcher(sess, features, attrs, &tts.tts)
     } else {
         let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
@@ -467,8 +471,8 @@ fn check_lhs_nt_follows(
 
 /// Checks that the lhs contains no repetition which could match an empty token
 /// tree, because then the matcher would hang indefinitely.
-fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
-    use quoted::TokenTree;
+fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
+    use mbe::TokenTree;
     for tt in tts {
         match *tt {
             TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
@@ -482,8 +486,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
                     && seq.tts.iter().all(|seq_tt| match *seq_tt {
                         TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
                         TokenTree::Sequence(_, ref sub_seq) => {
-                            sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
-                                || sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
+                            sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
+                                || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
                         }
                         _ => false,
                     })
@@ -502,9 +506,9 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
     true
 }
 
-fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
+fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
     match *rhs {
-        quoted::TokenTree::Delimited(..) => return true,
+        mbe::TokenTree::Delimited(..) => return true,
         _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"),
     }
     false
@@ -514,7 +518,7 @@ fn check_matcher(
     sess: &ParseSess,
     features: &Features,
     attrs: &[ast::Attribute],
-    matcher: &[quoted::TokenTree],
+    matcher: &[mbe::TokenTree],
 ) -> bool {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
@@ -546,8 +550,8 @@ struct FirstSets {
 }
 
 impl FirstSets {
-    fn new(tts: &[quoted::TokenTree]) -> FirstSets {
-        use quoted::TokenTree;
+    fn new(tts: &[mbe::TokenTree]) -> FirstSets {
+        use mbe::TokenTree;
 
         let mut sets = FirstSets { first: FxHashMap::default() };
         build_recur(&mut sets, tts);
@@ -594,8 +598,8 @@ impl FirstSets {
 
                         // Reverse scan: Sequence comes before `first`.
                         if subfirst.maybe_empty
-                            || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
-                            || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
+                            || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore
+                            || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne
                         {
                             // If sequence is potentially empty, then
                             // union them (preserving first emptiness).
@@ -615,8 +619,8 @@ impl FirstSets {
 
     // walks forward over `tts` until all potential FIRST tokens are
     // identified.
-    fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet {
-        use quoted::TokenTree;
+    fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet {
+        use mbe::TokenTree;
 
         let mut first = TokenSet::empty();
         for tt in tts.iter() {
@@ -652,8 +656,8 @@ impl FirstSets {
                     assert!(first.maybe_empty);
                     first.add_all(subfirst);
                     if subfirst.maybe_empty
-                        || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
-                        || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
+                        || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore
+                        || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne
                     {
                         // Continue scanning for more first
                         // tokens, but also make sure we
@@ -674,7 +678,7 @@ impl FirstSets {
     }
 }
 
-// A set of `quoted::TokenTree`s, which may include `TokenTree::Match`s
+// A set of `mbe::TokenTree`s, which may include `TokenTree::Match`s
 // (for macro-by-example syntactic variables). It also carries the
 // `maybe_empty` flag; that is true if and only if the matcher can
 // match an empty token sequence.
@@ -686,7 +690,7 @@ impl FirstSets {
 // (Notably, we must allow for *-op to occur zero times.)
 #[derive(Clone, Debug)]
 struct TokenSet {
-    tokens: Vec<quoted::TokenTree>,
+    tokens: Vec<mbe::TokenTree>,
     maybe_empty: bool,
 }
 
@@ -698,13 +702,13 @@ impl TokenSet {
 
     // Returns the set `{ tok }` for the single-token (and thus
     // non-empty) sequence [tok].
-    fn singleton(tok: quoted::TokenTree) -> Self {
+    fn singleton(tok: mbe::TokenTree) -> Self {
         TokenSet { tokens: vec![tok], maybe_empty: false }
     }
 
     // Changes self to be the set `{ tok }`.
     // Since `tok` is always present, marks self as non-empty.
-    fn replace_with(&mut self, tok: quoted::TokenTree) {
+    fn replace_with(&mut self, tok: mbe::TokenTree) {
         self.tokens.clear();
         self.tokens.push(tok);
         self.maybe_empty = false;
@@ -719,7 +723,7 @@ impl TokenSet {
     }
 
     // Adds `tok` to the set for `self`, marking sequence as non-empy.
-    fn add_one(&mut self, tok: quoted::TokenTree) {
+    fn add_one(&mut self, tok: mbe::TokenTree) {
         if !self.tokens.contains(&tok) {
             self.tokens.push(tok);
         }
@@ -727,7 +731,7 @@ impl TokenSet {
     }
 
     // Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.)
-    fn add_one_maybe(&mut self, tok: quoted::TokenTree) {
+    fn add_one_maybe(&mut self, tok: mbe::TokenTree) {
         if !self.tokens.contains(&tok) {
             self.tokens.push(tok);
         }
@@ -768,10 +772,10 @@ fn check_matcher_core(
     features: &Features,
     attrs: &[ast::Attribute],
     first_sets: &FirstSets,
-    matcher: &[quoted::TokenTree],
+    matcher: &[mbe::TokenTree],
     follow: &TokenSet,
 ) -> TokenSet {
-    use quoted::TokenTree;
+    use mbe::TokenTree;
 
     let mut last = TokenSet::empty();
 
@@ -946,8 +950,8 @@ fn check_matcher_core(
     last
 }
 
-fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
-    if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
+fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
+    if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
         frag_can_be_followed_by_any(frag_spec.name)
     } else {
         // (Non NT's can always be followed by anthing in matchers.)
@@ -993,8 +997,8 @@ enum IsInFollow {
 /// break macros that were relying on that binary operator as a
 /// separator.
 // when changing this do not forget to update doc/book/macros.md!
-fn is_in_follow(tok: &quoted::TokenTree, frag: Symbol) -> IsInFollow {
-    use quoted::TokenTree;
+fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
+    use mbe::TokenTree;
 
     if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
         // closing a token tree can never be matched by any fragment;
@@ -1112,10 +1116,10 @@ fn has_legal_fragment_specifier(
     sess: &ParseSess,
     features: &Features,
     attrs: &[ast::Attribute],
-    tok: &quoted::TokenTree,
+    tok: &mbe::TokenTree,
 ) -> Result<(), String> {
     debug!("has_legal_fragment_specifier({:?})", tok);
-    if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
+    if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
         let frag_span = tok.span();
         if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) {
             return Err(frag_spec.to_string());
@@ -1156,14 +1160,27 @@ fn is_legal_fragment_specifier(
     }
 }
 
-fn quoted_tt_to_string(tt: &quoted::TokenTree) -> String {
+fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     match *tt {
-        quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
-        quoted::TokenTree::MetaVar(_, name) => format!("${}", name),
-        quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
+        mbe::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
+        mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
+        mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
         _ => panic!(
-            "unexpected quoted::TokenTree::{{Sequence or Delimited}} \
+            "unexpected mbe::TokenTree::{{Sequence or Delimited}} \
              in follow set checker"
         ),
     }
 }
+
+impl TokenTree {
+    /// Use this token tree as a matcher to parse given tts.
+    fn parse(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream)
+             -> NamedParseResult {
+        // `None` is because we're not interpolating
+        let directory = Directory {
+            path: Cow::from(cx.current_expansion.module.directory.as_path()),
+            ownership: cx.current_expansion.directory_ownership,
+        };
+        parse(cx.parse_sess(), tts, mtch, Some(directory), true)
+    }
+}
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs
index cad94a0e4c1..3952e29a5f0 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/mbe/quoted.rs
@@ -1,179 +1,19 @@
 use crate::ast;
 use crate::ast::NodeId;
-use crate::ext::tt::macro_parser;
+use crate::ext::mbe::macro_parser;
+use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited};
 use crate::feature_gate::Features;
-use crate::parse::token::{self, Token, TokenKind};
+use crate::parse::token::{self, Token};
 use crate::parse::ParseSess;
 use crate::print::pprust;
 use crate::symbol::kw;
-use crate::tokenstream::{self, DelimSpan};
+use crate::tokenstream;
 
-use syntax_pos::{edition::Edition, BytePos, Span};
+use syntax_pos::{edition::Edition, Span};
 
 use rustc_data_structures::sync::Lrc;
 use std::iter::Peekable;
 
-/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
-/// that the delimiter itself might be `NoDelim`.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
-pub struct Delimited {
-    pub delim: token::DelimToken,
-    pub tts: Vec<TokenTree>,
-}
-
-impl Delimited {
-    /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
-    pub fn open_tt(&self, span: Span) -> TokenTree {
-        let open_span = if span.is_dummy() {
-            span
-        } else {
-            span.with_hi(span.lo() + BytePos(self.delim.len() as u32))
-        };
-        TokenTree::token(token::OpenDelim(self.delim), open_span)
-    }
-
-    /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
-    pub fn close_tt(&self, span: Span) -> TokenTree {
-        let close_span = if span.is_dummy() {
-            span
-        } else {
-            span.with_lo(span.hi() - BytePos(self.delim.len() as u32))
-        };
-        TokenTree::token(token::CloseDelim(self.delim), close_span)
-    }
-}
-
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
-pub struct SequenceRepetition {
-    /// The sequence of token trees
-    pub tts: Vec<TokenTree>,
-    /// The optional separator
-    pub separator: Option<Token>,
-    /// Whether the sequence can be repeated zero (*), or one or more times (+)
-    pub kleene: KleeneToken,
-    /// The number of `Match`s that appear in the sequence (and subsequences)
-    pub num_captures: usize,
-}
-
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
-pub struct KleeneToken {
-    pub span: Span,
-    pub op: KleeneOp,
-}
-
-impl KleeneToken {
-    pub fn new(op: KleeneOp, span: Span) -> KleeneToken {
-        KleeneToken { span, op }
-    }
-}
-
-/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
-/// for token sequences.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum KleeneOp {
-    /// Kleene star (`*`) for zero or more repetitions
-    ZeroOrMore,
-    /// Kleene plus (`+`) for one or more repetitions
-    OneOrMore,
-    /// Kleene optional (`?`) for zero or one reptitions
-    ZeroOrOne,
-}
-
-/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
-/// are "first-class" token trees. Useful for parsing macros.
-#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
-pub enum TokenTree {
-    Token(Token),
-    Delimited(DelimSpan, Lrc<Delimited>),
-    /// A kleene-style repetition sequence
-    Sequence(DelimSpan, Lrc<SequenceRepetition>),
-    /// e.g., `$var`
-    MetaVar(Span, ast::Ident),
-    /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
-    MetaVarDecl(
-        Span,
-        ast::Ident, /* name to bind */
-        ast::Ident, /* kind of nonterminal */
-    ),
-}
-
-impl TokenTree {
-    /// Return the number of tokens in the tree.
-    pub fn len(&self) -> usize {
-        match *self {
-            TokenTree::Delimited(_, ref delimed) => match delimed.delim {
-                token::NoDelim => delimed.tts.len(),
-                _ => delimed.tts.len() + 2,
-            },
-            TokenTree::Sequence(_, ref seq) => seq.tts.len(),
-            _ => 0,
-        }
-    }
-
-    /// Returns `true` if the given token tree contains no other tokens. This is vacuously true for
-    /// single tokens or metavar/decls, but may be false for delimited trees or sequences.
-    pub fn is_empty(&self) -> bool {
-        match *self {
-            TokenTree::Delimited(_, ref delimed) => match delimed.delim {
-                token::NoDelim => delimed.tts.is_empty(),
-                _ => false,
-            },
-            TokenTree::Sequence(_, ref seq) => seq.tts.is_empty(),
-            _ => true,
-        }
-    }
-
-    /// Returns `true` if the given token tree is delimited.
-    pub fn is_delimited(&self) -> bool {
-        match *self {
-            TokenTree::Delimited(..) => true,
-            _ => false,
-        }
-    }
-
-    /// Returns `true` if the given token tree is a token of the given kind.
-    pub fn is_token(&self, expected_kind: &TokenKind) -> bool {
-        match self {
-            TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind,
-            _ => false,
-        }
-    }
-
-    /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences.
-    pub fn get_tt(&self, index: usize) -> TokenTree {
-        match (self, index) {
-            (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
-                delimed.tts[index].clone()
-            }
-            (&TokenTree::Delimited(span, ref delimed), _) => {
-                if index == 0 {
-                    return delimed.open_tt(span.open);
-                }
-                if index == delimed.tts.len() + 1 {
-                    return delimed.close_tt(span.close);
-                }
-                delimed.tts[index - 1].clone()
-            }
-            (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
-            _ => panic!("Cannot expand a token tree"),
-        }
-    }
-
-    /// Retrieves the `TokenTree`'s span.
-    pub fn span(&self) -> Span {
-        match *self {
-            TokenTree::Token(Token { span, .. })
-            | TokenTree::MetaVar(span, _)
-            | TokenTree::MetaVarDecl(span, _, _) => span,
-            TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
-        }
-    }
-
-    crate fn token(kind: TokenKind, span: Span) -> TokenTree {
-        TokenTree::Token(Token::new(kind, span))
-    }
-}
-
 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
 /// collection of `TokenTree` for use in parsing a macro.
@@ -195,7 +35,7 @@ impl TokenTree {
 /// # Returns
 ///
 /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
-pub fn parse(
+pub(super) fn parse(
     input: tokenstream::TokenStream,
     expect_matchers: bool,
     sess: &ParseSess,
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs
index f9c07e3a2e4..ba818ebd35c 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/mbe/transcribe.rs
@@ -1,7 +1,7 @@
 use crate::ast::{Ident, Mac};
 use crate::ext::base::ExtCtxt;
-use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
-use crate::ext::tt::quoted;
+use crate::ext::mbe;
+use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
 use crate::mut_visit::{self, MutVisitor};
 use crate::parse::token::{self, NtTT, Token};
 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
@@ -38,22 +38,22 @@ impl Marker {
 
 /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
 enum Frame {
-    Delimited { forest: Lrc<quoted::Delimited>, idx: usize, span: DelimSpan },
-    Sequence { forest: Lrc<quoted::SequenceRepetition>, idx: usize, sep: Option<Token> },
+    Delimited { forest: Lrc<mbe::Delimited>, idx: usize, span: DelimSpan },
+    Sequence { forest: Lrc<mbe::SequenceRepetition>, idx: usize, sep: Option<Token> },
 }
 
 impl Frame {
     /// Construct a new frame around the delimited set of tokens.
-    fn new(tts: Vec<quoted::TokenTree>) -> Frame {
-        let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts });
+    fn new(tts: Vec<mbe::TokenTree>) -> Frame {
+        let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, tts });
         Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() }
     }
 }
 
 impl Iterator for Frame {
-    type Item = quoted::TokenTree;
+    type Item = mbe::TokenTree;
 
-    fn next(&mut self) -> Option<quoted::TokenTree> {
+    fn next(&mut self) -> Option<mbe::TokenTree> {
         match *self {
             Frame::Delimited { ref forest, ref mut idx, .. } => {
                 *idx += 1;
@@ -90,7 +90,7 @@ impl Iterator for Frame {
 pub(super) fn transcribe(
     cx: &ExtCtxt<'_>,
     interp: &FxHashMap<Ident, NamedMatch>,
-    src: Vec<quoted::TokenTree>,
+    src: Vec<mbe::TokenTree>,
     transparency: Transparency,
 ) -> TokenStream {
     // Nothing for us to transcribe...
@@ -178,7 +178,7 @@ pub(super) fn transcribe(
             // We are descending into a sequence. We first make sure that the matchers in the RHS
             // and the matches in `interp` have the same shape. Otherwise, either the caller or the
             // macro writer has made a mistake.
-            seq @ quoted::TokenTree::Sequence(..) => {
+            seq @ mbe::TokenTree::Sequence(..) => {
                 match lockstep_iter_size(&seq, interp, &repeats) {
                     LockstepIterSize::Unconstrained => {
                         cx.span_fatal(
@@ -199,7 +199,7 @@ pub(super) fn transcribe(
                     LockstepIterSize::Constraint(len, _) => {
                         // We do this to avoid an extra clone above. We know that this is a
                         // sequence already.
-                        let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq {
+                        let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq {
                             (sp, seq)
                         } else {
                             unreachable!()
@@ -207,7 +207,7 @@ pub(super) fn transcribe(
 
                         // Is the repetition empty?
                         if len == 0 {
-                            if seq.kleene.op == quoted::KleeneOp::OneOrMore {
+                            if seq.kleene.op == mbe::KleeneOp::OneOrMore {
                                 // FIXME: this really ought to be caught at macro definition
                                 // time... It happens when the Kleene operator in the matcher and
                                 // the body for the same meta-variable do not match.
@@ -232,7 +232,7 @@ pub(super) fn transcribe(
             }
 
             // Replace the meta-var with the matched token tree from the invocation.
-            quoted::TokenTree::MetaVar(mut sp, mut ident) => {
+            mbe::TokenTree::MetaVar(mut sp, mut ident) => {
                 // Find the matched nonterminal from the macro invocation, and use it to replace
                 // the meta-var.
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
@@ -269,7 +269,7 @@ pub(super) fn transcribe(
             // We will produce all of the results of the inside of the `Delimited` and then we will
             // jump back out of the Delimited, pop the result_stack and add the new results back to
             // the previous results (from outside the Delimited).
-            quoted::TokenTree::Delimited(mut span, delimited) => {
+            mbe::TokenTree::Delimited(mut span, delimited) => {
                 marker.visit_delim_span(&mut span);
                 stack.push(Frame::Delimited { forest: delimited, idx: 0, span });
                 result_stack.push(mem::take(&mut result));
@@ -277,14 +277,14 @@ pub(super) fn transcribe(
 
             // Nothing much to do here. Just push the token to the result, being careful to
             // preserve syntax context.
-            quoted::TokenTree::Token(token) => {
+            mbe::TokenTree::Token(token) => {
                 let mut tt = TokenTree::Token(token);
                 marker.visit_tt(&mut tt);
                 result.push(tt.into());
             }
 
             // There should be no meta-var declarations in the invocation of a macro.
-            quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
+            mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
         }
     }
 }
@@ -368,11 +368,11 @@ impl LockstepIterSize {
 /// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of
 /// multiple nested matcher sequences.
 fn lockstep_iter_size(
-    tree: &quoted::TokenTree,
+    tree: &mbe::TokenTree,
     interpolations: &FxHashMap<Ident, NamedMatch>,
     repeats: &[(usize, usize)],
 ) -> LockstepIterSize {
-    use quoted::TokenTree;
+    use mbe::TokenTree;
     match *tree {
         TokenTree::Delimited(_, ref delimed) => {
             delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index b4ae1e87bca..b0833010fe0 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -162,19 +162,14 @@ pub mod ext {
     mod proc_macro_server;
 
     pub use syntax_pos::hygiene;
+    pub use mbe::macro_rules::compile_declarative_macro;
     pub mod allocator;
     pub mod base;
     pub mod build;
     pub mod expand;
     pub mod proc_macro;
 
-    pub mod tt {
-        pub mod transcribe;
-        pub mod macro_check;
-        pub mod macro_parser;
-        pub mod macro_rules;
-        pub mod quoted;
-    }
+    crate mod mbe;
 }
 
 pub mod early_buffered_lints;
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index cf196645e4f..0d073f0cc97 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -24,7 +24,7 @@ use crate::symbol::{kw, sym};
 use std::mem;
 use log::debug;
 use rustc_target::spec::abi::Abi;
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
 
 /// Whether the type alias or associated type is a concrete type or an opaque type.
 #[derive(Debug)]
@@ -1477,10 +1477,23 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with
+    /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
+    ///
+    /// When `m` is `"const"`, `$ident` may also be `"_"`.
     fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
         let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
+
+        // Parse the type of a `const` or `static mut?` item.
+        // That is, the `":" $ty` fragment.
+        let ty = if self.token == token::Eq {
+            self.recover_missing_const_type(id, m)
+        } else {
+            // Not `=` so expect `":"" $ty` as usual.
+            self.expect(&token::Colon)?;
+            self.parse_ty()?
+        };
+
         self.expect(&token::Eq)?;
         let e = self.parse_expr()?;
         self.expect(&token::Semi)?;
@@ -1491,6 +1504,34 @@ impl<'a> Parser<'a> {
         Ok((id, item, None))
     }
 
+    /// We were supposed to parse `:` but instead, we're already at `=`.
+    /// This means that the type is missing.
+    fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
+        // Construct the error and stash it away with the hope
+        // that typeck will later enrich the error with a type.
+        let kind = match m {
+            Some(Mutability::Mutable) => "static mut",
+            Some(Mutability::Immutable) => "static",
+            None => "const",
+        };
+        let mut err = self.struct_span_err(id.span, &format!("missing type for `{}` item", kind));
+        err.span_suggestion(
+            id.span,
+            "provide a type for the item",
+            format!("{}: <type>", id),
+            Applicability::HasPlaceholders,
+        );
+        err.stash(id.span, StashKey::ItemNoType);
+
+        // The user intended that the type be inferred,
+        // so treat this as if the user wrote e.g. `const A: _ = expr;`.
+        P(Ty {
+            node: TyKind::Infer,
+            span: id.span,
+            id: ast::DUMMY_NODE_ID,
+        })
+    }
+
     /// Parses `type Foo = Bar;` or returns `None`
     /// without modifying the parser state.
     fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, Generics)>> {
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index d702038f54e..26cae2a8e7c 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -13,9 +13,6 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::ext::base;
-use crate::ext::tt::{macro_parser, quoted};
-use crate::parse::Directory;
 use crate::parse::token::{self, DelimToken, Token, TokenKind};
 use crate::print::pprust;
 
@@ -26,7 +23,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use smallvec::{SmallVec, smallvec};
 
-use std::borrow::Cow;
 use std::{fmt, iter, mem};
 
 #[cfg(test)]
@@ -63,17 +59,6 @@ where
 {}
 
 impl TokenTree {
-    /// Use this token tree as a matcher to parse given tts.
-    pub fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream)
-                 -> macro_parser::NamedParseResult {
-        // `None` is because we're not interpolating
-        let directory = Directory {
-            path: Cow::from(cx.current_expansion.module.directory.as_path()),
-            ownership: cx.current_expansion.directory_ownership,
-        };
-        macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true)
-    }
-
     /// Checks if this TokenTree is equal to the other, regardless of span information.
     pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
         match (self, other) {
diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml
index 791ee94b4fa..73310df305b 100644
--- a/src/libsyntax_ext/Cargo.toml
+++ b/src/libsyntax_ext/Cargo.toml
@@ -18,4 +18,3 @@ rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-rustc_lexer = { path = "../librustc_lexer" }
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 26455df17b8..2765346b333 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -295,7 +295,7 @@ impl<'a, 'b> Context<'a, 'b> {
             .filter(|fmt| fmt.precision_span.is_some())
             .count();
         if self.names.is_empty() && !numbered_position_args && count != self.args.len() {
-            e = self.ecx.mut_span_err(
+            e = self.ecx.struct_span_err(
                 sp,
                 &format!(
                     "{} positional argument{} in format string, but {}",
@@ -336,7 +336,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 sp = MultiSpan::from_span(self.fmtsp);
             }
 
-            e = self.ecx.mut_span_err(sp,
+            e = self.ecx.struct_span_err(sp,
                 &format!("invalid reference to positional {} ({})",
                          arg_list,
                          self.describe_num_args()));
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index afc92638fda..e290f7fa6b1 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
     };
 
     interface::run_compiler(config, |compiler| {
-        compiler.compile().ok();
+        // This runs all the passes prior to linking, too.
+        compiler.link().ok();
     });
 }
diff --git a/src/test/ui/error-codes/E0023.rs b/src/test/ui/error-codes/E0023.rs
index dc421e060e8..7ac22bb7109 100644
--- a/src/test/ui/error-codes/E0023.rs
+++ b/src/test/ui/error-codes/E0023.rs
@@ -2,9 +2,9 @@ enum Fruit {
     Apple(String, String),
     Pear(u32),
     Orange((String, String)),
+    Banana(()),
 }
 
-
 fn main() {
     let x = Fruit::Apple(String::new(), String::new());
     match x {
@@ -12,5 +12,6 @@ fn main() {
         Fruit::Apple(a, b, c) => {}, //~ ERROR E0023
         Fruit::Pear(1, 2) => {}, //~ ERROR E0023
         Fruit::Orange(a, b) => {}, //~ ERROR E0023
+        Fruit::Banana() => {}, //~ ERROR E0023
     }
 }
diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr
index 8ae7d01ed5f..dbce6003a2b 100644
--- a/src/test/ui/error-codes/E0023.stderr
+++ b/src/test/ui/error-codes/E0023.stderr
@@ -38,6 +38,19 @@ help: missing parenthesis
 LL |         Fruit::Orange((a, b)) => {},
    |                       ^    ^
 
-error: aborting due to 4 previous errors
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field
+  --> $DIR/E0023.rs:15:9
+   |
+LL |     Banana(()),
+   |     ---------- tuple variant defined here
+...
+LL |         Fruit::Banana() => {},
+   |         ^^^^^^^^^^^^^^^ expected 1 field, found 0
+help: missing parenthesis
+   |
+LL |         Fruit::Banana(()) => {},
+   |                      ^  ^
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0023`.
diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs
new file mode 100644
index 00000000000..c7675781208
--- /dev/null
+++ b/src/test/ui/impl-trait/auto-trait.rs
@@ -0,0 +1,23 @@
+// Tests that type alias impls traits do not leak auto-traits for
+// the purposes of coherence checking
+#![feature(type_alias_impl_trait)]
+
+trait OpaqueTrait { }
+impl<T> OpaqueTrait for T { }
+type OpaqueType = impl OpaqueTrait;
+fn mk_opaque() -> OpaqueType { () }
+
+#[derive(Debug)]
+struct D<T>(T);
+
+trait AnotherTrait { }
+impl<T: Send> AnotherTrait for T { }
+
+// This is in error, because we cannot assume that `OpaqueType: !Send`.
+// (We treat opaque types as "foreign types" that could grow more impls
+// in the future.)
+impl AnotherTrait for D<OpaqueType> {
+    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr
new file mode 100644
index 00000000000..5e72ca7a47b
--- /dev/null
+++ b/src/test/ui/impl-trait/auto-trait.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
+  --> $DIR/auto-trait.rs:19:1
+   |
+LL | impl<T: Send> AnotherTrait for T { }
+   | -------------------------------- first implementation here
+...
+LL | impl AnotherTrait for D<OpaqueType> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs
new file mode 100644
index 00000000000..4977f9bdbac
--- /dev/null
+++ b/src/test/ui/impl-trait/negative-reasoning.rs
@@ -0,0 +1,22 @@
+// Tests that we cannot assume that an opaque type does *not* implement some
+// other trait
+#![feature(type_alias_impl_trait)]
+
+trait OpaqueTrait { }
+impl<T> OpaqueTrait for T { }
+type OpaqueType = impl OpaqueTrait;
+fn mk_opaque() -> OpaqueType { () }
+
+#[derive(Debug)]
+struct D<T>(T);
+
+trait AnotherTrait { }
+impl<T: std::fmt::Debug> AnotherTrait for T { }
+
+
+// This is in error, because we cannot assume that `OpaqueType: !Debug`
+impl AnotherTrait for D<OpaqueType> {
+    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
new file mode 100644
index 00000000000..526a664726a
--- /dev/null
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
+  --> $DIR/negative-reasoning.rs:18:1
+   |
+LL | impl<T: std::fmt::Debug> AnotherTrait for T { }
+   | ------------------------------------------- first implementation here
+...
+LL | impl AnotherTrait for D<OpaqueType> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
+   |
+   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs
new file mode 100644
index 00000000000..99200a965dd
--- /dev/null
+++ b/src/test/ui/suggestions/const-no-type.rs
@@ -0,0 +1,46 @@
+// In the cases below, the type is missing from the `const` and `static` items.
+//
+// Here, we test that we:
+//
+// a) Perform parser recovery.
+//
+// b) Emit a diagnostic with the actual inferred type to RHS of `=` as the suggestion.
+
+fn main() {}
+
+// These will not reach typeck:
+
+#[cfg(FALSE)]
+const C2 = 42;
+//~^ ERROR missing type for `const` item
+//~| HELP provide a type for the item
+//~| SUGGESTION C2: <type>
+
+#[cfg(FALSE)]
+static S2 = "abc";
+//~^ ERROR missing type for `static` item
+//~| HELP provide a type for the item
+//~| SUGGESTION S2: <type>
+
+#[cfg(FALSE)]
+static mut SM2 = "abc";
+//~^ ERROR missing type for `static mut` item
+//~| HELP provide a type for the item
+//~| SUGGESTION SM2: <type>
+
+// These will, so the diagnostics should be stolen by typeck:
+
+const C = 42;
+//~^ ERROR missing type for `const` item
+//~| HELP provide a type for the item
+//~| SUGGESTION C: i32
+
+static S = Vec::<String>::new();
+//~^ ERROR missing type for `static` item
+//~| HELP provide a type for the item
+//~| SUGGESTION S: std::vec::Vec<std::string::String>
+
+static mut SM = "abc";
+//~^ ERROR missing type for `static mut` item
+//~| HELP provide a type for the item
+//~| SUGGESTION &'static str
diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr
new file mode 100644
index 00000000000..c4f17109dc5
--- /dev/null
+++ b/src/test/ui/suggestions/const-no-type.stderr
@@ -0,0 +1,38 @@
+error: missing type for `const` item
+  --> $DIR/const-no-type.rs:33:7
+   |
+LL | const C = 42;
+   |       ^ help: provide a type for the item: `C: i32`
+
+error: missing type for `static` item
+  --> $DIR/const-no-type.rs:38:8
+   |
+LL | static S = Vec::<String>::new();
+   |        ^ help: provide a type for the item: `S: std::vec::Vec<std::string::String>`
+
+error: missing type for `static mut` item
+  --> $DIR/const-no-type.rs:43:12
+   |
+LL | static mut SM = "abc";
+   |            ^^ help: provide a type for the item: `SM: &'static str`
+
+error: missing type for `const` item
+  --> $DIR/const-no-type.rs:14:7
+   |
+LL | const C2 = 42;
+   |       ^^ help: provide a type for the item: `C2: <type>`
+
+error: missing type for `static` item
+  --> $DIR/const-no-type.rs:20:8
+   |
+LL | static S2 = "abc";
+   |        ^^ help: provide a type for the item: `S2: <type>`
+
+error: missing type for `static mut` item
+  --> $DIR/const-no-type.rs:26:12
+   |
+LL | static mut SM2 = "abc";
+   |            ^^^ help: provide a type for the item: `SM2: <type>`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs
new file mode 100644
index 00000000000..52802dd8fbb
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs
@@ -0,0 +1,2 @@
+pub trait ForeignTrait {}
+pub struct ForeignType<T>(pub T);
diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs
new file mode 100644
index 00000000000..1c0f83d6c12
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/coherence.rs
@@ -0,0 +1,17 @@
+// aux-build:foreign-crate.rs
+#![feature(type_alias_impl_trait)]
+
+extern crate foreign_crate;
+
+trait LocalTrait {}
+impl<T> LocalTrait for foreign_crate::ForeignType<T> {}
+
+type AliasOfForeignType<T> = impl LocalTrait;
+fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
+    foreign_crate::ForeignType(val)
+}
+
+impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
+//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr
new file mode 100644
index 00000000000..6ede0fa14ba
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/coherence.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/coherence.rs:14:6
+   |
+LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
+   |      ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs
new file mode 100644
index 00000000000..28f4a85c9f2
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs
@@ -0,0 +1,21 @@
+// check-pass
+// Regression test for issue #63677 - ensure that
+// coherence checking can properly handle 'impl trait'
+// in type aliases
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {}
+pub struct S1<T>(T);
+pub struct S2<T>(T);
+
+pub type T1 = impl Trait;
+pub type T2 = S1<T1>;
+pub type T3 = S2<T2>;
+
+impl<T> Trait for S1<T> {}
+impl<T: Trait> S2<T> {}
+impl T3 {}
+
+pub fn use_t1() -> T1 { S1(()) }
+
+fn main() {}