diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 61e53f53e9797..2e9df48d00002 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1327,661 +1327,4 @@ impl<'a> Builder<'a> {
 }
 
 #[cfg(test)]
-mod __test {
-    use super::*;
-    use crate::config::Config;
-    use std::thread;
-
-    use pretty_assertions::assert_eq;
-
-    fn configure(host: &[&str], target: &[&str]) -> Config {
-        let mut config = Config::default_opts();
-        // don't save toolstates
-        config.save_toolstates = None;
-        config.skip_only_host_steps = false;
-        config.dry_run = true;
-        // try to avoid spurious failures in dist where we create/delete each others file
-        let dir = config.out.join("tmp-rustbuild-tests").join(
-            &thread::current()
-                .name()
-                .unwrap_or("unknown")
-                .replace(":", "-"),
-        );
-        t!(fs::create_dir_all(&dir));
-        config.out = dir;
-        config.build = INTERNER.intern_str("A");
-        config.hosts = vec![config.build]
-            .clone()
-            .into_iter()
-            .chain(host.iter().map(|s| INTERNER.intern_str(s)))
-            .collect::<Vec<_>>();
-        config.targets = config
-            .hosts
-            .clone()
-            .into_iter()
-            .chain(target.iter().map(|s| INTERNER.intern_str(s)))
-            .collect::<Vec<_>>();
-        config
-    }
-
-    fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
-        v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
-    }
-
-    #[test]
-    fn dist_baseline() {
-        let build = Build::new(configure(&[], &[]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[dist::Docs { host: a },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[dist::Mingw { host: a },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[dist::Rustc {
-                compiler: Compiler { host: a, stage: 2 }
-            },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[dist::Std {
-                compiler: Compiler { host: a, stage: 1 },
-                target: a,
-            },]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    }
-
-    #[test]
-    fn dist_with_targets() {
-        let build = Build::new(configure(&[], &["B"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[
-                dist::Docs { host: a },
-                dist::Docs { host: b },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[dist::Rustc {
-                compiler: Compiler { host: a, stage: 2 }
-            },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: b,
-                },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    }
-
-    #[test]
-    fn dist_with_hosts() {
-        let build = Build::new(configure(&["B"], &[]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[
-                dist::Docs { host: a },
-                dist::Docs { host: b },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[
-                dist::Rustc {
-                    compiler: Compiler { host: a, stage: 2 }
-                },
-                dist::Rustc {
-                    compiler: Compiler { host: b, stage: 2 }
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    }
-
-    #[test]
-    fn dist_only_cross_host() {
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-        let mut build = Build::new(configure(&["B"], &[]));
-        build.config.docs = false;
-        build.config.extended = true;
-        build.hosts = vec![b];
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[
-                dist::Rustc {
-                    compiler: Compiler { host: b, stage: 2 }
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-    }
-
-    #[test]
-    fn dist_with_targets_and_hosts() {
-        let build = Build::new(configure(&["B"], &["C"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-        let c = INTERNER.intern_str("C");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[
-                dist::Docs { host: a },
-                dist::Docs { host: b },
-                dist::Docs { host: c },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[
-                dist::Mingw { host: a },
-                dist::Mingw { host: b },
-                dist::Mingw { host: c },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[
-                dist::Rustc {
-                    compiler: Compiler { host: a, stage: 2 }
-                },
-                dist::Rustc {
-                    compiler: Compiler { host: b, stage: 2 }
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: c,
-                },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    }
-
-    #[test]
-    fn dist_with_target_flag() {
-        let mut config = configure(&["B"], &["C"]);
-        config.skip_only_host_steps = true; // as-if --target=C was passed
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-        let c = INTERNER.intern_str("C");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[
-                dist::Docs { host: a },
-                dist::Docs { host: b },
-                dist::Docs { host: c },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[
-                dist::Mingw { host: a },
-                dist::Mingw { host: b },
-                dist::Mingw { host: c },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: c,
-                },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
-    }
-
-    #[test]
-    fn dist_with_same_targets_and_hosts() {
-        let build = Build::new(configure(&["B"], &["B"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[
-                dist::Docs { host: a },
-                dist::Docs { host: b },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Rustc>()),
-            &[
-                dist::Rustc {
-                    compiler: Compiler { host: a, stage: 2 }
-                },
-                dist::Rustc {
-                    compiler: Compiler { host: b, stage: 2 }
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                dist::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-        assert_eq!(
-            first(builder.cache.all::<compile::Std>()),
-            &[
-                compile::Std {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Std {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: a,
-                },
-                compile::Std {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<compile::Test>()),
-            &[
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<compile::Assemble>()),
-            &[
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 0 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 1 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 2 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: b, stage: 2 },
-                },
-            ]
-        );
-    }
-
-    #[test]
-    fn build_default() {
-        let build = Build::new(configure(&["B"], &["C"]));
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-        let c = INTERNER.intern_str("C");
-
-        assert!(!builder.cache.all::<compile::Std>().is_empty());
-        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
-        assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: b,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: b,
-                },
-            ]
-        );
-
-        assert_eq!(
-            first(builder.cache.all::<compile::Test>()),
-            &[
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: c,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: c,
-                },
-            ]
-        );
-    }
-
-    #[test]
-    fn build_with_target_flag() {
-        let mut config = configure(&["B"], &["C"]);
-        config.skip_only_host_steps = true;
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
-
-        let a = INTERNER.intern_str("A");
-        let b = INTERNER.intern_str("B");
-        let c = INTERNER.intern_str("C");
-
-        assert!(!builder.cache.all::<compile::Std>().is_empty());
-        assert_eq!(
-            first(builder.cache.all::<compile::Assemble>()),
-            &[
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 0 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 1 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: a, stage: 2 },
-                },
-                compile::Assemble {
-                    target_compiler: Compiler { host: b, stage: 2 },
-                },
-            ]
-        );
-        assert_eq!(
-            first(builder.cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Rustc {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-            ]
-        );
-
-        assert_eq!(
-            first(builder.cache.all::<compile::Test>()),
-            &[
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 0 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: a,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 1 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: b,
-                },
-                compile::Test {
-                    compiler: Compiler { host: a, stage: 2 },
-                    target: c,
-                },
-                compile::Test {
-                    compiler: Compiler { host: b, stage: 2 },
-                    target: c,
-                },
-            ]
-        );
-    }
-
-    #[test]
-    fn test_with_no_doc_stage0() {
-        let mut config = configure(&[], &[]);
-        config.stage = Some(0);
-        config.cmd = Subcommand::Test {
-            paths: vec!["src/libstd".into()],
-            test_args: vec![],
-            rustc_args: vec![],
-            fail_fast: true,
-            doc_tests: DocTests::No,
-            bless: false,
-            compare_mode: None,
-            rustfix_coverage: false,
-        };
-
-        let build = Build::new(config);
-        let mut builder = Builder::new(&build);
-
-        let host = INTERNER.intern_str("A");
-
-        builder.run_step_descriptions(
-            &[StepDescription::from::<test::Crate>()],
-            &["src/libstd".into()],
-        );
-
-        // Ensure we don't build any compiler artifacts.
-        assert!(!builder.cache.contains::<compile::Rustc>());
-        assert_eq!(
-            first(builder.cache.all::<test::Crate>()),
-            &[test::Crate {
-                compiler: Compiler { host, stage: 0 },
-                target: host,
-                mode: Mode::Std,
-                test_kind: test::TestKind::Test,
-                krate: INTERNER.intern_str("std"),
-            },]
-        );
-    }
-
-    #[test]
-    fn test_exclude() {
-        let mut config = configure(&[], &[]);
-        config.exclude = vec![
-            "src/test/run-pass".into(),
-            "src/tools/tidy".into(),
-        ];
-        config.cmd = Subcommand::Test {
-            paths: Vec::new(),
-            test_args: Vec::new(),
-            rustc_args: Vec::new(),
-            fail_fast: true,
-            doc_tests: DocTests::No,
-            bless: false,
-            compare_mode: None,
-            rustfix_coverage: false,
-        };
-
-        let build = Build::new(config);
-        let builder = Builder::new(&build);
-        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-
-        // Ensure we have really excluded run-pass & tidy
-        assert!(!builder.cache.contains::<test::RunPass>());
-        assert!(!builder.cache.contains::<test::Tidy>());
-
-        // Ensure other tests are not affected.
-        assert!(builder.cache.contains::<test::RunPassFullDeps>());
-        assert!(builder.cache.contains::<test::RustdocUi>());
-    }
-}
+mod tests;
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
new file mode 100644
index 0000000000000..46c58d118f743
--- /dev/null
+++ b/src/bootstrap/builder/tests.rs
@@ -0,0 +1,656 @@
+use super::*;
+use crate::config::Config;
+use std::thread;
+
+use pretty_assertions::assert_eq;
+
+fn configure(host: &[&str], target: &[&str]) -> Config {
+    let mut config = Config::default_opts();
+    // don't save toolstates
+    config.save_toolstates = None;
+    config.skip_only_host_steps = false;
+    config.dry_run = true;
+    // try to avoid spurious failures in dist where we create/delete each others file
+    let dir = config.out.join("tmp-rustbuild-tests").join(
+        &thread::current()
+            .name()
+            .unwrap_or("unknown")
+            .replace(":", "-"),
+    );
+    t!(fs::create_dir_all(&dir));
+    config.out = dir;
+    config.build = INTERNER.intern_str("A");
+    config.hosts = vec![config.build]
+        .clone()
+        .into_iter()
+        .chain(host.iter().map(|s| INTERNER.intern_str(s)))
+        .collect::<Vec<_>>();
+    config.targets = config
+        .hosts
+        .clone()
+        .into_iter()
+        .chain(target.iter().map(|s| INTERNER.intern_str(s)))
+        .collect::<Vec<_>>();
+    config
+}
+
+fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
+    v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
+}
+
+#[test]
+fn dist_baseline() {
+    let build = Build::new(configure(&[], &[]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[dist::Docs { host: a },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[dist::Mingw { host: a },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[dist::Rustc {
+            compiler: Compiler { host: a, stage: 2 }
+        },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[dist::Std {
+            compiler: Compiler { host: a, stage: 1 },
+            target: a,
+        },]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+}
+
+#[test]
+fn dist_with_targets() {
+    let build = Build::new(configure(&[], &["B"]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[
+            dist::Docs { host: a },
+            dist::Docs { host: b },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[dist::Rustc {
+            compiler: Compiler { host: a, stage: 2 }
+        },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+}
+
+#[test]
+fn dist_with_hosts() {
+    let build = Build::new(configure(&["B"], &[]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[
+            dist::Docs { host: a },
+            dist::Docs { host: b },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[
+            dist::Rustc {
+                compiler: Compiler { host: a, stage: 2 }
+            },
+            dist::Rustc {
+                compiler: Compiler { host: b, stage: 2 }
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+}
+
+#[test]
+fn dist_only_cross_host() {
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+    let mut build = Build::new(configure(&["B"], &[]));
+    build.config.docs = false;
+    build.config.extended = true;
+    build.hosts = vec![b];
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[
+            dist::Rustc {
+                compiler: Compiler { host: b, stage: 2 }
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<compile::Rustc>()),
+        &[
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+}
+
+#[test]
+fn dist_with_targets_and_hosts() {
+    let build = Build::new(configure(&["B"], &["C"]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+    let c = INTERNER.intern_str("C");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[
+            dist::Docs { host: a },
+            dist::Docs { host: b },
+            dist::Docs { host: c },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[
+            dist::Mingw { host: a },
+            dist::Mingw { host: b },
+            dist::Mingw { host: c },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[
+            dist::Rustc {
+                compiler: Compiler { host: a, stage: 2 }
+            },
+            dist::Rustc {
+                compiler: Compiler { host: b, stage: 2 }
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: c,
+            },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+}
+
+#[test]
+fn dist_with_target_flag() {
+    let mut config = configure(&["B"], &["C"]);
+    config.skip_only_host_steps = true; // as-if --target=C was passed
+    let build = Build::new(config);
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+    let c = INTERNER.intern_str("C");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[
+            dist::Docs { host: a },
+            dist::Docs { host: b },
+            dist::Docs { host: c },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[
+            dist::Mingw { host: a },
+            dist::Mingw { host: b },
+            dist::Mingw { host: c },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: c,
+            },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
+}
+
+#[test]
+fn dist_with_same_targets_and_hosts() {
+    let build = Build::new(configure(&["B"], &["B"]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+
+    assert_eq!(
+        first(builder.cache.all::<dist::Docs>()),
+        &[
+            dist::Docs { host: a },
+            dist::Docs { host: b },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Mingw>()),
+        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Rustc>()),
+        &[
+            dist::Rustc {
+                compiler: Compiler { host: a, stage: 2 }
+            },
+            dist::Rustc {
+                compiler: Compiler { host: b, stage: 2 }
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<dist::Std>()),
+        &[
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            dist::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+    assert_eq!(
+        first(builder.cache.all::<compile::Std>()),
+        &[
+            compile::Std {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: a,
+            },
+            compile::Std {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<compile::Test>()),
+        &[
+            compile::Test {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<compile::Assemble>()),
+        &[
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 0 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 1 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 2 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: b, stage: 2 },
+            },
+        ]
+    );
+}
+
+#[test]
+fn build_default() {
+    let build = Build::new(configure(&["B"], &["C"]));
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+    let c = INTERNER.intern_str("C");
+
+    assert!(!builder.cache.all::<compile::Std>().is_empty());
+    assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+    assert_eq!(
+        first(builder.cache.all::<compile::Rustc>()),
+        &[
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 2 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: b, stage: 2 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: b, stage: 2 },
+                target: b,
+            },
+        ]
+    );
+
+    assert_eq!(
+        first(builder.cache.all::<compile::Test>()),
+        &[
+            compile::Test {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: c,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: c,
+            },
+        ]
+    );
+}
+
+#[test]
+fn build_with_target_flag() {
+    let mut config = configure(&["B"], &["C"]);
+    config.skip_only_host_steps = true;
+    let build = Build::new(config);
+    let mut builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+
+    let a = INTERNER.intern_str("A");
+    let b = INTERNER.intern_str("B");
+    let c = INTERNER.intern_str("C");
+
+    assert!(!builder.cache.all::<compile::Std>().is_empty());
+    assert_eq!(
+        first(builder.cache.all::<compile::Assemble>()),
+        &[
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 0 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 1 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: a, stage: 2 },
+            },
+            compile::Assemble {
+                target_compiler: Compiler { host: b, stage: 2 },
+            },
+        ]
+    );
+    assert_eq!(
+        first(builder.cache.all::<compile::Rustc>()),
+        &[
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Rustc {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+        ]
+    );
+
+    assert_eq!(
+        first(builder.cache.all::<compile::Test>()),
+        &[
+            compile::Test {
+                compiler: Compiler { host: a, stage: 0 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: a,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 1 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: b,
+            },
+            compile::Test {
+                compiler: Compiler { host: a, stage: 2 },
+                target: c,
+            },
+            compile::Test {
+                compiler: Compiler { host: b, stage: 2 },
+                target: c,
+            },
+        ]
+    );
+}
+
+#[test]
+fn test_with_no_doc_stage0() {
+    let mut config = configure(&[], &[]);
+    config.stage = Some(0);
+    config.cmd = Subcommand::Test {
+        paths: vec!["src/libstd".into()],
+        test_args: vec![],
+        rustc_args: vec![],
+        fail_fast: true,
+        doc_tests: DocTests::No,
+        bless: false,
+        compare_mode: None,
+        rustfix_coverage: false,
+    };
+
+    let build = Build::new(config);
+    let mut builder = Builder::new(&build);
+
+    let host = INTERNER.intern_str("A");
+
+    builder.run_step_descriptions(
+        &[StepDescription::from::<test::Crate>()],
+        &["src/libstd".into()],
+    );
+
+    // Ensure we don't build any compiler artifacts.
+    assert!(!builder.cache.contains::<compile::Rustc>());
+    assert_eq!(
+        first(builder.cache.all::<test::Crate>()),
+        &[test::Crate {
+            compiler: Compiler { host, stage: 0 },
+            target: host,
+            mode: Mode::Std,
+            test_kind: test::TestKind::Test,
+            krate: INTERNER.intern_str("std"),
+        },]
+    );
+}
+
+#[test]
+fn test_exclude() {
+    let mut config = configure(&[], &[]);
+    config.exclude = vec![
+        "src/test/run-pass".into(),
+        "src/tools/tidy".into(),
+    ];
+    config.cmd = Subcommand::Test {
+        paths: Vec::new(),
+        test_args: Vec::new(),
+        rustc_args: Vec::new(),
+        fail_fast: true,
+        doc_tests: DocTests::No,
+        bless: false,
+        compare_mode: None,
+        rustfix_coverage: false,
+    };
+
+    let build = Build::new(config);
+    let builder = Builder::new(&build);
+    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
+
+    // Ensure we have really excluded run-pass & tidy
+    assert!(!builder.cache.contains::<test::RunPass>());
+    assert!(!builder.cache.contains::<test::Tidy>());
+
+    // Ensure other tests are not affected.
+    assert!(builder.cache.contains::<test::RunPassFullDeps>());
+    assert!(builder.cache.contains::<test::RustdocUi>());
+}
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index c530ac24275c2..5fc58c8ab5a7b 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -141,7 +141,7 @@ mod boxed {
     pub use std::boxed::Box;
 }
 #[cfg(test)]
-mod boxed_test;
+mod tests;
 pub mod collections;
 #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
 pub mod sync;
diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/tests.rs
similarity index 100%
rename from src/liballoc/boxed_test.rs
rename to src/liballoc/tests.rs
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 1739b2236e89d..e2a249c8e61c0 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -617,218 +617,4 @@ impl SyncDroplessArena {
 }
 
 #[cfg(test)]
-mod tests {
-    extern crate test;
-    use test::Bencher;
-    use super::TypedArena;
-    use std::cell::Cell;
-
-    #[allow(dead_code)]
-    #[derive(Debug, Eq, PartialEq)]
-    struct Point {
-        x: i32,
-        y: i32,
-        z: i32,
-    }
-
-    #[test]
-    pub fn test_unused() {
-        let arena: TypedArena<Point> = TypedArena::default();
-        assert!(arena.chunks.borrow().is_empty());
-    }
-
-    #[test]
-    fn test_arena_alloc_nested() {
-        struct Inner {
-            value: u8,
-        }
-        struct Outer<'a> {
-            inner: &'a Inner,
-        }
-        enum EI<'e> {
-            I(Inner),
-            O(Outer<'e>),
-        }
-
-        struct Wrap<'a>(TypedArena<EI<'a>>);
-
-        impl<'a> Wrap<'a> {
-            fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
-                let r: &EI<'_> = self.0.alloc(EI::I(f()));
-                if let &EI::I(ref i) = r {
-                    i
-                } else {
-                    panic!("mismatch");
-                }
-            }
-            fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer<'_> {
-                let r: &EI<'_> = self.0.alloc(EI::O(f()));
-                if let &EI::O(ref o) = r {
-                    o
-                } else {
-                    panic!("mismatch");
-                }
-            }
-        }
-
-        let arena = Wrap(TypedArena::default());
-
-        let result = arena.alloc_outer(|| Outer {
-            inner: arena.alloc_inner(|| Inner { value: 10 }),
-        });
-
-        assert_eq!(result.inner.value, 10);
-    }
-
-    #[test]
-    pub fn test_copy() {
-        let arena = TypedArena::default();
-        for _ in 0..100000 {
-            arena.alloc(Point { x: 1, y: 2, z: 3 });
-        }
-    }
-
-    #[bench]
-    pub fn bench_copy(b: &mut Bencher) {
-        let arena = TypedArena::default();
-        b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
-    }
-
-    #[bench]
-    pub fn bench_copy_nonarena(b: &mut Bencher) {
-        b.iter(|| {
-            let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 });
-        })
-    }
-
-    #[allow(dead_code)]
-    struct Noncopy {
-        string: String,
-        array: Vec<i32>,
-    }
-
-    #[test]
-    pub fn test_noncopy() {
-        let arena = TypedArena::default();
-        for _ in 0..100000 {
-            arena.alloc(Noncopy {
-                string: "hello world".to_string(),
-                array: vec![1, 2, 3, 4, 5],
-            });
-        }
-    }
-
-    #[test]
-    pub fn test_typed_arena_zero_sized() {
-        let arena = TypedArena::default();
-        for _ in 0..100000 {
-            arena.alloc(());
-        }
-    }
-
-    #[test]
-    pub fn test_typed_arena_clear() {
-        let mut arena = TypedArena::default();
-        for _ in 0..10 {
-            arena.clear();
-            for _ in 0..10000 {
-                arena.alloc(Point { x: 1, y: 2, z: 3 });
-            }
-        }
-    }
-
-    #[bench]
-    pub fn bench_typed_arena_clear(b: &mut Bencher) {
-        let mut arena = TypedArena::default();
-        b.iter(|| {
-            arena.alloc(Point { x: 1, y: 2, z: 3 });
-            arena.clear();
-        })
-    }
-
-    // Drop tests
-
-    struct DropCounter<'a> {
-        count: &'a Cell<u32>,
-    }
-
-    impl Drop for DropCounter<'_> {
-        fn drop(&mut self) {
-            self.count.set(self.count.get() + 1);
-        }
-    }
-
-    #[test]
-    fn test_typed_arena_drop_count() {
-        let counter = Cell::new(0);
-        {
-            let arena: TypedArena<DropCounter<'_>> = TypedArena::default();
-            for _ in 0..100 {
-                // Allocate something with drop glue to make sure it doesn't leak.
-                arena.alloc(DropCounter { count: &counter });
-            }
-        };
-        assert_eq!(counter.get(), 100);
-    }
-
-    #[test]
-    fn test_typed_arena_drop_on_clear() {
-        let counter = Cell::new(0);
-        let mut arena: TypedArena<DropCounter<'_>> = TypedArena::default();
-        for i in 0..10 {
-            for _ in 0..100 {
-                // Allocate something with drop glue to make sure it doesn't leak.
-                arena.alloc(DropCounter { count: &counter });
-            }
-            arena.clear();
-            assert_eq!(counter.get(), i * 100 + 100);
-        }
-    }
-
-    thread_local! {
-        static DROP_COUNTER: Cell<u32> = Cell::new(0)
-    }
-
-    struct SmallDroppable;
-
-    impl Drop for SmallDroppable {
-        fn drop(&mut self) {
-            DROP_COUNTER.with(|c| c.set(c.get() + 1));
-        }
-    }
-
-    #[test]
-    fn test_typed_arena_drop_small_count() {
-        DROP_COUNTER.with(|c| c.set(0));
-        {
-            let arena: TypedArena<SmallDroppable> = TypedArena::default();
-            for _ in 0..100 {
-                // Allocate something with drop glue to make sure it doesn't leak.
-                arena.alloc(SmallDroppable);
-            }
-            // dropping
-        };
-        assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
-    }
-
-    #[bench]
-    pub fn bench_noncopy(b: &mut Bencher) {
-        let arena = TypedArena::default();
-        b.iter(|| {
-            arena.alloc(Noncopy {
-                string: "hello world".to_string(),
-                array: vec![1, 2, 3, 4, 5],
-            })
-        })
-    }
-
-    #[bench]
-    pub fn bench_noncopy_nonarena(b: &mut Bencher) {
-        b.iter(|| {
-            let _: Box<_> = Box::new(Noncopy {
-                string: "hello world".to_string(),
-                array: vec![1, 2, 3, 4, 5],
-            });
-        })
-    }
-}
+mod tests;
diff --git a/src/libarena/tests.rs b/src/libarena/tests.rs
new file mode 100644
index 0000000000000..fa4189409d0e8
--- /dev/null
+++ b/src/libarena/tests.rs
@@ -0,0 +1,213 @@
+extern crate test;
+use test::Bencher;
+use super::TypedArena;
+use std::cell::Cell;
+
+#[allow(dead_code)]
+#[derive(Debug, Eq, PartialEq)]
+struct Point {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+
+#[test]
+pub fn test_unused() {
+    let arena: TypedArena<Point> = TypedArena::default();
+    assert!(arena.chunks.borrow().is_empty());
+}
+
+#[test]
+fn test_arena_alloc_nested() {
+    struct Inner {
+        value: u8,
+    }
+    struct Outer<'a> {
+        inner: &'a Inner,
+    }
+    enum EI<'e> {
+        I(Inner),
+        O(Outer<'e>),
+    }
+
+    struct Wrap<'a>(TypedArena<EI<'a>>);
+
+    impl<'a> Wrap<'a> {
+        fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
+            let r: &EI<'_> = self.0.alloc(EI::I(f()));
+            if let &EI::I(ref i) = r {
+                i
+            } else {
+                panic!("mismatch");
+            }
+        }
+        fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer<'_> {
+            let r: &EI<'_> = self.0.alloc(EI::O(f()));
+            if let &EI::O(ref o) = r {
+                o
+            } else {
+                panic!("mismatch");
+            }
+        }
+    }
+
+    let arena = Wrap(TypedArena::default());
+
+    let result = arena.alloc_outer(|| Outer {
+        inner: arena.alloc_inner(|| Inner { value: 10 }),
+    });
+
+    assert_eq!(result.inner.value, 10);
+}
+
+#[test]
+pub fn test_copy() {
+    let arena = TypedArena::default();
+    for _ in 0..100000 {
+        arena.alloc(Point { x: 1, y: 2, z: 3 });
+    }
+}
+
+#[bench]
+pub fn bench_copy(b: &mut Bencher) {
+    let arena = TypedArena::default();
+    b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
+}
+
+#[bench]
+pub fn bench_copy_nonarena(b: &mut Bencher) {
+    b.iter(|| {
+        let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 });
+    })
+}
+
+#[allow(dead_code)]
+struct Noncopy {
+    string: String,
+    array: Vec<i32>,
+}
+
+#[test]
+pub fn test_noncopy() {
+    let arena = TypedArena::default();
+    for _ in 0..100000 {
+        arena.alloc(Noncopy {
+            string: "hello world".to_string(),
+            array: vec![1, 2, 3, 4, 5],
+        });
+    }
+}
+
+#[test]
+pub fn test_typed_arena_zero_sized() {
+    let arena = TypedArena::default();
+    for _ in 0..100000 {
+        arena.alloc(());
+    }
+}
+
+#[test]
+pub fn test_typed_arena_clear() {
+    let mut arena = TypedArena::default();
+    for _ in 0..10 {
+        arena.clear();
+        for _ in 0..10000 {
+            arena.alloc(Point { x: 1, y: 2, z: 3 });
+        }
+    }
+}
+
+#[bench]
+pub fn bench_typed_arena_clear(b: &mut Bencher) {
+    let mut arena = TypedArena::default();
+    b.iter(|| {
+        arena.alloc(Point { x: 1, y: 2, z: 3 });
+        arena.clear();
+    })
+}
+
+// Drop tests
+
+struct DropCounter<'a> {
+    count: &'a Cell<u32>,
+}
+
+impl Drop for DropCounter<'_> {
+    fn drop(&mut self) {
+        self.count.set(self.count.get() + 1);
+    }
+}
+
+#[test]
+fn test_typed_arena_drop_count() {
+    let counter = Cell::new(0);
+    {
+        let arena: TypedArena<DropCounter<'_>> = TypedArena::default();
+        for _ in 0..100 {
+            // Allocate something with drop glue to make sure it doesn't leak.
+            arena.alloc(DropCounter { count: &counter });
+        }
+    };
+    assert_eq!(counter.get(), 100);
+}
+
+#[test]
+fn test_typed_arena_drop_on_clear() {
+    let counter = Cell::new(0);
+    let mut arena: TypedArena<DropCounter<'_>> = TypedArena::default();
+    for i in 0..10 {
+        for _ in 0..100 {
+            // Allocate something with drop glue to make sure it doesn't leak.
+            arena.alloc(DropCounter { count: &counter });
+        }
+        arena.clear();
+        assert_eq!(counter.get(), i * 100 + 100);
+    }
+}
+
+thread_local! {
+    static DROP_COUNTER: Cell<u32> = Cell::new(0)
+}
+
+struct SmallDroppable;
+
+impl Drop for SmallDroppable {
+    fn drop(&mut self) {
+        DROP_COUNTER.with(|c| c.set(c.get() + 1));
+    }
+}
+
+#[test]
+fn test_typed_arena_drop_small_count() {
+    DROP_COUNTER.with(|c| c.set(0));
+    {
+        let arena: TypedArena<SmallDroppable> = TypedArena::default();
+        for _ in 0..100 {
+            // Allocate something with drop glue to make sure it doesn't leak.
+            arena.alloc(SmallDroppable);
+        }
+        // dropping
+    };
+    assert_eq!(DROP_COUNTER.with(|c| c.get()), 100);
+}
+
+#[bench]
+pub fn bench_noncopy(b: &mut Bencher) {
+    let arena = TypedArena::default();
+    b.iter(|| {
+        arena.alloc(Noncopy {
+            string: "hello world".to_string(),
+            array: vec![1, 2, 3, 4, 5],
+        })
+    })
+}
+
+#[bench]
+pub fn bench_noncopy_nonarena(b: &mut Bencher) {
+    b.iter(|| {
+        let _: Box<_> = Box::new(Noncopy {
+            string: "hello world".to_string(),
+            array: vec![1, 2, 3, 4, 5],
+        });
+    })
+}
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 7d0a0035dc846..f6e9143dd0583 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -622,248 +622,4 @@ impl<'a> Parser<'a> {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn same(fmt: &'static str, p: &[Piece<'static>]) {
-        let parser = Parser::new(fmt, None, vec![], false);
-        assert!(parser.collect::<Vec<Piece<'static>>>() == p);
-    }
-
-    fn fmtdflt() -> FormatSpec<'static> {
-        return FormatSpec {
-            fill: None,
-            align: AlignUnknown,
-            flags: 0,
-            precision: CountImplied,
-            width: CountImplied,
-            ty: "",
-        };
-    }
-
-    fn musterr(s: &str) {
-        let mut p = Parser::new(s, None, vec![], false);
-        p.next();
-        assert!(!p.errors.is_empty());
-    }
-
-    #[test]
-    fn simple() {
-        same("asdf", &[String("asdf")]);
-        same("a{{b", &[String("a"), String("{b")]);
-        same("a}}b", &[String("a"), String("}b")]);
-        same("a}}", &[String("a"), String("}")]);
-        same("}}", &[String("}")]);
-        same("\\}}", &[String("\\"), String("}")]);
-    }
-
-    #[test]
-    fn invalid01() {
-        musterr("{")
-    }
-    #[test]
-    fn invalid02() {
-        musterr("}")
-    }
-    #[test]
-    fn invalid04() {
-        musterr("{3a}")
-    }
-    #[test]
-    fn invalid05() {
-        musterr("{:|}")
-    }
-    #[test]
-    fn invalid06() {
-        musterr("{:>>>}")
-    }
-
-    #[test]
-    fn format_nothing() {
-        same("{}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: fmtdflt(),
-               })]);
-    }
-    #[test]
-    fn format_position() {
-        same("{3}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: fmtdflt(),
-               })]);
-    }
-    #[test]
-    fn format_position_nothing_else() {
-        same("{3:}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: fmtdflt(),
-               })]);
-    }
-    #[test]
-    fn format_type() {
-        same("{3:a}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "a",
-                   },
-               })]);
-    }
-    #[test]
-    fn format_align_fill() {
-        same("{3:>}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignRight,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "",
-                   },
-               })]);
-        same("{3:0<}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: FormatSpec {
-                       fill: Some('0'),
-                       align: AlignLeft,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "",
-                   },
-               })]);
-        same("{3:*<abcd}",
-             &[NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: FormatSpec {
-                       fill: Some('*'),
-                       align: AlignLeft,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "abcd",
-                   },
-               })]);
-    }
-    #[test]
-    fn format_counts() {
-        use syntax_pos::{GLOBALS, Globals, edition};
-        GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
-        same("{:10s}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountIs(10),
-                       ty: "s",
-                   },
-               })]);
-        same("{:10$.10s}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountIs(10),
-                       width: CountIsParam(10),
-                       ty: "s",
-                   },
-               })]);
-        same("{:.*s}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(1),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountIsParam(0),
-                       width: CountImplied,
-                       ty: "s",
-                   },
-               })]);
-        same("{:.10$s}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountIsParam(10),
-                       width: CountImplied,
-                       ty: "s",
-                   },
-               })]);
-        same("{:a$.b$s}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountIsName(Symbol::intern("b")),
-                       width: CountIsName(Symbol::intern("a")),
-                       ty: "s",
-                   },
-               })]);
-        });
-    }
-    #[test]
-    fn format_flags() {
-        same("{:-}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: (1 << FlagSignMinus as u32),
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "",
-                   },
-               })]);
-        same("{:+#}",
-             &[NextArgument(Argument {
-                   position: ArgumentImplicitlyIs(0),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "",
-                   },
-               })]);
-    }
-    #[test]
-    fn format_mixture() {
-        same("abcd {3:a} efg",
-             &[String("abcd "),
-               NextArgument(Argument {
-                   position: ArgumentIs(3),
-                   format: FormatSpec {
-                       fill: None,
-                       align: AlignUnknown,
-                       flags: 0,
-                       precision: CountImplied,
-                       width: CountImplied,
-                       ty: "a",
-                   },
-               }),
-               String(" efg")]);
-    }
-}
+mod tests;
diff --git a/src/libfmt_macros/tests.rs b/src/libfmt_macros/tests.rs
new file mode 100644
index 0000000000000..7282d4a5f248b
--- /dev/null
+++ b/src/libfmt_macros/tests.rs
@@ -0,0 +1,243 @@
+use super::*;
+
+fn same(fmt: &'static str, p: &[Piece<'static>]) {
+    let parser = Parser::new(fmt, None, vec![], false);
+    assert!(parser.collect::<Vec<Piece<'static>>>() == p);
+}
+
+fn fmtdflt() -> FormatSpec<'static> {
+    return FormatSpec {
+        fill: None,
+        align: AlignUnknown,
+        flags: 0,
+        precision: CountImplied,
+        width: CountImplied,
+        ty: "",
+    };
+}
+
+fn musterr(s: &str) {
+    let mut p = Parser::new(s, None, vec![], false);
+    p.next();
+    assert!(!p.errors.is_empty());
+}
+
+#[test]
+fn simple() {
+    same("asdf", &[String("asdf")]);
+    same("a{{b", &[String("a"), String("{b")]);
+    same("a}}b", &[String("a"), String("}b")]);
+    same("a}}", &[String("a"), String("}")]);
+    same("}}", &[String("}")]);
+    same("\\}}", &[String("\\"), String("}")]);
+}
+
+#[test]
+fn invalid01() {
+    musterr("{")
+}
+#[test]
+fn invalid02() {
+    musterr("}")
+}
+#[test]
+fn invalid04() {
+    musterr("{3a}")
+}
+#[test]
+fn invalid05() {
+    musterr("{:|}")
+}
+#[test]
+fn invalid06() {
+    musterr("{:>>>}")
+}
+
+#[test]
+fn format_nothing() {
+    same("{}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: fmtdflt(),
+           })]);
+}
+#[test]
+fn format_position() {
+    same("{3}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: fmtdflt(),
+           })]);
+}
+#[test]
+fn format_position_nothing_else() {
+    same("{3:}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: fmtdflt(),
+           })]);
+}
+#[test]
+fn format_type() {
+    same("{3:a}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "a",
+               },
+           })]);
+}
+#[test]
+fn format_align_fill() {
+    same("{3:>}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignRight,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "",
+               },
+           })]);
+    same("{3:0<}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: FormatSpec {
+                   fill: Some('0'),
+                   align: AlignLeft,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "",
+               },
+           })]);
+    same("{3:*<abcd}",
+         &[NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: FormatSpec {
+                   fill: Some('*'),
+                   align: AlignLeft,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "abcd",
+               },
+           })]);
+}
+#[test]
+fn format_counts() {
+    use syntax_pos::{GLOBALS, Globals, edition};
+    GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
+    same("{:10s}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountIs(10),
+                   ty: "s",
+               },
+           })]);
+    same("{:10$.10s}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountIs(10),
+                   width: CountIsParam(10),
+                   ty: "s",
+               },
+           })]);
+    same("{:.*s}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(1),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountIsParam(0),
+                   width: CountImplied,
+                   ty: "s",
+               },
+           })]);
+    same("{:.10$s}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountIsParam(10),
+                   width: CountImplied,
+                   ty: "s",
+               },
+           })]);
+    same("{:a$.b$s}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountIsName(Symbol::intern("b")),
+                   width: CountIsName(Symbol::intern("a")),
+                   ty: "s",
+               },
+           })]);
+    });
+}
+#[test]
+fn format_flags() {
+    same("{:-}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: (1 << FlagSignMinus as u32),
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "",
+               },
+           })]);
+    same("{:+#}",
+         &[NextArgument(Argument {
+               position: ArgumentImplicitlyIs(0),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "",
+               },
+           })]);
+}
+#[test]
+fn format_mixture() {
+    same("abcd {3:a} efg",
+         &[String("abcd "),
+           NextArgument(Argument {
+               position: ArgumentIs(3),
+               format: FormatSpec {
+                   fill: None,
+                   align: AlignUnknown,
+                   flags: 0,
+                   precision: CountImplied,
+                   width: CountImplied,
+                   ty: "a",
+               },
+           }),
+           String(" efg")]);
+}
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 489020d4ee778..a34e4fb89ff27 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -684,385 +684,4 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G,
 }
 
 #[cfg(test)]
