]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/test.rs
Rollup merge of #61092 - spastorino:sanitize-place-iterative, r=oli-obk
[rust.git] / src / bootstrap / test.rs
1 //! Implementation of the test-related targets of the build system.
2 //!
3 //! This file implements the various regression test suites that we execute on
4 //! our CI.
5
6 use std::env;
7 use std::ffi::OsString;
8 use std::fmt;
9 use std::fs;
10 use std::iter;
11 use std::path::{Path, PathBuf};
12 use std::process::Command;
13
14 use build_helper::{self, output, t};
15
16 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
17 use crate::cache::{Interned, INTERNER};
18 use crate::compile;
19 use crate::dist;
20 use crate::flags::Subcommand;
21 use crate::native;
22 use crate::tool::{self, Tool, SourceType};
23 use crate::toolstate::ToolState;
24 use crate::util::{self, dylib_path, dylib_path_var};
25 use crate::Crate as CargoCrate;
26 use crate::{DocTests, Mode, GitRepo};
27
28 const ADB_TEST_DIR: &str = "/data/tmp/work";
29
30 /// The two modes of the test runner; tests or benchmarks.
31 #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
32 pub enum TestKind {
33     /// Run `cargo test`.
34     Test,
35     /// Run `cargo bench`.
36     Bench,
37 }
38
39 impl From<Kind> for TestKind {
40     fn from(kind: Kind) -> Self {
41         match kind {
42             Kind::Test => TestKind::Test,
43             Kind::Bench => TestKind::Bench,
44             _ => panic!("unexpected kind in crate: {:?}", kind),
45         }
46     }
47 }
48
49 impl TestKind {
50     // Return the cargo subcommand for this test kind
51     fn subcommand(self) -> &'static str {
52         match self {
53             TestKind::Test => "test",
54             TestKind::Bench => "bench",
55         }
56     }
57 }
58
59 impl fmt::Display for TestKind {
60     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61         f.write_str(match *self {
62             TestKind::Test => "Testing",
63             TestKind::Bench => "Benchmarking",
64         })
65     }
66 }
67
68 fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
69     if !builder.fail_fast {
70         if !builder.try_run(cmd) {
71             let mut failures = builder.delayed_failures.borrow_mut();
72             failures.push(format!("{:?}", cmd));
73             return false;
74         }
75     } else {
76         builder.run(cmd);
77     }
78     true
79 }
80
81 fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
82     if !builder.fail_fast {
83         if !builder.try_run_quiet(cmd) {
84             let mut failures = builder.delayed_failures.borrow_mut();
85             failures.push(format!("{:?}", cmd));
86             return false;
87         }
88     } else {
89         builder.run_quiet(cmd);
90     }
91     true
92 }
93
94 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
95 pub struct Linkcheck {
96     host: Interned<String>,
97 }
98
99 impl Step for Linkcheck {
100     type Output = ();
101     const ONLY_HOSTS: bool = true;
102     const DEFAULT: bool = true;
103
104     /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
105     ///
106     /// This tool in `src/tools` will verify the validity of all our links in the
107     /// documentation to ensure we don't have a bunch of dead ones.
108     fn run(self, builder: &Builder<'_>) {
109         let host = self.host;
110
111         builder.info(&format!("Linkcheck ({})", host));
112
113         builder.default_doc(None);
114
115         let _time = util::timeit(&builder);
116         try_run(
117             builder,
118             builder
119                 .tool_cmd(Tool::Linkchecker)
120                 .arg(builder.out.join(host).join("doc")),
121         );
122     }
123
124     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
125         let builder = run.builder;
126         run.path("src/tools/linkchecker")
127             .default_condition(builder.config.docs)
128     }
129
130     fn make_run(run: RunConfig<'_>) {
131         run.builder.ensure(Linkcheck { host: run.target });
132     }
133 }
134
135 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
136 pub struct Cargotest {
137     stage: u32,
138     host: Interned<String>,
139 }
140
141 impl Step for Cargotest {
142     type Output = ();
143     const ONLY_HOSTS: bool = true;
144
145     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
146         run.path("src/tools/cargotest")
147     }
148
149     fn make_run(run: RunConfig<'_>) {
150         run.builder.ensure(Cargotest {
151             stage: run.builder.top_stage,
152             host: run.target,
153         });
154     }
155
156     /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
157     ///
158     /// This tool in `src/tools` will check out a few Rust projects and run `cargo
159     /// test` to ensure that we don't regress the test suites there.
160     fn run(self, builder: &Builder<'_>) {
161         let compiler = builder.compiler(self.stage, self.host);
162         builder.ensure(compile::Rustc {
163             compiler,
164             target: compiler.host,
165         });
166
167         // Note that this is a short, cryptic, and not scoped directory name. This
168         // is currently to minimize the length of path on Windows where we otherwise
169         // quickly run into path name limit constraints.
170         let out_dir = builder.out.join("ct");
171         t!(fs::create_dir_all(&out_dir));
172
173         let _time = util::timeit(&builder);
174         let mut cmd = builder.tool_cmd(Tool::CargoTest);
175         try_run(
176             builder,
177             cmd.arg(&builder.initial_cargo)
178                 .arg(&out_dir)
179                 .env("RUSTC", builder.rustc(compiler))
180                 .env("RUSTDOC", builder.rustdoc(compiler)),
181         );
182     }
183 }
184
185 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
186 pub struct Cargo {
187     stage: u32,
188     host: Interned<String>,
189 }
190
191 impl Step for Cargo {
192     type Output = ();
193     const ONLY_HOSTS: bool = true;
194
195     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
196         run.path("src/tools/cargo")
197     }
198
199     fn make_run(run: RunConfig<'_>) {
200         run.builder.ensure(Cargo {
201             stage: run.builder.top_stage,
202             host: run.target,
203         });
204     }
205
206     /// Runs `cargo test` for `cargo` packaged with Rust.
207     fn run(self, builder: &Builder<'_>) {
208         let compiler = builder.compiler(self.stage, self.host);
209
210         builder.ensure(tool::Cargo {
211             compiler,
212             target: self.host,
213         });
214         let mut cargo = tool::prepare_tool_cargo(builder,
215                                                  compiler,
216                                                  Mode::ToolRustc,
217                                                  self.host,
218                                                  "test",
219                                                  "src/tools/cargo",
220                                                  SourceType::Submodule,
221                                                  &[]);
222
223         if !builder.fail_fast {
224             cargo.arg("--no-fail-fast");
225         }
226
227         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
228         // available.
229         cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
230         // Disable a test that has issues with mingw.
231         cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
232
233         try_run(
234             builder,
235             cargo.env("PATH", &path_for_cargo(builder, compiler)),
236         );
237     }
238 }
239
240 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
241 pub struct Rls {
242     stage: u32,
243     host: Interned<String>,
244 }
245
246 impl Step for Rls {
247     type Output = ();
248     const ONLY_HOSTS: bool = true;
249
250     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
251         run.path("src/tools/rls")
252     }
253
254     fn make_run(run: RunConfig<'_>) {
255         run.builder.ensure(Rls {
256             stage: run.builder.top_stage,
257             host: run.target,
258         });
259     }
260
261     /// Runs `cargo test` for the rls.
262     fn run(self, builder: &Builder<'_>) {
263         let stage = self.stage;
264         let host = self.host;
265         let compiler = builder.compiler(stage, host);
266
267         let build_result = builder.ensure(tool::Rls {
268             compiler,
269             target: self.host,
270             extra_features: Vec::new(),
271         });
272         if build_result.is_none() {
273             eprintln!("failed to test rls: could not build");
274             return;
275         }
276
277         let mut cargo = tool::prepare_tool_cargo(builder,
278                                                  compiler,
279                                                  Mode::ToolRustc,
280                                                  host,
281                                                  "test",
282                                                  "src/tools/rls",
283                                                  SourceType::Submodule,
284                                                  &[]);
285
286         builder.add_rustc_lib_path(compiler, &mut cargo);
287         cargo.arg("--")
288             .args(builder.config.cmd.test_args());
289
290         if try_run(builder, &mut cargo) {
291             builder.save_toolstate("rls", ToolState::TestPass);
292         }
293     }
294 }
295
296 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
297 pub struct Rustfmt {
298     stage: u32,
299     host: Interned<String>,
300 }
301
302 impl Step for Rustfmt {
303     type Output = ();
304     const ONLY_HOSTS: bool = true;
305
306     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
307         run.path("src/tools/rustfmt")
308     }
309
310     fn make_run(run: RunConfig<'_>) {
311         run.builder.ensure(Rustfmt {
312             stage: run.builder.top_stage,
313             host: run.target,
314         });
315     }
316
317     /// Runs `cargo test` for rustfmt.
318     fn run(self, builder: &Builder<'_>) {
319         let stage = self.stage;
320         let host = self.host;
321         let compiler = builder.compiler(stage, host);
322
323         let build_result = builder.ensure(tool::Rustfmt {
324             compiler,
325             target: self.host,
326             extra_features: Vec::new(),
327         });
328         if build_result.is_none() {
329             eprintln!("failed to test rustfmt: could not build");
330             return;
331         }
332
333         let mut cargo = tool::prepare_tool_cargo(builder,
334                                                  compiler,
335                                                  Mode::ToolRustc,
336                                                  host,
337                                                  "test",
338                                                  "src/tools/rustfmt",
339                                                  SourceType::Submodule,
340                                                  &[]);
341
342         let dir = testdir(builder, compiler.host);
343         t!(fs::create_dir_all(&dir));
344         cargo.env("RUSTFMT_TEST_DIR", dir);
345
346         builder.add_rustc_lib_path(compiler, &mut cargo);
347
348         if try_run(builder, &mut cargo) {
349             builder.save_toolstate("rustfmt", ToolState::TestPass);
350         }
351     }
352 }
353
354 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
355 pub struct Miri {
356     stage: u32,
357     host: Interned<String>,
358 }
359
360 impl Step for Miri {
361     type Output = ();
362     const ONLY_HOSTS: bool = true;
363     const DEFAULT: bool = true;
364
365     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
366         let test_miri = run.builder.config.test_miri;
367         run.path("src/tools/miri").default_condition(test_miri)
368     }
369
370     fn make_run(run: RunConfig<'_>) {
371         run.builder.ensure(Miri {
372             stage: run.builder.top_stage,
373             host: run.target,
374         });
375     }
376
377     /// Runs `cargo test` for miri.
378     fn run(self, builder: &Builder<'_>) {
379         let stage = self.stage;
380         let host = self.host;
381         let compiler = builder.compiler(stage, host);
382
383         let miri = builder.ensure(tool::Miri {
384             compiler,
385             target: self.host,
386             extra_features: Vec::new(),
387         });
388         if let Some(miri) = miri {
389             let mut cargo = tool::prepare_tool_cargo(builder,
390                                                  compiler,
391                                                  Mode::ToolRustc,
392                                                  host,
393                                                  "test",
394                                                  "src/tools/miri",
395                                                  SourceType::Submodule,
396                                                  &[]);
397
398             // miri tests need to know about the stage sysroot
399             cargo.env("MIRI_SYSROOT", builder.sysroot(compiler));
400             cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
401             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
402             cargo.env("MIRI_PATH", miri);
403
404             builder.add_rustc_lib_path(compiler, &mut cargo);
405
406             if try_run(builder, &mut cargo) {
407                 builder.save_toolstate("miri", ToolState::TestPass);
408             }
409         } else {
410             eprintln!("failed to test miri: could not build");
411         }
412     }
413 }
414
415 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
416 pub struct CompiletestTest {
417     host: Interned<String>,
418 }
419
420 impl Step for CompiletestTest {
421     type Output = ();
422
423     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
424         run.path("src/tools/compiletest")
425     }
426
427     fn make_run(run: RunConfig<'_>) {
428         run.builder.ensure(CompiletestTest {
429             host: run.target,
430         });
431     }
432
433     /// Runs `cargo test` for compiletest.
434     fn run(self, builder: &Builder<'_>) {
435         let host = self.host;
436         let compiler = builder.compiler(0, host);
437
438         let mut cargo = tool::prepare_tool_cargo(builder,
439                                                  compiler,
440                                                  Mode::ToolBootstrap,
441                                                  host,
442                                                  "test",
443                                                  "src/tools/compiletest",
444                                                  SourceType::InTree,
445                                                  &[]);
446
447         try_run(builder, &mut cargo);
448     }
449 }
450
451 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
452 pub struct Clippy {
453     stage: u32,
454     host: Interned<String>,
455 }
456
457 impl Step for Clippy {
458     type Output = ();
459     const ONLY_HOSTS: bool = true;
460     const DEFAULT: bool = false;
461
462     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
463         run.path("src/tools/clippy")
464     }
465
466     fn make_run(run: RunConfig<'_>) {
467         run.builder.ensure(Clippy {
468             stage: run.builder.top_stage,
469             host: run.target,
470         });
471     }
472
473     /// Runs `cargo test` for clippy.
474     fn run(self, builder: &Builder<'_>) {
475         let stage = self.stage;
476         let host = self.host;
477         let compiler = builder.compiler(stage, host);
478
479         let clippy = builder.ensure(tool::Clippy {
480             compiler,
481             target: self.host,
482             extra_features: Vec::new(),
483         });
484         if let Some(clippy) = clippy {
485             let mut cargo = tool::prepare_tool_cargo(builder,
486                                                  compiler,
487                                                  Mode::ToolRustc,
488                                                  host,
489                                                  "test",
490                                                  "src/tools/clippy",
491                                                  SourceType::Submodule,
492                                                  &[]);
493
494             // clippy tests need to know about the stage sysroot
495             cargo.env("SYSROOT", builder.sysroot(compiler));
496             cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
497             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
498             let host_libs = builder
499                 .stage_out(compiler, Mode::ToolRustc)
500                 .join(builder.cargo_dir());
501             cargo.env("HOST_LIBS", host_libs);
502             // clippy tests need to find the driver
503             cargo.env("CLIPPY_DRIVER_PATH", clippy);
504
505             builder.add_rustc_lib_path(compiler, &mut cargo);
506
507             if try_run(builder, &mut cargo) {
508                 builder.save_toolstate("clippy-driver", ToolState::TestPass);
509             }
510         } else {
511             eprintln!("failed to test clippy: could not build");
512         }
513     }
514 }
515
516 fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {
517     // Configure PATH to find the right rustc. NB. we have to use PATH
518     // and not RUSTC because the Cargo test suite has tests that will
519     // fail if rustc is not spelled `rustc`.
520     let path = builder.sysroot(compiler).join("bin");
521     let old_path = env::var_os("PATH").unwrap_or_default();
522     env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")
523 }
524
525 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
526 pub struct RustdocTheme {
527     pub compiler: Compiler,
528 }
529
530 impl Step for RustdocTheme {
531     type Output = ();
532     const DEFAULT: bool = true;
533     const ONLY_HOSTS: bool = true;
534
535     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
536         run.path("src/tools/rustdoc-themes")
537     }
538
539     fn make_run(run: RunConfig<'_>) {
540         let compiler = run.builder.compiler(run.builder.top_stage, run.host);
541
542         run.builder.ensure(RustdocTheme { compiler });
543     }
544
545     fn run(self, builder: &Builder<'_>) {
546         let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
547         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
548         cmd.arg(rustdoc.to_str().unwrap())
549             .arg(
550                 builder
551                     .src
552                     .join("src/librustdoc/html/static/themes")
553                     .to_str()
554                     .unwrap(),
555             )
556             .env("RUSTC_STAGE", self.compiler.stage.to_string())
557             .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
558             .env(
559                 "RUSTDOC_LIBDIR",
560                 builder.sysroot_libdir(self.compiler, self.compiler.host),
561             )
562             .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
563             .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
564             .env("RUSTDOC_CRATE_VERSION", builder.rust_version())
565             .env("RUSTC_BOOTSTRAP", "1");
566         if let Some(linker) = builder.linker(self.compiler.host) {
567             cmd.env("RUSTC_TARGET_LINKER", linker);
568         }
569         try_run(builder, &mut cmd);
570     }
571 }
572
573 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
574 pub struct RustdocJSStd {
575     pub host: Interned<String>,
576     pub target: Interned<String>,
577 }
578
579 impl Step for RustdocJSStd {
580     type Output = ();
581     const DEFAULT: bool = true;
582     const ONLY_HOSTS: bool = true;
583
584     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
585         run.path("src/test/rustdoc-js-std")
586     }
587
588     fn make_run(run: RunConfig<'_>) {
589         run.builder.ensure(RustdocJSStd {
590             host: run.host,
591             target: run.target,
592         });
593     }
594
595     fn run(self, builder: &Builder<'_>) {
596         if let Some(ref nodejs) = builder.config.nodejs {
597             let mut command = Command::new(nodejs);
598             command.args(&["src/tools/rustdoc-js-std/tester.js", &*self.host]);
599             builder.ensure(crate::doc::Std {
600                 target: self.target,
601                 stage: builder.top_stage,
602             });
603             builder.run(&mut command);
604         } else {
605             builder.info(
606                 "No nodejs found, skipping \"src/test/rustdoc-js-std\" tests"
607             );
608         }
609     }
610 }
611
612 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
613 pub struct RustdocJSNotStd {
614     pub host: Interned<String>,
615     pub target: Interned<String>,
616     pub compiler: Compiler,
617 }
618
619 impl Step for RustdocJSNotStd {
620     type Output = ();
621     const DEFAULT: bool = true;
622     const ONLY_HOSTS: bool = true;
623
624     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
625         run.path("src/test/rustdoc-js")
626     }
627
628     fn make_run(run: RunConfig<'_>) {
629         let compiler = run.builder.compiler(run.builder.top_stage, run.host);
630         run.builder.ensure(RustdocJSNotStd {
631             host: run.host,
632             target: run.target,
633             compiler,
634         });
635     }
636
637     fn run(self, builder: &Builder<'_>) {
638         if builder.config.nodejs.is_some() {
639             builder.ensure(Compiletest {
640                 compiler: self.compiler,
641                 target: self.target,
642                 mode: "js-doc-test",
643                 suite: "rustdoc-js",
644                 path: None,
645                 compare_mode: None,
646             });
647         } else {
648             builder.info(
649                 "No nodejs found, skipping \"src/test/rustdoc-js\" tests"
650             );
651         }
652     }
653 }
654
655 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
656 pub struct RustdocUi {
657     pub host: Interned<String>,
658     pub target: Interned<String>,
659     pub compiler: Compiler,
660 }
661
662 impl Step for RustdocUi {
663     type Output = ();
664     const DEFAULT: bool = true;
665     const ONLY_HOSTS: bool = true;
666
667     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
668         run.path("src/test/rustdoc-ui")
669     }
670
671     fn make_run(run: RunConfig<'_>) {
672         let compiler = run.builder.compiler(run.builder.top_stage, run.host);
673         run.builder.ensure(RustdocUi {
674             host: run.host,
675             target: run.target,
676             compiler,
677         });
678     }
679
680     fn run(self, builder: &Builder<'_>) {
681         builder.ensure(Compiletest {
682             compiler: self.compiler,
683             target: self.target,
684             mode: "ui",
685             suite: "rustdoc-ui",
686             path: Some("src/test/rustdoc-ui"),
687             compare_mode: None,
688         })
689     }
690 }
691
692 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
693 pub struct Tidy;
694
695 impl Step for Tidy {
696     type Output = ();
697     const DEFAULT: bool = true;
698     const ONLY_HOSTS: bool = true;
699
700     /// Runs the `tidy` tool.
701     ///
702     /// This tool in `src/tools` checks up on various bits and pieces of style and
703     /// otherwise just implements a few lint-like checks that are specific to the
704     /// compiler itself.
705     fn run(self, builder: &Builder<'_>) {
706         let mut cmd = builder.tool_cmd(Tool::Tidy);
707         cmd.arg(builder.src.join("src"));
708         cmd.arg(&builder.initial_cargo);
709         if !builder.config.vendor {
710             cmd.arg("--no-vendor");
711         }
712         if !builder.config.verbose_tests {
713             cmd.arg("--quiet");
714         }
715
716         let _folder = builder.fold_output(|| "tidy");
717         builder.info("tidy check");
718         try_run(builder, &mut cmd);
719     }
720
721     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
722         run.path("src/tools/tidy")
723     }
724
725     fn make_run(run: RunConfig<'_>) {
726         run.builder.ensure(Tidy);
727     }
728 }
729
730 fn testdir(builder: &Builder<'_>, host: Interned<String>) -> PathBuf {
731     builder.out.join(host).join("test")
732 }
733
734 macro_rules! default_test {
735     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
736         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
737     }
738 }
739
740 macro_rules! default_test_with_compare_mode {
741     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
742                    compare_mode: $compare_mode:expr }) => {
743         test_with_compare_mode!($name { path: $path, mode: $mode, suite: $suite, default: true,
744                                         host: false, compare_mode: $compare_mode });
745     }
746 }
747
748 macro_rules! host_test {
749     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
750         test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
751     }
752 }
753
754 macro_rules! test {
755     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
756                    host: $host:expr }) => {
757         test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
758                                   host: $host, compare_mode: None });
759     }
760 }
761
762 macro_rules! test_with_compare_mode {
763     ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
764                    host: $host:expr, compare_mode: $compare_mode:expr }) => {
765         test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
766                                   host: $host, compare_mode: Some($compare_mode) });
767     }
768 }
769
770 macro_rules! test_definitions {
771     ($name:ident {
772         path: $path:expr,
773         mode: $mode:expr,
774         suite: $suite:expr,
775         default: $default:expr,
776         host: $host:expr,
777         compare_mode: $compare_mode:expr
778     }) => {
779         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
780         pub struct $name {
781             pub compiler: Compiler,
782             pub target: Interned<String>,
783         }
784
785         impl Step for $name {
786             type Output = ();
787             const DEFAULT: bool = $default;
788             const ONLY_HOSTS: bool = $host;
789
790             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
791                 run.suite_path($path)
792             }
793
794             fn make_run(run: RunConfig<'_>) {
795                 let compiler = run.builder.compiler(run.builder.top_stage, run.host);
796
797                 run.builder.ensure($name {
798                     compiler,
799                     target: run.target,
800                 });
801             }
802
803             fn run(self, builder: &Builder<'_>) {
804                 builder.ensure(Compiletest {
805                     compiler: self.compiler,
806                     target: self.target,
807                     mode: $mode,
808                     suite: $suite,
809                     path: Some($path),
810                     compare_mode: $compare_mode,
811                 })
812             }
813         }
814     }
815 }
816
817 default_test_with_compare_mode!(Ui {
818     path: "src/test/ui",
819     mode: "ui",
820     suite: "ui",
821     compare_mode: "nll"
822 });
823
824 default_test_with_compare_mode!(RunPass {
825     path: "src/test/run-pass",
826     mode: "run-pass",
827     suite: "run-pass",
828     compare_mode: "nll"
829 });
830
831 default_test!(CompileFail {
832     path: "src/test/compile-fail",
833     mode: "compile-fail",
834     suite: "compile-fail"
835 });
836
837 default_test!(RunFail {
838     path: "src/test/run-fail",
839     mode: "run-fail",
840     suite: "run-fail"
841 });
842
843 default_test!(RunPassValgrind {
844     path: "src/test/run-pass-valgrind",
845     mode: "run-pass-valgrind",
846     suite: "run-pass-valgrind"
847 });
848
849 default_test!(MirOpt {
850     path: "src/test/mir-opt",
851     mode: "mir-opt",
852     suite: "mir-opt"
853 });
854
855 default_test!(Codegen {
856     path: "src/test/codegen",
857     mode: "codegen",
858     suite: "codegen"
859 });
860
861 default_test!(CodegenUnits {
862     path: "src/test/codegen-units",
863     mode: "codegen-units",
864     suite: "codegen-units"
865 });
866
867 default_test!(Incremental {
868     path: "src/test/incremental",
869     mode: "incremental",
870     suite: "incremental"
871 });
872
873 default_test!(Debuginfo {
874     path: "src/test/debuginfo",
875     mode: "debuginfo",
876     suite: "debuginfo"
877 });
878
879 host_test!(UiFullDeps {
880     path: "src/test/ui-fulldeps",
881     mode: "ui",
882     suite: "ui-fulldeps"
883 });
884
885 host_test!(RunPassFullDeps {
886     path: "src/test/run-pass-fulldeps",
887     mode: "run-pass",
888     suite: "run-pass-fulldeps"
889 });
890
891 host_test!(Rustdoc {
892     path: "src/test/rustdoc",
893     mode: "rustdoc",
894     suite: "rustdoc"
895 });
896
897 host_test!(Pretty {
898     path: "src/test/pretty",
899     mode: "pretty",
900     suite: "pretty"
901 });
902 test!(RunPassPretty {
903     path: "src/test/run-pass/pretty",
904     mode: "pretty",
905     suite: "run-pass",
906     default: false,
907     host: true
908 });
909 test!(RunFailPretty {
910     path: "src/test/run-fail/pretty",
911     mode: "pretty",
912     suite: "run-fail",
913     default: false,
914     host: true
915 });
916 test!(RunPassValgrindPretty {
917     path: "src/test/run-pass-valgrind/pretty",
918     mode: "pretty",
919     suite: "run-pass-valgrind",
920     default: false,
921     host: true
922 });
923
924 default_test!(RunMake {
925     path: "src/test/run-make",
926     mode: "run-make",
927     suite: "run-make"
928 });
929
930 host_test!(RunMakeFullDeps {
931     path: "src/test/run-make-fulldeps",
932     mode: "run-make",
933     suite: "run-make-fulldeps"
934 });
935
936 default_test!(Assembly {
937     path: "src/test/assembly",
938     mode: "assembly",
939     suite: "assembly"
940 });
941
942 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
943 struct Compiletest {
944     compiler: Compiler,
945     target: Interned<String>,
946     mode: &'static str,
947     suite: &'static str,
948     path: Option<&'static str>,
949     compare_mode: Option<&'static str>,
950 }
951
952 impl Step for Compiletest {
953     type Output = ();
954
955     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
956         run.never()
957     }
958
959     /// Executes the `compiletest` tool to run a suite of tests.
960     ///
961     /// Compiles all tests with `compiler` for `target` with the specified
962     /// compiletest `mode` and `suite` arguments. For example `mode` can be
963     /// "run-pass" or `suite` can be something like `debuginfo`.
964     fn run(self, builder: &Builder<'_>) {
965         let compiler = self.compiler;
966         let target = self.target;
967         let mode = self.mode;
968         let suite = self.suite;
969
970         // Path for test suite
971         let suite_path = self.path.unwrap_or("");
972
973         // Skip codegen tests if they aren't enabled in configuration.
974         if !builder.config.codegen_tests && suite == "codegen" {
975             return;
976         }
977
978         if suite == "debuginfo" {
979             let msvc = builder.config.build.contains("msvc");
980             if mode == "debuginfo" {
981                 return builder.ensure(Compiletest {
982                     mode: if msvc { "debuginfo-cdb" } else { "debuginfo-gdb+lldb" },
983                     ..self
984                 });
985             }
986
987             builder.ensure(dist::DebuggerScripts {
988                 sysroot: builder.sysroot(compiler),
989                 host: target,
990             });
991         }
992
993         if suite.ends_with("fulldeps") {
994             builder.ensure(compile::Rustc { compiler, target });
995         }
996
997         if builder.no_std(target) == Some(true) {
998             // the `test` doesn't compile for no-std targets
999             builder.ensure(compile::Std { compiler, target });
1000         } else {
1001             builder.ensure(compile::Test { compiler, target });
1002         }
1003
1004         if builder.no_std(target) == Some(true) {
1005             // for no_std run-make (e.g., thumb*),
1006             // we need a host compiler which is called by cargo.
1007             builder.ensure(compile::Std { compiler, target: compiler.host });
1008         }
1009
1010         // HACK(eddyb) ensure that `libproc_macro` is available on the host.
1011         builder.ensure(compile::Test { compiler, target: compiler.host });
1012         // Also provide `rust_test_helpers` for the host.
1013         builder.ensure(native::TestHelpers { target: compiler.host });
1014
1015         // wasm32 can't build the test helpers
1016         if !target.contains("wasm32") {
1017             builder.ensure(native::TestHelpers { target });
1018         }
1019         builder.ensure(RemoteCopyLibs { compiler, target });
1020
1021         let mut cmd = builder.tool_cmd(Tool::Compiletest);
1022
1023         // compiletest currently has... a lot of arguments, so let's just pass all
1024         // of them!
1025
1026         cmd.arg("--compile-lib-path")
1027             .arg(builder.rustc_libdir(compiler));
1028         cmd.arg("--run-lib-path")
1029             .arg(builder.sysroot_libdir(compiler, target));
1030         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1031
1032         let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
1033
1034         // Avoid depending on rustdoc when we don't need it.
1035         if mode == "rustdoc"
1036             || (mode == "run-make" && suite.ends_with("fulldeps"))
1037             || (mode == "ui" && is_rustdoc)
1038             || mode == "js-doc-test"
1039         {
1040             cmd.arg("--rustdoc-path")
1041                 .arg(builder.rustdoc(compiler));
1042         }
1043
1044         cmd.arg("--src-base")
1045             .arg(builder.src.join("src/test").join(suite));
1046         cmd.arg("--build-base")
1047             .arg(testdir(builder, compiler.host).join(suite));
1048         cmd.arg("--stage-id")
1049             .arg(format!("stage{}-{}", compiler.stage, target));
1050         cmd.arg("--mode").arg(mode);
1051         cmd.arg("--target").arg(target);
1052         cmd.arg("--host").arg(&*compiler.host);
1053         cmd.arg("--llvm-filecheck")
1054             .arg(builder.llvm_filecheck(builder.config.build));
1055
1056         if builder.config.cmd.bless() {
1057             cmd.arg("--bless");
1058         }
1059
1060         let compare_mode = builder.config.cmd.compare_mode().or_else(|| {
1061             if builder.config.test_compare_mode {
1062                 self.compare_mode
1063             } else {
1064                 None
1065             }
1066         });
1067
1068         if let Some(ref nodejs) = builder.config.nodejs {
1069             cmd.arg("--nodejs").arg(nodejs);
1070         }
1071
1072         let mut flags = if is_rustdoc {
1073             Vec::new()
1074         } else {
1075             vec!["-Crpath".to_string()]
1076         };
1077         if !is_rustdoc {
1078             if builder.config.rust_optimize_tests {
1079                 flags.push("-O".to_string());
1080             }
1081         }
1082         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
1083         flags.push("-Zunstable-options".to_string());
1084         flags.push(builder.config.cmd.rustc_args().join(" "));
1085
1086         if let Some(linker) = builder.linker(target) {
1087             cmd.arg("--linker").arg(linker);
1088         }
1089
1090         let mut hostflags = flags.clone();
1091         hostflags.push(format!(
1092             "-Lnative={}",
1093             builder.test_helpers_out(compiler.host).display()
1094         ));
1095         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
1096
1097         let mut targetflags = flags;
1098         targetflags.push(format!(
1099             "-Lnative={}",
1100             builder.test_helpers_out(target).display()
1101         ));
1102         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
1103
1104         cmd.arg("--docck-python").arg(builder.python());
1105
1106         if builder.config.build.ends_with("apple-darwin") {
1107             // Force /usr/bin/python on macOS for LLDB tests because we're loading the
1108             // LLDB plugin's compiled module which only works with the system python
1109             // (namely not Homebrew-installed python)
1110             cmd.arg("--lldb-python").arg("/usr/bin/python");
1111         } else {
1112             cmd.arg("--lldb-python").arg(builder.python());
1113         }
1114
1115         if let Some(ref gdb) = builder.config.gdb {
1116             cmd.arg("--gdb").arg(gdb);
1117         }
1118
1119         let run = |cmd: &mut Command| {
1120             cmd.output().map(|output| {
1121                 String::from_utf8_lossy(&output.stdout)
1122                     .lines().next().unwrap_or_else(|| {
1123                         panic!("{:?} failed {:?}", cmd, output)
1124                     }).to_string()
1125             })
1126         };
1127         let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
1128             // Test against the lldb that was just built.
1129             builder.llvm_out(target).join("bin").join("lldb")
1130         } else {
1131             PathBuf::from("lldb")
1132         };
1133         let lldb_version = Command::new(&lldb_exe)
1134             .arg("--version")
1135             .output()
1136             .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
1137             .ok();
1138         if let Some(ref vers) = lldb_version {
1139             cmd.arg("--lldb-version").arg(vers);
1140             let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
1141             if let Some(ref dir) = lldb_python_dir {
1142                 cmd.arg("--lldb-python-dir").arg(dir);
1143             }
1144         }
1145
1146         if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
1147             match &var.to_string_lossy().to_lowercase()[..] {
1148                 "1" | "yes" | "on" => {
1149                     assert!(builder.config.lldb_enabled,
1150                         "RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \
1151                          be built.");
1152                     let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1153                     cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1154                 }
1155                 "0" | "no" | "off" => {
1156                     // Nothing to do.
1157                 }
1158                 other => {
1159                     // Let's make sure typos don't get unnoticed
1160                     panic!("Unrecognized option '{}' set in \
1161                             RUSTBUILD_FORCE_CLANG_BASED_TESTS", other);
1162                 }
1163             }
1164         }
1165
1166         // Get paths from cmd args
1167         let paths = match &builder.config.cmd {
1168             Subcommand::Test { ref paths, .. } => &paths[..],
1169             _ => &[],
1170         };
1171
1172         // Get test-args by striping suite path
1173         let mut test_args: Vec<&str> = paths
1174             .iter()
1175             .map(|p| {
1176                 match p.strip_prefix(".") {
1177                     Ok(path) => path,
1178                     Err(_) => p,
1179                 }
1180             })
1181             .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
1182             .filter_map(|p| {
1183                 // Since test suite paths are themselves directories, if we don't
1184                 // specify a directory or file, we'll get an empty string here
1185                 // (the result of the test suite directory without its suite prefix).
1186                 // Therefore, we need to filter these out, as only the first --test-args
1187                 // flag is respected, so providing an empty --test-args conflicts with
1188                 // any following it.
1189                 match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
1190                     Some(s) if s != "" => Some(s),
1191                     _ => None,
1192                 }
1193             })
1194             .collect();
1195
1196         test_args.append(&mut builder.config.cmd.test_args());
1197
1198         cmd.args(&test_args);
1199
1200         if builder.is_verbose() {
1201             cmd.arg("--verbose");
1202         }
1203
1204         if !builder.config.verbose_tests {
1205             cmd.arg("--quiet");
1206         }
1207
1208         if builder.config.llvm_enabled() {
1209             let llvm_config = builder.ensure(native::Llvm {
1210                 target: builder.config.build,
1211                 emscripten: false,
1212             });
1213             if !builder.config.dry_run {
1214                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1215                 cmd.arg("--llvm-version").arg(llvm_version);
1216             }
1217             if !builder.is_rust_llvm(target) {
1218                 cmd.arg("--system-llvm");
1219             }
1220
1221             // Only pass correct values for these flags for the `run-make` suite as it
1222             // requires that a C++ compiler was configured which isn't always the case.
1223             if !builder.config.dry_run && suite == "run-make-fulldeps" {
1224                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1225                 let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
1226                 cmd.arg("--cc")
1227                     .arg(builder.cc(target))
1228                     .arg("--cxx")
1229                     .arg(builder.cxx(target).unwrap())
1230                     .arg("--cflags")
1231                     .arg(builder.cflags(target, GitRepo::Rustc).join(" "))
1232                     .arg("--llvm-components")
1233                     .arg(llvm_components.trim())
1234                     .arg("--llvm-cxxflags")
1235                     .arg(llvm_cxxflags.trim());
1236                 if let Some(ar) = builder.ar(target) {
1237                     cmd.arg("--ar").arg(ar);
1238                 }
1239
1240                 // The llvm/bin directory contains many useful cross-platform
1241                 // tools. Pass the path to run-make tests so they can use them.
1242                 let llvm_bin_path = llvm_config.parent()
1243                     .expect("Expected llvm-config to be contained in directory");
1244                 assert!(llvm_bin_path.is_dir());
1245                 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1246
1247                 // If LLD is available, add it to the PATH
1248                 if builder.config.lld_enabled {
1249                     let lld_install_root = builder.ensure(native::Lld {
1250                         target: builder.config.build,
1251                     });
1252
1253                     let lld_bin_path = lld_install_root.join("bin");
1254
1255                     let old_path = env::var_os("PATH").unwrap_or_default();
1256                     let new_path = env::join_paths(std::iter::once(lld_bin_path)
1257                         .chain(env::split_paths(&old_path)))
1258                         .expect("Could not add LLD bin path to PATH");
1259                     cmd.env("PATH", new_path);
1260                 }
1261             }
1262         }
1263
1264         if suite != "run-make-fulldeps" {
1265             cmd.arg("--cc")
1266                 .arg("")
1267                 .arg("--cxx")
1268                 .arg("")
1269                 .arg("--cflags")
1270                 .arg("")
1271                 .arg("--llvm-components")
1272                 .arg("")
1273                 .arg("--llvm-cxxflags")
1274                 .arg("");
1275         }
1276
1277         if builder.remote_tested(target) {
1278             cmd.arg("--remote-test-client")
1279                 .arg(builder.tool_exe(Tool::RemoteTestClient));
1280         }
1281
1282         // Running a C compiler on MSVC requires a few env vars to be set, to be
1283         // sure to set them here.
1284         //
1285         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
1286         // rather than stomp over it.
1287         if target.contains("msvc") {
1288             for &(ref k, ref v) in builder.cc[&target].env() {
1289                 if k != "PATH" {
1290                     cmd.env(k, v);
1291                 }
1292             }
1293         }
1294         cmd.env("RUSTC_BOOTSTRAP", "1");
1295         builder.add_rust_test_threads(&mut cmd);
1296
1297         if builder.config.sanitizers {
1298             cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1299         }
1300
1301         if builder.config.profiler {
1302             cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1303         }
1304
1305         cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp"));
1306
1307         cmd.arg("--adb-path").arg("adb");
1308         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
1309         if target.contains("android") {
1310             // Assume that cc for this target comes from the android sysroot
1311             cmd.arg("--android-cross-path")
1312                 .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1313         } else {
1314             cmd.arg("--android-cross-path").arg("");
1315         }
1316
1317         if builder.config.cmd.rustfix_coverage() {
1318             cmd.arg("--rustfix-coverage");
1319         }
1320
1321         builder.ci_env.force_coloring_in_ci(&mut cmd);
1322
1323         let _folder = builder.fold_output(|| format!("test_{}", suite));
1324         builder.info(&format!(
1325             "Check compiletest suite={} mode={} ({} -> {})",
1326             suite, mode, &compiler.host, target
1327         ));
1328         let _time = util::timeit(&builder);
1329         try_run(builder, &mut cmd);
1330
1331         if let Some(compare_mode) = compare_mode {
1332             cmd.arg("--compare-mode").arg(compare_mode);
1333             let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode));
1334             builder.info(&format!(
1335                 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
1336                 suite, mode, compare_mode, &compiler.host, target
1337             ));
1338             let _time = util::timeit(&builder);
1339             try_run(builder, &mut cmd);
1340         }
1341     }
1342 }
1343
1344 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1345 struct DocTest {
1346     compiler: Compiler,
1347     path: &'static str,
1348     name: &'static str,
1349     is_ext_doc: bool,
1350 }
1351
1352 impl Step for DocTest {
1353     type Output = ();
1354     const ONLY_HOSTS: bool = true;
1355
1356     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1357         run.never()
1358     }
1359
1360     /// Runs `rustdoc --test` for all documentation in `src/doc`.
1361     ///
1362     /// This will run all tests in our markdown documentation (e.g., the book)
1363     /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
1364     /// `compiler`.
1365     fn run(self, builder: &Builder<'_>) {
1366         let compiler = self.compiler;
1367
1368         builder.ensure(compile::Test {
1369             compiler,
1370             target: compiler.host,
1371         });
1372
1373         // Do a breadth-first traversal of the `src/doc` directory and just run
1374         // tests for all files that end in `*.md`
1375         let mut stack = vec![builder.src.join(self.path)];
1376         let _time = util::timeit(&builder);
1377         let _folder = builder.fold_output(|| format!("test_{}", self.name));
1378
1379         let mut files = Vec::new();
1380         while let Some(p) = stack.pop() {
1381             if p.is_dir() {
1382                 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
1383                 continue;
1384             }
1385
1386             if p.extension().and_then(|s| s.to_str()) != Some("md") {
1387                 continue;
1388             }
1389
1390             // The nostarch directory in the book is for no starch, and so isn't
1391             // guaranteed to builder. We don't care if it doesn't build, so skip it.
1392             if p.to_str().map_or(false, |p| p.contains("nostarch")) {
1393                 continue;
1394             }
1395
1396             files.push(p);
1397         }
1398
1399         files.sort();
1400
1401         let mut toolstate = ToolState::TestPass;
1402         for file in files {
1403             if !markdown_test(builder, compiler, &file) {
1404                 toolstate = ToolState::TestFail;
1405             }
1406         }
1407         if self.is_ext_doc {
1408             builder.save_toolstate(self.name, toolstate);
1409         }
1410     }
1411 }
1412
1413 macro_rules! test_book {
1414     ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
1415         $(
1416             #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1417             pub struct $name {
1418                 compiler: Compiler,
1419             }
1420
1421             impl Step for $name {
1422                 type Output = ();
1423                 const DEFAULT: bool = $default;
1424                 const ONLY_HOSTS: bool = true;
1425
1426                 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1427                     run.path($path)
1428                 }
1429
1430                 fn make_run(run: RunConfig<'_>) {
1431                     run.builder.ensure($name {
1432                         compiler: run.builder.compiler(run.builder.top_stage, run.host),
1433                     });
1434                 }
1435
1436                 fn run(self, builder: &Builder<'_>) {
1437                     builder.ensure(DocTest {
1438                         compiler: self.compiler,
1439                         path: $path,
1440                         name: $book_name,
1441                         is_ext_doc: !$default,
1442                     });
1443                 }
1444             }
1445         )+
1446     }
1447 }
1448
1449 test_book!(
1450     Nomicon, "src/doc/nomicon", "nomicon", default=false;
1451     Reference, "src/doc/reference", "reference", default=false;
1452     RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
1453     RustcBook, "src/doc/rustc", "rustc", default=true;
1454     RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1455     EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1456     TheBook, "src/doc/book", "book", default=false;
1457     UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
1458     EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1459 );
1460
1461 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1462 pub struct ErrorIndex {
1463     compiler: Compiler,
1464 }
1465
1466 impl Step for ErrorIndex {
1467     type Output = ();
1468     const DEFAULT: bool = true;
1469     const ONLY_HOSTS: bool = true;
1470
1471     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1472         run.path("src/tools/error_index_generator")
1473     }
1474
1475     fn make_run(run: RunConfig<'_>) {
1476         run.builder.ensure(ErrorIndex {
1477             compiler: run.builder.compiler(run.builder.top_stage, run.host),
1478         });
1479     }
1480
1481     /// Runs the error index generator tool to execute the tests located in the error
1482     /// index.
1483     ///
1484     /// The `error_index_generator` tool lives in `src/tools` and is used to
1485     /// generate a markdown file from the error indexes of the code base which is
1486     /// then passed to `rustdoc --test`.
1487     fn run(self, builder: &Builder<'_>) {
1488         let compiler = self.compiler;
1489
1490         builder.ensure(compile::Std {
1491             compiler,
1492             target: compiler.host,
1493         });
1494
1495         let dir = testdir(builder, compiler.host);
1496         t!(fs::create_dir_all(&dir));
1497         let output = dir.join("error-index.md");
1498
1499         let mut tool = tool::ErrorIndex::command(
1500             builder,
1501             builder.compiler(compiler.stage, builder.config.build),
1502         );
1503         tool.arg("markdown")
1504             .arg(&output)
1505             .env("CFG_BUILD", &builder.config.build)
1506             .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
1507
1508         let _folder = builder.fold_output(|| "test_error_index");
1509         builder.info(&format!("Testing error-index stage{}", compiler.stage));
1510         let _time = util::timeit(&builder);
1511         builder.run(&mut tool);
1512         markdown_test(builder, compiler, &output);
1513     }
1514 }
1515
1516 fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1517     match fs::read_to_string(markdown) {
1518         Ok(contents) => {
1519             if !contents.contains("```") {
1520                 return true;
1521             }
1522         }
1523         Err(_) => {}
1524     }
1525
1526     builder.info(&format!("doc tests for: {}", markdown.display()));
1527     let mut cmd = builder.rustdoc_cmd(compiler);
1528     builder.add_rust_test_threads(&mut cmd);
1529     cmd.arg("--test");
1530     cmd.arg(markdown);
1531     cmd.env("RUSTC_BOOTSTRAP", "1");
1532
1533     let test_args = builder.config.cmd.test_args().join(" ");
1534     cmd.arg("--test-args").arg(test_args);
1535
1536     if builder.config.verbose_tests {
1537         try_run(builder, &mut cmd)
1538     } else {
1539         try_run_quiet(builder, &mut cmd)
1540     }
1541 }
1542
1543 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1544 pub struct CrateLibrustc {
1545     compiler: Compiler,
1546     target: Interned<String>,
1547     test_kind: TestKind,
1548     krate: Interned<String>,
1549 }
1550
1551 impl Step for CrateLibrustc {
1552     type Output = ();
1553     const DEFAULT: bool = true;
1554     const ONLY_HOSTS: bool = true;
1555
1556     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1557         run.krate("rustc-main")
1558     }
1559
1560     fn make_run(run: RunConfig<'_>) {
1561         let builder = run.builder;
1562         let compiler = builder.compiler(builder.top_stage, run.host);
1563
1564         for krate in builder.in_tree_crates("rustc-main") {
1565             if run.path.ends_with(&krate.path) {
1566                 let test_kind = builder.kind.into();
1567
1568                 builder.ensure(CrateLibrustc {
1569                     compiler,
1570                     target: run.target,
1571                     test_kind,
1572                     krate: krate.name,
1573                 });
1574             }
1575         }
1576     }
1577
1578     fn run(self, builder: &Builder<'_>) {
1579         builder.ensure(Crate {
1580             compiler: self.compiler,
1581             target: self.target,
1582             mode: Mode::Rustc,
1583             test_kind: self.test_kind,
1584             krate: self.krate,
1585         });
1586     }
1587 }
1588
1589 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1590 pub struct CrateNotDefault {
1591     compiler: Compiler,
1592     target: Interned<String>,
1593     test_kind: TestKind,
1594     krate: &'static str,
1595 }
1596
1597 impl Step for CrateNotDefault {
1598     type Output = ();
1599
1600     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1601         run.path("src/librustc_asan")
1602             .path("src/librustc_lsan")
1603             .path("src/librustc_msan")
1604             .path("src/librustc_tsan")
1605     }
1606
1607     fn make_run(run: RunConfig<'_>) {
1608         let builder = run.builder;
1609         let compiler = builder.compiler(builder.top_stage, run.host);
1610
1611         let test_kind = builder.kind.into();
1612
1613         builder.ensure(CrateNotDefault {
1614             compiler,
1615             target: run.target,
1616             test_kind,
1617             krate: match run.path {
1618                 _ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
1619                 _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
1620                 _ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
1621                 _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan",
1622                 _ => panic!("unexpected path {:?}", run.path),
1623             },
1624         });
1625     }
1626
1627     fn run(self, builder: &Builder<'_>) {
1628         builder.ensure(Crate {
1629             compiler: self.compiler,
1630             target: self.target,
1631             mode: Mode::Std,
1632             test_kind: self.test_kind,
1633             krate: INTERNER.intern_str(self.krate),
1634         });
1635     }
1636 }
1637
1638 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1639 pub struct Crate {
1640     pub compiler: Compiler,
1641     pub target: Interned<String>,
1642     pub mode: Mode,
1643     pub test_kind: TestKind,
1644     pub krate: Interned<String>,
1645 }
1646
1647 impl Step for Crate {
1648     type Output = ();
1649     const DEFAULT: bool = true;
1650
1651     fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1652         let builder = run.builder;
1653         run = run.krate("test");
1654         for krate in run.builder.in_tree_crates("std") {
1655             if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
1656                 run = run.path(krate.local_path(&builder).to_str().unwrap());
1657             }
1658         }
1659         run
1660     }
1661
1662     fn make_run(run: RunConfig<'_>) {
1663         let builder = run.builder;
1664         let compiler = builder.compiler(builder.top_stage, run.host);
1665
1666         let make = |mode: Mode, krate: &CargoCrate| {
1667             let test_kind = builder.kind.into();
1668
1669             builder.ensure(Crate {
1670                 compiler,
1671                 target: run.target,
1672                 mode,
1673                 test_kind,
1674                 krate: krate.name,
1675             });
1676         };
1677
1678         for krate in builder.in_tree_crates("std") {
1679             if run.path.ends_with(&krate.local_path(&builder)) {
1680                 make(Mode::Std, krate);
1681             }
1682         }
1683         for krate in builder.in_tree_crates("test") {
1684             if run.path.ends_with(&krate.local_path(&builder)) {
1685                 make(Mode::Test, krate);
1686             }
1687         }
1688     }
1689
1690     /// Runs all unit tests plus documentation tests for a given crate defined
1691     /// by a `Cargo.toml` (single manifest)
1692     ///
1693     /// This is what runs tests for crates like the standard library, compiler, etc.
1694     /// It essentially is the driver for running `cargo test`.
1695     ///
1696     /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
1697     /// arguments, and those arguments are discovered from `cargo metadata`.
1698     fn run(self, builder: &Builder<'_>) {
1699         let compiler = self.compiler;
1700         let target = self.target;
1701         let mode = self.mode;
1702         let test_kind = self.test_kind;
1703         let krate = self.krate;
1704
1705         builder.ensure(compile::Test { compiler, target });
1706         builder.ensure(RemoteCopyLibs { compiler, target });
1707
1708         // If we're not doing a full bootstrap but we're testing a stage2 version of
1709         // libstd, then what we're actually testing is the libstd produced in
1710         // stage1. Reflect that here by updating the compiler that we're working
1711         // with automatically.
1712         let compiler = if builder.force_use_stage1(compiler, target) {
1713             builder.compiler(1, compiler.host)
1714         } else {
1715             compiler.clone()
1716         };
1717
1718         let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
1719         match mode {
1720             Mode::Std => {
1721                 compile::std_cargo(builder, &compiler, target, &mut cargo);
1722             }
1723             Mode::Test => {
1724                 compile::test_cargo(builder, &compiler, target, &mut cargo);
1725             }
1726             Mode::Rustc => {
1727                 builder.ensure(compile::Rustc { compiler, target });
1728                 compile::rustc_cargo(builder, &mut cargo);
1729             }
1730             _ => panic!("can only test libraries"),
1731         };
1732
1733         // Build up the base `cargo test` command.
1734         //
1735         // Pass in some standard flags then iterate over the graph we've discovered
1736         // in `cargo metadata` with the maps above and figure out what `-p`
1737         // arguments need to get passed.
1738         if test_kind.subcommand() == "test" && !builder.fail_fast {
1739             cargo.arg("--no-fail-fast");
1740         }
1741         match builder.doc_tests {
1742             DocTests::Only => {
1743                 cargo.arg("--doc");
1744             }
1745             DocTests::No => {
1746                 cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
1747             }
1748             DocTests::Yes => {}
1749         }
1750
1751         cargo.arg("-p").arg(krate);
1752
1753         // The tests are going to run with the *target* libraries, so we need to
1754         // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
1755         //
1756         // Note that to run the compiler we need to run with the *host* libraries,
1757         // but our wrapper scripts arrange for that to be the case anyway.
1758         let mut dylib_path = dylib_path();
1759         dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1760         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
1761
1762         cargo.arg("--");
1763         cargo.args(&builder.config.cmd.test_args());
1764
1765         if !builder.config.verbose_tests {
1766             cargo.arg("--quiet");
1767         }
1768
1769         if target.contains("emscripten") {
1770             cargo.env(
1771                 format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1772                 builder
1773                     .config
1774                     .nodejs
1775                     .as_ref()
1776                     .expect("nodejs not configured"),
1777             );
1778         } else if target.starts_with("wasm32") {
1779             // Warn about running tests without the `wasm_syscall` feature enabled.
1780             // The javascript shim implements the syscall interface so that test
1781             // output can be correctly reported.
1782             if !builder.config.wasm_syscall {
1783                 builder.info(
1784                     "Libstd was built without `wasm_syscall` feature enabled: \
1785                      test output may not be visible."
1786                 );
1787             }
1788
1789             // On the wasm32-unknown-unknown target we're using LTO which is
1790             // incompatible with `-C prefer-dynamic`, so disable that here
1791             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
1792
1793             let node = builder
1794                 .config
1795                 .nodejs
1796                 .as_ref()
1797                 .expect("nodejs not configured");
1798             let runner = format!(
1799                 "{} {}/src/etc/wasm32-shim.js",
1800                 node.display(),
1801                 builder.src.display()
1802             );
1803             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
1804         } else if builder.remote_tested(target) {
1805             cargo.env(
1806                 format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1807                 format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()),
1808             );
1809         }
1810
1811         let _folder = builder.fold_output(|| {
1812             format!(
1813                 "{}_stage{}-{}",
1814                 test_kind.subcommand(),
1815                 compiler.stage,
1816                 krate
1817             )
1818         });
1819         builder.info(&format!(
1820             "{} {} stage{} ({} -> {})",
1821             test_kind, krate, compiler.stage, &compiler.host, target
1822         ));
1823         let _time = util::timeit(&builder);
1824         try_run(builder, &mut cargo);
1825     }
1826 }
1827
1828 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1829 pub struct CrateRustdoc {
1830     host: Interned<String>,
1831     test_kind: TestKind,
1832 }
1833
1834 impl Step for CrateRustdoc {
1835     type Output = ();
1836     const DEFAULT: bool = true;
1837     const ONLY_HOSTS: bool = true;
1838
1839     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1840         run.paths(&["src/librustdoc", "src/tools/rustdoc"])
1841     }
1842
1843     fn make_run(run: RunConfig<'_>) {
1844         let builder = run.builder;
1845
1846         let test_kind = builder.kind.into();
1847
1848         builder.ensure(CrateRustdoc {
1849             host: run.host,
1850             test_kind,
1851         });
1852     }
1853
1854     fn run(self, builder: &Builder<'_>) {
1855         let test_kind = self.test_kind;
1856
1857         let compiler = builder.compiler(builder.top_stage, self.host);
1858         let target = compiler.host;
1859         builder.ensure(compile::Rustc { compiler, target });
1860
1861         let mut cargo = tool::prepare_tool_cargo(builder,
1862                                                  compiler,
1863                                                  Mode::ToolRustc,
1864                                                  target,
1865                                                  test_kind.subcommand(),
1866                                                  "src/tools/rustdoc",
1867                                                  SourceType::InTree,
1868                                                  &[]);
1869         if test_kind.subcommand() == "test" && !builder.fail_fast {
1870             cargo.arg("--no-fail-fast");
1871         }
1872
1873         cargo.arg("-p").arg("rustdoc:0.0.0");
1874
1875         cargo.arg("--");
1876         cargo.args(&builder.config.cmd.test_args());
1877
1878         if self.host.contains("musl") {
1879             cargo.arg("'-Ctarget-feature=-crt-static'");
1880         }
1881
1882         if !builder.config.verbose_tests {
1883             cargo.arg("--quiet");
1884         }
1885
1886         let _folder = builder
1887             .fold_output(|| format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage));
1888         builder.info(&format!(
1889             "{} rustdoc stage{} ({} -> {})",
1890             test_kind, compiler.stage, &compiler.host, target
1891         ));
1892         let _time = util::timeit(&builder);
1893
1894         try_run(builder, &mut cargo);
1895     }
1896 }
1897
1898 fn envify(s: &str) -> String {
1899     s.chars()
1900         .map(|c| match c {
1901             '-' => '_',
1902             c => c,
1903         })
1904         .flat_map(|c| c.to_uppercase())
1905         .collect()
1906 }
1907
1908 /// Some test suites are run inside emulators or on remote devices, and most
1909 /// of our test binaries are linked dynamically which means we need to ship
1910 /// the standard library and such to the emulator ahead of time. This step
1911 /// represents this and is a dependency of all test suites.
1912 ///
1913 /// Most of the time this is a no-op. For some steps such as shipping data to
1914 /// QEMU we have to build our own tools so we've got conditional dependencies
1915 /// on those programs as well. Note that the remote test client is built for
1916 /// the build target (us) and the server is built for the target.
1917 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1918 pub struct RemoteCopyLibs {
1919     compiler: Compiler,
1920     target: Interned<String>,
1921 }
1922
1923 impl Step for RemoteCopyLibs {
1924     type Output = ();
1925
1926     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1927         run.never()
1928     }
1929
1930     fn run(self, builder: &Builder<'_>) {
1931         let compiler = self.compiler;
1932         let target = self.target;
1933         if !builder.remote_tested(target) {
1934             return;
1935         }
1936
1937         builder.ensure(compile::Test { compiler, target });
1938
1939         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
1940         t!(fs::create_dir_all(builder.out.join("tmp")));
1941
1942         let server = builder.ensure(tool::RemoteTestServer {
1943             compiler: compiler.with_stage(0),
1944             target,
1945         });
1946
1947         // Spawn the emulator and wait for it to come online
1948         let tool = builder.tool_exe(Tool::RemoteTestClient);
1949         let mut cmd = Command::new(&tool);
1950         cmd.arg("spawn-emulator")
1951             .arg(target)
1952             .arg(&server)
1953             .arg(builder.out.join("tmp"));
1954         if let Some(rootfs) = builder.qemu_rootfs(target) {
1955             cmd.arg(rootfs);
1956         }
1957         builder.run(&mut cmd);
1958
1959         // Push all our dylibs to the emulator
1960         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1961             let f = t!(f);
1962             let name = f.file_name().into_string().unwrap();
1963             if util::is_dylib(&name) {
1964                 builder.run(Command::new(&tool).arg("push").arg(f.path()));
1965             }
1966         }
1967     }
1968 }
1969
1970 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1971 pub struct Distcheck;
1972
1973 impl Step for Distcheck {
1974     type Output = ();
1975
1976     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1977         run.path("distcheck")
1978     }
1979
1980     fn make_run(run: RunConfig<'_>) {
1981         run.builder.ensure(Distcheck);
1982     }
1983
1984     /// Runs "distcheck", a 'make check' from a tarball
1985     fn run(self, builder: &Builder<'_>) {
1986         builder.info("Distcheck");
1987         let dir = builder.out.join("tmp").join("distcheck");
1988         let _ = fs::remove_dir_all(&dir);
1989         t!(fs::create_dir_all(&dir));
1990
1991         // Guarantee that these are built before we begin running.
1992         builder.ensure(dist::PlainSourceTarball);
1993         builder.ensure(dist::Src);
1994
1995         let mut cmd = Command::new("tar");
1996         cmd.arg("-xzf")
1997             .arg(builder.ensure(dist::PlainSourceTarball))
1998             .arg("--strip-components=1")
1999             .current_dir(&dir);
2000         builder.run(&mut cmd);
2001         builder.run(
2002             Command::new("./configure")
2003                 .args(&builder.config.configure_args)
2004                 .arg("--enable-vendor")
2005                 .current_dir(&dir),
2006         );
2007         builder.run(
2008             Command::new(build_helper::make(&builder.config.build))
2009                 .arg("check")
2010                 .current_dir(&dir),
2011         );
2012
2013         // Now make sure that rust-src has all of libstd's dependencies
2014         builder.info("Distcheck rust-src");
2015         let dir = builder.out.join("tmp").join("distcheck-src");
2016         let _ = fs::remove_dir_all(&dir);
2017         t!(fs::create_dir_all(&dir));
2018
2019         let mut cmd = Command::new("tar");
2020         cmd.arg("-xzf")
2021             .arg(builder.ensure(dist::Src))
2022             .arg("--strip-components=1")
2023             .current_dir(&dir);
2024         builder.run(&mut cmd);
2025
2026         let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
2027         builder.run(
2028             Command::new(&builder.initial_cargo)
2029                 .arg("generate-lockfile")
2030                 .arg("--manifest-path")
2031                 .arg(&toml)
2032                 .current_dir(&dir),
2033         );
2034     }
2035 }
2036
2037 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2038 pub struct Bootstrap;
2039
2040 impl Step for Bootstrap {
2041     type Output = ();
2042     const DEFAULT: bool = true;
2043     const ONLY_HOSTS: bool = true;
2044
2045     /// Tests the build system itself.
2046     fn run(self, builder: &Builder<'_>) {
2047         let mut cmd = Command::new(&builder.initial_cargo);
2048         cmd.arg("test")
2049             .current_dir(builder.src.join("src/bootstrap"))
2050             .env("RUSTFLAGS", "-Cdebuginfo=2")
2051             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
2052             .env("RUSTC_BOOTSTRAP", "1")
2053             .env("RUSTC", &builder.initial_rustc);
2054         if let Some(flags) = option_env!("RUSTFLAGS") {
2055             // Use the same rustc flags for testing as for "normal" compilation,
2056             // so that Cargo doesn’t recompile the entire dependency graph every time:
2057             // https://github.com/rust-lang/rust/issues/49215
2058             cmd.env("RUSTFLAGS", flags);
2059         }
2060         if !builder.fail_fast {
2061             cmd.arg("--no-fail-fast");
2062         }
2063         cmd.arg("--").args(&builder.config.cmd.test_args());
2064         // rustbuild tests are racy on directory creation so just run them one at a time.
2065         // Since there's not many this shouldn't be a problem.
2066         cmd.arg("--test-threads=1");
2067         try_run(builder, &mut cmd);
2068     }
2069
2070     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2071         run.path("src/bootstrap")
2072     }
2073
2074     fn make_run(run: RunConfig<'_>) {
2075         run.builder.ensure(Bootstrap);
2076     }
2077 }