diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index d6210ed59c4d1..f3716c81e11ec 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -8,7 +8,6 @@
 //! `rustdoc`.
 
 use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 
 use crate::builder::crate_description;
@@ -694,11 +693,12 @@ impl Step for Rustc {
         // rustc. rustdoc needs to be able to see everything, for example when
         // merging the search index, or generating local (relative) links.
         let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
-        t!(symlink_dir_force(&builder.config, &out, &out_dir));
+        t!(fs::create_dir_all(out_dir.parent().unwrap()));
+        symlink_dir_force(&builder.config, &out, &out_dir);
         // Cargo puts proc macros in `target/doc` even if you pass `--target`
         // explicitly (https://github.com/rust-lang/cargo/issues/7677).
         let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
-        t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir));
+        symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
@@ -816,7 +816,7 @@ macro_rules! tool_doc {
                 ];
                 for out_dir in out_dirs {
                     t!(fs::create_dir_all(&out_dir));
-                    t!(symlink_dir_force(&builder.config, &out, &out_dir));
+                    symlink_dir_force(&builder.config, &out, &out_dir);
                 }
 
                 // Build cargo command.
@@ -959,21 +959,24 @@ impl Step for UnstableBookGen {
     }
 }
 
-fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
+fn symlink_dir_force(config: &Config, original: &Path, link: &Path) {
     if config.dry_run() {
-        return Ok(());
+        return;
     }
-    if let Ok(m) = fs::symlink_metadata(dst) {
+    if let Ok(m) = fs::symlink_metadata(link) {
         if m.file_type().is_dir() {
-            fs::remove_dir_all(dst)?;
+            t!(fs::remove_dir_all(link));
         } else {
             // handle directory junctions on windows by falling back to
             // `remove_dir`.
-            fs::remove_file(dst).or_else(|_| fs::remove_dir(dst))?;
+            t!(fs::remove_file(link).or_else(|_| fs::remove_dir(link)));
         }
     }
 
-    symlink_dir(config, src, dst)
+    t!(
+        symlink_dir(config, original, link),
+        format!("failed to create link from {} -> {}", link.display(), original.display())
+    );
 }
 
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index eec8c4ad69f23..6a1e4556de85d 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -700,7 +700,7 @@ impl Step for CompiletestTest {
     /// Runs `cargo test` for compiletest.
     fn run(self, builder: &Builder<'_>) {
         let host = self.host;
-        let compiler = builder.compiler(1, host);
+        let compiler = builder.compiler(builder.top_stage, host);
 
         // We need `ToolStd` for the locally-built sysroot because
         // compiletest uses unstable features of the `test` crate.
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index e4bbccdb067c2..7e29f671f028b 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -134,17 +134,17 @@ pub(crate) fn program_out_of_date(stamp: &Path, key: &str) -> bool {
 
 /// Symlinks two directories, using junctions on Windows and normal symlinks on
 /// Unix.
-pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
+pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<()> {
     if config.dry_run() {
         return Ok(());
     }
-    let _ = fs::remove_dir(dest);
-    return symlink_dir_inner(src, dest);
+    let _ = fs::remove_dir(link);
+    return symlink_dir_inner(original, link);
 
     #[cfg(not(windows))]
-    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
+    fn symlink_dir_inner(original: &Path, link: &Path) -> io::Result<()> {
         use std::os::unix::fs;
-        fs::symlink(src, dest)
+        fs::symlink(original, link)
     }
 
     #[cfg(windows)]