-mod tests {
-    use NodeLabels::*;
-    use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style};
-    use super::LabelText::{self, LabelStr, EscStr, HtmlStr};
-    use std::io;
-    use std::io::prelude::*;
-
-    /// each node is an index in a vector in the graph.
-    type Node = usize;
-    struct Edge {
-        from: usize,
-        to: usize,
-        label: &'static str,
-        style: Style,
-    }
-
-    fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge {
-        Edge {
-            from,
-            to,
-            label,
-            style,
-        }
-    }
-
-    struct LabelledGraph {
-        /// The name for this graph. Used for labeling generated `digraph`.
-        name: &'static str,
-
-        /// Each node is an index into `node_labels`; these labels are
-        /// used as the label text for each node. (The node *names*,
-        /// which are unique identifiers, are derived from their index
-        /// in this array.)
-        ///
-        /// If a node maps to None here, then just use its name as its
-        /// text.
-        node_labels: Vec<Option<&'static str>>,
-
-        node_styles: Vec<Style>,
-
-        /// Each edge relates a from-index to a to-index along with a
-        /// label; `edges` collects them.
-        edges: Vec<Edge>,
-    }
-
-    // A simple wrapper around LabelledGraph that forces the labels to
-    // be emitted as EscStr.
-    struct LabelledGraphWithEscStrs {
-        graph: LabelledGraph,
-    }
-
-    enum NodeLabels<L> {
-        AllNodesLabelled(Vec<L>),
-        UnlabelledNodes(usize),
-        SomeNodesLabelled(Vec<Option<L>>),
-    }
-
-    type Trivial = NodeLabels<&'static str>;
-
-    impl NodeLabels<&'static str> {
-        fn to_opt_strs(self) -> Vec<Option<&'static str>> {
-            match self {
-                UnlabelledNodes(len) => vec![None; len],
-                AllNodesLabelled(lbls) => lbls.into_iter().map(|l| Some(l)).collect(),
-                SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
-            }
-        }
-
-        fn len(&self) -> usize {
-            match self {
-                &UnlabelledNodes(len) => len,
-                &AllNodesLabelled(ref lbls) => lbls.len(),
-                &SomeNodesLabelled(ref lbls) => lbls.len(),
-            }
-        }
-    }
-
-    impl LabelledGraph {
-        fn new(name: &'static str,
-               node_labels: Trivial,
-               edges: Vec<Edge>,
-               node_styles: Option<Vec<Style>>)
-               -> LabelledGraph {
-            let count = node_labels.len();
-            LabelledGraph {
-                name,
-                node_labels: node_labels.to_opt_strs(),
-                edges,
-                node_styles: match node_styles {
-                    Some(nodes) => nodes,
-                    None => vec![Style::None; count],
-                },
-            }
-        }
-    }
-
-    impl LabelledGraphWithEscStrs {
-        fn new(name: &'static str,
-               node_labels: Trivial,
-               edges: Vec<Edge>)
-               -> LabelledGraphWithEscStrs {
-            LabelledGraphWithEscStrs { graph: LabelledGraph::new(name, node_labels, edges, None) }
-        }
-    }
-
-    fn id_name<'a>(n: &Node) -> Id<'a> {
-        Id::new(format!("N{}", *n)).unwrap()
-    }
-
-    impl<'a> Labeller<'a> for LabelledGraph {
-        type Node = Node;
-        type Edge = &'a Edge;
-        fn graph_id(&'a self) -> Id<'a> {
-            Id::new(self.name).unwrap()
-        }
-        fn node_id(&'a self, n: &Node) -> Id<'a> {
-            id_name(n)
-        }
-        fn node_label(&'a self, n: &Node) -> LabelText<'a> {
-            match self.node_labels[*n] {
-                Some(l) => LabelStr(l.into()),
-                None => LabelStr(id_name(n).name()),
-            }
-        }
-        fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
-            LabelStr(e.label.into())
-        }
-        fn node_style(&'a self, n: &Node) -> Style {
-            self.node_styles[*n]
-        }
-        fn edge_style(&'a self, e: &&'a Edge) -> Style {
-            e.style
-        }
-    }
-
-    impl<'a> Labeller<'a> for LabelledGraphWithEscStrs {
-        type Node = Node;
-        type Edge = &'a Edge;
-        fn graph_id(&'a self) -> Id<'a> {
-            self.graph.graph_id()
-        }
-        fn node_id(&'a self, n: &Node) -> Id<'a> {
-            self.graph.node_id(n)
-        }
-        fn node_label(&'a self, n: &Node) -> LabelText<'a> {
-            match self.graph.node_label(n) {
-                LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
-            }
-        }
-        fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
-            match self.graph.edge_label(e) {
-                LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
-            }
-        }
-    }
-
-    impl<'a> GraphWalk<'a> for LabelledGraph {
-        type Node = Node;
-        type Edge = &'a Edge;
-        fn nodes(&'a self) -> Nodes<'a, Node> {
-            (0..self.node_labels.len()).collect()
-        }
-        fn edges(&'a self) -> Edges<'a, &'a Edge> {
-            self.edges.iter().collect()
-        }
-        fn source(&'a self, edge: &&'a Edge) -> Node {
-            edge.from
-        }
-        fn target(&'a self, edge: &&'a Edge) -> Node {
-            edge.to
-        }
-    }
-
-    impl<'a> GraphWalk<'a> for LabelledGraphWithEscStrs {
-        type Node = Node;
-        type Edge = &'a Edge;
-        fn nodes(&'a self) -> Nodes<'a, Node> {
-            self.graph.nodes()
-        }
-        fn edges(&'a self) -> Edges<'a, &'a Edge> {
-            self.graph.edges()
-        }
-        fn source(&'a self, edge: &&'a Edge) -> Node {
-            edge.from
-        }
-        fn target(&'a self, edge: &&'a Edge) -> Node {
-            edge.to
-        }
-    }
-
-    fn test_input(g: LabelledGraph) -> io::Result<String> {
-        let mut writer = Vec::new();
-        render(&g, &mut writer).unwrap();
-        let mut s = String::new();
-        Read::read_to_string(&mut &*writer, &mut s)?;
-        Ok(s)
-    }
-
-    // All of the tests use raw-strings as the format for the expected outputs,
-    // so that you can cut-and-paste the content into a .dot file yourself to
-    // see what the graphviz visualizer would produce.
-
-    #[test]
-    fn empty_graph() {
-        let labels: Trivial = UnlabelledNodes(0);
-        let r = test_input(LabelledGraph::new("empty_graph", labels, vec![], None));
-        assert_eq!(r.unwrap(),
-r#"digraph empty_graph {
-}
-"#);
-    }
-
-    #[test]
-    fn single_node() {
-        let labels: Trivial = UnlabelledNodes(1);
-        let r = test_input(LabelledGraph::new("single_node", labels, vec![], None));
-        assert_eq!(r.unwrap(),
-r#"digraph single_node {
-    N0[label="N0"];
-}
-"#);
-    }
-
-    #[test]
-    fn single_node_with_style() {
-        let labels: Trivial = UnlabelledNodes(1);
-        let styles = Some(vec![Style::Dashed]);
-        let r = test_input(LabelledGraph::new("single_node", labels, vec![], styles));
-        assert_eq!(r.unwrap(),
-r#"digraph single_node {
-    N0[label="N0"][style="dashed"];
-}
-"#);
-    }
-
-    #[test]
-    fn single_edge() {
-        let labels: Trivial = UnlabelledNodes(2);
-        let result = test_input(LabelledGraph::new("single_edge",
-                                                   labels,
-                                                   vec![edge(0, 1, "E", Style::None)],
-                                                   None));
-        assert_eq!(result.unwrap(),
-r#"digraph single_edge {
-    N0[label="N0"];
-    N1[label="N1"];
-    N0 -> N1[label="E"];
-}
-"#);
-    }
-
-    #[test]
-    fn single_edge_with_style() {
-        let labels: Trivial = UnlabelledNodes(2);
-        let result = test_input(LabelledGraph::new("single_edge",
-                                                   labels,
-                                                   vec![edge(0, 1, "E", Style::Bold)],
-                                                   None));
-        assert_eq!(result.unwrap(),
-r#"digraph single_edge {
-    N0[label="N0"];
-    N1[label="N1"];
-    N0 -> N1[label="E"][style="bold"];
-}
-"#);
-    }
-
-    #[test]
-    fn test_some_labelled() {
-        let labels: Trivial = SomeNodesLabelled(vec![Some("A"), None]);
-        let styles = Some(vec![Style::None, Style::Dotted]);
-        let result = test_input(LabelledGraph::new("test_some_labelled",
-                                                   labels,
-                                                   vec![edge(0, 1, "A-1", Style::None)],
-                                                   styles));
-        assert_eq!(result.unwrap(),
-r#"digraph test_some_labelled {
-    N0[label="A"];
-    N1[label="N1"][style="dotted"];
-    N0 -> N1[label="A-1"];
-}
-"#);
-    }
-
-    #[test]
-    fn single_cyclic_node() {
-        let labels: Trivial = UnlabelledNodes(1);
-        let r = test_input(LabelledGraph::new("single_cyclic_node",
-                                              labels,
-                                              vec![edge(0, 0, "E", Style::None)],
-                                              None));
-        assert_eq!(r.unwrap(),
-r#"digraph single_cyclic_node {
-    N0[label="N0"];
-    N0 -> N0[label="E"];
-}
-"#);
-    }
-
-    #[test]
-    fn hasse_diagram() {
-        let labels = AllNodesLabelled(vec!["{x,y}", "{x}", "{y}", "{}"]);
-        let r = test_input(LabelledGraph::new("hasse_diagram",
-                                              labels,
-                                              vec![edge(0, 1, "", Style::None),
-                                                   edge(0, 2, "", Style::None),
-                                                   edge(1, 3, "", Style::None),
-                                                   edge(2, 3, "", Style::None)],
-                                              None));
-        assert_eq!(r.unwrap(),
-r#"digraph hasse_diagram {
-    N0[label="{x,y}"];
-    N1[label="{x}"];
-    N2[label="{y}"];
-    N3[label="{}"];
-    N0 -> N1[label=""];
-    N0 -> N2[label=""];
-    N1 -> N3[label=""];
-    N2 -> N3[label=""];
-}
-"#);
-    }
-
-    #[test]
-    fn left_aligned_text() {
-        let labels = AllNodesLabelled(vec![
-            "if test {\
-           \\l    branch1\
-           \\l} else {\
-           \\l    branch2\
-           \\l}\
-           \\lafterward\
-           \\l",
-            "branch1",
-            "branch2",
-            "afterward"]);
-
-        let mut writer = Vec::new();
-
-        let g = LabelledGraphWithEscStrs::new("syntax_tree",
-                                              labels,
-                                              vec![edge(0, 1, "then", Style::None),
-                                                   edge(0, 2, "else", Style::None),
-                                                   edge(1, 3, ";", Style::None),
-                                                   edge(2, 3, ";", Style::None)]);
-
-        render(&g, &mut writer).unwrap();
-        let mut r = String::new();
-        Read::read_to_string(&mut &*writer, &mut r).unwrap();
-
-        assert_eq!(r,
-r#"digraph syntax_tree {
-    N0[label="if test {\l    branch1\l} else {\l    branch2\l}\lafterward\l"];
-    N1[label="branch1"];
-    N2[label="branch2"];
-    N3[label="afterward"];
-    N0 -> N1[label="then"];
-    N0 -> N2[label="else"];
-    N1 -> N3[label=";"];
-    N2 -> N3[label=";"];
-}
-"#);
-    }
-
-    #[test]
-    fn simple_id_construction() {
-        let id1 = Id::new("hello");
-        match id1 {
-            Ok(_) => {}
-            Err(..) => panic!("'hello' is not a valid value for id anymore"),
-        }
-    }
-
-    #[test]
-    fn badly_formatted_id() {
-        let id2 = Id::new("Weird { struct : ure } !!!");
-        match id2 {
-            Ok(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
-            Err(..) => {}
-        }
-    }
-}
+mod tests;
diff --git a/src/libgraphviz/tests.rs b/src/libgraphviz/tests.rs
new file mode 100644
index 0000000000000..2f713579b17fa
--- /dev/null
+++ b/src/libgraphviz/tests.rs
@@ -0,0 +1,380 @@
+use NodeLabels::*;
+use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style};
+use super::LabelText::{self, LabelStr, EscStr, HtmlStr};
+use std::io;
+use std::io::prelude::*;
+
+/// each node is an index in a vector in the graph.
+type Node = usize;
+struct Edge {
+    from: usize,
+    to: usize,
+    label: &'static str,
+    style: Style,
+}
+
+fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge {
+    Edge {
+        from,
+        to,
+        label,
+        style,
+    }
+}
+
+struct LabelledGraph {
+    /// The name for this graph. Used for labeling generated `digraph`.
+    name: &'static str,
+
+    /// Each node is an index into `node_labels`; these labels are
+    /// used as the label text for each node. (The node *names*,
+    /// which are unique identifiers, are derived from their index
+    /// in this array.)
+    ///
+    /// If a node maps to None here, then just use its name as its
+    /// text.
+    node_labels: Vec<Option<&'static str>>,
+
+    node_styles: Vec<Style>,
+
+    /// Each edge relates a from-index to a to-index along with a
+    /// label; `edges` collects them.
+    edges: Vec<Edge>,
+}
+
+// A simple wrapper around LabelledGraph that forces the labels to
+// be emitted as EscStr.
+struct LabelledGraphWithEscStrs {
+    graph: LabelledGraph,
+}
+
+enum NodeLabels<L> {
+    AllNodesLabelled(Vec<L>),
+    UnlabelledNodes(usize),
+    SomeNodesLabelled(Vec<Option<L>>),
+}
+
+type Trivial = NodeLabels<&'static str>;
+
+impl NodeLabels<&'static str> {
+    fn to_opt_strs(self) -> Vec<Option<&'static str>> {
+        match self {
+            UnlabelledNodes(len) => vec![None; len],
+            AllNodesLabelled(lbls) => lbls.into_iter().map(|l| Some(l)).collect(),
+            SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
+        }
+    }
+
+    fn len(&self) -> usize {
+        match self {
+            &UnlabelledNodes(len) => len,
+            &AllNodesLabelled(ref lbls) => lbls.len(),
+            &SomeNodesLabelled(ref lbls) => lbls.len(),
+        }
+    }
+}
+
+impl LabelledGraph {
+    fn new(name: &'static str,
+           node_labels: Trivial,
+           edges: Vec<Edge>,
+           node_styles: Option<Vec<Style>>)
+           -> LabelledGraph {
+        let count = node_labels.len();
+        LabelledGraph {
+            name,
+            node_labels: node_labels.to_opt_strs(),
+            edges,
+            node_styles: match node_styles {
+                Some(nodes) => nodes,
+                None => vec![Style::None; count],
+            },
+        }
+    }
+}
+
+impl LabelledGraphWithEscStrs {
+    fn new(name: &'static str,
+           node_labels: Trivial,
+           edges: Vec<Edge>)
+           -> LabelledGraphWithEscStrs {
+        LabelledGraphWithEscStrs { graph: LabelledGraph::new(name, node_labels, edges, None) }
+    }
+}
+
+fn id_name<'a>(n: &Node) -> Id<'a> {
+    Id::new(format!("N{}", *n)).unwrap()
+}
+
+impl<'a> Labeller<'a> for LabelledGraph {
+    type Node = Node;
+    type Edge = &'a Edge;
+    fn graph_id(&'a self) -> Id<'a> {
+        Id::new(self.name).unwrap()
+    }
+    fn node_id(&'a self, n: &Node) -> Id<'a> {
+        id_name(n)
+    }
+    fn node_label(&'a self, n: &Node) -> LabelText<'a> {
+        match self.node_labels[*n] {
+            Some(l) => LabelStr(l.into()),
+            None => LabelStr(id_name(n).name()),
+        }
+    }
+    fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
+        LabelStr(e.label.into())
+    }
+    fn node_style(&'a self, n: &Node) -> Style {
+        self.node_styles[*n]
+    }
+    fn edge_style(&'a self, e: &&'a Edge) -> Style {
+        e.style
+    }
+}
+
+impl<'a> Labeller<'a> for LabelledGraphWithEscStrs {
+    type Node = Node;
+    type Edge = &'a Edge;
+    fn graph_id(&'a self) -> Id<'a> {
+        self.graph.graph_id()
+    }
+    fn node_id(&'a self, n: &Node) -> Id<'a> {
+        self.graph.node_id(n)
+    }
+    fn node_label(&'a self, n: &Node) -> LabelText<'a> {
+        match self.graph.node_label(n) {
+            LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
+        }
+    }
+    fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
+        match self.graph.edge_label(e) {
+            LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
+        }
+    }
+}
+
+impl<'a> GraphWalk<'a> for LabelledGraph {
+    type Node = Node;
+    type Edge = &'a Edge;
+    fn nodes(&'a self) -> Nodes<'a, Node> {
+        (0..self.node_labels.len()).collect()
+    }
+    fn edges(&'a self) -> Edges<'a, &'a Edge> {
+        self.edges.iter().collect()
+    }
+    fn source(&'a self, edge: &&'a Edge) -> Node {
+        edge.from
+    }
+    fn target(&'a self, edge: &&'a Edge) -> Node {
+        edge.to
+    }
+}
+
+impl<'a> GraphWalk<'a> for LabelledGraphWithEscStrs {
+    type Node = Node;
+    type Edge = &'a Edge;
+    fn nodes(&'a self) -> Nodes<'a, Node> {
+        self.graph.nodes()
+    }
+    fn edges(&'a self) -> Edges<'a, &'a Edge> {
+        self.graph.edges()
+    }
+    fn source(&'a self, edge: &&'a Edge) -> Node {
+        edge.from
+    }
+    fn target(&'a self, edge: &&'a Edge) -> Node {
+        edge.to
+    }
+}
+
+fn test_input(g: LabelledGraph) -> io::Result<String> {
+    let mut writer = Vec::new();
+    render(&g, &mut writer).unwrap();
+    let mut s = String::new();
+    Read::read_to_string(&mut &*writer, &mut s)?;
+    Ok(s)
+}
+
+// All of the tests use raw-strings as the format for the expected outputs,
+// so that you can cut-and-paste the content into a .dot file yourself to
+// see what the graphviz visualizer would produce.
+
+#[test]
+fn empty_graph() {
+    let labels: Trivial = UnlabelledNodes(0);
+    let r = test_input(LabelledGraph::new("empty_graph", labels, vec![], None));
+    assert_eq!(r.unwrap(),
+r#"digraph empty_graph {
+}
+"#);
+}
+
+#[test]
+fn single_node() {
+    let labels: Trivial = UnlabelledNodes(1);
+    let r = test_input(LabelledGraph::new("single_node", labels, vec![], None));
+    assert_eq!(r.unwrap(),
+r#"digraph single_node {
+    N0[label="N0"];
+}
+"#);
+}
+
+#[test]
+fn single_node_with_style() {
+    let labels: Trivial = UnlabelledNodes(1);
+    let styles = Some(vec![Style::Dashed]);
+    let r = test_input(LabelledGraph::new("single_node", labels, vec![], styles));
+    assert_eq!(r.unwrap(),
+r#"digraph single_node {
+    N0[label="N0"][style="dashed"];
+}
+"#);
+}
+
+#[test]
+fn single_edge() {
+    let labels: Trivial = UnlabelledNodes(2);
+    let result = test_input(LabelledGraph::new("single_edge",
+                                               labels,
+                                               vec![edge(0, 1, "E", Style::None)],
+                                               None));
+    assert_eq!(result.unwrap(),
+r#"digraph single_edge {
+    N0[label="N0"];
+    N1[label="N1"];
+    N0 -> N1[label="E"];
+}
+"#);
+}
+
+#[test]
+fn single_edge_with_style() {
+    let labels: Trivial = UnlabelledNodes(2);
+    let result = test_input(LabelledGraph::new("single_edge",
+                                               labels,
+                                               vec![edge(0, 1, "E", Style::Bold)],
+                                               None));
+    assert_eq!(result.unwrap(),
+r#"digraph single_edge {
+    N0[label="N0"];
+    N1[label="N1"];
+    N0 -> N1[label="E"][style="bold"];
+}
+"#);
+}
+
+#[test]
+fn test_some_labelled() {
+    let labels: Trivial = SomeNodesLabelled(vec![Some("A"), None]);
+    let styles = Some(vec![Style::None, Style::Dotted]);
+    let result = test_input(LabelledGraph::new("test_some_labelled",
+                                               labels,
+                                               vec![edge(0, 1, "A-1", Style::None)],
+                                               styles));
+    assert_eq!(result.unwrap(),
+r#"digraph test_some_labelled {
+    N0[label="A"];
+    N1[label="N1"][style="dotted"];
+    N0 -> N1[label="A-1"];
+}
+"#);
+}
+
+#[test]
+fn single_cyclic_node() {
+    let labels: Trivial = UnlabelledNodes(1);
+    let r = test_input(LabelledGraph::new("single_cyclic_node",
+                                          labels,
+                                          vec![edge(0, 0, "E", Style::None)],
+                                          None));
+    assert_eq!(r.unwrap(),
+r#"digraph single_cyclic_node {
+    N0[label="N0"];
+    N0 -> N0[label="E"];
+}
+"#);
+}
+
+#[test]
+fn hasse_diagram() {
+    let labels = AllNodesLabelled(vec!["{x,y}", "{x}", "{y}", "{}"]);
+    let r = test_input(LabelledGraph::new("hasse_diagram",
+                                          labels,
+                                          vec![edge(0, 1, "", Style::None),
+                                               edge(0, 2, "", Style::None),
+                                               edge(1, 3, "", Style::None),
+                                               edge(2, 3, "", Style::None)],
+                                          None));
+    assert_eq!(r.unwrap(),
+r#"digraph hasse_diagram {
+    N0[label="{x,y}"];
+    N1[label="{x}"];
+    N2[label="{y}"];
+    N3[label="{}"];
+    N0 -> N1[label=""];
+    N0 -> N2[label=""];
+    N1 -> N3[label=""];
+    N2 -> N3[label=""];
+}
+"#);
+}
+
+#[test]
+fn left_aligned_text() {
+    let labels = AllNodesLabelled(vec![
+        "if test {\
+       \\l    branch1\
+       \\l} else {\
+       \\l    branch2\
+       \\l}\
+       \\lafterward\
+       \\l",
+        "branch1",
+        "branch2",
+        "afterward"]);
+
+    let mut writer = Vec::new();
+
+    let g = LabelledGraphWithEscStrs::new("syntax_tree",
+                                          labels,
+                                          vec![edge(0, 1, "then", Style::None),
+                                               edge(0, 2, "else", Style::None),
+                                               edge(1, 3, ";", Style::None),
+                                               edge(2, 3, ";", Style::None)]);
+
+    render(&g, &mut writer).unwrap();
+    let mut r = String::new();
+    Read::read_to_string(&mut &*writer, &mut r).unwrap();
+
+    assert_eq!(r,
+r#"digraph syntax_tree {
+    N0[label="if test {\l    branch1\l} else {\l    branch2\l}\lafterward\l"];
+    N1[label="branch1"];
+    N2[label="branch2"];
+    N3[label="afterward"];
+    N0 -> N1[label="then"];
+    N0 -> N2[label="else"];
+    N1 -> N3[label=";"];
+    N2 -> N3[label=";"];
+}
+"#);
+}
+
+#[test]
+fn simple_id_construction() {
+    let id1 = Id::new("hello");
+    match id1 {
+        Ok(_) => {}
+        Err(..) => panic!("'hello' is not a valid value for id anymore"),
+    }
+}
+
+#[test]
+fn badly_formatted_id() {
+    let id2 = Id::new("Weird { struct : ure } !!!");
+    match id2 {
+        Ok(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
+        Err(..) => {}
+    }
+}
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index f4d523b92338c..fc092481a4a96 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command line options.
 
@@ -2720,711 +2718,4 @@ mod dep_tracking {
 }
 
 #[cfg(test)]
-mod tests {
-    use getopts;
-    use crate::lint;
-    use crate::middle::cstore;
-    use crate::session::config::{
-        build_configuration,
-        build_session_options_and_crate_config,
-        to_crate_config
-    };
-    use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
-    use crate::session::build_session;
-    use crate::session::search_paths::SearchPath;
-    use std::collections::{BTreeMap, BTreeSet};
-    use std::iter::FromIterator;
-    use std::path::PathBuf;
-    use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
-    use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
-    use syntax::symbol::sym;
-    use syntax::edition::{Edition, DEFAULT_EDITION};
-    use syntax;
-    use super::Options;
-
-    impl ExternEntry {
-        fn new_public<S: Into<String>,
-                      I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
-            let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
-                .collect();
-
-            ExternEntry {
-                locations,
-                is_private_dep: false
-            }
-        }
-    }
-
-    fn optgroups() -> getopts::Options {
-        let mut opts = getopts::Options::new();
-        for group in super::rustc_optgroups() {
-            (group.apply)(&mut opts);
-        }
-        return opts;
-    }
-
-    fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
-        BTreeMap::from_iter(entries.into_iter())
-    }
-
-    // When the user supplies --test we should implicitly supply --cfg test
-    #[test]
-    fn test_switch_implies_cfg_test() {
-        syntax::with_default_globals(|| {
-            let matches = &match optgroups().parse(&["--test".to_string()]) {
-                Ok(m) => m,
-                Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
-            };
-            let registry = errors::registry::Registry::new(&[]);
-            let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-            let sess = build_session(sessopts, None, registry);
-            let cfg = build_configuration(&sess, to_crate_config(cfg));
-            assert!(cfg.contains(&(sym::test, None)));
-        });
-    }
-
-    // When the user supplies --test and --cfg test, don't implicitly add
-    // another --cfg test
-    #[test]
-    fn test_switch_implies_cfg_test_unless_cfg_test() {
-        syntax::with_default_globals(|| {
-            let matches = &match optgroups().parse(&["--test".to_string(),
-                                                     "--cfg=test".to_string()]) {
-                Ok(m) => m,
-                Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
-            };
-            let registry = errors::registry::Registry::new(&[]);
-            let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-            let sess = build_session(sessopts, None, registry);
-            let cfg = build_configuration(&sess, to_crate_config(cfg));
-            let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
-            assert!(test_items.next().is_some());
-            assert!(test_items.next().is_none());
-        });
-    }
-
-    #[test]
-    fn test_can_print_warnings() {
-        syntax::with_default_globals(|| {
-            let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
-            let registry = errors::registry::Registry::new(&[]);
-            let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, None, registry);
-            assert!(!sess.diagnostic().flags.can_emit_warnings);
-        });
-
-        syntax::with_default_globals(|| {
-            let matches = optgroups()
-                .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
-                .unwrap();
-            let registry = errors::registry::Registry::new(&[]);
-            let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, None, registry);
-            assert!(sess.diagnostic().flags.can_emit_warnings);
-        });
-
-        syntax::with_default_globals(|| {
-            let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
-            let registry = errors::registry::Registry::new(&[]);
-            let (sessopts, _) = build_session_options_and_crate_config(&matches);
-            let sess = build_session(sessopts, None, registry);
-            assert!(sess.diagnostic().flags.can_emit_warnings);
-        });
-    }
-
-    #[test]
-    fn test_output_types_tracking_hash_different_paths() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-
-        v1.output_types =
-            OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
-        v2.output_types =
-            OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
-        v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
-
-        assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-        assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_output_types_tracking_hash_different_construction_order() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-
-        v1.output_types = OutputTypes::new(&[
-            (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
-            (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
-        ]);
-
-        v2.output_types = OutputTypes::new(&[
-            (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
-            (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
-        ]);
-
-        assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_externs_tracking_hash_different_construction_order() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-
-        v1.externs = Externs::new(mk_map(vec![
-            (
-                String::from("a"),
-                ExternEntry::new_public(vec![Some("b"), Some("c")])
-            ),
-            (
-                String::from("d"),
-                ExternEntry::new_public(vec![Some("e"), Some("f")])
-            ),
-        ]));
-
-        v2.externs = Externs::new(mk_map(vec![
-            (
-                String::from("d"),
-                ExternEntry::new_public(vec![Some("e"), Some("f")])
-            ),
-            (
-                String::from("a"),
-                ExternEntry::new_public(vec![Some("b"), Some("c")])
-            ),
-        ]));
-
-        v3.externs = Externs::new(mk_map(vec![
-            (
-                String::from("a"),
-                ExternEntry::new_public(vec![Some("b"), Some("c")])
-            ),
-            (
-                String::from("d"),
-                ExternEntry::new_public(vec![Some("f"), Some("e")])
-            ),
-        ]));
-
-        assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-        assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_lints_tracking_hash_different_values() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-
-        v1.lint_opts = vec![
-            (String::from("a"), lint::Allow),
-            (String::from("b"), lint::Warn),
-            (String::from("c"), lint::Deny),
-            (String::from("d"), lint::Forbid),
-        ];
-
-        v2.lint_opts = vec![
-            (String::from("a"), lint::Allow),
-            (String::from("b"), lint::Warn),
-            (String::from("X"), lint::Deny),
-            (String::from("d"), lint::Forbid),
-        ];
-
-        v3.lint_opts = vec![
-            (String::from("a"), lint::Allow),
-            (String::from("b"), lint::Warn),
-            (String::from("c"), lint::Forbid),
-            (String::from("d"), lint::Deny),
-        ];
-
-        assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-        assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_lints_tracking_hash_different_construction_order() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-
-        v1.lint_opts = vec![
-            (String::from("a"), lint::Allow),
-            (String::from("b"), lint::Warn),
-            (String::from("c"), lint::Deny),
-            (String::from("d"), lint::Forbid),
-        ];
-
-        v2.lint_opts = vec![
-            (String::from("a"), lint::Allow),
-            (String::from("c"), lint::Deny),
-            (String::from("b"), lint::Warn),
-            (String::from("d"), lint::Forbid),
-        ];
-
-        assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_search_paths_tracking_hash_different_order() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-        let mut v4 = Options::default();
-
-        const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
-            pretty: false,
-            json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
-        };
-
-        // Reference
-        v1.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", JSON));
-        v1.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", JSON));
-        v1.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-        v1.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
-        v1.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", JSON));
-
-        v2.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", JSON));
-        v2.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-        v2.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", JSON));
-        v2.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
-        v2.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", JSON));
-
-        v3.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", JSON));
-        v3.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
-        v3.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", JSON));
-        v3.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-        v3.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", JSON));
-
-        v4.search_paths
-            .push(SearchPath::from_cli_opt("all=mno", JSON));
-        v4.search_paths
-            .push(SearchPath::from_cli_opt("native=abc", JSON));
-        v4.search_paths
-            .push(SearchPath::from_cli_opt("crate=def", JSON));
-        v4.search_paths
-            .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-        v4.search_paths
-            .push(SearchPath::from_cli_opt("framework=jkl", JSON));
-
-        assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-        assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_native_libs_tracking_hash_different_values() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-        let mut v4 = Options::default();
-
-        // Reference
-        v1.libs = vec![
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("b"), None, Some(cstore::NativeFramework)),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        // Change label
-        v2.libs = vec![
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("X"), None, Some(cstore::NativeFramework)),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        // Change kind
-        v3.libs = vec![
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("b"), None, Some(cstore::NativeStatic)),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        // Change new-name
-        v4.libs = vec![
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (
-                String::from("b"),
-                Some(String::from("X")),
-                Some(cstore::NativeFramework),
-            ),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-        assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_native_libs_tracking_hash_different_order() {
-        let mut v1 = Options::default();
-        let mut v2 = Options::default();
-        let mut v3 = Options::default();
-
-        // Reference
-        v1.libs = vec![
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("b"), None, Some(cstore::NativeFramework)),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        v2.libs = vec![
-            (String::from("b"), None, Some(cstore::NativeFramework)),
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-        ];
-
-        v3.libs = vec![
-            (String::from("c"), None, Some(cstore::NativeUnknown)),
-            (String::from("a"), None, Some(cstore::NativeStatic)),
-            (String::from("b"), None, Some(cstore::NativeFramework)),
-        ];
-
-        assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-        assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-        assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
-
-        // Check clone
-        assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-        assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-        assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_codegen_options_tracking_hash() {
-        let reference = Options::default();
-        let mut opts = Options::default();
-
-        // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
-        opts.cg.ar = Some(String::from("abc"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.linker = Some(PathBuf::from("linker"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.link_dead_code = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.rpath = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.extra_filename = String::from("extra-filename");
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.codegen_units = Some(42);
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.save_temps = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts.cg.incremental = Some(String::from("abc"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        // Make sure changing a [TRACKED] option changes the hash
-        opts = reference.clone();
-        opts.cg.lto = LtoCli::Fat;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.target_cpu = Some(String::from("abc"));
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.target_feature = String::from("all the features, all of them");
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.passes = vec![String::from("1"), String::from("2")];
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.overflow_checks = Some(true);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.no_prepopulate_passes = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.no_vectorize_loops = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.no_vectorize_slp = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.soft_float = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.prefer_dynamic = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.no_integrated_as = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.no_redzone = Some(true);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.relocation_model = Some(String::from("relocation model"));
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.code_model = Some(String::from("code model"));
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.tls_model = Some(String::from("tls model"));
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.pgo_gen = SwitchWithOptPath::Enabled(None);
-        assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
-        assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.metadata = vec![String::from("A"), String::from("B")];
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.debuginfo = Some(0xdeadbeef);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.debuginfo = Some(0xba5eba11);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.force_frame_pointers = Some(false);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.debug_assertions = Some(true);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.inline_threshold = Some(0xf007ba11);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.panic = Some(PanicStrategy::Abort);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_debugging_options_tracking_hash() {
-        let reference = Options::default();
-        let mut opts = Options::default();
-
-        // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
-        opts.debugging_opts.verbose = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.time_passes = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.time_llvm_passes = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.input_stats = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.borrowck_stats = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.meta_stats = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.print_link_args = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.print_llvm_passes = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.ast_json = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.ast_json_noexpand = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.ls = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.save_analysis = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.flowgraph_print_loans = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.flowgraph_print_moves = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.flowgraph_print_assigns = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.flowgraph_print_all = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.print_region_graph = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.parse_only = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.incremental = Some(String::from("abc"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.dump_dep_graph = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.query_dep_graph = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.no_analysis = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.unstable_options = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.trace_macros = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.keep_hygiene_data = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.keep_ast = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.print_mono_items = Some(String::from("abc"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.dump_mir = Some(String::from("abc"));
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.dump_mir_dir = String::from("abc");
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.dump_mir_graphviz = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-
-        // Make sure changing a [TRACKED] option changes the hash
-        opts = reference.clone();
-        opts.debugging_opts.asm_comments = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.verify_llvm_ir = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.no_landing_pads = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.fewer_names = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.no_codegen = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.treat_err_as_bug = Some(1);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.report_delayed_bugs = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.continue_parse_after_error = true;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.force_overflow_checks = Some(true);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.show_span = Some(String::from("abc"));
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.mir_opt_level = 3;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.relro_level = Some(RelroLevel::Full);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
-        opts = reference.clone();
-        opts.debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-    }
-
-    #[test]
-    fn test_edition_parsing() {
-        // test default edition
-        let options = Options::default();
-        assert!(options.edition == DEFAULT_EDITION);
-
-        let matches = optgroups()
-            .parse(&["--edition=2018".to_string()])
-            .unwrap();
-        let (sessopts, _) = build_session_options_and_crate_config(&matches);
-        assert!(sessopts.edition == Edition::Edition2018)
-    }
-}
+mod tests;
diff --git a/src/librustc/session/config/tests.rs b/src/librustc/session/config/tests.rs
new file mode 100644
index 0000000000000..b8477f8dd1789
--- /dev/null
+++ b/src/librustc/session/config/tests.rs
@@ -0,0 +1,706 @@
+use getopts;
+use crate::lint;
+use crate::middle::cstore;
+use crate::session::config::{
+    build_configuration,
+    build_session_options_and_crate_config,
+    to_crate_config
+};
+use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
+use crate::session::build_session;
+use crate::session::search_paths::SearchPath;
+use std::collections::{BTreeMap, BTreeSet};
+use std::iter::FromIterator;
+use std::path::PathBuf;
+use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
+use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
+use syntax::symbol::sym;
+use syntax::edition::{Edition, DEFAULT_EDITION};
+use syntax;
+use super::Options;
+
+impl ExternEntry {
+    fn new_public<S: Into<String>,
+                  I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
+        let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
+            .collect();
+
+        ExternEntry {
+            locations,
+            is_private_dep: false
+        }
+    }
+}
+
+fn optgroups() -> getopts::Options {
+    let mut opts = getopts::Options::new();
+    for group in super::rustc_optgroups() {
+        (group.apply)(&mut opts);
+    }
+    return opts;
+}
+
+fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
+    BTreeMap::from_iter(entries.into_iter())
+}
+
+// When the user supplies --test we should implicitly supply --cfg test
+#[test]
+fn test_switch_implies_cfg_test() {
+    syntax::with_default_globals(|| {
+        let matches = &match optgroups().parse(&["--test".to_string()]) {
+            Ok(m) => m,
+            Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
+        };
+        let registry = errors::registry::Registry::new(&[]);
+        let (sessopts, cfg) = build_session_options_and_crate_config(matches);
+        let sess = build_session(sessopts, None, registry);
+        let cfg = build_configuration(&sess, to_crate_config(cfg));
+        assert!(cfg.contains(&(sym::test, None)));
+    });
+}
+
+// When the user supplies --test and --cfg test, don't implicitly add
+// another --cfg test
+#[test]
+fn test_switch_implies_cfg_test_unless_cfg_test() {
+    syntax::with_default_globals(|| {
+        let matches = &match optgroups().parse(&["--test".to_string(),
+                                                 "--cfg=test".to_string()]) {
+            Ok(m) => m,
+            Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
+        };
+        let registry = errors::registry::Registry::new(&[]);
+        let (sessopts, cfg) = build_session_options_and_crate_config(matches);
+        let sess = build_session(sessopts, None, registry);
+        let cfg = build_configuration(&sess, to_crate_config(cfg));
+        let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
+        assert!(test_items.next().is_some());
+        assert!(test_items.next().is_none());
+    });
+}
+
+#[test]
+fn test_can_print_warnings() {
+    syntax::with_default_globals(|| {
+        let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
+        let registry = errors::registry::Registry::new(&[]);
+        let (sessopts, _) = build_session_options_and_crate_config(&matches);
+        let sess = build_session(sessopts, None, registry);
+        assert!(!sess.diagnostic().flags.can_emit_warnings);
+    });
+
+    syntax::with_default_globals(|| {
+        let matches = optgroups()
+            .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
+            .unwrap();
+        let registry = errors::registry::Registry::new(&[]);
+        let (sessopts, _) = build_session_options_and_crate_config(&matches);
+        let sess = build_session(sessopts, None, registry);
+        assert!(sess.diagnostic().flags.can_emit_warnings);
+    });
+
+    syntax::with_default_globals(|| {
+        let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
+        let registry = errors::registry::Registry::new(&[]);
+        let (sessopts, _) = build_session_options_and_crate_config(&matches);
+        let sess = build_session(sessopts, None, registry);
+        assert!(sess.diagnostic().flags.can_emit_warnings);
+    });
+}
+
+#[test]
+fn test_output_types_tracking_hash_different_paths() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+
+    v1.output_types =
+        OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
+    v2.output_types =
+        OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
+    v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
+
+    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_output_types_tracking_hash_different_construction_order() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+
+    v1.output_types = OutputTypes::new(&[
+        (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
+        (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
+    ]);
+
+    v2.output_types = OutputTypes::new(&[
+        (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
+        (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
+    ]);
+
+    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_externs_tracking_hash_different_construction_order() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+
+    v1.externs = Externs::new(mk_map(vec![
+        (
+            String::from("a"),
+            ExternEntry::new_public(vec![Some("b"), Some("c")])
+        ),
+        (
+            String::from("d"),
+            ExternEntry::new_public(vec![Some("e"), Some("f")])
+        ),
+    ]));
+
+    v2.externs = Externs::new(mk_map(vec![
+        (
+            String::from("d"),
+            ExternEntry::new_public(vec![Some("e"), Some("f")])
+        ),
+        (
+            String::from("a"),
+            ExternEntry::new_public(vec![Some("b"), Some("c")])
+        ),
+    ]));
+
+    v3.externs = Externs::new(mk_map(vec![
+        (
+            String::from("a"),
+            ExternEntry::new_public(vec![Some("b"), Some("c")])
+        ),
+        (
+            String::from("d"),
+            ExternEntry::new_public(vec![Some("f"), Some("e")])
+        ),
+    ]));
+
+    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+    assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_lints_tracking_hash_different_values() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+
+    v1.lint_opts = vec![
+        (String::from("a"), lint::Allow),
+        (String::from("b"), lint::Warn),
+        (String::from("c"), lint::Deny),
+        (String::from("d"), lint::Forbid),
+    ];
+
+    v2.lint_opts = vec![
+        (String::from("a"), lint::Allow),
+        (String::from("b"), lint::Warn),
+        (String::from("X"), lint::Deny),
+        (String::from("d"), lint::Forbid),
+    ];
+
+    v3.lint_opts = vec![
+        (String::from("a"), lint::Allow),
+        (String::from("b"), lint::Warn),
+        (String::from("c"), lint::Forbid),
+        (String::from("d"), lint::Deny),
+    ];
+
+    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_lints_tracking_hash_different_construction_order() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+
+    v1.lint_opts = vec![
+        (String::from("a"), lint::Allow),
+        (String::from("b"), lint::Warn),
+        (String::from("c"), lint::Deny),
+        (String::from("d"), lint::Forbid),
+    ];
+
+    v2.lint_opts = vec![
+        (String::from("a"), lint::Allow),
+        (String::from("c"), lint::Deny),
+        (String::from("b"), lint::Warn),
+        (String::from("d"), lint::Forbid),
+    ];
+
+    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_search_paths_tracking_hash_different_order() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+    let mut v4 = Options::default();
+
+    const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
+        pretty: false,
+        json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
+    };
+
+    // Reference
+    v1.search_paths
+        .push(SearchPath::from_cli_opt("native=abc", JSON));
+    v1.search_paths
+        .push(SearchPath::from_cli_opt("crate=def", JSON));
+    v1.search_paths
+        .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
+    v1.search_paths
+        .push(SearchPath::from_cli_opt("framework=jkl", JSON));
+    v1.search_paths
+        .push(SearchPath::from_cli_opt("all=mno", JSON));
+
+    v2.search_paths
+        .push(SearchPath::from_cli_opt("native=abc", JSON));
+    v2.search_paths
+        .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
+    v2.search_paths
+        .push(SearchPath::from_cli_opt("crate=def", JSON));
+    v2.search_paths
+        .push(SearchPath::from_cli_opt("framework=jkl", JSON));
+    v2.search_paths
+        .push(SearchPath::from_cli_opt("all=mno", JSON));
+
+    v3.search_paths
+        .push(SearchPath::from_cli_opt("crate=def", JSON));
+    v3.search_paths
+        .push(SearchPath::from_cli_opt("framework=jkl", JSON));
+    v3.search_paths
+        .push(SearchPath::from_cli_opt("native=abc", JSON));
+    v3.search_paths
+        .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
+    v3.search_paths
+        .push(SearchPath::from_cli_opt("all=mno", JSON));
+
+    v4.search_paths
+        .push(SearchPath::from_cli_opt("all=mno", JSON));
+    v4.search_paths
+        .push(SearchPath::from_cli_opt("native=abc", JSON));
+    v4.search_paths
+        .push(SearchPath::from_cli_opt("crate=def", JSON));
+    v4.search_paths
+        .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
+    v4.search_paths
+        .push(SearchPath::from_cli_opt("framework=jkl", JSON));
+
+    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_native_libs_tracking_hash_different_values() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+    let mut v4 = Options::default();
+
+    // Reference
+    v1.libs = vec![
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("b"), None, Some(cstore::NativeFramework)),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    // Change label
+    v2.libs = vec![
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("X"), None, Some(cstore::NativeFramework)),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    // Change kind
+    v3.libs = vec![
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("b"), None, Some(cstore::NativeStatic)),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    // Change new-name
+    v4.libs = vec![
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (
+            String::from("b"),
+            Some(String::from("X")),
+            Some(cstore::NativeFramework),
+        ),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_native_libs_tracking_hash_different_order() {
+    let mut v1 = Options::default();
+    let mut v2 = Options::default();
+    let mut v3 = Options::default();
+
+    // Reference
+    v1.libs = vec![
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("b"), None, Some(cstore::NativeFramework)),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    v2.libs = vec![
+        (String::from("b"), None, Some(cstore::NativeFramework)),
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+    ];
+
+    v3.libs = vec![
+        (String::from("c"), None, Some(cstore::NativeUnknown)),
+        (String::from("a"), None, Some(cstore::NativeStatic)),
+        (String::from("b"), None, Some(cstore::NativeFramework)),
+    ];
+
+    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
+    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
+    assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
+
+    // Check clone
+    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+}
+
+#[test]
+fn test_codegen_options_tracking_hash() {
+    let reference = Options::default();
+    let mut opts = Options::default();
+
+    // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
+    opts.cg.ar = Some(String::from("abc"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.linker = Some(PathBuf::from("linker"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.link_dead_code = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.rpath = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.extra_filename = String::from("extra-filename");
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.codegen_units = Some(42);
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.save_temps = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts.cg.incremental = Some(String::from("abc"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    // Make sure changing a [TRACKED] option changes the hash
+    opts = reference.clone();
+    opts.cg.lto = LtoCli::Fat;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.target_cpu = Some(String::from("abc"));
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.target_feature = String::from("all the features, all of them");
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.passes = vec![String::from("1"), String::from("2")];
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.overflow_checks = Some(true);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.no_prepopulate_passes = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.no_vectorize_loops = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.no_vectorize_slp = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.soft_float = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.prefer_dynamic = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.no_integrated_as = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.no_redzone = Some(true);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.relocation_model = Some(String::from("relocation model"));
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.code_model = Some(String::from("code model"));
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.tls_model = Some(String::from("tls model"));
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.pgo_gen = SwitchWithOptPath::Enabled(None);
+    assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
+    assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.metadata = vec![String::from("A"), String::from("B")];
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.debuginfo = Some(0xdeadbeef);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.debuginfo = Some(0xba5eba11);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.force_frame_pointers = Some(false);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.debug_assertions = Some(true);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.inline_threshold = Some(0xf007ba11);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.panic = Some(PanicStrategy::Abort);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+}
+
+#[test]
+fn test_debugging_options_tracking_hash() {
+    let reference = Options::default();
+    let mut opts = Options::default();
+
+    // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
+    opts.debugging_opts.verbose = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.time_passes = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.time_llvm_passes = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.input_stats = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.borrowck_stats = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.meta_stats = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.print_link_args = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.print_llvm_passes = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.ast_json = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.ast_json_noexpand = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.ls = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.save_analysis = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.flowgraph_print_loans = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.flowgraph_print_moves = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.flowgraph_print_assigns = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.flowgraph_print_all = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.print_region_graph = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.parse_only = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.incremental = Some(String::from("abc"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.dump_dep_graph = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.query_dep_graph = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.no_analysis = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.unstable_options = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.trace_macros = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.keep_hygiene_data = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.keep_ast = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.print_mono_items = Some(String::from("abc"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.dump_mir = Some(String::from("abc"));
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.dump_mir_dir = String::from("abc");
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+    opts.debugging_opts.dump_mir_graphviz = true;
+    assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+    // Make sure changing a [TRACKED] option changes the hash
+    opts = reference.clone();
+    opts.debugging_opts.asm_comments = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.verify_llvm_ir = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.no_landing_pads = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.fewer_names = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.no_codegen = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.treat_err_as_bug = Some(1);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.report_delayed_bugs = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.continue_parse_after_error = true;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.force_overflow_checks = Some(true);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.show_span = Some(String::from("abc"));
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.mir_opt_level = 3;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.relro_level = Some(RelroLevel::Full);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+}
+
+#[test]
+fn test_edition_parsing() {
+    // test default edition
+    let options = Options::default();
+    assert!(options.edition == DEFAULT_EDITION);
+
+    let matches = optgroups()
+        .parse(&["--edition=2018".to_string()])
+        .unwrap();
+    let (sessopts, _) = build_session_options_and_crate_config(&matches);
+    assert!(sessopts.edition == Edition::Edition2018)
+}
diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs
index 2b7abcb52bef8..e27cb6d8dda89 100644
--- a/src/librustc_codegen_ssa/back/rpath.rs
+++ b/src/librustc_codegen_ssa/back/rpath.rs
@@ -173,98 +173,4 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
 }
 
 #[cfg(all(unix, test))]
-mod tests {
-    use super::{RPathConfig};
-    use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
-    use std::path::{Path, PathBuf};
-
-    #[test]
-    fn test_rpaths_to_flags() {
-        let flags = rpaths_to_flags(&[
-            "path1".to_string(),
-            "path2".to_string()
-        ]);
-        assert_eq!(flags,
-                   ["-Wl,-rpath,path1",
-                    "-Wl,-rpath,path2"]);
-    }
-
-    #[test]
-    fn test_minimize1() {
-        let res = minimize_rpaths(&[
-            "rpath1".to_string(),
-            "rpath2".to_string(),
-            "rpath1".to_string()
-        ]);
-        assert!(res == [
-            "rpath1",
-            "rpath2",
-        ]);
-    }
-
-    #[test]
-    fn test_minimize2() {
-        let res = minimize_rpaths(&[
-            "1a".to_string(),
-            "2".to_string(),
-            "2".to_string(),
-            "1a".to_string(),
-            "4a".to_string(),
-            "1a".to_string(),
-            "2".to_string(),
-            "3".to_string(),
-            "4a".to_string(),
-            "3".to_string()
-        ]);
-        assert!(res == [
-            "1a",
-            "2",
-            "4a",
-            "3",
-        ]);
-    }
-
-    #[test]
-    fn test_rpath_relative() {
-        if cfg!(target_os = "macos") {
-            let config = &mut RPathConfig {
-                used_crates: Vec::new(),
-                has_rpath: true,
-                is_like_osx: true,
-                linker_is_gnu: false,
-                out_filename: PathBuf::from("bin/rustc"),
-                get_install_prefix_lib_path: &mut || panic!(),
-            };
-            let res = get_rpath_relative_to_output(config,
-                                                   Path::new("lib/libstd.so"));
-            assert_eq!(res, "@loader_path/../lib");
-        } else {
-            let config = &mut RPathConfig {
-                used_crates: Vec::new(),
-                out_filename: PathBuf::from("bin/rustc"),
-                get_install_prefix_lib_path: &mut || panic!(),
-                has_rpath: true,
-                is_like_osx: false,
-                linker_is_gnu: true,
-            };
-            let res = get_rpath_relative_to_output(config,
-                                                   Path::new("lib/libstd.so"));
-            assert_eq!(res, "$ORIGIN/../lib");
-        }
-    }
-
-    #[test]
-    fn test_xlinker() {
-        let args = rpaths_to_flags(&[
-            "a/normal/path".to_string(),
-            "a,comma,path".to_string()
-        ]);
-
-        assert_eq!(args, vec![
-            "-Wl,-rpath,a/normal/path".to_string(),
-            "-Wl,-rpath".to_string(),
-            "-Xlinker".to_string(),
-            "a,comma,path".to_string()
-        ]);
-    }
-}
+mod tests;
diff --git a/src/librustc_codegen_ssa/back/rpath/tests.rs b/src/librustc_codegen_ssa/back/rpath/tests.rs
new file mode 100644
index 0000000000000..e42a878d7e45e
--- /dev/null
+++ b/src/librustc_codegen_ssa/back/rpath/tests.rs
@@ -0,0 +1,93 @@
+use super::{RPathConfig};
+use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
+use std::path::{Path, PathBuf};
+
+#[test]
+fn test_rpaths_to_flags() {
+    let flags = rpaths_to_flags(&[
+        "path1".to_string(),
+        "path2".to_string()
+    ]);
+    assert_eq!(flags,
+               ["-Wl,-rpath,path1",
+                "-Wl,-rpath,path2"]);
+}
+
+#[test]
+fn test_minimize1() {
+    let res = minimize_rpaths(&[
+        "rpath1".to_string(),
+        "rpath2".to_string(),
+        "rpath1".to_string()
+    ]);
+    assert!(res == [
+        "rpath1",
+        "rpath2",
+    ]);
+}
+
+#[test]
+fn test_minimize2() {
+    let res = minimize_rpaths(&[
+        "1a".to_string(),
+        "2".to_string(),
+        "2".to_string(),
+        "1a".to_string(),
+        "4a".to_string(),
+        "1a".to_string(),
+        "2".to_string(),
+        "3".to_string(),
+        "4a".to_string(),
+        "3".to_string()
+    ]);
+    assert!(res == [
+        "1a",
+        "2",
+        "4a",
+        "3",
+    ]);
+}
+
+#[test]
+fn test_rpath_relative() {
+    if cfg!(target_os = "macos") {
+        let config = &mut RPathConfig {
+            used_crates: Vec::new(),
+            has_rpath: true,
+            is_like_osx: true,
+            linker_is_gnu: false,
+            out_filename: PathBuf::from("bin/rustc"),
+            get_install_prefix_lib_path: &mut || panic!(),
+        };
+        let res = get_rpath_relative_to_output(config,
+                                               Path::new("lib/libstd.so"));
+        assert_eq!(res, "@loader_path/../lib");
+    } else {
+        let config = &mut RPathConfig {
+            used_crates: Vec::new(),
+            out_filename: PathBuf::from("bin/rustc"),
+            get_install_prefix_lib_path: &mut || panic!(),
+            has_rpath: true,
+            is_like_osx: false,
+            linker_is_gnu: true,
+        };
+        let res = get_rpath_relative_to_output(config,
+                                               Path::new("lib/libstd.so"));
+        assert_eq!(res, "$ORIGIN/../lib");
+    }
+}
+
+#[test]
+fn test_xlinker() {
+    let args = rpaths_to_flags(&[
+        "a/normal/path".to_string(),
+        "a,comma,path".to_string()
+    ]);
+
+    assert_eq!(args, vec![
+        "-Wl,-rpath,a/normal/path".to_string(),
+        "-Wl,-rpath".to_string(),
+        "-Xlinker".to_string(),
+        "a,comma,path".to_string()
+    ]);
+}
diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs
index 0301891c9b292..a7af615fa5000 100644
--- a/src/librustc_data_structures/owning_ref/mod.rs
+++ b/src/librustc_data_structures/owning_ref/mod.rs
@@ -1221,717 +1221,4 @@ pub type ErasedArcRef<U> = OwningRef<Arc<dyn Erased>, U>;
 pub type ErasedBoxRefMut<U> = OwningRefMut<Box<dyn Erased>, U>;
 
 #[cfg(test)]
-mod tests {
-    mod owning_ref {
-        use super::super::OwningRef;
-        use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef};
-        use std::cmp::{PartialEq, Ord, PartialOrd, Ordering};
-        use std::hash::{Hash, Hasher};
-        use std::collections::hash_map::DefaultHasher;
-        use std::collections::HashMap;
-        use std::rc::Rc;
-
-        #[derive(Debug, PartialEq)]
-        struct Example(u32, String, [u8; 3]);
-        fn example() -> Example {
-            Example(42, "hello world".to_string(), [1, 2, 3])
-        }
-
-        #[test]
-        fn new_deref() {
-            let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
-            assert_eq!(&*or, &());
-        }
-
-        #[test]
-        fn into() {
-            let or: OwningRef<Box<()>, ()> = Box::new(()).into();
-            assert_eq!(&*or, &());
-        }
-
-        #[test]
-        fn map_offset_ref() {
-            let or: BoxRef<Example> = Box::new(example()).into();
-            let or: BoxRef<_, u32> = or.map(|x| &x.0);
-            assert_eq!(&*or, &42);
-
-            let or: BoxRef<Example> = Box::new(example()).into();
-            let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
-            assert_eq!(&*or, &2);
-        }
-
-        #[test]
-        fn map_heap_ref() {
-            let or: BoxRef<Example> = Box::new(example()).into();
-            let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
-            assert_eq!(&*or, "hello");
-        }
-
-        #[test]
-        fn map_static_ref() {
-            let or: BoxRef<()> = Box::new(()).into();
-            let or: BoxRef<_, str> = or.map(|_| "hello");
-            assert_eq!(&*or, "hello");
-        }
-
-        #[test]
-        fn map_chained() {
-            let or: BoxRef<String> = Box::new(example().1).into();
-            let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
-            let or: BoxRef<_, str> = or.map(|x| &x[..2]);
-            assert_eq!(&*or, "el");
-        }
-
-        #[test]
-        fn map_chained_inference() {
-            let or = BoxRef::new(Box::new(example().1))
-                .map(|x| &x[..5])
-                .map(|x| &x[1..3]);
-            assert_eq!(&*or, "el");
-        }
-
-        #[test]
-        fn owner() {
-            let or: BoxRef<String> = Box::new(example().1).into();
-            let or = or.map(|x| &x[..5]);
-            assert_eq!(&*or, "hello");
-            assert_eq!(&**or.owner(), "hello world");
-        }
-
-        #[test]
-        fn into_inner() {
-            let or: BoxRef<String> = Box::new(example().1).into();
-            let or = or.map(|x| &x[..5]);
-            assert_eq!(&*or, "hello");
-            let s = *or.into_inner();
-            assert_eq!(&s, "hello world");
-        }
-
-        #[test]
-        fn fmt_debug() {
-            let or: BoxRef<String> = Box::new(example().1).into();
-            let or = or.map(|x| &x[..5]);
-            let s = format!("{:?}", or);
-            assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
-        }
-
-        #[test]
-        fn erased_owner() {
-            let o1: BoxRef<Example, str> = BoxRef::new(Box::new(example()))
-                .map(|x| &x.1[..]);
-
-            let o2: BoxRef<String, str> = BoxRef::new(Box::new(example().1))
-                .map(|x| &x[..]);
-
-            let os: Vec<ErasedBoxRef<str>> = vec![o1.erase_owner(), o2.erase_owner()];
-            assert!(os.iter().all(|e| &e[..] == "hello world"));
-        }
-
-        #[test]
-        fn raii_locks() {
-            use super::super::{RefRef, RefMutRef};
-            use std::cell::RefCell;
-            use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef};
-            use std::sync::{Mutex, RwLock};
-
-            {
-                let a = RefCell::new(1);
-                let a = {
-                    let a = RefRef::new(a.borrow());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = RefCell::new(1);
-                let a = {
-                    let a = RefMutRef::new(a.borrow_mut());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = Mutex::new(1);
-                let a = {
-                    let a = MutexGuardRef::new(a.lock().unwrap());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = RwLock::new(1);
-                let a = {
-                    let a = RwLockReadGuardRef::new(a.read().unwrap());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = RwLock::new(1);
-                let a = {
-                    let a = RwLockWriteGuardRef::new(a.write().unwrap());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-        }
-
-        #[test]
-        fn eq() {
-            let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-            assert_eq!(or1.eq(&or2), true);
-        }
-
-        #[test]
-        fn cmp() {
-            let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
-            assert_eq!(or1.cmp(&or2), Ordering::Less);
-        }
-
-        #[test]
-        fn partial_cmp() {
-            let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
-            let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-            assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
-        }
-
-        #[test]
-        fn hash() {
-            let mut h1 = DefaultHasher::new();
-            let mut h2 = DefaultHasher::new();
-
-            let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
-
-            or1.hash(&mut h1);
-            or2.hash(&mut h2);
-
-            assert_eq!(h1.finish(), h2.finish());
-        }
-
-        #[test]
-        fn borrow() {
-            let mut hash = HashMap::new();
-            let     key  = RcRef::<String>::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]);
-
-            hash.insert(key.clone().map(|s| &s[..3]), 42);
-            hash.insert(key.clone().map(|s| &s[4..]), 23);
-
-            assert_eq!(hash.get("foo"), Some(&42));
-            assert_eq!(hash.get("bar"), Some(&23));
-        }
-
-        #[test]
-        fn total_erase() {
-            let a: OwningRef<Vec<u8>, [u8]>
-                = OwningRef::new(vec![]).map(|x| &x[..]);
-            let b: OwningRef<Box<[u8]>, [u8]>
-                = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
-
-            let c: OwningRef<Rc<Vec<u8>>, [u8]> = unsafe {a.map_owner(Rc::new)};
-            let d: OwningRef<Rc<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Rc::new)};
-
-            let e: OwningRef<Rc<dyn Erased>, [u8]> = c.erase_owner();
-            let f: OwningRef<Rc<dyn Erased>, [u8]> = d.erase_owner();
-
-            let _g = e.clone();
-            let _h = f.clone();
-        }
-
-        #[test]
-        fn total_erase_box() {
-            let a: OwningRef<Vec<u8>, [u8]>
-                = OwningRef::new(vec![]).map(|x| &x[..]);
-            let b: OwningRef<Box<[u8]>, [u8]>
-                = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
-
-            let c: OwningRef<Box<Vec<u8>>, [u8]> = a.map_owner_box();
-            let d: OwningRef<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
-
-            let _e: OwningRef<Box<dyn Erased>, [u8]> = c.erase_owner();
-            let _f: OwningRef<Box<dyn Erased>, [u8]> = d.erase_owner();
-        }
-
-        #[test]
-        fn try_map1() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
-        }
-
-        #[test]
-        fn try_map2() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(!OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
-        }
-    }
-
-    mod owning_handle {
-        use super::super::OwningHandle;
-        use super::super::RcRef;
-        use std::rc::Rc;
-        use std::cell::RefCell;
-        use std::sync::Arc;
-        use std::sync::RwLock;
-
-        #[test]
-        fn owning_handle() {
-            use std::cell::RefCell;
-            let cell = Rc::new(RefCell::new(2));
-            let cell_ref = RcRef::new(cell);
-            let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
-            assert_eq!(*handle, 2);
-            *handle = 3;
-            assert_eq!(*handle, 3);
-        }
-
-        #[test]
-        fn try_owning_handle_ok() {
-            use std::cell::RefCell;
-            let cell = Rc::new(RefCell::new(2));
-            let cell_ref = RcRef::new(cell);
-            let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
-                Ok(unsafe {
-                    x.as_ref()
-                }.unwrap().borrow_mut())
-            }).unwrap();
-            assert_eq!(*handle, 2);
-            *handle = 3;
-            assert_eq!(*handle, 3);
-        }
-
-        #[test]
-        fn try_owning_handle_err() {
-            use std::cell::RefCell;
-            let cell = Rc::new(RefCell::new(2));
-            let cell_ref = RcRef::new(cell);
-            let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
-                if false {
-                    return Ok(unsafe {
-                        x.as_ref()
-                    }.unwrap().borrow_mut())
-                }
-                Err(())
-            });
-            assert!(handle.is_err());
-        }
-
-        #[test]
-        fn nested() {
-            use std::cell::RefCell;
-            use std::sync::{Arc, RwLock};
-
-            let result = {
-                let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
-                let curr = RcRef::new(complex);
-                let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
-                let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
-                assert_eq!(*curr, "someString");
-                *curr = "someOtherString";
-                curr
-            };
-            assert_eq!(*result, "someOtherString");
-        }
-
-        #[test]
-        fn owning_handle_safe() {
-            use std::cell::RefCell;
-            let cell = Rc::new(RefCell::new(2));
-            let cell_ref = RcRef::new(cell);
-            let handle = OwningHandle::new(cell_ref);
-            assert_eq!(*handle, 2);
-        }
-
-        #[test]
-        fn owning_handle_mut_safe() {
-            use std::cell::RefCell;
-            let cell = Rc::new(RefCell::new(2));
-            let cell_ref = RcRef::new(cell);
-            let mut handle = OwningHandle::new_mut(cell_ref);
-            assert_eq!(*handle, 2);
-            *handle = 3;
-            assert_eq!(*handle, 3);
-        }
-
-        #[test]
-        fn owning_handle_safe_2() {
-            let result = {
-                let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
-                let curr = RcRef::new(complex);
-                let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
-                let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
-                assert_eq!(*curr, "someString");
-                *curr = "someOtherString";
-                curr
-            };
-            assert_eq!(*result, "someOtherString");
-        }
-    }
-
-    mod owning_ref_mut {
-        use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut};
-        use super::super::BoxRef;
-        use std::cmp::{PartialEq, Ord, PartialOrd, Ordering};
-        use std::hash::{Hash, Hasher};
-        use std::collections::hash_map::DefaultHasher;
-        use std::collections::HashMap;
-
-        #[derive(Debug, PartialEq)]
-        struct Example(u32, String, [u8; 3]);
-        fn example() -> Example {
-            Example(42, "hello world".to_string(), [1, 2, 3])
-        }
-
-        #[test]
-        fn new_deref() {
-            let or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
-            assert_eq!(&*or, &());
-        }
-
-        #[test]
-        fn new_deref_mut() {
-            let mut or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
-            assert_eq!(&mut *or, &mut ());
-        }
-
-        #[test]
-        fn mutate() {
-            let mut or: OwningRefMut<Box<usize>, usize> = OwningRefMut::new(Box::new(0));
-            assert_eq!(&*or, &0);
-            *or = 1;
-            assert_eq!(&*or, &1);
-        }
-
-        #[test]
-        fn into() {
-            let or: OwningRefMut<Box<()>, ()> = Box::new(()).into();
-            assert_eq!(&*or, &());
-        }
-
-        #[test]
-        fn map_offset_ref() {
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRef<_, u32> = or.map(|x| &mut x.0);
-            assert_eq!(&*or, &42);
-
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]);
-            assert_eq!(&*or, &2);
-        }
-
-        #[test]
-        fn map_heap_ref() {
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]);
-            assert_eq!(&*or, "hello");
-        }
-
-        #[test]
-        fn map_static_ref() {
-            let or: BoxRefMut<()> = Box::new(()).into();
-            let or: BoxRef<_, str> = or.map(|_| "hello");
-            assert_eq!(&*or, "hello");
-        }
-
-        #[test]
-        fn map_mut_offset_ref() {
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0);
-            assert_eq!(&*or, &42);
-
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]);
-            assert_eq!(&*or, &2);
-        }
-
-        #[test]
-        fn map_mut_heap_ref() {
-            let or: BoxRefMut<Example> = Box::new(example()).into();
-            let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]);
-            assert_eq!(&*or, "hello");
-        }
-
-        #[test]
-        fn map_mut_static_ref() {
-            static mut MUT_S: [u8; 5] = *b"hello";
-
-            let mut_s: &'static mut [u8] = unsafe { &mut MUT_S };
-
-            let or: BoxRefMut<()> = Box::new(()).into();
-            let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s);
-            assert_eq!(&*or, b"hello");
-        }
-
-        #[test]
-        fn map_mut_chained() {
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]);
-            let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]);
-            assert_eq!(&*or, "el");
-        }
-
-        #[test]
-        fn map_chained_inference() {
-            let or = BoxRefMut::new(Box::new(example().1))
-                .map_mut(|x| &mut x[..5])
-                .map_mut(|x| &mut x[1..3]);
-            assert_eq!(&*or, "el");
-        }
-
-        #[test]
-        fn try_map_mut() {
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|x| Ok(&mut x[1..5]));
-            assert_eq!(&*or.unwrap(), "ello");
-
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|_| Err(()));
-            assert!(or.is_err());
-        }
-
-        #[test]
-        fn owner() {
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or = or.map_mut(|x| &mut x[..5]);
-            assert_eq!(&*or, "hello");
-            assert_eq!(&**or.owner(), "hello world");
-        }
-
-        #[test]
-        fn into_inner() {
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or = or.map_mut(|x| &mut x[..5]);
-            assert_eq!(&*or, "hello");
-            let s = *or.into_inner();
-            assert_eq!(&s, "hello world");
-        }
-
-        #[test]
-        fn fmt_debug() {
-            let or: BoxRefMut<String> = Box::new(example().1).into();
-            let or = or.map_mut(|x| &mut x[..5]);
-            let s = format!("{:?}", or);
-            assert_eq!(&s,
-                       "OwningRefMut { owner: \"hello world\", reference: \"hello\" }");
-        }
-
-        #[test]
-        fn erased_owner() {
-            let o1: BoxRefMut<Example, str> = BoxRefMut::new(Box::new(example()))
-                .map_mut(|x| &mut x.1[..]);
-
-            let o2: BoxRefMut<String, str> = BoxRefMut::new(Box::new(example().1))
-                .map_mut(|x| &mut x[..]);
-
-            let os: Vec<ErasedBoxRefMut<str>> = vec![o1.erase_owner(), o2.erase_owner()];
-            assert!(os.iter().all(|e| &e[..] == "hello world"));
-        }
-
-        #[test]
-        fn raii_locks() {
-            use super::super::RefMutRefMut;
-            use std::cell::RefCell;
-            use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut};
-            use std::sync::{Mutex, RwLock};
-
-            {
-                let a = RefCell::new(1);
-                let a = {
-                    let a = RefMutRefMut::new(a.borrow_mut());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = Mutex::new(1);
-                let a = {
-                    let a = MutexGuardRefMut::new(a.lock().unwrap());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-            {
-                let a = RwLock::new(1);
-                let a = {
-                    let a = RwLockWriteGuardRefMut::new(a.write().unwrap());
-                    assert_eq!(*a, 1);
-                    a
-                };
-                assert_eq!(*a, 1);
-                drop(a);
-            }
-        }
-
-        #[test]
-        fn eq() {
-            let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-            assert_eq!(or1.eq(&or2), true);
-        }
-
-        #[test]
-        fn cmp() {
-            let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
-            assert_eq!(or1.cmp(&or2), Ordering::Less);
-        }
-
-        #[test]
-        fn partial_cmp() {
-            let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
-            let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-            assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
-        }
-
-        #[test]
-        fn hash() {
-            let mut h1 = DefaultHasher::new();
-            let mut h2 = DefaultHasher::new();
-
-            let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-            let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
-
-            or1.hash(&mut h1);
-            or2.hash(&mut h2);
-
-            assert_eq!(h1.finish(), h2.finish());
-        }
-
-        #[test]
-        fn borrow() {
-            let mut hash = HashMap::new();
-            let     key1 = BoxRefMut::<String>::new(Box::new("foo".to_string())).map(|s| &s[..]);
-            let     key2 = BoxRefMut::<String>::new(Box::new("bar".to_string())).map(|s| &s[..]);
-
-            hash.insert(key1, 42);
-            hash.insert(key2, 23);
-
-            assert_eq!(hash.get("foo"), Some(&42));
-            assert_eq!(hash.get("bar"), Some(&23));
-        }
-
-        #[test]
-        fn total_erase() {
-            let a: OwningRefMut<Vec<u8>, [u8]>
-                = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
-            let b: OwningRefMut<Box<[u8]>, [u8]>
-                = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
-
-            let c: OwningRefMut<Box<Vec<u8>>, [u8]> = unsafe {a.map_owner(Box::new)};
-            let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Box::new)};
-
-            let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
-            let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
-        }
-
-        #[test]
-        fn total_erase_box() {
-            let a: OwningRefMut<Vec<u8>, [u8]>
-                = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
-            let b: OwningRefMut<Box<[u8]>, [u8]>
-                = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
-
-            let c: OwningRefMut<Box<Vec<u8>>, [u8]> = a.map_owner_box();
-            let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
-
-            let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
-            let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
-        }
-
-        #[test]
-        fn try_map1() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_ok());
-        }
-
-        #[test]
-        fn try_map2() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(!OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_err());
-        }
-
-        #[test]
-        fn try_map3() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
-        }
-
-        #[test]
-        fn try_map4() {
-            use std::any::Any;
-
-            let x = Box::new(123_i32);
-            let y: Box<dyn Any> = x;
-
-            assert!(!OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
-        }
-
-        #[test]
-        fn into_owning_ref() {
-            use super::super::BoxRef;
-
-            let or: BoxRefMut<()> = Box::new(()).into();
-            let or: BoxRef<()> = or.into();
-            assert_eq!(&*or, &());
-        }
-
-        struct Foo {
-            u: u32,
-        }
-        struct Bar {
-            f: Foo,
-        }
-
-        #[test]
-        fn ref_mut() {
-            use std::cell::RefCell;
-
-            let a = RefCell::new(Bar { f: Foo { u: 42 } });
-            let mut b = OwningRefMut::new(a.borrow_mut());
-            assert_eq!(b.f.u, 42);
-            b.f.u = 43;
-            let mut c = b.map_mut(|x| &mut x.f);
-            assert_eq!(c.u, 43);
-            c.u = 44;
-            let mut d = c.map_mut(|x| &mut x.u);
-            assert_eq!(*d, 44);
-            *d = 45;
-            assert_eq!(*d, 45);
-        }
-    }
-}
+mod tests;
diff --git a/src/librustc_data_structures/owning_ref/tests.rs b/src/librustc_data_structures/owning_ref/tests.rs
new file mode 100644
index 0000000000000..d368219cab3eb
--- /dev/null
+++ b/src/librustc_data_structures/owning_ref/tests.rs
@@ -0,0 +1,712 @@
+mod owning_ref {
+    use super::super::OwningRef;
+    use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef};
+    use std::cmp::{PartialEq, Ord, PartialOrd, Ordering};
+    use std::hash::{Hash, Hasher};
+    use std::collections::hash_map::DefaultHasher;
+    use std::collections::HashMap;
+    use std::rc::Rc;
+
+    #[derive(Debug, PartialEq)]
+    struct Example(u32, String, [u8; 3]);
+    fn example() -> Example {
+        Example(42, "hello world".to_string(), [1, 2, 3])
+    }
+
+    #[test]
+    fn new_deref() {
+        let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
+        assert_eq!(&*or, &());
+    }
+
+    #[test]
+    fn into() {
+        let or: OwningRef<Box<()>, ()> = Box::new(()).into();
+        assert_eq!(&*or, &());
+    }
+
+    #[test]
+    fn map_offset_ref() {
+        let or: BoxRef<Example> = Box::new(example()).into();
+        let or: BoxRef<_, u32> = or.map(|x| &x.0);
+        assert_eq!(&*or, &42);
+
+        let or: BoxRef<Example> = Box::new(example()).into();
+        let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
+        assert_eq!(&*or, &2);
+    }
+
+    #[test]
+    fn map_heap_ref() {
+        let or: BoxRef<Example> = Box::new(example()).into();
+        let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
+        assert_eq!(&*or, "hello");
+    }
+
+    #[test]
+    fn map_static_ref() {
+        let or: BoxRef<()> = Box::new(()).into();
+        let or: BoxRef<_, str> = or.map(|_| "hello");
+        assert_eq!(&*or, "hello");
+    }
+
+    #[test]
+    fn map_chained() {
+        let or: BoxRef<String> = Box::new(example().1).into();
+        let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
+        let or: BoxRef<_, str> = or.map(|x| &x[..2]);
+        assert_eq!(&*or, "el");
+    }
+
+    #[test]
+    fn map_chained_inference() {
+        let or = BoxRef::new(Box::new(example().1))
+            .map(|x| &x[..5])
+            .map(|x| &x[1..3]);
+        assert_eq!(&*or, "el");
+    }
+
+    #[test]
+    fn owner() {
+        let or: BoxRef<String> = Box::new(example().1).into();
+        let or = or.map(|x| &x[..5]);
+        assert_eq!(&*or, "hello");
+        assert_eq!(&**or.owner(), "hello world");
+    }
+
+    #[test]
+    fn into_inner() {
+        let or: BoxRef<String> = Box::new(example().1).into();
+        let or = or.map(|x| &x[..5]);
+        assert_eq!(&*or, "hello");
+        let s = *or.into_inner();
+        assert_eq!(&s, "hello world");
+    }
+
+    #[test]
+    fn fmt_debug() {
+        let or: BoxRef<String> = Box::new(example().1).into();
+        let or = or.map(|x| &x[..5]);
+        let s = format!("{:?}", or);
+        assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
+    }
+
+    #[test]
+    fn erased_owner() {
+        let o1: BoxRef<Example, str> = BoxRef::new(Box::new(example()))
+            .map(|x| &x.1[..]);
+
+        let o2: BoxRef<String, str> = BoxRef::new(Box::new(example().1))
+            .map(|x| &x[..]);
+
+        let os: Vec<ErasedBoxRef<str>> = vec![o1.erase_owner(), o2.erase_owner()];
+        assert!(os.iter().all(|e| &e[..] == "hello world"));
+    }
+
+    #[test]
+    fn raii_locks() {
+        use super::super::{RefRef, RefMutRef};
+        use std::cell::RefCell;
+        use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef};
+        use std::sync::{Mutex, RwLock};
+
+        {
+            let a = RefCell::new(1);
+            let a = {
+                let a = RefRef::new(a.borrow());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = RefCell::new(1);
+            let a = {
+                let a = RefMutRef::new(a.borrow_mut());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = Mutex::new(1);
+            let a = {
+                let a = MutexGuardRef::new(a.lock().unwrap());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = RwLock::new(1);
+            let a = {
+                let a = RwLockReadGuardRef::new(a.read().unwrap());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = RwLock::new(1);
+            let a = {
+                let a = RwLockWriteGuardRef::new(a.write().unwrap());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+    }
+
+    #[test]
+    fn eq() {
+        let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+        assert_eq!(or1.eq(&or2), true);
+    }
+
+    #[test]
+    fn cmp() {
+        let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
+        assert_eq!(or1.cmp(&or2), Ordering::Less);
+    }
+
+    #[test]
+    fn partial_cmp() {
+        let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
+        let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+        assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
+    }
+
+    #[test]
+    fn hash() {
+        let mut h1 = DefaultHasher::new();
+        let mut h2 = DefaultHasher::new();
+
+        let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
+
+        or1.hash(&mut h1);
+        or2.hash(&mut h2);
+
+        assert_eq!(h1.finish(), h2.finish());
+    }
+
+    #[test]
+    fn borrow() {
+        let mut hash = HashMap::new();
+        let     key  = RcRef::<String>::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]);
+
+        hash.insert(key.clone().map(|s| &s[..3]), 42);
+        hash.insert(key.clone().map(|s| &s[4..]), 23);
+
+        assert_eq!(hash.get("foo"), Some(&42));
+        assert_eq!(hash.get("bar"), Some(&23));
+    }
+
+    #[test]
+    fn total_erase() {
+        let a: OwningRef<Vec<u8>, [u8]>
+            = OwningRef::new(vec![]).map(|x| &x[..]);
+        let b: OwningRef<Box<[u8]>, [u8]>
+            = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
+
+        let c: OwningRef<Rc<Vec<u8>>, [u8]> = unsafe {a.map_owner(Rc::new)};
+        let d: OwningRef<Rc<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Rc::new)};
+
+        let e: OwningRef<Rc<dyn Erased>, [u8]> = c.erase_owner();
+        let f: OwningRef<Rc<dyn Erased>, [u8]> = d.erase_owner();
+
+        let _g = e.clone();
+        let _h = f.clone();
+    }
+
+    #[test]
+    fn total_erase_box() {
+        let a: OwningRef<Vec<u8>, [u8]>
+            = OwningRef::new(vec![]).map(|x| &x[..]);
+        let b: OwningRef<Box<[u8]>, [u8]>
+            = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
+
+        let c: OwningRef<Box<Vec<u8>>, [u8]> = a.map_owner_box();
+        let d: OwningRef<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
+
+        let _e: OwningRef<Box<dyn Erased>, [u8]> = c.erase_owner();
+        let _f: OwningRef<Box<dyn Erased>, [u8]> = d.erase_owner();
+    }
+
+    #[test]
+    fn try_map1() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
+    }
+
+    #[test]
+    fn try_map2() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(!OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
+    }
+}
+
+mod owning_handle {
+    use super::super::OwningHandle;
+    use super::super::RcRef;
+    use std::rc::Rc;
+    use std::cell::RefCell;
+    use std::sync::Arc;
+    use std::sync::RwLock;
+
+    #[test]
+    fn owning_handle() {
+        use std::cell::RefCell;
+        let cell = Rc::new(RefCell::new(2));
+        let cell_ref = RcRef::new(cell);
+        let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
+        assert_eq!(*handle, 2);
+        *handle = 3;
+        assert_eq!(*handle, 3);
+    }
+
+    #[test]
+    fn try_owning_handle_ok() {
+        use std::cell::RefCell;
+        let cell = Rc::new(RefCell::new(2));
+        let cell_ref = RcRef::new(cell);
+        let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
+            Ok(unsafe {
+                x.as_ref()
+            }.unwrap().borrow_mut())
+        }).unwrap();
+        assert_eq!(*handle, 2);
+        *handle = 3;
+        assert_eq!(*handle, 3);
+    }
+
+    #[test]
+    fn try_owning_handle_err() {
+        use std::cell::RefCell;
+        let cell = Rc::new(RefCell::new(2));
+        let cell_ref = RcRef::new(cell);
+        let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
+            if false {
+                return Ok(unsafe {
+                    x.as_ref()
+                }.unwrap().borrow_mut())
+            }
+            Err(())
+        });
+        assert!(handle.is_err());
+    }
+
+    #[test]
+    fn nested() {
+        use std::cell::RefCell;
+        use std::sync::{Arc, RwLock};
+
+        let result = {
+            let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
+            let curr = RcRef::new(complex);
+            let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
+            let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
+            assert_eq!(*curr, "someString");
+            *curr = "someOtherString";
+            curr
+        };
+        assert_eq!(*result, "someOtherString");
+    }
+
+    #[test]
+    fn owning_handle_safe() {
+        use std::cell::RefCell;
+        let cell = Rc::new(RefCell::new(2));
+        let cell_ref = RcRef::new(cell);
+        let handle = OwningHandle::new(cell_ref);
+        assert_eq!(*handle, 2);
+    }
+
+    #[test]
+    fn owning_handle_mut_safe() {
+        use std::cell::RefCell;
+        let cell = Rc::new(RefCell::new(2));
+        let cell_ref = RcRef::new(cell);
+        let mut handle = OwningHandle::new_mut(cell_ref);
+        assert_eq!(*handle, 2);
+        *handle = 3;
+        assert_eq!(*handle, 3);
+    }
+
+    #[test]
+    fn owning_handle_safe_2() {
+        let result = {
+            let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
+            let curr = RcRef::new(complex);
+            let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
+            let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
+            assert_eq!(*curr, "someString");
+            *curr = "someOtherString";
+            curr
+        };
+        assert_eq!(*result, "someOtherString");
+    }
+}
+
+mod owning_ref_mut {
+    use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut};
+    use super::super::BoxRef;
+    use std::cmp::{PartialEq, Ord, PartialOrd, Ordering};
+    use std::hash::{Hash, Hasher};
+    use std::collections::hash_map::DefaultHasher;
+    use std::collections::HashMap;
+
+    #[derive(Debug, PartialEq)]
+    struct Example(u32, String, [u8; 3]);
+    fn example() -> Example {
+        Example(42, "hello world".to_string(), [1, 2, 3])
+    }
+
+    #[test]
+    fn new_deref() {
+        let or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
+        assert_eq!(&*or, &());
+    }
+
+    #[test]
+    fn new_deref_mut() {
+        let mut or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
+        assert_eq!(&mut *or, &mut ());
+    }
+
+    #[test]
+    fn mutate() {
+        let mut or: OwningRefMut<Box<usize>, usize> = OwningRefMut::new(Box::new(0));
+        assert_eq!(&*or, &0);
+        *or = 1;
+        assert_eq!(&*or, &1);
+    }
+
+    #[test]
+    fn into() {
+        let or: OwningRefMut<Box<()>, ()> = Box::new(()).into();
+        assert_eq!(&*or, &());
+    }
+
+    #[test]
+    fn map_offset_ref() {
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRef<_, u32> = or.map(|x| &mut x.0);
+        assert_eq!(&*or, &42);
+
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]);
+        assert_eq!(&*or, &2);
+    }
+
+    #[test]
+    fn map_heap_ref() {
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]);
+        assert_eq!(&*or, "hello");
+    }
+
+    #[test]
+    fn map_static_ref() {
+        let or: BoxRefMut<()> = Box::new(()).into();
+        let or: BoxRef<_, str> = or.map(|_| "hello");
+        assert_eq!(&*or, "hello");
+    }
+
+    #[test]
+    fn map_mut_offset_ref() {
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0);
+        assert_eq!(&*or, &42);
+
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]);
+        assert_eq!(&*or, &2);
+    }
+
+    #[test]
+    fn map_mut_heap_ref() {
+        let or: BoxRefMut<Example> = Box::new(example()).into();
+        let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]);
+        assert_eq!(&*or, "hello");
+    }
+
+    #[test]
+    fn map_mut_static_ref() {
+        static mut MUT_S: [u8; 5] = *b"hello";
+
+        let mut_s: &'static mut [u8] = unsafe { &mut MUT_S };
+
+        let or: BoxRefMut<()> = Box::new(()).into();
+        let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s);
+        assert_eq!(&*or, b"hello");
+    }
+
+    #[test]
+    fn map_mut_chained() {
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]);
+        let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]);
+        assert_eq!(&*or, "el");
+    }
+
+    #[test]
+    fn map_chained_inference() {
+        let or = BoxRefMut::new(Box::new(example().1))
+            .map_mut(|x| &mut x[..5])
+            .map_mut(|x| &mut x[1..3]);
+        assert_eq!(&*or, "el");
+    }
+
+    #[test]
+    fn try_map_mut() {
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|x| Ok(&mut x[1..5]));
+        assert_eq!(&*or.unwrap(), "ello");
+
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|_| Err(()));
+        assert!(or.is_err());
+    }
+
+    #[test]
+    fn owner() {
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or = or.map_mut(|x| &mut x[..5]);
+        assert_eq!(&*or, "hello");
+        assert_eq!(&**or.owner(), "hello world");
+    }
+
+    #[test]
+    fn into_inner() {
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or = or.map_mut(|x| &mut x[..5]);
+        assert_eq!(&*or, "hello");
+        let s = *or.into_inner();
+        assert_eq!(&s, "hello world");
+    }
+
+    #[test]
+    fn fmt_debug() {
+        let or: BoxRefMut<String> = Box::new(example().1).into();
+        let or = or.map_mut(|x| &mut x[..5]);
+        let s = format!("{:?}", or);
+        assert_eq!(&s,
+                   "OwningRefMut { owner: \"hello world\", reference: \"hello\" }");
+    }
+
+    #[test]
+    fn erased_owner() {
+        let o1: BoxRefMut<Example, str> = BoxRefMut::new(Box::new(example()))
+            .map_mut(|x| &mut x.1[..]);
+
+        let o2: BoxRefMut<String, str> = BoxRefMut::new(Box::new(example().1))
+            .map_mut(|x| &mut x[..]);
+
+        let os: Vec<ErasedBoxRefMut<str>> = vec![o1.erase_owner(), o2.erase_owner()];
+        assert!(os.iter().all(|e| &e[..] == "hello world"));
+    }
+
+    #[test]
+    fn raii_locks() {
+        use super::super::RefMutRefMut;
+        use std::cell::RefCell;
+        use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut};
+        use std::sync::{Mutex, RwLock};
+
+        {
+            let a = RefCell::new(1);
+            let a = {
+                let a = RefMutRefMut::new(a.borrow_mut());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = Mutex::new(1);
+            let a = {
+                let a = MutexGuardRefMut::new(a.lock().unwrap());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+        {
+            let a = RwLock::new(1);
+            let a = {
+                let a = RwLockWriteGuardRefMut::new(a.write().unwrap());
+                assert_eq!(*a, 1);
+                a
+            };
+            assert_eq!(*a, 1);
+            drop(a);
+        }
+    }
+
+    #[test]
+    fn eq() {
+        let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+        assert_eq!(or1.eq(&or2), true);
+    }
+
+    #[test]
+    fn cmp() {
+        let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
+        assert_eq!(or1.cmp(&or2), Ordering::Less);
+    }
+
+    #[test]
+    fn partial_cmp() {
+        let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
+        let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+        assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
+    }
+
+    #[test]
+    fn hash() {
+        let mut h1 = DefaultHasher::new();
+        let mut h2 = DefaultHasher::new();
+
+        let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+        let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
+
+        or1.hash(&mut h1);
+        or2.hash(&mut h2);
+
+        assert_eq!(h1.finish(), h2.finish());
+    }
+
+    #[test]
+    fn borrow() {
+        let mut hash = HashMap::new();
+        let     key1 = BoxRefMut::<String>::new(Box::new("foo".to_string())).map(|s| &s[..]);
+        let     key2 = BoxRefMut::<String>::new(Box::new("bar".to_string())).map(|s| &s[..]);
+
+        hash.insert(key1, 42);
+        hash.insert(key2, 23);
+
+        assert_eq!(hash.get("foo"), Some(&42));
+        assert_eq!(hash.get("bar"), Some(&23));
+    }
+
+    #[test]
+    fn total_erase() {
+        let a: OwningRefMut<Vec<u8>, [u8]>
+            = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
+        let b: OwningRefMut<Box<[u8]>, [u8]>
+            = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
+
+        let c: OwningRefMut<Box<Vec<u8>>, [u8]> = unsafe {a.map_owner(Box::new)};
+        let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Box::new)};
+
+        let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
+        let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
+    }
+
+    #[test]
+    fn total_erase_box() {
+        let a: OwningRefMut<Vec<u8>, [u8]>
+            = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
+        let b: OwningRefMut<Box<[u8]>, [u8]>
+            = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
+
+        let c: OwningRefMut<Box<Vec<u8>>, [u8]> = a.map_owner_box();
+        let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
+
+        let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
+        let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
+    }
+
+    #[test]
+    fn try_map1() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_ok());
+    }
+
+    #[test]
+    fn try_map2() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(!OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_err());
+    }
+
+    #[test]
+    fn try_map3() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
+    }
+
+    #[test]
+    fn try_map4() {
+        use std::any::Any;
+
+        let x = Box::new(123_i32);
+        let y: Box<dyn Any> = x;
+
+        assert!(!OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
+    }
+
+    #[test]
+    fn into_owning_ref() {
+        use super::super::BoxRef;
+
+        let or: BoxRefMut<()> = Box::new(()).into();
+        let or: BoxRef<()> = or.into();
+        assert_eq!(&*or, &());
+    }
+
+    struct Foo {
+        u: u32,
+    }
+    struct Bar {
+        f: Foo,
+    }
+
+    #[test]
+    fn ref_mut() {
+        use std::cell::RefCell;
+
+        let a = RefCell::new(Bar { f: Foo { u: 42 } });
+        let mut b = OwningRefMut::new(a.borrow_mut());
+        assert_eq!(b.f.u, 42);
+        b.f.u = 43;
+        let mut c = b.map_mut(|x| &mut x.f);
+        assert_eq!(c.u, 43);
+        c.u = 44;
+        let mut d = c.map_mut(|x| &mut x.u);
+        assert_eq!(*d, 44);
+        *d = 45;
+        assert_eq!(*d, 45);
+    }
+}
diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs
index 1f674c1c664e4..fb819dd18a8d6 100644
--- a/src/librustc_data_structures/sorted_map.rs
+++ b/src/librustc_data_structures/sorted_map.rs
@@ -305,204 +305,4 @@ impl<K: Ord, V> FromIterator<(K, V)> for SortedMap<K, V> {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::SortedMap;
-
-    #[test]
-    fn test_insert_and_iter() {
-        let mut map = SortedMap::new();
-        let mut expected = Vec::new();
-
-        for x in 0 .. 100 {
-            assert_eq!(map.iter().cloned().collect::<Vec<_>>(), expected);
-
-            let x = 1000 - x * 2;
-            map.insert(x, x);
-            expected.insert(0, (x, x));
-        }
-    }
-
-    #[test]
-    fn test_get_and_index() {
-        let mut map = SortedMap::new();
-        let mut expected = Vec::new();
-
-        for x in 0 .. 100 {
-            let x = 1000 - x;
-            if x & 1 == 0 {
-                map.insert(x, x);
-            }
-            expected.push(x);
-        }
-
-        for mut x in expected {
-            if x & 1 == 0 {
-                assert_eq!(map.get(&x), Some(&x));
-                assert_eq!(map.get_mut(&x), Some(&mut x));
-                assert_eq!(map[&x], x);
-                assert_eq!(&mut map[&x], &mut x);
-            } else {
-                assert_eq!(map.get(&x), None);
-                assert_eq!(map.get_mut(&x), None);
-            }
-        }
-    }
-
-    #[test]
-    fn test_range() {
-        let mut map = SortedMap::new();
-        map.insert(1, 1);
-        map.insert(3, 3);
-        map.insert(6, 6);
-        map.insert(9, 9);
-
-        let keys = |s: &[(_, _)]| {
-            s.into_iter().map(|e| e.0).collect::<Vec<u32>>()
-        };
-
-        for start in 0 .. 11 {
-            for end in 0 .. 11 {
-                if end < start {
-                    continue
-                }
-
-                let mut expected = vec![1, 3, 6, 9];
-                expected.retain(|&x| x >= start && x < end);
-
-                assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end);
-            }
-        }
-    }
-
-
-    #[test]
-    fn test_offset_keys() {
-        let mut map = SortedMap::new();
-        map.insert(1, 1);
-        map.insert(3, 3);
-        map.insert(6, 6);
-
-        map.offset_keys(|k| *k += 1);
-
-        let mut expected = SortedMap::new();
-        expected.insert(2, 1);
-        expected.insert(4, 3);
-        expected.insert(7, 6);
-
-        assert_eq!(map, expected);
-    }
-
-    fn keys(s: SortedMap<u32, u32>) -> Vec<u32> {
-        s.into_iter().map(|(k, _)| k).collect::<Vec<u32>>()
-    }
-
-    fn elements(s: SortedMap<u32, u32>) -> Vec<(u32, u32)> {
-        s.into_iter().collect::<Vec<(u32, u32)>>()
-    }
-
-    #[test]
-    fn test_remove_range() {
-        let mut map = SortedMap::new();
-        map.insert(1, 1);
-        map.insert(3, 3);
-        map.insert(6, 6);
-        map.insert(9, 9);
-
-        for start in 0 .. 11 {
-            for end in 0 .. 11 {
-                if end < start {
-                    continue
-                }
-
-                let mut expected = vec![1, 3, 6, 9];
-                expected.retain(|&x| x < start || x >= end);
-
-                let mut map = map.clone();
-                map.remove_range(start .. end);
-
-                assert_eq!(keys(map), expected, "range = {}..{}", start, end);
-            }
-        }
-    }
-
-    #[test]
-    fn test_remove() {
-        let mut map = SortedMap::new();
-        let mut expected = Vec::new();
-
-        for x in 0..10 {
-            map.insert(x, x);
-            expected.push((x, x));
-        }
-
-        for x in 0 .. 10 {
-            let mut map = map.clone();
-            let mut expected = expected.clone();
-
-            assert_eq!(map.remove(&x), Some(x));
-            expected.remove(x as usize);
-
-            assert_eq!(map.iter().cloned().collect::<Vec<_>>(), expected);
-        }
-    }
-
-    #[test]
-    fn test_insert_presorted_non_overlapping() {
-        let mut map = SortedMap::new();
-        map.insert(2, 0);
-        map.insert(8, 0);
-
-        map.insert_presorted(vec![(3, 0), (7, 0)]);
-
-        let expected = vec![2, 3, 7, 8];
-        assert_eq!(keys(map), expected);
-    }
-
-    #[test]
-    fn test_insert_presorted_first_elem_equal() {
-        let mut map = SortedMap::new();
-        map.insert(2, 2);
-        map.insert(8, 8);
-
-        map.insert_presorted(vec![(2, 0), (7, 7)]);
-
-        let expected = vec![(2, 0), (7, 7), (8, 8)];
-        assert_eq!(elements(map), expected);
-    }
-
-    #[test]
-    fn test_insert_presorted_last_elem_equal() {
-        let mut map = SortedMap::new();
-        map.insert(2, 2);
-        map.insert(8, 8);
-
-        map.insert_presorted(vec![(3, 3), (8, 0)]);
-
-        let expected = vec![(2, 2), (3, 3), (8, 0)];
-        assert_eq!(elements(map), expected);
-    }
-
-    #[test]
-    fn test_insert_presorted_shuffle() {
-        let mut map = SortedMap::new();
-        map.insert(2, 2);
-        map.insert(7, 7);
-
-        map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]);
-
-        let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)];
-        assert_eq!(elements(map), expected);
-    }
-
-    #[test]
-    fn test_insert_presorted_at_end() {
-        let mut map = SortedMap::new();
-        map.insert(1, 1);
-        map.insert(2, 2);
-
-        map.insert_presorted(vec![(3, 3), (8, 8)]);
-
-        let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)];
-        assert_eq!(elements(map), expected);
-    }
-}
+mod tests;
diff --git a/src/librustc_data_structures/sorted_map/tests.rs b/src/librustc_data_structures/sorted_map/tests.rs
new file mode 100644
index 0000000000000..f970409cc3d58
--- /dev/null
+++ b/src/librustc_data_structures/sorted_map/tests.rs
@@ -0,0 +1,199 @@
+use super::SortedMap;
+
+#[test]
+fn test_insert_and_iter() {
+    let mut map = SortedMap::new();
+    let mut expected = Vec::new();
+
+    for x in 0 .. 100 {
+        assert_eq!(map.iter().cloned().collect::<Vec<_>>(), expected);
+
+        let x = 1000 - x * 2;
+        map.insert(x, x);
+        expected.insert(0, (x, x));
+    }
+}
+
+#[test]
+fn test_get_and_index() {
+    let mut map = SortedMap::new();
+    let mut expected = Vec::new();
+
+    for x in 0 .. 100 {
+        let x = 1000 - x;
+        if x & 1 == 0 {
+            map.insert(x, x);
+        }
+        expected.push(x);
+    }
+
+    for mut x in expected {
+        if x & 1 == 0 {
+            assert_eq!(map.get(&x), Some(&x));
+            assert_eq!(map.get_mut(&x), Some(&mut x));
+            assert_eq!(map[&x], x);
+            assert_eq!(&mut map[&x], &mut x);
+        } else {
+            assert_eq!(map.get(&x), None);
+            assert_eq!(map.get_mut(&x), None);
+        }
+    }
+}
+
+#[test]
+fn test_range() {
+    let mut map = SortedMap::new();
+    map.insert(1, 1);
+    map.insert(3, 3);
+    map.insert(6, 6);
+    map.insert(9, 9);
+
+    let keys = |s: &[(_, _)]| {
+        s.into_iter().map(|e| e.0).collect::<Vec<u32>>()
+    };
+
+    for start in 0 .. 11 {
+        for end in 0 .. 11 {
+            if end < start {
+                continue
+            }
+
+            let mut expected = vec![1, 3, 6, 9];
+            expected.retain(|&x| x >= start && x < end);
+
+            assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end);
+        }
+    }
+}
+
+
+#[test]
+fn test_offset_keys() {
+    let mut map = SortedMap::new();
+    map.insert(1, 1);
+    map.insert(3, 3);
+    map.insert(6, 6);
+
+    map.offset_keys(|k| *k += 1);
+
+    let mut expected = SortedMap::new();
+    expected.insert(2, 1);
+    expected.insert(4, 3);
+    expected.insert(7, 6);
+
+    assert_eq!(map, expected);
+}
+
+fn keys(s: SortedMap<u32, u32>) -> Vec<u32> {
+    s.into_iter().map(|(k, _)| k).collect::<Vec<u32>>()
+}
+
+fn elements(s: SortedMap<u32, u32>) -> Vec<(u32, u32)> {
+    s.into_iter().collect::<Vec<(u32, u32)>>()
+}
+
+#[test]
+fn test_remove_range() {
+    let mut map = SortedMap::new();
+    map.insert(1, 1);
+    map.insert(3, 3);
+    map.insert(6, 6);
+    map.insert(9, 9);
+
+    for start in 0 .. 11 {
+        for end in 0 .. 11 {
+            if end < start {
+                continue
+            }
+
+            let mut expected = vec![1, 3, 6, 9];
+            expected.retain(|&x| x < start || x >= end);
+
+            let mut map = map.clone();
+            map.remove_range(start .. end);
+
+            assert_eq!(keys(map), expected, "range = {}..{}", start, end);
+        }
+    }
+}
+
+#[test]
+fn test_remove() {
+    let mut map = SortedMap::new();
+    let mut expected = Vec::new();
+
+    for x in 0..10 {
+        map.insert(x, x);
+        expected.push((x, x));
+    }
+
+    for x in 0 .. 10 {
+        let mut map = map.clone();
+        let mut expected = expected.clone();
+
+        assert_eq!(map.remove(&x), Some(x));
+        expected.remove(x as usize);
+
+        assert_eq!(map.iter().cloned().collect::<Vec<_>>(), expected);
+    }
+}
+
+#[test]
+fn test_insert_presorted_non_overlapping() {
+    let mut map = SortedMap::new();
+    map.insert(2, 0);
+    map.insert(8, 0);
+
+    map.insert_presorted(vec![(3, 0), (7, 0)]);
+
+    let expected = vec![2, 3, 7, 8];
+    assert_eq!(keys(map), expected);
+}
+
+#[test]
+fn test_insert_presorted_first_elem_equal() {
+    let mut map = SortedMap::new();
+    map.insert(2, 2);
+    map.insert(8, 8);
+
+    map.insert_presorted(vec![(2, 0), (7, 7)]);
+
+    let expected = vec![(2, 0), (7, 7), (8, 8)];
+    assert_eq!(elements(map), expected);
+}
+
+#[test]
+fn test_insert_presorted_last_elem_equal() {
+    let mut map = SortedMap::new();
+    map.insert(2, 2);
+    map.insert(8, 8);
+
+    map.insert_presorted(vec![(3, 3), (8, 0)]);
+
+    let expected = vec![(2, 2), (3, 3), (8, 0)];
+    assert_eq!(elements(map), expected);
+}
+
+#[test]
+fn test_insert_presorted_shuffle() {
+    let mut map = SortedMap::new();
+    map.insert(2, 2);
+    map.insert(7, 7);
+
+    map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]);
+
+    let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)];
+    assert_eq!(elements(map), expected);
+}
+
+#[test]
+fn test_insert_presorted_at_end() {
+    let mut map = SortedMap::new();
+    map.insert(1, 1);
+    map.insert(2, 2);
+
+    map.insert_presorted(vec![(3, 3), (8, 8)]);
+
+    let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)];
+    assert_eq!(elements(map), expected);
+}
diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs
index 551eded9858a3..903a2d6801230 100644
--- a/src/librustc_lint/nonstandard_style.rs
+++ b/src/librustc_lint/nonstandard_style.rs
@@ -440,26 +440,4 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::{is_camel_case, to_camel_case};
-
-    #[test]
-    fn camel_case() {
-        assert!(!is_camel_case("userData"));
-        assert_eq!(to_camel_case("userData"), "UserData");
-
-        assert!(is_camel_case("X86_64"));
-
-        assert!(!is_camel_case("X86__64"));
-        assert_eq!(to_camel_case("X86__64"), "X86_64");
-
-        assert!(!is_camel_case("Abc_123"));
-        assert_eq!(to_camel_case("Abc_123"), "Abc123");
-
-        assert!(!is_camel_case("A1_b2_c3"));
-        assert_eq!(to_camel_case("A1_b2_c3"), "A1B2C3");
-
-        assert!(!is_camel_case("ONE_TWO_THREE"));
-        assert_eq!(to_camel_case("ONE_TWO_THREE"), "OneTwoThree");
-    }
-}
+mod tests;
diff --git a/src/librustc_lint/nonstandard_style/tests.rs b/src/librustc_lint/nonstandard_style/tests.rs
new file mode 100644
index 0000000000000..39c525b8623d0
--- /dev/null
+++ b/src/librustc_lint/nonstandard_style/tests.rs
@@ -0,0 +1,21 @@
+use super::{is_camel_case, to_camel_case};
+
+#[test]
+fn camel_case() {
+    assert!(!is_camel_case("userData"));
+    assert_eq!(to_camel_case("userData"), "UserData");
+
+    assert!(is_camel_case("X86_64"));
+
+    assert!(!is_camel_case("X86__64"));
+    assert_eq!(to_camel_case("X86__64"), "X86_64");
+
+    assert!(!is_camel_case("Abc_123"));
+    assert_eq!(to_camel_case("Abc_123"), "Abc123");
+
+    assert!(!is_camel_case("A1_b2_c3"));
+    assert_eq!(to_camel_case("A1_b2_c3"), "A1B2C3");
+
+    assert!(!is_camel_case("ONE_TWO_THREE"));
+    assert_eq!(to_camel_case("ONE_TWO_THREE"), "OneTwoThree");
+}
diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs
index 395270f5bb53a..76a9a3405bd81 100644
--- a/src/librustc_metadata/dynamic_lib.rs
+++ b/src/librustc_metadata/dynamic_lib.rs
@@ -74,55 +74,7 @@ impl DynamicLibrary {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::*;
-    use std::mem;
-
-    #[test]
-    fn test_loading_atoi() {
-        if cfg!(windows) {
-            return
-        }
-
-        // The C library does not need to be loaded since it is already linked in
-        let lib = match DynamicLibrary::open(None) {
-            Err(error) => panic!("Could not load self as module: {}", error),
-            Ok(lib) => lib
-        };
-
-        let atoi: extern fn(*const libc::c_char) -> libc::c_int = unsafe {
-            match lib.symbol("atoi") {
-                Err(error) => panic!("Could not load function atoi: {}", error),
-                Ok(atoi) => mem::transmute::<*mut u8, _>(atoi)
-            }
-        };
-
-        let argument = CString::new("1383428980").unwrap();
-        let expected_result = 0x52757374;
-        let result = atoi(argument.as_ptr());
-        if result != expected_result {
-            panic!("atoi({:?}) != {} but equaled {} instead", argument,
-                   expected_result, result)
-        }
-    }
-
-    #[test]
-    fn test_errors_do_not_crash() {
-        use std::path::Path;
-
-        if !cfg!(unix) {
-            return
-        }
-
-        // Open /dev/null as a library to get an error, and make sure
-        // that only causes an error, and not a crash.
-        let path = Path::new("/dev/null");
-        match DynamicLibrary::open(Some(&path)) {
-            Err(_) => {}
-            Ok(_) => panic!("Successfully opened the empty library.")
-        }
-    }
-}
+mod tests;
 
 #[cfg(unix)]
 mod dl {
diff --git a/src/librustc_metadata/dynamic_lib/tests.rs b/src/librustc_metadata/dynamic_lib/tests.rs
new file mode 100644
index 0000000000000..b2302f2f1b5b7
--- /dev/null
+++ b/src/librustc_metadata/dynamic_lib/tests.rs
@@ -0,0 +1,47 @@
+use super::*;
+use std::mem;
+
+#[test]
+fn test_loading_atoi() {
+    if cfg!(windows) {
+        return
+    }
+
+    // The C library does not need to be loaded since it is already linked in
+    let lib = match DynamicLibrary::open(None) {
+        Err(error) => panic!("Could not load self as module: {}", error),
+        Ok(lib) => lib
+    };
+
+    let atoi: extern fn(*const libc::c_char) -> libc::c_int = unsafe {
+        match lib.symbol("atoi") {
+            Err(error) => panic!("Could not load function atoi: {}", error),
+            Ok(atoi) => mem::transmute::<*mut u8, _>(atoi)
+        }
+    };
+
+    let argument = CString::new("1383428980").unwrap();
+    let expected_result = 0x52757374;
+    let result = atoi(argument.as_ptr());
+    if result != expected_result {
+        panic!("atoi({:?}) != {} but equaled {} instead", argument,
+               expected_result, result)
+    }
+}
+
+#[test]
+fn test_errors_do_not_crash() {
+    use std::path::Path;
+
+    if !cfg!(unix) {
+        return
+    }
+
+    // Open /dev/null as a library to get an error, and make sure
+    // that only causes an error, and not a crash.
+    let path = Path::new("/dev/null");
+    match DynamicLibrary::open(Some(&path)) {
+        Err(_) => {}
+        Ok(_) => panic!("Successfully opened the empty library.")
+    }
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 334b831565076..c698200039623 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -43,25 +43,30 @@ fn opts() -> Options {
     Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES
 }
 
-/// A unit struct which has the `fmt::Display` trait implemented. When
-/// formatted, this struct will emit the HTML corresponding to the rendered
+/// A tuple struct that has the `fmt::Display` trait implemented.
+/// When formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
-///
-/// The second parameter is a list of link replacements.
-///
-/// The third is the current list of used header IDs.
-///
-/// The fourth is whether to allow the use of explicit error codes in doctest lang strings.
-///
-/// The fifth is what default edition to use when parsing doctests (to add a `fn main`).
 pub struct Markdown<'a>(
-    pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
-/// A unit struct like `Markdown`, that renders the markdown with a
-/// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
-/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
+    pub &'a str,
+    /// A list of link replacements.
+    pub &'a [(String, String)],
+    /// The current list of used header IDs.
+    pub RefCell<&'a mut IdMap>,
+    /// Whether to allow the use of explicit error codes in doctest lang strings.
+    pub ErrorCodes,
+    /// Default edition to use when parsing doctests (to add a `fn main`).
+    pub Edition,
+);
+/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
+pub struct MarkdownWithToc<'a>(
+    pub &'a str,
+    pub RefCell<&'a mut IdMap>,
+    pub ErrorCodes,
+    pub Edition,
+);
+/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags.
 pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
-/// A unit struct like `Markdown`, that renders only the first paragraph.
+/// A tuple struct like `Markdown` that renders only the first paragraph.
 pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -1050,130 +1055,4 @@ fn test_unique_id() {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
-    use super::plain_summary_line;
-    use std::cell::RefCell;
-    use syntax::edition::{Edition, DEFAULT_EDITION};
-
-    #[test]
-    fn test_lang_string_parse() {
-        fn t(s: &str,
-            should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
-            compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
-             edition: Option<Edition>) {
-            assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
-                should_panic,
-                no_run,
-                ignore,
-                rust,
-                test_harness,
-                compile_fail,
-                error_codes,
-                original: s.to_owned(),
-                allow_fail,
-                edition,
-            })
-        }
-
-        fn v() -> Vec<String> {
-            Vec::new()
-        }
-
-        // ignore-tidy-linelength
-        // marker                | should_panic | no_run | ignore | rust | test_harness
-        //                       | compile_fail | allow_fail | error_codes | edition
-        t("",                      false,         false,   false,   true,  false, false, false, v(), None);
-        t("rust",                  false,         false,   false,   true,  false, false, false, v(), None);
-        t("sh",                    false,         false,   false,   false, false, false, false, v(), None);
-        t("ignore",                false,         false,   true,    true,  false, false, false, v(), None);
-        t("should_panic",          true,          false,   false,   true,  false, false, false, v(), None);
-        t("no_run",                false,         true,    false,   true,  false, false, false, v(), None);
-        t("test_harness",          false,         false,   false,   true,  true,  false, false, v(), None);
-        t("compile_fail",          false,         true,    false,   true,  false, true,  false, v(), None);
-        t("allow_fail",            false,         false,   false,   true,  false, false, true,  v(), None);
-        t("{.no_run .example}",    false,         true,    false,   true,  false, false, false, v(), None);
-        t("{.sh .should_panic}",   true,          false,   false,   false, false, false, false, v(), None);
-        t("{.example .rust}",      false,         false,   false,   true,  false, false, false, v(), None);
-        t("{.test_harness .rust}", false,         false,   false,   true,  true,  false, false, v(), None);
-        t("text, no_run",          false,         true,    false,   false, false, false, false, v(), None);
-        t("text,no_run",           false,         true,    false,   false, false, false, false, v(), None);
-        t("edition2015",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2015));
-        t("edition2018",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2018));
-    }
-
-    #[test]
-    fn test_header() {
-        fn t(input: &str, expect: &str) {
-            let mut map = IdMap::new();
-            let output = Markdown(input, &[], RefCell::new(&mut map),
-                                  ErrorCodes::Yes, DEFAULT_EDITION).to_string();
-            assert_eq!(output, expect, "original: {}", input);
-        }
-
-        t("# Foo bar", "<h1 id=\"foo-bar\" class=\"section-header\">\
-          <a href=\"#foo-bar\">Foo bar</a></h1>");
-        t("## Foo-bar_baz qux", "<h2 id=\"foo-bar_baz-qux\" class=\"section-\
-          header\"><a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h2>");
-        t("### **Foo** *bar* baz!?!& -_qux_-%",
-          "<h3 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
-          <a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
-          <em>bar</em> baz!?!&amp; -<em>qux</em>-%</a></h3>");
-        t("#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
-          "<h4 id=\"foo--bar--baz--qux\" class=\"section-header\">\
-          <a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!*  \
-          <em><code>baz</code></em> ❤ #qux</a></h4>");
-    }
-
-    #[test]
-    fn test_header_ids_multiple_blocks() {
-        let mut map = IdMap::new();
-        fn t(map: &mut IdMap, input: &str, expect: &str) {
-            let output = Markdown(input, &[], RefCell::new(map),
-                                  ErrorCodes::Yes, DEFAULT_EDITION).to_string();
-            assert_eq!(output, expect, "original: {}", input);
-        }
-
-        t(&mut map, "# Example", "<h1 id=\"example\" class=\"section-header\">\
-            <a href=\"#example\">Example</a></h1>");
-        t(&mut map, "# Panics", "<h1 id=\"panics\" class=\"section-header\">\
-            <a href=\"#panics\">Panics</a></h1>");
-        t(&mut map, "# Example", "<h1 id=\"example-1\" class=\"section-header\">\
-            <a href=\"#example-1\">Example</a></h1>");
-        t(&mut map, "# Main", "<h1 id=\"main\" class=\"section-header\">\
-            <a href=\"#main\">Main</a></h1>");
-        t(&mut map, "# Example", "<h1 id=\"example-2\" class=\"section-header\">\
-            <a href=\"#example-2\">Example</a></h1>");
-        t(&mut map, "# Panics", "<h1 id=\"panics-1\" class=\"section-header\">\
-            <a href=\"#panics-1\">Panics</a></h1>");
-    }
-
-    #[test]
-    fn test_plain_summary_line() {
-        fn t(input: &str, expect: &str) {
-            let output = plain_summary_line(input);
-            assert_eq!(output, expect, "original: {}", input);
-        }
-
-        t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
-        t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
-        t("code `let x = i32;` ...", "code `let x = i32;` ...");
-        t("type `Type<'static>` ...", "type `Type<'static>` ...");
-        t("# top header", "top header");
-        t("## header", "header");
-    }
-
-    #[test]
-    fn test_markdown_html_escape() {
-        fn t(input: &str, expect: &str) {
-            let mut idmap = IdMap::new();
-            let output = MarkdownHtml(input, RefCell::new(&mut idmap),
-                                      ErrorCodes::Yes, DEFAULT_EDITION).to_string();
-            assert_eq!(output, expect, "original: {}", input);
-        }
-
-        t("`Struct<'a, T>`", "<p><code>Struct&lt;'a, T&gt;</code></p>\n");
-        t("Struct<'a, T>", "<p>Struct&lt;'a, T&gt;</p>\n");
-        t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n");
-    }
-}
+mod tests;
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
new file mode 100644
index 0000000000000..f470e649d8265
--- /dev/null
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -0,0 +1,125 @@
+use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
+use super::plain_summary_line;
+use std::cell::RefCell;
+use syntax::edition::{Edition, DEFAULT_EDITION};
+
+#[test]
+fn test_lang_string_parse() {
+    fn t(s: &str,
+        should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
+        compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
+         edition: Option<Edition>) {
+        assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
+            should_panic,
+            no_run,
+            ignore,
+            rust,
+            test_harness,
+            compile_fail,
+            error_codes,
+            original: s.to_owned(),
+            allow_fail,
+            edition,
+        })
+    }
+
+    fn v() -> Vec<String> {
+        Vec::new()
+    }
+
+    // ignore-tidy-linelength
+    // marker                | should_panic | no_run | ignore | rust | test_harness
+    //                       | compile_fail | allow_fail | error_codes | edition
+    t("",                      false,         false,   false,   true,  false, false, false, v(), None);
+    t("rust",                  false,         false,   false,   true,  false, false, false, v(), None);
+    t("sh",                    false,         false,   false,   false, false, false, false, v(), None);
+    t("ignore",                false,         false,   true,    true,  false, false, false, v(), None);
+    t("should_panic",          true,          false,   false,   true,  false, false, false, v(), None);
+    t("no_run",                false,         true,    false,   true,  false, false, false, v(), None);
+    t("test_harness",          false,         false,   false,   true,  true,  false, false, v(), None);
+    t("compile_fail",          false,         true,    false,   true,  false, true,  false, v(), None);
+    t("allow_fail",            false,         false,   false,   true,  false, false, true,  v(), None);
+    t("{.no_run .example}",    false,         true,    false,   true,  false, false, false, v(), None);
+    t("{.sh .should_panic}",   true,          false,   false,   false, false, false, false, v(), None);
+    t("{.example .rust}",      false,         false,   false,   true,  false, false, false, v(), None);
+    t("{.test_harness .rust}", false,         false,   false,   true,  true,  false, false, v(), None);
+    t("text, no_run",          false,         true,    false,   false, false, false, false, v(), None);
+    t("text,no_run",           false,         true,    false,   false, false, false, false, v(), None);
+    t("edition2015",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2015));
+    t("edition2018",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2018));
+}
+
+#[test]
+fn test_header() {
+    fn t(input: &str, expect: &str) {
+        let mut map = IdMap::new();
+        let output = Markdown(input, &[], RefCell::new(&mut map),
+                              ErrorCodes::Yes, DEFAULT_EDITION).to_string();
+        assert_eq!(output, expect, "original: {}", input);
+    }
+
+    t("# Foo bar", "<h1 id=\"foo-bar\" class=\"section-header\">\
+      <a href=\"#foo-bar\">Foo bar</a></h1>");
+    t("## Foo-bar_baz qux", "<h2 id=\"foo-bar_baz-qux\" class=\"section-\
+      header\"><a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h2>");
+    t("### **Foo** *bar* baz!?!& -_qux_-%",
+      "<h3 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
+      <a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
+      <em>bar</em> baz!?!&amp; -<em>qux</em>-%</a></h3>");
+    t("#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
+      "<h4 id=\"foo--bar--baz--qux\" class=\"section-header\">\
+      <a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!*  \
+      <em><code>baz</code></em> ❤ #qux</a></h4>");
+}
+
+#[test]
+fn test_header_ids_multiple_blocks() {
+    let mut map = IdMap::new();
+    fn t(map: &mut IdMap, input: &str, expect: &str) {
+        let output = Markdown(input, &[], RefCell::new(map),
+                              ErrorCodes::Yes, DEFAULT_EDITION).to_string();
+        assert_eq!(output, expect, "original: {}", input);
+    }
+
+    t(&mut map, "# Example", "<h1 id=\"example\" class=\"section-header\">\
+        <a href=\"#example\">Example</a></h1>");
+    t(&mut map, "# Panics", "<h1 id=\"panics\" class=\"section-header\">\
+        <a href=\"#panics\">Panics</a></h1>");
+    t(&mut map, "# Example", "<h1 id=\"example-1\" class=\"section-header\">\
+        <a href=\"#example-1\">Example</a></h1>");
+    t(&mut map, "# Main", "<h1 id=\"main\" class=\"section-header\">\
+        <a href=\"#main\">Main</a></h1>");
+    t(&mut map, "# Example", "<h1 id=\"example-2\" class=\"section-header\">\
+        <a href=\"#example-2\">Example</a></h1>");
+    t(&mut map, "# Panics", "<h1 id=\"panics-1\" class=\"section-header\">\
+        <a href=\"#panics-1\">Panics</a></h1>");
+}
+
+#[test]
+fn test_plain_summary_line() {
+    fn t(input: &str, expect: &str) {
+        let output = plain_summary_line(input);
+        assert_eq!(output, expect, "original: {}", input);
+    }
+
+    t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
+    t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
+    t("code `let x = i32;` ...", "code `let x = i32;` ...");
+    t("type `Type<'static>` ...", "type `Type<'static>` ...");
+    t("# top header", "top header");
+    t("## header", "header");
+}
+
+#[test]
+fn test_markdown_html_escape() {
+    fn t(input: &str, expect: &str) {
+        let mut idmap = IdMap::new();
+        let output = MarkdownHtml(input, RefCell::new(&mut idmap),
+                                  ErrorCodes::Yes, DEFAULT_EDITION).to_string();
+        assert_eq!(output, expect, "original: {}", input);
+    }
+
+    t("`Struct<'a, T>`", "<p><code>Struct&lt;'a, T&gt;</code></p>\n");
+    t("Struct<'a, T>", "<p>Struct&lt;'a, T&gt;</p>\n");
+    t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n");
+}
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index 409f2479ccc7c..2564c611e54e5 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -188,85 +188,4 @@ impl fmt::Display for Toc {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::{TocBuilder, Toc, TocEntry};
-
-    #[test]
-    fn builder_smoke() {
-        let mut builder = TocBuilder::new();
-
-        // this is purposely not using a fancy macro like below so
-        // that we're sure that this is doing the correct thing, and
-        // there's been no macro mistake.
-        macro_rules! push {
-            ($level: expr, $name: expr) => {
-                assert_eq!(builder.push($level,
-                                        $name.to_string(),
-                                        "".to_string()),
-                           $name);
-            }
-        }
-        push!(2, "0.1");
-        push!(1, "1");
-        {
-            push!(2, "1.1");
-            {
-                push!(3, "1.1.1");
-                push!(3, "1.1.2");
-            }
-            push!(2, "1.2");
-            {
-                push!(3, "1.2.1");
-                push!(3, "1.2.2");
-            }
-        }
-        push!(1, "2");
-        push!(1, "3");
-        {
-            push!(4, "3.0.0.1");
-            {
-                push!(6, "3.0.0.1.0.1");
-            }
-            push!(4, "3.0.0.2");
-            push!(2, "3.1");
-            {
-                push!(4, "3.1.0.1");
-            }
-        }
-
-        macro_rules! toc {
-            ($(($level: expr, $name: expr, $(($sub: tt))* )),*) => {
-                Toc {
-                    entries: vec![
-                        $(
-                            TocEntry {
-                                level: $level,
-                                name: $name.to_string(),
-                                sec_number: $name.to_string(),
-                                id: "".to_string(),
-                                children: toc!($($sub),*)
-                            }
-                            ),*
-                        ]
-                }
-            }
-        }
-        let expected = toc!(
-            (2, "0.1", ),
-
-            (1, "1",
-             ((2, "1.1", ((3, "1.1.1", )) ((3, "1.1.2", ))))
-             ((2, "1.2", ((3, "1.2.1", )) ((3, "1.2.2", ))))
-             ),
-
-            (1, "2", ),
-
-            (1, "3",
-             ((4, "3.0.0.1", ((6, "3.0.0.1.0.1", ))))
-             ((4, "3.0.0.2", ))
-             ((2, "3.1", ((4, "3.1.0.1", ))))
-             )
-            );
-        assert_eq!(expected, builder.into_toc());
-    }
-}
+mod tests;
diff --git a/src/librustdoc/html/toc/tests.rs b/src/librustdoc/html/toc/tests.rs
new file mode 100644
index 0000000000000..ef69ada466496
--- /dev/null
+++ b/src/librustdoc/html/toc/tests.rs
@@ -0,0 +1,80 @@
+use super::{TocBuilder, Toc, TocEntry};
+
+#[test]
+fn builder_smoke() {
+    let mut builder = TocBuilder::new();
+
+    // this is purposely not using a fancy macro like below so
+    // that we're sure that this is doing the correct thing, and
+    // there's been no macro mistake.
+    macro_rules! push {
+        ($level: expr, $name: expr) => {
+            assert_eq!(builder.push($level,
+                                    $name.to_string(),
+                                    "".to_string()),
+                       $name);
+        }
+    }
+    push!(2, "0.1");
+    push!(1, "1");
+    {
+        push!(2, "1.1");
+        {
+            push!(3, "1.1.1");
+            push!(3, "1.1.2");
+        }
+        push!(2, "1.2");
+        {
+            push!(3, "1.2.1");
+            push!(3, "1.2.2");
+        }
+    }
+    push!(1, "2");
+    push!(1, "3");
+    {
+        push!(4, "3.0.0.1");
+        {
+            push!(6, "3.0.0.1.0.1");
+        }
+        push!(4, "3.0.0.2");
+        push!(2, "3.1");
+        {
+            push!(4, "3.1.0.1");
+        }
+    }
+
+    macro_rules! toc {
+        ($(($level: expr, $name: expr, $(($sub: tt))* )),*) => {
+            Toc {
+                entries: vec![
+                    $(
+                        TocEntry {
+                            level: $level,
+                            name: $name.to_string(),
+                            sec_number: $name.to_string(),
+                            id: "".to_string(),
+                            children: toc!($($sub),*)
+                        }
+                        ),*
+                    ]
+            }
+        }
+    }
+    let expected = toc!(
+        (2, "0.1", ),
+
+        (1, "1",
+         ((2, "1.1", ((3, "1.1.1", )) ((3, "1.1.2", ))))
+         ((2, "1.2", ((3, "1.2.1", )) ((3, "1.2.2", ))))
+         ),
+
+        (1, "2", ),
+
+        (1, "3",
+         ((4, "3.0.0.1", ((6, "3.0.0.1.0.1", ))))
+         ((4, "3.0.0.2", ))
+         ((2, "3.1", ((4, "3.1.0.1", ))))
+         )
+        );
+    assert_eq!(expected, builder.into_toc());
+}
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index baf99bacb8ee6..9a9fd941240bc 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -975,304 +975,4 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::{TestOptions, make_test};
-    use syntax::edition::DEFAULT_EDITION;
-
-    #[test]
-    fn make_test_basic() {
-        //basic use: wraps with `fn main`, adds `#![allow(unused)]`
-        let opts = TestOptions::default();
-        let input =
-"assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_crate_name_no_use() {
-        // If you give a crate name but *don't* use it within the test, it won't bother inserting
-        // the `extern crate` statement.
-        let opts = TestOptions::default();
-        let input =
-"assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_crate_name() {
-        // If you give a crate name and use it within the test, it will insert an `extern crate`
-        // statement before `fn main`.
-        let opts = TestOptions::default();
-        let input =
-"use asdf::qwop;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-extern crate asdf;
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 3));
-    }
-
-    #[test]
-    fn make_test_no_crate_inject() {
-        // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
-        // adding it anyway.
-        let opts = TestOptions {
-            no_crate_inject: true,
-            display_warnings: false,
-            attrs: vec![],
-        };
-        let input =
-"use asdf::qwop;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_ignore_std() {
-        // Even if you include a crate name, and use it in the doctest, we still won't include an
-        // `extern crate` statement if the crate is "std" -- that's included already by the
-        // compiler!
-        let opts = TestOptions::default();
-        let input =
-"use std::*;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-fn main() {
-use std::*;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_manual_extern_crate() {
-        // When you manually include an `extern crate` statement in your doctest, `make_test`
-        // assumes you've included one for your own crate too.
-        let opts = TestOptions::default();
-        let input =
-"extern crate asdf;
-use asdf::qwop;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-extern crate asdf;
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_manual_extern_crate_with_macro_use() {
-        let opts = TestOptions::default();
-        let input =
-"#[macro_use] extern crate asdf;
-use asdf::qwop;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-#[macro_use] extern crate asdf;
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_opts_attrs() {
-        // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use
-        // those instead of the stock `#![allow(unused)]`.
-        let mut opts = TestOptions::default();
-        opts.attrs.push("feature(sick_rad)".to_string());
-        let input =
-"use asdf::qwop;
-assert_eq!(2+2, 4);";
-        let expected =
-"#![feature(sick_rad)]
-extern crate asdf;
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 3));
-
-        // Adding more will also bump the returned line offset.
-        opts.attrs.push("feature(hella_dope)".to_string());
-        let expected =
-"#![feature(sick_rad)]
-#![feature(hella_dope)]
-extern crate asdf;
-fn main() {
-use asdf::qwop;
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 4));
-    }
-
-    #[test]
-    fn make_test_crate_attrs() {
-        // Including inner attributes in your doctest will apply them to the whole "crate", pasting
-        // them outside the generated main function.
-        let opts = TestOptions::default();
-        let input =
-"#![feature(sick_rad)]
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-#![feature(sick_rad)]
-fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_with_main() {
-        // Including your own `fn main` wrapper lets the test use it verbatim.
-        let opts = TestOptions::default();
-        let input =
-"fn main() {
-    assert_eq!(2+2, 4);
-}";
-        let expected =
-"#![allow(unused)]
-fn main() {
-    assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 1));
-    }
-
-    #[test]
-    fn make_test_fake_main() {
-        // ... but putting it in a comment will still provide a wrapper.
-        let opts = TestOptions::default();
-        let input =
-"//Ceci n'est pas une `fn main`
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-//Ceci n'est pas une `fn main`
-fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-    }
-
-    #[test]
-    fn make_test_dont_insert_main() {
-        // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper.
-        let opts = TestOptions::default();
-        let input =
-"//Ceci n'est pas une `fn main`
-assert_eq!(2+2, 4);";
-        let expected =
-"#![allow(unused)]
-//Ceci n'est pas une `fn main`
-assert_eq!(2+2, 4);".to_string();
-        let output = make_test(input, None, true, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 1));
-    }
-
-    #[test]
-    fn make_test_display_warnings() {
-        // If the user is asking to display doctest warnings, suppress the default `allow(unused)`.
-        let mut opts = TestOptions::default();
-        opts.display_warnings = true;
-        let input =
-"assert_eq!(2+2, 4);";
-        let expected =
-"fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 1));
-    }
-
-    #[test]
-    fn make_test_issues_21299_33731() {
-        let opts = TestOptions::default();
-
-        let input =
-"// fn main
-assert_eq!(2+2, 4);";
-
-        let expected =
-"#![allow(unused)]
-// fn main
-fn main() {
-assert_eq!(2+2, 4);
-}".to_string();
-
-        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 2));
-
-        let input =
-"extern crate hella_qwop;
-assert_eq!(asdf::foo, 4);";
-
-        let expected =
-"#![allow(unused)]
-extern crate hella_qwop;
-extern crate asdf;
-fn main() {
-assert_eq!(asdf::foo, 4);
-}".to_string();
-
-        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 3));
-    }
-
-    #[test]
-    fn make_test_main_in_macro() {
-        let opts = TestOptions::default();
-        let input =
-"#[macro_use] extern crate my_crate;
-test_wrapper! {
-    fn main() {}
-}";
-        let expected =
-"#![allow(unused)]
-#[macro_use] extern crate my_crate;
-test_wrapper! {
-    fn main() {}
-}".to_string();
-
-        let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
-        assert_eq!(output, (expected, 1));
-    }
-}
+mod tests;
diff --git a/src/librustdoc/test/tests.rs b/src/librustdoc/test/tests.rs
new file mode 100644
index 0000000000000..d4d558b7cd78c
--- /dev/null
+++ b/src/librustdoc/test/tests.rs
@@ -0,0 +1,299 @@
+use super::{TestOptions, make_test};
+use syntax::edition::DEFAULT_EDITION;
+
+#[test]
+fn make_test_basic() {
+    //basic use: wraps with `fn main`, adds `#![allow(unused)]`
+    let opts = TestOptions::default();
+    let input =
+"assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_crate_name_no_use() {
+    // If you give a crate name but *don't* use it within the test, it won't bother inserting
+    // the `extern crate` statement.
+    let opts = TestOptions::default();
+    let input =
+"assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_crate_name() {
+    // If you give a crate name and use it within the test, it will insert an `extern crate`
+    // statement before `fn main`.
+    let opts = TestOptions::default();
+    let input =
+"use asdf::qwop;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 3));
+}
+
+#[test]
+fn make_test_no_crate_inject() {
+    // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
+    // adding it anyway.
+    let opts = TestOptions {
+        no_crate_inject: true,
+        display_warnings: false,
+        attrs: vec![],
+    };
+    let input =
+"use asdf::qwop;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_ignore_std() {
+    // Even if you include a crate name, and use it in the doctest, we still won't include an
+    // `extern crate` statement if the crate is "std" -- that's included already by the
+    // compiler!
+    let opts = TestOptions::default();
+    let input =
+"use std::*;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+fn main() {
+use std::*;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_manual_extern_crate() {
+    // When you manually include an `extern crate` statement in your doctest, `make_test`
+    // assumes you've included one for your own crate too.
+    let opts = TestOptions::default();
+    let input =
+"extern crate asdf;
+use asdf::qwop;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_manual_extern_crate_with_macro_use() {
+    let opts = TestOptions::default();
+    let input =
+"#[macro_use] extern crate asdf;
+use asdf::qwop;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+#[macro_use] extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_opts_attrs() {
+    // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use
+    // those instead of the stock `#![allow(unused)]`.
+    let mut opts = TestOptions::default();
+    opts.attrs.push("feature(sick_rad)".to_string());
+    let input =
+"use asdf::qwop;
+assert_eq!(2+2, 4);";
+        let expected =
+"#![feature(sick_rad)]
+extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 3));
+
+    // Adding more will also bump the returned line offset.
+    opts.attrs.push("feature(hella_dope)".to_string());
+    let expected =
+"#![feature(sick_rad)]
+#![feature(hella_dope)]
+extern crate asdf;
+fn main() {
+use asdf::qwop;
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 4));
+}
+
+#[test]
+fn make_test_crate_attrs() {
+    // Including inner attributes in your doctest will apply them to the whole "crate", pasting
+    // them outside the generated main function.
+    let opts = TestOptions::default();
+    let input =
+"#![feature(sick_rad)]
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+#![feature(sick_rad)]
+fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_with_main() {
+    // Including your own `fn main` wrapper lets the test use it verbatim.
+    let opts = TestOptions::default();
+    let input =
+"fn main() {
+    assert_eq!(2+2, 4);
+}";
+    let expected =
+"#![allow(unused)]
+fn main() {
+    assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 1));
+}
+
+#[test]
+fn make_test_fake_main() {
+    // ... but putting it in a comment will still provide a wrapper.
+    let opts = TestOptions::default();
+    let input =
+"//Ceci n'est pas une `fn main`
+assert_eq!(2+2, 4);";
+    let expected =
+"#![allow(unused)]
+//Ceci n'est pas une `fn main`
+fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+}
+
+#[test]
+fn make_test_dont_insert_main() {
+    // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper.
+    let opts = TestOptions::default();
+    let input =
+"//Ceci n'est pas une `fn main`
+assert_eq!(2+2, 4);";
+        let expected =
+"#![allow(unused)]
+//Ceci n'est pas une `fn main`
+assert_eq!(2+2, 4);".to_string();
+    let output = make_test(input, None, true, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 1));
+}
+
+#[test]
+fn make_test_display_warnings() {
+    // If the user is asking to display doctest warnings, suppress the default `allow(unused)`.
+    let mut opts = TestOptions::default();
+    opts.display_warnings = true;
+    let input =
+"assert_eq!(2+2, 4);";
+        let expected =
+"fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 1));
+}
+
+#[test]
+fn make_test_issues_21299_33731() {
+    let opts = TestOptions::default();
+
+    let input =
+"// fn main
+assert_eq!(2+2, 4);";
+
+    let expected =
+"#![allow(unused)]
+// fn main
+fn main() {
+assert_eq!(2+2, 4);
+}".to_string();
+
+    let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 2));
+
+    let input =
+"extern crate hella_qwop;
+assert_eq!(asdf::foo, 4);";
+
+    let expected =
+"#![allow(unused)]
+extern crate hella_qwop;
+extern crate asdf;
+fn main() {
+assert_eq!(asdf::foo, 4);
+}".to_string();
+
+    let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 3));
+}
+
+#[test]
+fn make_test_main_in_macro() {
+    let opts = TestOptions::default();
+    let input =
+"#[macro_use] extern crate my_crate;
+test_wrapper! {
+    fn main() {}
+}";
+    let expected =
+"#![allow(unused)]
+#[macro_use] extern crate my_crate;
+test_wrapper! {
+    fn main() {}
+}".to_string();
+
+    let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
+    assert_eq!(output, (expected, 1));
+}
diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs
index 8a7927e42c9c3..95d92f311ed3c 100644
--- a/src/libserialize/hex.rs
+++ b/src/libserialize/hex.rs
@@ -143,79 +143,4 @@ impl FromHex for str {
 }
 
 #[cfg(test)]
-mod tests {
-    extern crate test;
-    use test::Bencher;
-    use crate::hex::{FromHex, ToHex};
-
-    #[test]
-    pub fn test_to_hex() {
-        assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
-    }
-
-    #[test]
-    pub fn test_from_hex_okay() {
-        assert_eq!("666f6f626172".from_hex().unwrap(),
-                   b"foobar");
-        assert_eq!("666F6F626172".from_hex().unwrap(),
-                   b"foobar");
-    }
-
-    #[test]
-    pub fn test_from_hex_odd_len() {
-        assert!("666".from_hex().is_err());
-        assert!("66 6".from_hex().is_err());
-    }
-
-    #[test]
-    pub fn test_from_hex_invalid_char() {
-        assert!("66y6".from_hex().is_err());
-    }
-
-    #[test]
-    pub fn test_from_hex_ignores_whitespace() {
-        assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
-                   b"foobar");
-    }
-
-    #[test]
-    pub fn test_to_hex_all_bytes() {
-        for i in 0..256 {
-            assert_eq!([i as u8].to_hex(), format!("{:02x}", i as usize));
-        }
-    }
-
-    #[test]
-    pub fn test_from_hex_all_bytes() {
-        for i in 0..256 {
-            let ii: &[u8] = &[i as u8];
-            assert_eq!(format!("{:02x}", i as usize).from_hex()
-                                                   .unwrap(),
-                       ii);
-            assert_eq!(format!("{:02X}", i as usize).from_hex()
-                                                   .unwrap(),
-                       ii);
-        }
-    }
-
-    #[bench]
-    pub fn bench_to_hex(b: &mut Bencher) {
-        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
-                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
-        b.iter(|| {
-            s.as_bytes().to_hex();
-        });
-        b.bytes = s.len() as u64;
-    }
-
-    #[bench]
-    pub fn bench_from_hex(b: &mut Bencher) {
-        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
-                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
-        let sb = s.as_bytes().to_hex();
-        b.iter(|| {
-            sb.from_hex().unwrap();
-        });
-        b.bytes = sb.len() as u64;
-    }
-}
+mod tests;
diff --git a/src/libserialize/hex/tests.rs b/src/libserialize/hex/tests.rs
new file mode 100644
index 0000000000000..471912c11d06f
--- /dev/null
+++ b/src/libserialize/hex/tests.rs
@@ -0,0 +1,74 @@
+extern crate test;
+use test::Bencher;
+use crate::hex::{FromHex, ToHex};
+
+#[test]
+pub fn test_to_hex() {
+    assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
+}
+
+#[test]
+pub fn test_from_hex_okay() {
+    assert_eq!("666f6f626172".from_hex().unwrap(),
+               b"foobar");
+    assert_eq!("666F6F626172".from_hex().unwrap(),
+               b"foobar");
+}
+
+#[test]
+pub fn test_from_hex_odd_len() {
+    assert!("666".from_hex().is_err());
+    assert!("66 6".from_hex().is_err());
+}
+
+#[test]
+pub fn test_from_hex_invalid_char() {
+    assert!("66y6".from_hex().is_err());
+}
+
+#[test]
+pub fn test_from_hex_ignores_whitespace() {
+    assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
+               b"foobar");
+}
+
+#[test]
+pub fn test_to_hex_all_bytes() {
+    for i in 0..256 {
+        assert_eq!([i as u8].to_hex(), format!("{:02x}", i as usize));
+    }
+}
+
+#[test]
+pub fn test_from_hex_all_bytes() {
+    for i in 0..256 {
+        let ii: &[u8] = &[i as u8];
+        assert_eq!(format!("{:02x}", i as usize).from_hex()
+                                               .unwrap(),
+                   ii);
+        assert_eq!(format!("{:02X}", i as usize).from_hex()
+                                               .unwrap(),
+                   ii);
+    }
+}
+
+#[bench]
+pub fn bench_to_hex(b: &mut Bencher) {
+    let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+             ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+    b.iter(|| {
+        s.as_bytes().to_hex();
+    });
+    b.bytes = s.len() as u64;
+}
+
+#[bench]
+pub fn bench_from_hex(b: &mut Bencher) {
+    let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+             ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+    let sb = s.as_bytes().to_hex();
+    b.iter(|| {
+        sb.from_hex().unwrap();
+    });
+    b.bytes = sb.len() as u64;
+}
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index a4fd288451205..8f926e6dd2909 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -2582,139 +2582,4 @@ impl FromStr for Json {
 }
 
 #[cfg(test)]
-mod tests {
-    // Benchmarks and tests that require private items
-
-    extern crate test;
-    use test::Bencher;
-    use super::{from_str, Parser, StackElement, Stack};
-    use std::string;
-
-    #[test]
-    fn test_stack() {
-        let mut stack = Stack::new();
-
-        assert!(stack.is_empty());
-        assert!(stack.is_empty());
-        assert!(!stack.last_is_index());
-
-        stack.push_index(0);
-        stack.bump_index();
-
-        assert!(stack.len() == 1);
-        assert!(stack.is_equal_to(&[StackElement::Index(1)]));
-        assert!(stack.starts_with(&[StackElement::Index(1)]));
-        assert!(stack.ends_with(&[StackElement::Index(1)]));
-        assert!(stack.last_is_index());
-        assert!(stack.get(0) == StackElement::Index(1));
-
-        stack.push_key("foo".to_string());
-
-        assert!(stack.len() == 2);
-        assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.starts_with(&[StackElement::Index(1)]));
-        assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.ends_with(&[StackElement::Key("foo")]));
-        assert!(!stack.last_is_index());
-        assert!(stack.get(0) == StackElement::Index(1));
-        assert!(stack.get(1) == StackElement::Key("foo"));
-
-        stack.push_key("bar".to_string());
-
-        assert!(stack.len() == 3);
-        assert!(stack.is_equal_to(&[StackElement::Index(1),
-                                    StackElement::Key("foo"),
-                                    StackElement::Key("bar")]));
-        assert!(stack.starts_with(&[StackElement::Index(1)]));
-        assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.starts_with(&[StackElement::Index(1),
-                                    StackElement::Key("foo"),
-                                    StackElement::Key("bar")]));
-        assert!(stack.ends_with(&[StackElement::Key("bar")]));
-        assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
-        assert!(stack.ends_with(&[StackElement::Index(1),
-                                  StackElement::Key("foo"),
-                                  StackElement::Key("bar")]));
-        assert!(!stack.last_is_index());
-        assert!(stack.get(0) == StackElement::Index(1));
-        assert!(stack.get(1) == StackElement::Key("foo"));
-        assert!(stack.get(2) == StackElement::Key("bar"));
-
-        stack.pop();
-
-        assert!(stack.len() == 2);
-        assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.starts_with(&[StackElement::Index(1)]));
-        assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-        assert!(stack.ends_with(&[StackElement::Key("foo")]));
-        assert!(!stack.last_is_index());
-        assert!(stack.get(0) == StackElement::Index(1));
-        assert!(stack.get(1) == StackElement::Key("foo"));
-    }
-
-    #[bench]
-    fn bench_streaming_small(b: &mut Bencher) {
-        b.iter( || {
-            let mut parser = Parser::new(
-                r#"{
-                    "a": 1.0,
-                    "b": [
-                        true,
-                        "foo\nbar",
-                        { "c": {"d": null} }
-                    ]
-                }"#.chars()
-            );
-            loop {
-                match parser.next() {
-                    None => return,
-                    _ => {}
-                }
-            }
-        });
-    }
-    #[bench]
-    fn bench_small(b: &mut Bencher) {
-        b.iter( || {
-            let _ = from_str(r#"{
-                "a": 1.0,
-                "b": [
-                    true,
-                    "foo\nbar",
-                    { "c": {"d": null} }
-                ]
-            }"#);
-        });
-    }
-
-    fn big_json() -> string::String {
-        let mut src = "[\n".to_string();
-        for _ in 0..500 {
-            src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
-                            [1,2,3]},"#);
-        }
-        src.push_str("{}]");
-        return src;
-    }
-
-    #[bench]
-    fn bench_streaming_large(b: &mut Bencher) {
-        let src = big_json();
-        b.iter( || {
-            let mut parser = Parser::new(src.chars());
-            loop {
-                match parser.next() {
-                    None => return,
-                    _ => {}
-                }
-            }
-        });
-    }
-    #[bench]
-    fn bench_large(b: &mut Bencher) {
-        let src = big_json();
-        b.iter( || { let _ = from_str(&src); });
-    }
-}
+mod tests;
diff --git a/src/libserialize/json/tests.rs b/src/libserialize/json/tests.rs
new file mode 100644
index 0000000000000..a16b8bdd78704
--- /dev/null
+++ b/src/libserialize/json/tests.rs
@@ -0,0 +1,134 @@
+// Benchmarks and tests that require private items
+
+extern crate test;
+use test::Bencher;
+use super::{from_str, Parser, StackElement, Stack};
+use std::string;
+
+#[test]
+fn test_stack() {
+    let mut stack = Stack::new();
+
+    assert!(stack.is_empty());
+    assert!(stack.is_empty());
+    assert!(!stack.last_is_index());
+
+    stack.push_index(0);
+    stack.bump_index();
+
+    assert!(stack.len() == 1);
+    assert!(stack.is_equal_to(&[StackElement::Index(1)]));
+    assert!(stack.starts_with(&[StackElement::Index(1)]));
+    assert!(stack.ends_with(&[StackElement::Index(1)]));
+    assert!(stack.last_is_index());
+    assert!(stack.get(0) == StackElement::Index(1));
+
+    stack.push_key("foo".to_string());
+
+    assert!(stack.len() == 2);
+    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.starts_with(&[StackElement::Index(1)]));
+    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.ends_with(&[StackElement::Key("foo")]));
+    assert!(!stack.last_is_index());
+    assert!(stack.get(0) == StackElement::Index(1));
+    assert!(stack.get(1) == StackElement::Key("foo"));
+
+    stack.push_key("bar".to_string());
+
+    assert!(stack.len() == 3);
+    assert!(stack.is_equal_to(&[StackElement::Index(1),
+                                StackElement::Key("foo"),
+                                StackElement::Key("bar")]));
+    assert!(stack.starts_with(&[StackElement::Index(1)]));
+    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.starts_with(&[StackElement::Index(1),
+                                StackElement::Key("foo"),
+                                StackElement::Key("bar")]));
+    assert!(stack.ends_with(&[StackElement::Key("bar")]));
+    assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
+    assert!(stack.ends_with(&[StackElement::Index(1),
+                              StackElement::Key("foo"),
+                              StackElement::Key("bar")]));
+    assert!(!stack.last_is_index());
+    assert!(stack.get(0) == StackElement::Index(1));
+    assert!(stack.get(1) == StackElement::Key("foo"));
+    assert!(stack.get(2) == StackElement::Key("bar"));
+
+    stack.pop();
+
+    assert!(stack.len() == 2);
+    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.starts_with(&[StackElement::Index(1)]));
+    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
+    assert!(stack.ends_with(&[StackElement::Key("foo")]));
+    assert!(!stack.last_is_index());
+    assert!(stack.get(0) == StackElement::Index(1));
+    assert!(stack.get(1) == StackElement::Key("foo"));
+}
+
+#[bench]
+fn bench_streaming_small(b: &mut Bencher) {
+    b.iter( || {
+        let mut parser = Parser::new(
+            r#"{
+                "a": 1.0,
+                "b": [
+                    true,
+                    "foo\nbar",
+                    { "c": {"d": null} }
+                ]
+            }"#.chars()
+        );
+        loop {
+            match parser.next() {
+                None => return,
+                _ => {}
+            }
+        }
+    });
+}
+#[bench]
+fn bench_small(b: &mut Bencher) {
+    b.iter( || {
+        let _ = from_str(r#"{
+            "a": 1.0,
+            "b": [
+                true,
+                "foo\nbar",
+                { "c": {"d": null} }
+            ]
+        }"#);
+    });
+}
+
+fn big_json() -> string::String {
+    let mut src = "[\n".to_string();
+    for _ in 0..500 {
+        src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
+                        [1,2,3]},"#);
+    }
+    src.push_str("{}]");
+    return src;
+}
+
+#[bench]
+fn bench_streaming_large(b: &mut Bencher) {
+    let src = big_json();
+    b.iter( || {
+        let mut parser = Parser::new(src.chars());
+        loop {
+            match parser.next() {
+                None => return,
+                _ => {}
+            }
+        }
+    });
+}
+#[bench]
+fn bench_large(b: &mut Bencher) {
+    let src = big_json();
+    b.iter( || { let _ = from_str(&src); });
+}
diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs
index 7ad5997bf2c09..3d4f82764413a 100644
--- a/src/libsyntax_ext/format_foreign.rs
+++ b/src/libsyntax_ext/format_foreign.rs
@@ -605,159 +605,7 @@ pub mod printf {
     }
 
     #[cfg(test)]
-    mod tests {
-        use super::{
-            Format as F,
-            Num as N,
-            Substitution as S,
-            iter_subs,
-            parse_next_substitution as pns,
-        };
-
-        macro_rules! assert_eq_pnsat {
-            ($lhs:expr, $rhs:expr) => {
-                assert_eq!(
-                    pns($lhs).and_then(|(s, _)| s.translate()),
-                    $rhs.map(<String as From<&str>>::from)
-                )
-            };
-        }
-
-        #[test]
-        fn test_escape() {
-            assert_eq!(pns("has no escapes"), None);
-            assert_eq!(pns("has no escapes, either %"), None);
-            assert_eq!(pns("*so* has a %% escape"), Some((S::Escape," escape")));
-            assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape")));
-            assert_eq!(pns("trailing escape %%"), Some((S::Escape, "")));
-        }
-
-        #[test]
-        fn test_parse() {
-            macro_rules! assert_pns_eq_sub {
-                ($in_:expr, {
-                    $param:expr, $flags:expr,
-                    $width:expr, $prec:expr, $len:expr, $type_:expr,
-                    $pos:expr,
-                }) => {
-                    assert_eq!(
-                        pns(concat!($in_, "!")),
-                        Some((
-                            S::Format(F {
-                                span: $in_,
-                                parameter: $param,
-                                flags: $flags,
-                                width: $width,
-                                precision: $prec,
-                                length: $len,
-                                type_: $type_,
-                                position: syntax_pos::InnerSpan::new($pos.0, $pos.1),
-                            }),
-                            "!"
-                        ))
-                    )
-                };
-            }
-
-            assert_pns_eq_sub!("%!",
-                { None, "", None, None, None, "!", (0, 2), });
-            assert_pns_eq_sub!("%c",
-                { None, "", None, None, None, "c", (0, 2), });
-            assert_pns_eq_sub!("%s",
-                { None, "", None, None, None, "s", (0, 2), });
-            assert_pns_eq_sub!("%06d",
-                { None, "0", Some(N::Num(6)), None, None, "d", (0, 4), });
-            assert_pns_eq_sub!("%4.2f",
-                { None, "", Some(N::Num(4)), Some(N::Num(2)), None, "f", (0, 5), });
-            assert_pns_eq_sub!("%#x",
-                { None, "#", None, None, None, "x", (0, 3), });
-            assert_pns_eq_sub!("%-10s",
-                { None, "-", Some(N::Num(10)), None, None, "s", (0, 5), });
-            assert_pns_eq_sub!("%*s",
-                { None, "", Some(N::Next), None, None, "s", (0, 3), });
-            assert_pns_eq_sub!("%-10.*s",
-                { None, "-", Some(N::Num(10)), Some(N::Next), None, "s", (0, 7), });
-            assert_pns_eq_sub!("%-*.*s",
-                { None, "-", Some(N::Next), Some(N::Next), None, "s", (0, 6), });
-            assert_pns_eq_sub!("%.6i",
-                { None, "", None, Some(N::Num(6)), None, "i", (0, 4), });
-            assert_pns_eq_sub!("%+i",
-                { None, "+", None, None, None, "i", (0, 3), });
-            assert_pns_eq_sub!("%08X",
-                { None, "0", Some(N::Num(8)), None, None, "X", (0, 4), });
-            assert_pns_eq_sub!("%lu",
-                { None, "", None, None, Some("l"), "u", (0, 3), });
-            assert_pns_eq_sub!("%Iu",
-                { None, "", None, None, Some("I"), "u", (0, 3), });
-            assert_pns_eq_sub!("%I32u",
-                { None, "", None, None, Some("I32"), "u", (0, 5), });
-            assert_pns_eq_sub!("%I64u",
-                { None, "", None, None, Some("I64"), "u", (0, 5), });
-            assert_pns_eq_sub!("%'d",
-                { None, "'", None, None, None, "d", (0, 3), });
-            assert_pns_eq_sub!("%10s",
-                { None, "", Some(N::Num(10)), None, None, "s", (0, 4), });
-            assert_pns_eq_sub!("%-10.10s",
-                { None, "-", Some(N::Num(10)), Some(N::Num(10)), None, "s", (0, 8), });
-            assert_pns_eq_sub!("%1$d",
-                { Some(1), "", None, None, None, "d", (0, 4), });
-            assert_pns_eq_sub!("%2$.*3$d",
-                { Some(2), "", None, Some(N::Arg(3)), None, "d", (0, 8), });
-            assert_pns_eq_sub!("%1$*2$.*3$d",
-                { Some(1), "", Some(N::Arg(2)), Some(N::Arg(3)), None, "d", (0, 11), });
-            assert_pns_eq_sub!("%-8ld",
-                { None, "-", Some(N::Num(8)), None, Some("l"), "d", (0, 5), });
-        }
-
-        #[test]
-        fn test_iter() {
-            let s = "The %d'th word %% is: `%.*s` %!\n";
-            let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
-            assert_eq!(
-                subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
-                vec![Some("{}"), None, Some("{:.*}"), None]
-            );
-        }
-
-        /// Checks that the translations are what we expect.
-        #[test]
-        fn test_translation() {
-            assert_eq_pnsat!("%c", Some("{}"));
-            assert_eq_pnsat!("%d", Some("{}"));
-            assert_eq_pnsat!("%u", Some("{}"));
-            assert_eq_pnsat!("%x", Some("{:x}"));
-            assert_eq_pnsat!("%X", Some("{:X}"));
-            assert_eq_pnsat!("%e", Some("{:e}"));
-            assert_eq_pnsat!("%E", Some("{:E}"));
-            assert_eq_pnsat!("%f", Some("{}"));
-            assert_eq_pnsat!("%g", Some("{:e}"));
-            assert_eq_pnsat!("%G", Some("{:E}"));
-            assert_eq_pnsat!("%s", Some("{}"));
-            assert_eq_pnsat!("%p", Some("{:p}"));
-
-            assert_eq_pnsat!("%06d",        Some("{:06}"));
-            assert_eq_pnsat!("%4.2f",       Some("{:4.2}"));
-            assert_eq_pnsat!("%#x",         Some("{:#x}"));
-            assert_eq_pnsat!("%-10s",       Some("{:<10}"));
-            assert_eq_pnsat!("%*s",         None);
-            assert_eq_pnsat!("%-10.*s",     Some("{:<10.*}"));
-            assert_eq_pnsat!("%-*.*s",      None);
-            assert_eq_pnsat!("%.6i",        Some("{:06}"));
-            assert_eq_pnsat!("%+i",         Some("{:+}"));
-            assert_eq_pnsat!("%08X",        Some("{:08X}"));
-            assert_eq_pnsat!("%lu",         Some("{}"));
-            assert_eq_pnsat!("%Iu",         Some("{}"));
-            assert_eq_pnsat!("%I32u",       Some("{}"));
-            assert_eq_pnsat!("%I64u",       Some("{}"));
-            assert_eq_pnsat!("%'d",         None);
-            assert_eq_pnsat!("%10s",        Some("{:>10}"));
-            assert_eq_pnsat!("%-10.10s",    Some("{:<10.10}"));
-            assert_eq_pnsat!("%1$d",        Some("{0}"));
-            assert_eq_pnsat!("%2$.*3$d",    Some("{1:02$}"));
-            assert_eq_pnsat!("%1$*2$.*3$s", Some("{0:>1$.2$}"));
-            assert_eq_pnsat!("%-8ld",       Some("{:<8}"));
-        }
-    }
+    mod tests;
 }
 
 pub mod shell {
@@ -899,68 +747,7 @@ pub mod shell {
     }
 
     #[cfg(test)]
-    mod tests {
-        use super::{
-            Substitution as S,
-            parse_next_substitution as pns,
-        };
-
-        macro_rules! assert_eq_pnsat {
-            ($lhs:expr, $rhs:expr) => {
-                assert_eq!(
-                    pns($lhs).and_then(|(f, _)| f.translate()),
-                    $rhs.map(<String as From<&str>>::from)
-                )
-            };
-        }
-
-        #[test]
-        fn test_escape() {
-            assert_eq!(pns("has no escapes"), None);
-            assert_eq!(pns("has no escapes, either $"), None);
-            assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape((11, 13)), " escape")));
-            assert_eq!(pns("$$ leading escape"), Some((S::Escape((0, 2)), " leading escape")));
-            assert_eq!(pns("trailing escape $$"), Some((S::Escape((16, 18)), "")));
-        }
-
-        #[test]
-        fn test_parse() {
-            macro_rules! assert_pns_eq_sub {
-                ($in_:expr, $kind:ident($arg:expr, $pos:expr)) => {
-                    assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into(), $pos), "!")))
-                };
-            }
-
-            assert_pns_eq_sub!("$0", Ordinal(0, (0, 2)));
-            assert_pns_eq_sub!("$1", Ordinal(1, (0, 2)));
-            assert_pns_eq_sub!("$9", Ordinal(9, (0, 2)));
-            assert_pns_eq_sub!("$N", Name("N", (0, 2)));
-            assert_pns_eq_sub!("$NAME", Name("NAME", (0, 5)));
-        }
-
-        #[test]
-        fn test_iter() {
-            use super::iter_subs;
-            let s = "The $0'th word $$ is: `$WORD` $!\n";
-            let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
-            assert_eq!(
-                subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
-                vec![Some("{0}"), None, Some("{WORD}")]
-            );
-        }
-
-        #[test]
-        fn test_translation() {
-            assert_eq_pnsat!("$0", Some("{0}"));
-            assert_eq_pnsat!("$9", Some("{9}"));
-            assert_eq_pnsat!("$1", Some("{1}"));
-            assert_eq_pnsat!("$10", Some("{1}"));
-            assert_eq_pnsat!("$stuff", Some("{stuff}"));
-            assert_eq_pnsat!("$NAME", Some("{NAME}"));
-            assert_eq_pnsat!("$PREFIX/bin", Some("{PREFIX}"));
-        }
-
-    }
+    mod tests;
 }
 
 mod strcursor {
diff --git a/src/libsyntax_ext/format_foreign/printf/tests.rs b/src/libsyntax_ext/format_foreign/printf/tests.rs
new file mode 100644
index 0000000000000..87021f1ef5a52
--- /dev/null
+++ b/src/libsyntax_ext/format_foreign/printf/tests.rs
@@ -0,0 +1,151 @@
+use super::{
+    Format as F,
+    Num as N,
+    Substitution as S,
+    iter_subs,
+    parse_next_substitution as pns,
+};
+
+macro_rules! assert_eq_pnsat {
+    ($lhs:expr, $rhs:expr) => {
+        assert_eq!(
+            pns($lhs).and_then(|(s, _)| s.translate()),
+            $rhs.map(<String as From<&str>>::from)
+        )
+    };
+}
+
+#[test]
+fn test_escape() {
+    assert_eq!(pns("has no escapes"), None);
+    assert_eq!(pns("has no escapes, either %"), None);
+    assert_eq!(pns("*so* has a %% escape"), Some((S::Escape," escape")));
+    assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape")));
+    assert_eq!(pns("trailing escape %%"), Some((S::Escape, "")));
+}
+
+#[test]
+fn test_parse() {
+    macro_rules! assert_pns_eq_sub {
+        ($in_:expr, {
+            $param:expr, $flags:expr,
+            $width:expr, $prec:expr, $len:expr, $type_:expr,
+            $pos:expr,
+        }) => {
+            assert_eq!(
+                pns(concat!($in_, "!")),
+                Some((
+                    S::Format(F {
+                        span: $in_,
+                        parameter: $param,
+                        flags: $flags,
+                        width: $width,
+                        precision: $prec,
+                        length: $len,
+                        type_: $type_,
+                        position: syntax_pos::InnerSpan::new($pos.0, $pos.1),
+                    }),
+                    "!"
+                ))
+            )
+        };
+    }
+
+    assert_pns_eq_sub!("%!",
+        { None, "", None, None, None, "!", (0, 2), });
+    assert_pns_eq_sub!("%c",
+        { None, "", None, None, None, "c", (0, 2), });
+    assert_pns_eq_sub!("%s",
+        { None, "", None, None, None, "s", (0, 2), });
+    assert_pns_eq_sub!("%06d",
+        { None, "0", Some(N::Num(6)), None, None, "d", (0, 4), });
+    assert_pns_eq_sub!("%4.2f",
+        { None, "", Some(N::Num(4)), Some(N::Num(2)), None, "f", (0, 5), });
+    assert_pns_eq_sub!("%#x",
+        { None, "#", None, None, None, "x", (0, 3), });
+    assert_pns_eq_sub!("%-10s",
+        { None, "-", Some(N::Num(10)), None, None, "s", (0, 5), });
+    assert_pns_eq_sub!("%*s",
+        { None, "", Some(N::Next), None, None, "s", (0, 3), });
+    assert_pns_eq_sub!("%-10.*s",
+        { None, "-", Some(N::Num(10)), Some(N::Next), None, "s", (0, 7), });
+    assert_pns_eq_sub!("%-*.*s",
+        { None, "-", Some(N::Next), Some(N::Next), None, "s", (0, 6), });
+    assert_pns_eq_sub!("%.6i",
+        { None, "", None, Some(N::Num(6)), None, "i", (0, 4), });
+    assert_pns_eq_sub!("%+i",
+        { None, "+", None, None, None, "i", (0, 3), });
+    assert_pns_eq_sub!("%08X",
+        { None, "0", Some(N::Num(8)), None, None, "X", (0, 4), });
+    assert_pns_eq_sub!("%lu",
+        { None, "", None, None, Some("l"), "u", (0, 3), });
+    assert_pns_eq_sub!("%Iu",
+        { None, "", None, None, Some("I"), "u", (0, 3), });
+    assert_pns_eq_sub!("%I32u",
+        { None, "", None, None, Some("I32"), "u", (0, 5), });
+    assert_pns_eq_sub!("%I64u",
+        { None, "", None, None, Some("I64"), "u", (0, 5), });
+    assert_pns_eq_sub!("%'d",
+        { None, "'", None, None, None, "d", (0, 3), });
+    assert_pns_eq_sub!("%10s",
+        { None, "", Some(N::Num(10)), None, None, "s", (0, 4), });
+    assert_pns_eq_sub!("%-10.10s",
+        { None, "-", Some(N::Num(10)), Some(N::Num(10)), None, "s", (0, 8), });
+    assert_pns_eq_sub!("%1$d",
+        { Some(1), "", None, None, None, "d", (0, 4), });
+    assert_pns_eq_sub!("%2$.*3$d",
+        { Some(2), "", None, Some(N::Arg(3)), None, "d", (0, 8), });
+    assert_pns_eq_sub!("%1$*2$.*3$d",
+        { Some(1), "", Some(N::Arg(2)), Some(N::Arg(3)), None, "d", (0, 11), });
+    assert_pns_eq_sub!("%-8ld",
+        { None, "-", Some(N::Num(8)), None, Some("l"), "d", (0, 5), });
+}
+
+#[test]
+fn test_iter() {
+    let s = "The %d'th word %% is: `%.*s` %!\n";
+    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
+    assert_eq!(
+        subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
+        vec![Some("{}"), None, Some("{:.*}"), None]
+    );
+}
+
+/// Checks that the translations are what we expect.
+#[test]
+fn test_translation() {
+    assert_eq_pnsat!("%c", Some("{}"));
+    assert_eq_pnsat!("%d", Some("{}"));
+    assert_eq_pnsat!("%u", Some("{}"));
+    assert_eq_pnsat!("%x", Some("{:x}"));
+    assert_eq_pnsat!("%X", Some("{:X}"));
+    assert_eq_pnsat!("%e", Some("{:e}"));
+    assert_eq_pnsat!("%E", Some("{:E}"));
+    assert_eq_pnsat!("%f", Some("{}"));
+    assert_eq_pnsat!("%g", Some("{:e}"));
+    assert_eq_pnsat!("%G", Some("{:E}"));
+    assert_eq_pnsat!("%s", Some("{}"));
+    assert_eq_pnsat!("%p", Some("{:p}"));
+
+    assert_eq_pnsat!("%06d",        Some("{:06}"));
+    assert_eq_pnsat!("%4.2f",       Some("{:4.2}"));
+    assert_eq_pnsat!("%#x",         Some("{:#x}"));
+    assert_eq_pnsat!("%-10s",       Some("{:<10}"));
+    assert_eq_pnsat!("%*s",         None);
+    assert_eq_pnsat!("%-10.*s",     Some("{:<10.*}"));
+    assert_eq_pnsat!("%-*.*s",      None);
+    assert_eq_pnsat!("%.6i",        Some("{:06}"));
+    assert_eq_pnsat!("%+i",         Some("{:+}"));
+    assert_eq_pnsat!("%08X",        Some("{:08X}"));
+    assert_eq_pnsat!("%lu",         Some("{}"));
+    assert_eq_pnsat!("%Iu",         Some("{}"));
+    assert_eq_pnsat!("%I32u",       Some("{}"));
+    assert_eq_pnsat!("%I64u",       Some("{}"));
+    assert_eq_pnsat!("%'d",         None);
+    assert_eq_pnsat!("%10s",        Some("{:>10}"));
+    assert_eq_pnsat!("%-10.10s",    Some("{:<10.10}"));
+    assert_eq_pnsat!("%1$d",        Some("{0}"));
+    assert_eq_pnsat!("%2$.*3$d",    Some("{1:02$}"));
+    assert_eq_pnsat!("%1$*2$.*3$s", Some("{0:>1$.2$}"));
+    assert_eq_pnsat!("%-8ld",       Some("{:<8}"));
+}
diff --git a/src/libsyntax_ext/format_foreign/shell/tests.rs b/src/libsyntax_ext/format_foreign/shell/tests.rs
new file mode 100644
index 0000000000000..8ef58b8387e5a
--- /dev/null
+++ b/src/libsyntax_ext/format_foreign/shell/tests.rs
@@ -0,0 +1,59 @@
+use super::{
+    Substitution as S,
+    parse_next_substitution as pns,
+};
+
+macro_rules! assert_eq_pnsat {
+    ($lhs:expr, $rhs:expr) => {
+        assert_eq!(
+            pns($lhs).and_then(|(f, _)| f.translate()),
+            $rhs.map(<String as From<&str>>::from)
+        )
+    };
+}
+
+#[test]
+fn test_escape() {
+    assert_eq!(pns("has no escapes"), None);
+    assert_eq!(pns("has no escapes, either $"), None);
+    assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape((11, 13)), " escape")));
+    assert_eq!(pns("$$ leading escape"), Some((S::Escape((0, 2)), " leading escape")));
+    assert_eq!(pns("trailing escape $$"), Some((S::Escape((16, 18)), "")));
+}
+
+#[test]
+fn test_parse() {
+    macro_rules! assert_pns_eq_sub {
+        ($in_:expr, $kind:ident($arg:expr, $pos:expr)) => {
+            assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into(), $pos), "!")))
+        };
+    }
+
+    assert_pns_eq_sub!("$0", Ordinal(0, (0, 2)));
+    assert_pns_eq_sub!("$1", Ordinal(1, (0, 2)));
+    assert_pns_eq_sub!("$9", Ordinal(9, (0, 2)));
+    assert_pns_eq_sub!("$N", Name("N", (0, 2)));
+    assert_pns_eq_sub!("$NAME", Name("NAME", (0, 5)));
+}
+
+#[test]
+fn test_iter() {
+    use super::iter_subs;
+    let s = "The $0'th word $$ is: `$WORD` $!\n";
+    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
+    assert_eq!(
+        subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
+        vec![Some("{0}"), None, Some("{WORD}")]
+    );
+}
+
+#[test]
+fn test_translation() {
+    assert_eq_pnsat!("$0", Some("{0}"));
+    assert_eq_pnsat!("$9", Some("{9}"));
+    assert_eq_pnsat!("$1", Some("{1}"));
+    assert_eq_pnsat!("$10", Some("{1}"));
+    assert_eq_pnsat!("$stuff", Some("{stuff}"));
+    assert_eq_pnsat!("$NAME", Some("{NAME}"));
+    assert_eq_pnsat!("$PREFIX/bin", Some("{PREFIX}"));
+}
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 810a98e4a014c..53bf67bdf671f 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1772,458 +1772,4 @@ pub mod bench {
 }
 
 #[cfg(test)]
-mod tests {
-    use crate::bench;
-    use crate::test::{
-        filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
-        ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
-        TrIgnored, TrOk,
-    };
-    use crate::Bencher;
-    use crate::Concurrent;
-    use std::sync::mpsc::channel;
-
-    fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
-        vec![
-            TestDescAndFn {
-                desc: TestDesc {
-                    name: StaticTestName("1"),
-                    ignore: true,
-                    should_panic: ShouldPanic::No,
-                    allow_fail: false,
-                },
-                testfn: DynTestFn(Box::new(move || {})),
-            },
-            TestDescAndFn {
-                desc: TestDesc {
-                    name: StaticTestName("2"),
-                    ignore: false,
-                    should_panic: ShouldPanic::No,
-                    allow_fail: false,
-                },
-                testfn: DynTestFn(Box::new(move || {})),
-            },
-        ]
-    }
-
-    #[test]
-    pub fn do_not_run_ignored_tests() {
-        fn f() {
-            panic!();
-        }
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: true,
-                should_panic: ShouldPanic::No,
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res != TrOk);
-    }
-
-    #[test]
-    pub fn ignored_tests_result_in_ignored() {
-        fn f() {}
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: true,
-                should_panic: ShouldPanic::No,
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res == TrIgnored);
-    }
-
-    #[test]
-    fn test_should_panic() {
-        fn f() {
-            panic!();
-        }
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: false,
-                should_panic: ShouldPanic::Yes,
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res == TrOk);
-    }
-
-    #[test]
-    fn test_should_panic_good_message() {
-        fn f() {
-            panic!("an error message");
-        }
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: false,
-                should_panic: ShouldPanic::YesWithMessage("error message"),
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res == TrOk);
-    }
-
-    #[test]
-    fn test_should_panic_bad_message() {
-        fn f() {
-            panic!("an error message");
-        }
-        let expected = "foobar";
-        let failed_msg = "panic did not include expected string";
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: false,
-                should_panic: ShouldPanic::YesWithMessage(expected),
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
-    }
-
-    #[test]
-    fn test_should_panic_but_succeeds() {
-        fn f() {}
-        let desc = TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("whatever"),
-                ignore: false,
-                should_panic: ShouldPanic::Yes,
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(f)),
-        };
-        let (tx, rx) = channel();
-        run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
-        let (_, res, _) = rx.recv().unwrap();
-        assert!(res == TrFailed);
-    }
-
-    #[test]
-    fn parse_ignored_flag() {
-        let args = vec![
-            "progname".to_string(),
-            "filter".to_string(),
-            "--ignored".to_string(),
-        ];
-        let opts = parse_opts(&args).unwrap().unwrap();
-        assert_eq!(opts.run_ignored, RunIgnored::Only);
-    }
-
-    #[test]
-    fn parse_include_ignored_flag() {
-        let args = vec![
-            "progname".to_string(),
-            "filter".to_string(),
-            "-Zunstable-options".to_string(),
-            "--include-ignored".to_string(),
-        ];
-        let opts = parse_opts(&args).unwrap().unwrap();
-        assert_eq!(opts.run_ignored, RunIgnored::Yes);
-    }
-
-    #[test]
-    pub fn filter_for_ignored_option() {
-        // When we run ignored tests the test filter should filter out all the
-        // unignored tests and flip the ignore flag on the rest to false
-
-        let mut opts = TestOpts::new();
-        opts.run_tests = true;
-        opts.run_ignored = RunIgnored::Only;
-
-        let tests = one_ignored_one_unignored_test();
-        let filtered = filter_tests(&opts, tests);
-
-        assert_eq!(filtered.len(), 1);
-        assert_eq!(filtered[0].desc.name.to_string(), "1");
-        assert!(!filtered[0].desc.ignore);
-    }
-
-    #[test]
-    pub fn run_include_ignored_option() {
-        // When we "--include-ignored" tests, the ignore flag should be set to false on
-        // all tests and no test filtered out
-
-        let mut opts = TestOpts::new();
-        opts.run_tests = true;
-        opts.run_ignored = RunIgnored::Yes;
-
-        let tests = one_ignored_one_unignored_test();
-        let filtered = filter_tests(&opts, tests);
-
-        assert_eq!(filtered.len(), 2);
-        assert!(!filtered[0].desc.ignore);
-        assert!(!filtered[1].desc.ignore);
-    }
-
-    #[test]
-    pub fn exclude_should_panic_option() {
-        let mut opts = TestOpts::new();
-        opts.run_tests = true;
-        opts.exclude_should_panic = true;
-
-        let mut tests = one_ignored_one_unignored_test();
-        tests.push(TestDescAndFn {
-            desc: TestDesc {
-                name: StaticTestName("3"),
-                ignore: false,
-                should_panic: ShouldPanic::Yes,
-                allow_fail: false,
-            },
-            testfn: DynTestFn(Box::new(move || {})),
-        });
-
-        let filtered = filter_tests(&opts, tests);
-
-        assert_eq!(filtered.len(), 2);
-        assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
-    }
-
-    #[test]
-    pub fn exact_filter_match() {
-        fn tests() -> Vec<TestDescAndFn> {
-            vec!["base", "base::test", "base::test1", "base::test2"]
-                .into_iter()
-                .map(|name| TestDescAndFn {
-                    desc: TestDesc {
-                        name: StaticTestName(name),
-                        ignore: false,
-                        should_panic: ShouldPanic::No,
-                        allow_fail: false,
-                    },
-                    testfn: DynTestFn(Box::new(move || {})),
-                })
-                .collect()
-        }
-
-        let substr = filter_tests(
-            &TestOpts {
-                filter: Some("base".into()),
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(substr.len(), 4);
-
-        let substr = filter_tests(
-            &TestOpts {
-                filter: Some("bas".into()),
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(substr.len(), 4);
-
-        let substr = filter_tests(
-            &TestOpts {
-                filter: Some("::test".into()),
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(substr.len(), 3);
-
-        let substr = filter_tests(
-            &TestOpts {
-                filter: Some("base::test".into()),
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(substr.len(), 3);
-
-        let exact = filter_tests(
-            &TestOpts {
-                filter: Some("base".into()),
-                filter_exact: true,
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(exact.len(), 1);
-
-        let exact = filter_tests(
-            &TestOpts {
-                filter: Some("bas".into()),
-                filter_exact: true,
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(exact.len(), 0);
-
-        let exact = filter_tests(
-            &TestOpts {
-                filter: Some("::test".into()),
-                filter_exact: true,
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(exact.len(), 0);
-
-        let exact = filter_tests(
-            &TestOpts {
-                filter: Some("base::test".into()),
-                filter_exact: true,
-                ..TestOpts::new()
-            },
-            tests(),
-        );
-        assert_eq!(exact.len(), 1);
-    }
-
-    #[test]
-    pub fn sort_tests() {
-        let mut opts = TestOpts::new();
-        opts.run_tests = true;
-
-        let names = vec![
-            "sha1::test".to_string(),
-            "isize::test_to_str".to_string(),
-            "isize::test_pow".to_string(),
-            "test::do_not_run_ignored_tests".to_string(),
-            "test::ignored_tests_result_in_ignored".to_string(),
-            "test::first_free_arg_should_be_a_filter".to_string(),
-            "test::parse_ignored_flag".to_string(),
-            "test::parse_include_ignored_flag".to_string(),
-            "test::filter_for_ignored_option".to_string(),
-            "test::run_include_ignored_option".to_string(),
-            "test::sort_tests".to_string(),
-        ];
-        let tests = {
-            fn testfn() {}
-            let mut tests = Vec::new();
-            for name in &names {
-                let test = TestDescAndFn {
-                    desc: TestDesc {
-                        name: DynTestName((*name).clone()),
-                        ignore: false,
-                        should_panic: ShouldPanic::No,
-                        allow_fail: false,
-                    },
-                    testfn: DynTestFn(Box::new(testfn)),
-                };
-                tests.push(test);
-            }
-            tests
-        };
-        let filtered = filter_tests(&opts, tests);
-
-        let expected = vec![
-            "isize::test_pow".to_string(),
-            "isize::test_to_str".to_string(),
-            "sha1::test".to_string(),
-            "test::do_not_run_ignored_tests".to_string(),
-            "test::filter_for_ignored_option".to_string(),
-            "test::first_free_arg_should_be_a_filter".to_string(),
-            "test::ignored_tests_result_in_ignored".to_string(),
-            "test::parse_ignored_flag".to_string(),
-            "test::parse_include_ignored_flag".to_string(),
-            "test::run_include_ignored_option".to_string(),
-            "test::sort_tests".to_string(),
-        ];
-
-        for (a, b) in expected.iter().zip(filtered) {
-            assert!(*a == b.desc.name.to_string());
-        }
-    }
-
-    #[test]
-    pub fn test_metricmap_compare() {
-        let mut m1 = MetricMap::new();
-        let mut m2 = MetricMap::new();
-        m1.insert_metric("in-both-noise", 1000.0, 200.0);
-        m2.insert_metric("in-both-noise", 1100.0, 200.0);
-
-        m1.insert_metric("in-first-noise", 1000.0, 2.0);
-        m2.insert_metric("in-second-noise", 1000.0, 2.0);
-
-        m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
-        m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
-
-        m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
-        m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
-
-        m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
-        m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
-
-        m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
-        m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
-    }
-
-    #[test]
-    pub fn test_bench_once_no_iter() {
-        fn f(_: &mut Bencher) {}
-        bench::run_once(f);
-    }
-
-    #[test]
-    pub fn test_bench_once_iter() {
-        fn f(b: &mut Bencher) {
-            b.iter(|| {})
-        }
-        bench::run_once(f);
-    }
-
-    #[test]
-    pub fn test_bench_no_iter() {
-        fn f(_: &mut Bencher) {}
-
-        let (tx, rx) = channel();
-
-        let desc = TestDesc {
-            name: StaticTestName("f"),
-            ignore: false,
-            should_panic: ShouldPanic::No,
-            allow_fail: false,
-        };
-
-        crate::bench::benchmark(desc, tx, true, f);
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    pub fn test_bench_iter() {
-        fn f(b: &mut Bencher) {
-            b.iter(|| {})
-        }
-
-        let (tx, rx) = channel();
-
-        let desc = TestDesc {
-            name: StaticTestName("f"),
-            ignore: false,
-            should_panic: ShouldPanic::No,
-            allow_fail: false,
-        };
-
-        crate::bench::benchmark(desc, tx, true, f);
-        rx.recv().unwrap();
-    }
-}
+mod tests;
diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs
index 5c9421d5ea4b0..32c30061983ab 100644
--- a/src/libtest/stats.rs
+++ b/src/libtest/stats.rs
@@ -318,582 +318,7 @@ pub fn winsorize(samples: &mut [f64], pct: f64) {
 // Test vectors generated from R, using the script src/etc/stat-test-vectors.r.
 
 #[cfg(test)]
-mod tests {
-    use crate::stats::Stats;
-    use crate::stats::Summary;
-    use std::f64;
-    use std::io::prelude::*;
-    use std::io;
-
-    macro_rules! assert_approx_eq {
-        ($a: expr, $b: expr) => {{
-            let (a, b) = (&$a, &$b);
-            assert!(
-                (*a - *b).abs() < 1.0e-6,
-                "{} is not approximately equal to {}",
-                *a,
-                *b
-            );
-        }};
-    }
-
-    fn check(samples: &[f64], summ: &Summary) {
-        let summ2 = Summary::new(samples);
-
-        let mut w = io::sink();
-        let w = &mut w;
-        (write!(w, "\n")).unwrap();
-
-        assert_eq!(summ.sum, summ2.sum);
-        assert_eq!(summ.min, summ2.min);
-        assert_eq!(summ.max, summ2.max);
-        assert_eq!(summ.mean, summ2.mean);
-        assert_eq!(summ.median, summ2.median);
-
-        // We needed a few more digits to get exact equality on these
-        // but they're within float epsilon, which is 1.0e-6.
-        assert_approx_eq!(summ.var, summ2.var);
-        assert_approx_eq!(summ.std_dev, summ2.std_dev);
-        assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct);
-        assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev);
-        assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct);
-
-        assert_eq!(summ.quartiles, summ2.quartiles);
-        assert_eq!(summ.iqr, summ2.iqr);
-    }
-
-    #[test]
-    fn test_min_max_nan() {
-        let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0];
-        let summary = Summary::new(xs);
-        assert_eq!(summary.min, 1.0);
-        assert_eq!(summary.max, 4.0);
-    }
-
-    #[test]
-    fn test_norm2() {
-        let val = &[958.0000000000, 924.0000000000];
-        let summ = &Summary {
-            sum: 1882.0000000000,
-            min: 924.0000000000,
-            max: 958.0000000000,
-            mean: 941.0000000000,
-            median: 941.0000000000,
-            var: 578.0000000000,
-            std_dev: 24.0416305603,
-            std_dev_pct: 2.5549022912,
-            median_abs_dev: 25.2042000000,
-            median_abs_dev_pct: 2.6784484591,
-            quartiles: (932.5000000000, 941.0000000000, 949.5000000000),
-            iqr: 17.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_norm10narrow() {
-        let val = &[
-            966.0000000000,
-            985.0000000000,
-            1110.0000000000,
-            848.0000000000,
-            821.0000000000,
-            975.0000000000,
-            962.0000000000,
-            1157.0000000000,
-            1217.0000000000,
-            955.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 9996.0000000000,
-            min: 821.0000000000,
-            max: 1217.0000000000,
-            mean: 999.6000000000,
-            median: 970.5000000000,
-            var: 16050.7111111111,
-            std_dev: 126.6914010938,
-            std_dev_pct: 12.6742097933,
-            median_abs_dev: 102.2994000000,
-            median_abs_dev_pct: 10.5408964451,
-            quartiles: (956.7500000000, 970.5000000000, 1078.7500000000),
-            iqr: 122.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_norm10medium() {
-        let val = &[
-            954.0000000000,
-            1064.0000000000,
-            855.0000000000,
-            1000.0000000000,
-            743.0000000000,
-            1084.0000000000,
-            704.0000000000,
-            1023.0000000000,
-            357.0000000000,
-            869.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 8653.0000000000,
-            min: 357.0000000000,
-            max: 1084.0000000000,
-            mean: 865.3000000000,
-            median: 911.5000000000,
-            var: 48628.4555555556,
-            std_dev: 220.5186059170,
-            std_dev_pct: 25.4846418487,
-            median_abs_dev: 195.7032000000,
-            median_abs_dev_pct: 21.4704552935,
-            quartiles: (771.0000000000, 911.5000000000, 1017.2500000000),
-            iqr: 246.2500000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_norm10wide() {
-        let val = &[
-            505.0000000000,
-            497.0000000000,
-            1591.0000000000,
-            887.0000000000,
-            1026.0000000000,
-            136.0000000000,
-            1580.0000000000,
-            940.0000000000,
-            754.0000000000,
-            1433.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 9349.0000000000,
-            min: 136.0000000000,
-            max: 1591.0000000000,
-            mean: 934.9000000000,
-            median: 913.5000000000,
-            var: 239208.9888888889,
-            std_dev: 489.0899599142,
-            std_dev_pct: 52.3146817750,
-            median_abs_dev: 611.5725000000,
-            median_abs_dev_pct: 66.9482758621,
-            quartiles: (567.2500000000, 913.5000000000, 1331.2500000000),
-            iqr: 764.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_norm25verynarrow() {
-        let val = &[
-            991.0000000000,
-            1018.0000000000,
-            998.0000000000,
-            1013.0000000000,
-            974.0000000000,
-            1007.0000000000,
-            1014.0000000000,
-            999.0000000000,
-            1011.0000000000,
-            978.0000000000,
-            985.0000000000,
-            999.0000000000,
-            983.0000000000,
-            982.0000000000,
-            1015.0000000000,
-            1002.0000000000,
-            977.0000000000,
-            948.0000000000,
-            1040.0000000000,
-            974.0000000000,
-            996.0000000000,
-            989.0000000000,
-            1015.0000000000,
-            994.0000000000,
-            1024.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 24926.0000000000,
-            min: 948.0000000000,
-            max: 1040.0000000000,
-            mean: 997.0400000000,
-            median: 998.0000000000,
-            var: 393.2066666667,
-            std_dev: 19.8294393937,
-            std_dev_pct: 1.9888308788,
-            median_abs_dev: 22.2390000000,
-            median_abs_dev_pct: 2.2283567134,
-            quartiles: (983.0000000000, 998.0000000000, 1013.0000000000),
-            iqr: 30.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_exp10a() {
-        let val = &[
-            23.0000000000,
-            11.0000000000,
-            2.0000000000,
-            57.0000000000,
-            4.0000000000,
-            12.0000000000,
-            5.0000000000,
-            29.0000000000,
-            3.0000000000,
-            21.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 167.0000000000,
-            min: 2.0000000000,
-            max: 57.0000000000,
-            mean: 16.7000000000,
-            median: 11.5000000000,
-            var: 287.7888888889,
-            std_dev: 16.9643416875,
-            std_dev_pct: 101.5828843560,
-            median_abs_dev: 13.3434000000,
-            median_abs_dev_pct: 116.0295652174,
-            quartiles: (4.2500000000, 11.5000000000, 22.5000000000),
-            iqr: 18.2500000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_exp10b() {
-        let val = &[
-            24.0000000000,
-            17.0000000000,
-            6.0000000000,
-            38.0000000000,
-            25.0000000000,
-            7.0000000000,
-            51.0000000000,
-            2.0000000000,
-            61.0000000000,
-            32.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 263.0000000000,
-            min: 2.0000000000,
-            max: 61.0000000000,
-            mean: 26.3000000000,
-            median: 24.5000000000,
-            var: 383.5666666667,
-            std_dev: 19.5848580967,
-            std_dev_pct: 74.4671410520,
-            median_abs_dev: 22.9803000000,
-            median_abs_dev_pct: 93.7971428571,
-            quartiles: (9.5000000000, 24.5000000000, 36.5000000000),
-            iqr: 27.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_exp10c() {
-        let val = &[
-            71.0000000000,
-            2.0000000000,
-            32.0000000000,
-            1.0000000000,
-            6.0000000000,
-            28.0000000000,
-            13.0000000000,
-            37.0000000000,
-            16.0000000000,
-            36.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 242.0000000000,
-            min: 1.0000000000,
-            max: 71.0000000000,
-            mean: 24.2000000000,
-            median: 22.0000000000,
-            var: 458.1777777778,
-            std_dev: 21.4050876611,
-            std_dev_pct: 88.4507754589,
-            median_abs_dev: 21.4977000000,
-            median_abs_dev_pct: 97.7168181818,
-            quartiles: (7.7500000000, 22.0000000000, 35.0000000000),
-            iqr: 27.2500000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_exp25() {
-        let val = &[
-            3.0000000000,
-            24.0000000000,
-            1.0000000000,
-            19.0000000000,
-            7.0000000000,
-            5.0000000000,
-            30.0000000000,
-            39.0000000000,
-            31.0000000000,
-            13.0000000000,
-            25.0000000000,
-            48.0000000000,
-            1.0000000000,
-            6.0000000000,
-            42.0000000000,
-            63.0000000000,
-            2.0000000000,
-            12.0000000000,
-            108.0000000000,
-            26.0000000000,
-            1.0000000000,
-            7.0000000000,
-            44.0000000000,
-            25.0000000000,
-            11.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 593.0000000000,
-            min: 1.0000000000,
-            max: 108.0000000000,
-            mean: 23.7200000000,
-            median: 19.0000000000,
-            var: 601.0433333333,
-            std_dev: 24.5161851301,
-            std_dev_pct: 103.3565983562,
-            median_abs_dev: 19.2738000000,
-            median_abs_dev_pct: 101.4410526316,
-            quartiles: (6.0000000000, 19.0000000000, 31.0000000000),
-            iqr: 25.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_binom25() {
-        let val = &[
-            18.0000000000,
-            17.0000000000,
-            27.0000000000,
-            15.0000000000,
-            21.0000000000,
-            25.0000000000,
-            17.0000000000,
-            24.0000000000,
-            25.0000000000,
-            24.0000000000,
-            26.0000000000,
-            26.0000000000,
-            23.0000000000,
-            15.0000000000,
-            23.0000000000,
-            17.0000000000,
-            18.0000000000,
-            18.0000000000,
-            21.0000000000,
-            16.0000000000,
-            15.0000000000,
-            31.0000000000,
-            20.0000000000,
-            17.0000000000,
-            15.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 514.0000000000,
-            min: 15.0000000000,
-            max: 31.0000000000,
-            mean: 20.5600000000,
-            median: 20.0000000000,
-            var: 20.8400000000,
-            std_dev: 4.5650848842,
-            std_dev_pct: 22.2037202539,
-            median_abs_dev: 5.9304000000,
-            median_abs_dev_pct: 29.6520000000,
-            quartiles: (17.0000000000, 20.0000000000, 24.0000000000),
-            iqr: 7.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_pois25lambda30() {
-        let val = &[
-            27.0000000000,
-            33.0000000000,
-            34.0000000000,
-            34.0000000000,
-            24.0000000000,
-            39.0000000000,
-            28.0000000000,
-            27.0000000000,
-            31.0000000000,
-            28.0000000000,
-            38.0000000000,
-            21.0000000000,
-            33.0000000000,
-            36.0000000000,
-            29.0000000000,
-            37.0000000000,
-            32.0000000000,
-            34.0000000000,
-            31.0000000000,
-            39.0000000000,
-            25.0000000000,
-            31.0000000000,
-            32.0000000000,
-            40.0000000000,
-            24.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 787.0000000000,
-            min: 21.0000000000,
-            max: 40.0000000000,
-            mean: 31.4800000000,
-            median: 32.0000000000,
-            var: 26.5933333333,
-            std_dev: 5.1568724372,
-            std_dev_pct: 16.3814245145,
-            median_abs_dev: 5.9304000000,
-            median_abs_dev_pct: 18.5325000000,
-            quartiles: (28.0000000000, 32.0000000000, 34.0000000000),
-            iqr: 6.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_pois25lambda40() {
-        let val = &[
-            42.0000000000,
-            50.0000000000,
-            42.0000000000,
-            46.0000000000,
-            34.0000000000,
-            45.0000000000,
-            34.0000000000,
-            49.0000000000,
-            39.0000000000,
-            28.0000000000,
-            40.0000000000,
-            35.0000000000,
-            37.0000000000,
-            39.0000000000,
-            46.0000000000,
-            44.0000000000,
-            32.0000000000,
-            45.0000000000,
-            42.0000000000,
-            37.0000000000,
-            48.0000000000,
-            42.0000000000,
-            33.0000000000,
-            42.0000000000,
-            48.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 1019.0000000000,
-            min: 28.0000000000,
-            max: 50.0000000000,
-            mean: 40.7600000000,
-            median: 42.0000000000,
-            var: 34.4400000000,
-            std_dev: 5.8685603004,
-            std_dev_pct: 14.3978417577,
-            median_abs_dev: 5.9304000000,
-            median_abs_dev_pct: 14.1200000000,
-            quartiles: (37.0000000000, 42.0000000000, 45.0000000000),
-            iqr: 8.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_pois25lambda50() {
-        let val = &[
-            45.0000000000,
-            43.0000000000,
-            44.0000000000,
-            61.0000000000,
-            51.0000000000,
-            53.0000000000,
-            59.0000000000,
-            52.0000000000,
-            49.0000000000,
-            51.0000000000,
-            51.0000000000,
-            50.0000000000,
-            49.0000000000,
-            56.0000000000,
-            42.0000000000,
-            52.0000000000,
-            51.0000000000,
-            43.0000000000,
-            48.0000000000,
-            48.0000000000,
-            50.0000000000,
-            42.0000000000,
-            43.0000000000,
-            42.0000000000,
-            60.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 1235.0000000000,
-            min: 42.0000000000,
-            max: 61.0000000000,
-            mean: 49.4000000000,
-            median: 50.0000000000,
-            var: 31.6666666667,
-            std_dev: 5.6273143387,
-            std_dev_pct: 11.3913245723,
-            median_abs_dev: 4.4478000000,
-            median_abs_dev_pct: 8.8956000000,
-            quartiles: (44.0000000000, 50.0000000000, 52.0000000000),
-            iqr: 8.0000000000,
-        };
-        check(val, summ);
-    }
-    #[test]
-    fn test_unif25() {
-        let val = &[
-            99.0000000000,
-            55.0000000000,
-            92.0000000000,
-            79.0000000000,
-            14.0000000000,
-            2.0000000000,
-            33.0000000000,
-            49.0000000000,
-            3.0000000000,
-            32.0000000000,
-            84.0000000000,
-            59.0000000000,
-            22.0000000000,
-            86.0000000000,
-            76.0000000000,
-            31.0000000000,
-            29.0000000000,
-            11.0000000000,
-            41.0000000000,
-            53.0000000000,
-            45.0000000000,
-            44.0000000000,
-            98.0000000000,
-            98.0000000000,
-            7.0000000000,
-        ];
-        let summ = &Summary {
-            sum: 1242.0000000000,
-            min: 2.0000000000,
-            max: 99.0000000000,
-            mean: 49.6800000000,
-            median: 45.0000000000,
-            var: 1015.6433333333,
-            std_dev: 31.8691595957,
-            std_dev_pct: 64.1488719719,
-            median_abs_dev: 45.9606000000,
-            median_abs_dev_pct: 102.1346666667,
-            quartiles: (29.0000000000, 45.0000000000, 79.0000000000),
-            iqr: 50.0000000000,
-        };
-        check(val, summ);
-    }
-
-    #[test]
-    fn test_sum_f64s() {
-        assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999);
-    }
-    #[test]
-    fn test_sum_f64_between_ints_that_sum_to_0() {
-        assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2);
-    }
-}
+mod tests;
 
 #[cfg(test)]
 mod bench {
diff --git a/src/libtest/stats/tests.rs b/src/libtest/stats/tests.rs
new file mode 100644
index 0000000000000..59f936453602a
--- /dev/null
+++ b/src/libtest/stats/tests.rs
@@ -0,0 +1,574 @@
+use crate::stats::Stats;
+use crate::stats::Summary;
+use std::f64;
+use std::io::prelude::*;
+use std::io;
+
+macro_rules! assert_approx_eq {
+    ($a: expr, $b: expr) => {{
+        let (a, b) = (&$a, &$b);
+        assert!(
+            (*a - *b).abs() < 1.0e-6,
+            "{} is not approximately equal to {}",
+            *a,
+            *b
+        );
+    }};
+}
+
+fn check(samples: &[f64], summ: &Summary) {
+    let summ2 = Summary::new(samples);
+
+    let mut w = io::sink();
+    let w = &mut w;
+    (write!(w, "\n")).unwrap();
+
+    assert_eq!(summ.sum, summ2.sum);
+    assert_eq!(summ.min, summ2.min);
+    assert_eq!(summ.max, summ2.max);
+    assert_eq!(summ.mean, summ2.mean);
+    assert_eq!(summ.median, summ2.median);
+
+    // We needed a few more digits to get exact equality on these
+    // but they're within float epsilon, which is 1.0e-6.
+    assert_approx_eq!(summ.var, summ2.var);
+    assert_approx_eq!(summ.std_dev, summ2.std_dev);
+    assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct);
+    assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev);
+    assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct);
+
+    assert_eq!(summ.quartiles, summ2.quartiles);
+    assert_eq!(summ.iqr, summ2.iqr);
+}
+
+#[test]
+fn test_min_max_nan() {
+    let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0];
+    let summary = Summary::new(xs);
+    assert_eq!(summary.min, 1.0);
+    assert_eq!(summary.max, 4.0);
+}
+
+#[test]
+fn test_norm2() {
+    let val = &[958.0000000000, 924.0000000000];
+    let summ = &Summary {
+        sum: 1882.0000000000,
+        min: 924.0000000000,
+        max: 958.0000000000,
+        mean: 941.0000000000,
+        median: 941.0000000000,
+        var: 578.0000000000,
+        std_dev: 24.0416305603,
+        std_dev_pct: 2.5549022912,
+        median_abs_dev: 25.2042000000,
+        median_abs_dev_pct: 2.6784484591,
+        quartiles: (932.5000000000, 941.0000000000, 949.5000000000),
+        iqr: 17.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_norm10narrow() {
+    let val = &[
+        966.0000000000,
+        985.0000000000,
+        1110.0000000000,
+        848.0000000000,
+        821.0000000000,
+        975.0000000000,
+        962.0000000000,
+        1157.0000000000,
+        1217.0000000000,
+        955.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 9996.0000000000,
+        min: 821.0000000000,
+        max: 1217.0000000000,
+        mean: 999.6000000000,
+        median: 970.5000000000,
+        var: 16050.7111111111,
+        std_dev: 126.6914010938,
+        std_dev_pct: 12.6742097933,
+        median_abs_dev: 102.2994000000,
+        median_abs_dev_pct: 10.5408964451,
+        quartiles: (956.7500000000, 970.5000000000, 1078.7500000000),
+        iqr: 122.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_norm10medium() {
+    let val = &[
+        954.0000000000,
+        1064.0000000000,
+        855.0000000000,
+        1000.0000000000,
+        743.0000000000,
+        1084.0000000000,
+        704.0000000000,
+        1023.0000000000,
+        357.0000000000,
+        869.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 8653.0000000000,
+        min: 357.0000000000,
+        max: 1084.0000000000,
+        mean: 865.3000000000,
+        median: 911.5000000000,
+        var: 48628.4555555556,
+        std_dev: 220.5186059170,
+        std_dev_pct: 25.4846418487,
+        median_abs_dev: 195.7032000000,
+        median_abs_dev_pct: 21.4704552935,
+        quartiles: (771.0000000000, 911.5000000000, 1017.2500000000),
+        iqr: 246.2500000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_norm10wide() {
+    let val = &[
+        505.0000000000,
+        497.0000000000,
+        1591.0000000000,
+        887.0000000000,
+        1026.0000000000,
+        136.0000000000,
+        1580.0000000000,
+        940.0000000000,
+        754.0000000000,
+        1433.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 9349.0000000000,
+        min: 136.0000000000,
+        max: 1591.0000000000,
+        mean: 934.9000000000,
+        median: 913.5000000000,
+        var: 239208.9888888889,
+        std_dev: 489.0899599142,
+        std_dev_pct: 52.3146817750,
+        median_abs_dev: 611.5725000000,
+        median_abs_dev_pct: 66.9482758621,
+        quartiles: (567.2500000000, 913.5000000000, 1331.2500000000),
+        iqr: 764.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_norm25verynarrow() {
+    let val = &[
+        991.0000000000,
+        1018.0000000000,
+        998.0000000000,
+        1013.0000000000,
+        974.0000000000,
+        1007.0000000000,
+        1014.0000000000,
+        999.0000000000,
+        1011.0000000000,
+        978.0000000000,
+        985.0000000000,
+        999.0000000000,
+        983.0000000000,
+        982.0000000000,
+        1015.0000000000,
+        1002.0000000000,
+        977.0000000000,
+        948.0000000000,
+        1040.0000000000,
+        974.0000000000,
+        996.0000000000,
+        989.0000000000,
+        1015.0000000000,
+        994.0000000000,
+        1024.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 24926.0000000000,
+        min: 948.0000000000,
+        max: 1040.0000000000,
+        mean: 997.0400000000,
+        median: 998.0000000000,
+        var: 393.2066666667,
+        std_dev: 19.8294393937,
+        std_dev_pct: 1.9888308788,
+        median_abs_dev: 22.2390000000,
+        median_abs_dev_pct: 2.2283567134,
+        quartiles: (983.0000000000, 998.0000000000, 1013.0000000000),
+        iqr: 30.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_exp10a() {
+    let val = &[
+        23.0000000000,
+        11.0000000000,
+        2.0000000000,
+        57.0000000000,
+        4.0000000000,
+        12.0000000000,
+        5.0000000000,
+        29.0000000000,
+        3.0000000000,
+        21.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 167.0000000000,
+        min: 2.0000000000,
+        max: 57.0000000000,
+        mean: 16.7000000000,
+        median: 11.5000000000,
+        var: 287.7888888889,
+        std_dev: 16.9643416875,
+        std_dev_pct: 101.5828843560,
+        median_abs_dev: 13.3434000000,
+        median_abs_dev_pct: 116.0295652174,
+        quartiles: (4.2500000000, 11.5000000000, 22.5000000000),
+        iqr: 18.2500000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_exp10b() {
+    let val = &[
+        24.0000000000,
+        17.0000000000,
+        6.0000000000,
+        38.0000000000,
+        25.0000000000,
+        7.0000000000,
+        51.0000000000,
+        2.0000000000,
+        61.0000000000,
+        32.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 263.0000000000,
+        min: 2.0000000000,
+        max: 61.0000000000,
+        mean: 26.3000000000,
+        median: 24.5000000000,
+        var: 383.5666666667,
+        std_dev: 19.5848580967,
+        std_dev_pct: 74.4671410520,
+        median_abs_dev: 22.9803000000,
+        median_abs_dev_pct: 93.7971428571,
+        quartiles: (9.5000000000, 24.5000000000, 36.5000000000),
+        iqr: 27.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_exp10c() {
+    let val = &[
+        71.0000000000,
+        2.0000000000,
+        32.0000000000,
+        1.0000000000,
+        6.0000000000,
+        28.0000000000,
+        13.0000000000,
+        37.0000000000,
+        16.0000000000,
+        36.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 242.0000000000,
+        min: 1.0000000000,
+        max: 71.0000000000,
+        mean: 24.2000000000,
+        median: 22.0000000000,
+        var: 458.1777777778,
+        std_dev: 21.4050876611,
+        std_dev_pct: 88.4507754589,
+        median_abs_dev: 21.4977000000,
+        median_abs_dev_pct: 97.7168181818,
+        quartiles: (7.7500000000, 22.0000000000, 35.0000000000),
+        iqr: 27.2500000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_exp25() {
+    let val = &[
+        3.0000000000,
+        24.0000000000,
+        1.0000000000,
+        19.0000000000,
+        7.0000000000,
+        5.0000000000,
+        30.0000000000,
+        39.0000000000,
+        31.0000000000,
+        13.0000000000,
+        25.0000000000,
+        48.0000000000,
+        1.0000000000,
+        6.0000000000,
+        42.0000000000,
+        63.0000000000,
+        2.0000000000,
+        12.0000000000,
+        108.0000000000,
+        26.0000000000,
+        1.0000000000,
+        7.0000000000,
+        44.0000000000,
+        25.0000000000,
+        11.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 593.0000000000,
+        min: 1.0000000000,
+        max: 108.0000000000,
+        mean: 23.7200000000,
+        median: 19.0000000000,
+        var: 601.0433333333,
+        std_dev: 24.5161851301,
+        std_dev_pct: 103.3565983562,
+        median_abs_dev: 19.2738000000,
+        median_abs_dev_pct: 101.4410526316,
+        quartiles: (6.0000000000, 19.0000000000, 31.0000000000),
+        iqr: 25.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_binom25() {
+    let val = &[
+        18.0000000000,
+        17.0000000000,
+        27.0000000000,
+        15.0000000000,
+        21.0000000000,
+        25.0000000000,
+        17.0000000000,
+        24.0000000000,
+        25.0000000000,
+        24.0000000000,
+        26.0000000000,
+        26.0000000000,
+        23.0000000000,
+        15.0000000000,
+        23.0000000000,
+        17.0000000000,
+        18.0000000000,
+        18.0000000000,
+        21.0000000000,
+        16.0000000000,
+        15.0000000000,
+        31.0000000000,
+        20.0000000000,
+        17.0000000000,
+        15.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 514.0000000000,
+        min: 15.0000000000,
+        max: 31.0000000000,
+        mean: 20.5600000000,
+        median: 20.0000000000,
+        var: 20.8400000000,
+        std_dev: 4.5650848842,
+        std_dev_pct: 22.2037202539,
+        median_abs_dev: 5.9304000000,
+        median_abs_dev_pct: 29.6520000000,
+        quartiles: (17.0000000000, 20.0000000000, 24.0000000000),
+        iqr: 7.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_pois25lambda30() {
+    let val = &[
+        27.0000000000,
+        33.0000000000,
+        34.0000000000,
+        34.0000000000,
+        24.0000000000,
+        39.0000000000,
+        28.0000000000,
+        27.0000000000,
+        31.0000000000,
+        28.0000000000,
+        38.0000000000,
+        21.0000000000,
+        33.0000000000,
+        36.0000000000,
+        29.0000000000,
+        37.0000000000,
+        32.0000000000,
+        34.0000000000,
+        31.0000000000,
+        39.0000000000,
+        25.0000000000,
+        31.0000000000,
+        32.0000000000,
+        40.0000000000,
+        24.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 787.0000000000,
+        min: 21.0000000000,
+        max: 40.0000000000,
+        mean: 31.4800000000,
+        median: 32.0000000000,
+        var: 26.5933333333,
+        std_dev: 5.1568724372,
+        std_dev_pct: 16.3814245145,
+        median_abs_dev: 5.9304000000,
+        median_abs_dev_pct: 18.5325000000,
+        quartiles: (28.0000000000, 32.0000000000, 34.0000000000),
+        iqr: 6.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_pois25lambda40() {
+    let val = &[
+        42.0000000000,
+        50.0000000000,
+        42.0000000000,
+        46.0000000000,
+        34.0000000000,
+        45.0000000000,
+        34.0000000000,
+        49.0000000000,
+        39.0000000000,
+        28.0000000000,
+        40.0000000000,
+        35.0000000000,
+        37.0000000000,
+        39.0000000000,
+        46.0000000000,
+        44.0000000000,
+        32.0000000000,
+        45.0000000000,
+        42.0000000000,
+        37.0000000000,
+        48.0000000000,
+        42.0000000000,
+        33.0000000000,
+        42.0000000000,
+        48.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 1019.0000000000,
+        min: 28.0000000000,
+        max: 50.0000000000,
+        mean: 40.7600000000,
+        median: 42.0000000000,
+        var: 34.4400000000,
+        std_dev: 5.8685603004,
+        std_dev_pct: 14.3978417577,
+        median_abs_dev: 5.9304000000,
+        median_abs_dev_pct: 14.1200000000,
+        quartiles: (37.0000000000, 42.0000000000, 45.0000000000),
+        iqr: 8.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_pois25lambda50() {
+    let val = &[
+        45.0000000000,
+        43.0000000000,
+        44.0000000000,
+        61.0000000000,
+        51.0000000000,
+        53.0000000000,
+        59.0000000000,
+        52.0000000000,
+        49.0000000000,
+        51.0000000000,
+        51.0000000000,
+        50.0000000000,
+        49.0000000000,
+        56.0000000000,
+        42.0000000000,
+        52.0000000000,
+        51.0000000000,
+        43.0000000000,
+        48.0000000000,
+        48.0000000000,
+        50.0000000000,
+        42.0000000000,
+        43.0000000000,
+        42.0000000000,
+        60.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 1235.0000000000,
+        min: 42.0000000000,
+        max: 61.0000000000,
+        mean: 49.4000000000,
+        median: 50.0000000000,
+        var: 31.6666666667,
+        std_dev: 5.6273143387,
+        std_dev_pct: 11.3913245723,
+        median_abs_dev: 4.4478000000,
+        median_abs_dev_pct: 8.8956000000,
+        quartiles: (44.0000000000, 50.0000000000, 52.0000000000),
+        iqr: 8.0000000000,
+    };
+    check(val, summ);
+}
+#[test]
+fn test_unif25() {
+    let val = &[
+        99.0000000000,
+        55.0000000000,
+        92.0000000000,
+        79.0000000000,
+        14.0000000000,
+        2.0000000000,
+        33.0000000000,
+        49.0000000000,
+        3.0000000000,
+        32.0000000000,
+        84.0000000000,
+        59.0000000000,
+        22.0000000000,
+        86.0000000000,
+        76.0000000000,
+        31.0000000000,
+        29.0000000000,
+        11.0000000000,
+        41.0000000000,
+        53.0000000000,
+        45.0000000000,
+        44.0000000000,
+        98.0000000000,
+        98.0000000000,
+        7.0000000000,
+    ];
+    let summ = &Summary {
+        sum: 1242.0000000000,
+        min: 2.0000000000,
+        max: 99.0000000000,
+        mean: 49.6800000000,
+        median: 45.0000000000,
+        var: 1015.6433333333,
+        std_dev: 31.8691595957,
+        std_dev_pct: 64.1488719719,
+        median_abs_dev: 45.9606000000,
+        median_abs_dev_pct: 102.1346666667,
+        quartiles: (29.0000000000, 45.0000000000, 79.0000000000),
+        iqr: 50.0000000000,
+    };
+    check(val, summ);
+}
+
+#[test]
+fn test_sum_f64s() {
+    assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999);
+}
+#[test]
+fn test_sum_f64_between_ints_that_sum_to_0() {
+    assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2);
+}
diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs
new file mode 100644
index 0000000000000..d8734d8caa03e
--- /dev/null
+++ b/src/libtest/tests.rs
@@ -0,0 +1,453 @@
+use crate::bench;
+use crate::test::{
+    filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
+    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
+    TrIgnored, TrOk,
+};
+use crate::Bencher;
+use crate::Concurrent;
+use std::sync::mpsc::channel;
+
+fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
+    vec![
+        TestDescAndFn {
+            desc: TestDesc {
+                name: StaticTestName("1"),
+                ignore: true,
+                should_panic: ShouldPanic::No,
+                allow_fail: false,
+            },
+            testfn: DynTestFn(Box::new(move || {})),
+        },
+        TestDescAndFn {
+            desc: TestDesc {
+                name: StaticTestName("2"),
+                ignore: false,
+                should_panic: ShouldPanic::No,
+                allow_fail: false,
+            },
+            testfn: DynTestFn(Box::new(move || {})),
+        },
+    ]
+}
+
+#[test]
+pub fn do_not_run_ignored_tests() {
+    fn f() {
+        panic!();
+    }
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: true,
+            should_panic: ShouldPanic::No,
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res != TrOk);
+}
+
+#[test]
+pub fn ignored_tests_result_in_ignored() {
+    fn f() {}
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: true,
+            should_panic: ShouldPanic::No,
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res == TrIgnored);
+}
+
+#[test]
+fn test_should_panic() {
+    fn f() {
+        panic!();
+    }
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: false,
+            should_panic: ShouldPanic::Yes,
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res == TrOk);
+}
+
+#[test]
+fn test_should_panic_good_message() {
+    fn f() {
+        panic!("an error message");
+    }
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: false,
+            should_panic: ShouldPanic::YesWithMessage("error message"),
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res == TrOk);
+}
+
+#[test]
+fn test_should_panic_bad_message() {
+    fn f() {
+        panic!("an error message");
+    }
+    let expected = "foobar";
+    let failed_msg = "panic did not include expected string";
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: false,
+            should_panic: ShouldPanic::YesWithMessage(expected),
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
+}
+
+#[test]
+fn test_should_panic_but_succeeds() {
+    fn f() {}
+    let desc = TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("whatever"),
+            ignore: false,
+            should_panic: ShouldPanic::Yes,
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(f)),
+    };
+    let (tx, rx) = channel();
+    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    let (_, res, _) = rx.recv().unwrap();
+    assert!(res == TrFailed);
+}
+
+#[test]
+fn parse_ignored_flag() {
+    let args = vec![
+        "progname".to_string(),
+        "filter".to_string(),
+        "--ignored".to_string(),
+    ];
+    let opts = parse_opts(&args).unwrap().unwrap();
+    assert_eq!(opts.run_ignored, RunIgnored::Only);
+}
+
+#[test]
+fn parse_include_ignored_flag() {
+    let args = vec![
+        "progname".to_string(),
+        "filter".to_string(),
+        "-Zunstable-options".to_string(),
+        "--include-ignored".to_string(),
+    ];
+    let opts = parse_opts(&args).unwrap().unwrap();
+    assert_eq!(opts.run_ignored, RunIgnored::Yes);
+}
+
+#[test]
+pub fn filter_for_ignored_option() {
+    // When we run ignored tests the test filter should filter out all the
+    // unignored tests and flip the ignore flag on the rest to false
+
+    let mut opts = TestOpts::new();
+    opts.run_tests = true;
+    opts.run_ignored = RunIgnored::Only;
+
+    let tests = one_ignored_one_unignored_test();
+    let filtered = filter_tests(&opts, tests);
+
+    assert_eq!(filtered.len(), 1);
+    assert_eq!(filtered[0].desc.name.to_string(), "1");
+    assert!(!filtered[0].desc.ignore);
+}
+
+#[test]
+pub fn run_include_ignored_option() {
+    // When we "--include-ignored" tests, the ignore flag should be set to false on
+    // all tests and no test filtered out
+
+    let mut opts = TestOpts::new();
+    opts.run_tests = true;
+    opts.run_ignored = RunIgnored::Yes;
+
+    let tests = one_ignored_one_unignored_test();
+    let filtered = filter_tests(&opts, tests);
+
+    assert_eq!(filtered.len(), 2);
+    assert!(!filtered[0].desc.ignore);
+    assert!(!filtered[1].desc.ignore);
+}
+
+#[test]
+pub fn exclude_should_panic_option() {
+    let mut opts = TestOpts::new();
+    opts.run_tests = true;
+    opts.exclude_should_panic = true;
+
+    let mut tests = one_ignored_one_unignored_test();
+    tests.push(TestDescAndFn {
+        desc: TestDesc {
+            name: StaticTestName("3"),
+            ignore: false,
+            should_panic: ShouldPanic::Yes,
+            allow_fail: false,
+        },
+        testfn: DynTestFn(Box::new(move || {})),
+    });
+
+    let filtered = filter_tests(&opts, tests);
+
+    assert_eq!(filtered.len(), 2);
+    assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
+}
+
+#[test]
+pub fn exact_filter_match() {
+    fn tests() -> Vec<TestDescAndFn> {
+        vec!["base", "base::test", "base::test1", "base::test2"]
+            .into_iter()
+            .map(|name| TestDescAndFn {
+                desc: TestDesc {
+                    name: StaticTestName(name),
+                    ignore: false,
+                    should_panic: ShouldPanic::No,
+                    allow_fail: false,
+                },
+                testfn: DynTestFn(Box::new(move || {})),
+            })
+            .collect()
+    }
+
+    let substr = filter_tests(
+        &TestOpts {
+            filter: Some("base".into()),
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(substr.len(), 4);
+
+    let substr = filter_tests(
+        &TestOpts {
+            filter: Some("bas".into()),
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(substr.len(), 4);
+
+    let substr = filter_tests(
+        &TestOpts {
+            filter: Some("::test".into()),
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(substr.len(), 3);
+
+    let substr = filter_tests(
+        &TestOpts {
+            filter: Some("base::test".into()),
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(substr.len(), 3);
+
+    let exact = filter_tests(
+        &TestOpts {
+            filter: Some("base".into()),
+            filter_exact: true,
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(exact.len(), 1);
+
+    let exact = filter_tests(
+        &TestOpts {
+            filter: Some("bas".into()),
+            filter_exact: true,
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(exact.len(), 0);
+
+    let exact = filter_tests(
+        &TestOpts {
+            filter: Some("::test".into()),
+            filter_exact: true,
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(exact.len(), 0);
+
+    let exact = filter_tests(
+        &TestOpts {
+            filter: Some("base::test".into()),
+            filter_exact: true,
+            ..TestOpts::new()
+        },
+        tests(),
+    );
+    assert_eq!(exact.len(), 1);
+}
+
+#[test]
+pub fn sort_tests() {
+    let mut opts = TestOpts::new();
+    opts.run_tests = true;
+
+    let names = vec![
+        "sha1::test".to_string(),
+        "isize::test_to_str".to_string(),
+        "isize::test_pow".to_string(),
+        "test::do_not_run_ignored_tests".to_string(),
+        "test::ignored_tests_result_in_ignored".to_string(),
+        "test::first_free_arg_should_be_a_filter".to_string(),
+        "test::parse_ignored_flag".to_string(),
+        "test::parse_include_ignored_flag".to_string(),
+        "test::filter_for_ignored_option".to_string(),
+        "test::run_include_ignored_option".to_string(),
+        "test::sort_tests".to_string(),
+    ];
+    let tests = {
+        fn testfn() {}
+        let mut tests = Vec::new();
+        for name in &names {
+            let test = TestDescAndFn {
+                desc: TestDesc {
+                    name: DynTestName((*name).clone()),
+                    ignore: false,
+                    should_panic: ShouldPanic::No,
+                    allow_fail: false,
+                },
+                testfn: DynTestFn(Box::new(testfn)),
+            };
+            tests.push(test);
+        }
+        tests
+    };
+    let filtered = filter_tests(&opts, tests);
+
+    let expected = vec![
+        "isize::test_pow".to_string(),
+        "isize::test_to_str".to_string(),
+        "sha1::test".to_string(),
+        "test::do_not_run_ignored_tests".to_string(),
+        "test::filter_for_ignored_option".to_string(),
+        "test::first_free_arg_should_be_a_filter".to_string(),
+        "test::ignored_tests_result_in_ignored".to_string(),
+        "test::parse_ignored_flag".to_string(),
+        "test::parse_include_ignored_flag".to_string(),
+        "test::run_include_ignored_option".to_string(),
+        "test::sort_tests".to_string(),
+    ];
+
+    for (a, b) in expected.iter().zip(filtered) {
+        assert!(*a == b.desc.name.to_string());
+    }
+}
+
+#[test]
+pub fn test_metricmap_compare() {
+    let mut m1 = MetricMap::new();
+    let mut m2 = MetricMap::new();
+    m1.insert_metric("in-both-noise", 1000.0, 200.0);
+    m2.insert_metric("in-both-noise", 1100.0, 200.0);
+
+    m1.insert_metric("in-first-noise", 1000.0, 2.0);
+    m2.insert_metric("in-second-noise", 1000.0, 2.0);
+
+    m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
+    m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
+
+    m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
+    m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
+
+    m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
+    m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
+
+    m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
+    m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
+}
+
+#[test]
+pub fn test_bench_once_no_iter() {
+    fn f(_: &mut Bencher) {}
+    bench::run_once(f);
+}
+
+#[test]
+pub fn test_bench_once_iter() {
+    fn f(b: &mut Bencher) {
+        b.iter(|| {})
+    }
+    bench::run_once(f);
+}
+
+#[test]
+pub fn test_bench_no_iter() {
+    fn f(_: &mut Bencher) {}
+
+    let (tx, rx) = channel();
+
+    let desc = TestDesc {
+        name: StaticTestName("f"),
+        ignore: false,
+        should_panic: ShouldPanic::No,
+        allow_fail: false,
+    };
+
+    crate::bench::benchmark(desc, tx, true, f);
+    rx.recv().unwrap();
+}
+
+#[test]
+pub fn test_bench_iter() {
+    fn f(b: &mut Bencher) {
+        b.iter(|| {})
+    }
+
+    let (tx, rx) = channel();
+
+    let desc = TestDesc {
+        name: StaticTestName("f"),
+        ignore: false,
+        should_panic: ShouldPanic::No,
+        allow_fail: false,
+    };
+
+    crate::bench::benchmark(desc, tx, true, f);
+    rx.recv().unwrap();
+}