]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/test.rs
Rollup merge of #60370 - Richard-W:const-layout-construction, r=sfackler
[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: None,
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             // Skip debuginfo tests on MSVC
980             if builder.config.build.contains("msvc") {
981                 return;
982             }
983
984             if mode == "debuginfo" {
985                 return builder.ensure(Compiletest {
986                     mode: "debuginfo-both",
987                     ..self
988                 });
989             }
990
991             builder.ensure(dist::DebuggerScripts {
992                 sysroot: builder.sysroot(compiler),
993                 host: target,
994             });
995         }
996
997         if suite.ends_with("fulldeps") {
998             builder.ensure(compile::Rustc { compiler, target });
999         }
1000
1001         if builder.no_std(target) == Some(true) {
1002             // the `test` doesn't compile for no-std targets
1003             builder.ensure(compile::Std { compiler, target });
1004         } else {
1005             builder.ensure(compile::Test { compiler, target });
1006         }
1007
1008         if builder.no_std(target) == Some(true) {
1009             // for no_std run-make (e.g., thumb*),
1010             // we need a host compiler which is called by cargo.
1011             builder.ensure(compile::Std { compiler, target: compiler.host });
1012         }
1013
1014         // HACK(eddyb) ensure that `libproc_macro` is available on the host.
1015         builder.ensure(compile::Test { compiler, target: compiler.host });
1016         // Also provide `rust_test_helpers` for the host.
1017         builder.ensure(native::TestHelpers { target: compiler.host });
1018
1019         // wasm32 can't build the test helpers
1020         if !target.contains("wasm32") {
1021             builder.ensure(native::TestHelpers { target });
1022         }
1023         builder.ensure(RemoteCopyLibs { compiler, target });
1024
1025         let mut cmd = builder.tool_cmd(Tool::Compiletest);
1026
1027         // compiletest currently has... a lot of arguments, so let's just pass all
1028         // of them!
1029
1030         cmd.arg("--compile-lib-path")
1031             .arg(builder.rustc_libdir(compiler));
1032         cmd.arg("--run-lib-path")
1033             .arg(builder.sysroot_libdir(compiler, target));
1034         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
1035
1036         let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
1037
1038         // Avoid depending on rustdoc when we don't need it.
1039         if mode == "rustdoc"
1040             || (mode == "run-make" && suite.ends_with("fulldeps"))
1041             || (mode == "ui" && is_rustdoc)
1042             || mode == "js-doc-test"
1043         {
1044             cmd.arg("--rustdoc-path")
1045                 .arg(builder.rustdoc(compiler));
1046         }
1047
1048         cmd.arg("--src-base")
1049             .arg(builder.src.join("src/test").join(suite));
1050         cmd.arg("--build-base")
1051             .arg(testdir(builder, compiler.host).join(suite));
1052         cmd.arg("--stage-id")
1053             .arg(format!("stage{}-{}", compiler.stage, target));
1054         cmd.arg("--mode").arg(mode);
1055         cmd.arg("--target").arg(target);
1056         cmd.arg("--host").arg(&*compiler.host);
1057         cmd.arg("--llvm-filecheck")
1058             .arg(builder.llvm_filecheck(builder.config.build));
1059
1060         if builder.config.cmd.bless() {
1061             cmd.arg("--bless");
1062         }
1063
1064         let compare_mode = builder.config.cmd.compare_mode().or_else(|| {
1065             if builder.config.test_compare_mode {
1066                 self.compare_mode
1067             } else {
1068                 None
1069             }
1070         });
1071
1072         if let Some(ref nodejs) = builder.config.nodejs {
1073             cmd.arg("--nodejs").arg(nodejs);
1074         }
1075
1076         let mut flags = if is_rustdoc {
1077             Vec::new()
1078         } else {
1079             vec!["-Crpath".to_string()]
1080         };
1081         if !is_rustdoc {
1082             if builder.config.rust_optimize_tests {
1083                 flags.push("-O".to_string());
1084             }
1085             if builder.config.rust_debuginfo_tests {
1086                 flags.push("-g".to_string());
1087             }
1088         }
1089         flags.push("-Zunstable-options".to_string());
1090         flags.push(builder.config.cmd.rustc_args().join(" "));
1091
1092         if let Some(linker) = builder.linker(target) {
1093             cmd.arg("--linker").arg(linker);
1094         }
1095
1096         let mut hostflags = flags.clone();
1097         hostflags.push(format!(
1098             "-Lnative={}",
1099             builder.test_helpers_out(compiler.host).display()
1100         ));
1101         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
1102
1103         let mut targetflags = flags;
1104         targetflags.push(format!(
1105             "-Lnative={}",
1106             builder.test_helpers_out(target).display()
1107         ));
1108         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
1109
1110         cmd.arg("--docck-python").arg(builder.python());
1111
1112         if builder.config.build.ends_with("apple-darwin") {
1113             // Force /usr/bin/python on macOS for LLDB tests because we're loading the
1114             // LLDB plugin's compiled module which only works with the system python
1115             // (namely not Homebrew-installed python)
1116             cmd.arg("--lldb-python").arg("/usr/bin/python");
1117         } else {
1118             cmd.arg("--lldb-python").arg(builder.python());
1119         }
1120
1121         if let Some(ref gdb) = builder.config.gdb {
1122             cmd.arg("--gdb").arg(gdb);
1123         }
1124
1125         let run = |cmd: &mut Command| {
1126             cmd.output().map(|output| {
1127                 String::from_utf8_lossy(&output.stdout)
1128                     .lines().next().unwrap_or_else(|| {
1129                         panic!("{:?} failed {:?}", cmd, output)
1130                     }).to_string()
1131             })
1132         };
1133         let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
1134             // Test against the lldb that was just built.
1135             builder.llvm_out(target).join("bin").join("lldb")
1136         } else {
1137             PathBuf::from("lldb")
1138         };
1139         let lldb_version = Command::new(&lldb_exe)
1140             .arg("--version")
1141             .output()
1142             .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
1143             .ok();
1144         if let Some(ref vers) = lldb_version {
1145             cmd.arg("--lldb-version").arg(vers);
1146             let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
1147             if let Some(ref dir) = lldb_python_dir {
1148                 cmd.arg("--lldb-python-dir").arg(dir);
1149             }
1150         }
1151
1152         if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
1153             match &var.to_string_lossy().to_lowercase()[..] {
1154                 "1" | "yes" | "on" => {
1155                     assert!(builder.config.lldb_enabled,
1156                         "RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \
1157                          be built.");
1158                     let clang_exe = builder.llvm_out(target).join("bin").join("clang");
1159                     cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
1160                 }
1161                 "0" | "no" | "off" => {
1162                     // Nothing to do.
1163                 }
1164                 other => {
1165                     // Let's make sure typos don't get unnoticed
1166                     panic!("Unrecognized option '{}' set in \
1167                             RUSTBUILD_FORCE_CLANG_BASED_TESTS", other);
1168                 }
1169             }
1170         }
1171
1172         // Get paths from cmd args
1173         let paths = match &builder.config.cmd {
1174             Subcommand::Test { ref paths, .. } => &paths[..],
1175             _ => &[],
1176         };
1177
1178         // Get test-args by striping suite path
1179         let mut test_args: Vec<&str> = paths
1180             .iter()
1181             .map(|p| {
1182                 match p.strip_prefix(".") {
1183                     Ok(path) => path,
1184                     Err(_) => p,
1185                 }
1186             })
1187             .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
1188             .filter_map(|p| {
1189                 // Since test suite paths are themselves directories, if we don't
1190                 // specify a directory or file, we'll get an empty string here
1191                 // (the result of the test suite directory without its suite prefix).
1192                 // Therefore, we need to filter these out, as only the first --test-args
1193                 // flag is respected, so providing an empty --test-args conflicts with
1194                 // any following it.
1195                 match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
1196                     Some(s) if s != "" => Some(s),
1197                     _ => None,
1198                 }
1199             })
1200             .collect();
1201
1202         test_args.append(&mut builder.config.cmd.test_args());
1203
1204         cmd.args(&test_args);
1205
1206         if builder.is_verbose() {
1207             cmd.arg("--verbose");
1208         }
1209
1210         if !builder.config.verbose_tests {
1211             cmd.arg("--quiet");
1212         }
1213
1214         if builder.config.llvm_enabled() {
1215             let llvm_config = builder.ensure(native::Llvm {
1216                 target: builder.config.build,
1217                 emscripten: false,
1218             });
1219             if !builder.config.dry_run {
1220                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
1221                 cmd.arg("--llvm-version").arg(llvm_version);
1222             }
1223             if !builder.is_rust_llvm(target) {
1224                 cmd.arg("--system-llvm");
1225             }
1226
1227             // Only pass correct values for these flags for the `run-make` suite as it
1228             // requires that a C++ compiler was configured which isn't always the case.
1229             if !builder.config.dry_run && suite == "run-make-fulldeps" {
1230                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
1231                 let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
1232                 cmd.arg("--cc")
1233                     .arg(builder.cc(target))
1234                     .arg("--cxx")
1235                     .arg(builder.cxx(target).unwrap())
1236                     .arg("--cflags")
1237                     .arg(builder.cflags(target, GitRepo::Rustc).join(" "))
1238                     .arg("--llvm-components")
1239                     .arg(llvm_components.trim())
1240                     .arg("--llvm-cxxflags")
1241                     .arg(llvm_cxxflags.trim());
1242                 if let Some(ar) = builder.ar(target) {
1243                     cmd.arg("--ar").arg(ar);
1244                 }
1245
1246                 // The llvm/bin directory contains many useful cross-platform
1247                 // tools. Pass the path to run-make tests so they can use them.
1248                 let llvm_bin_path = llvm_config.parent()
1249                     .expect("Expected llvm-config to be contained in directory");
1250                 assert!(llvm_bin_path.is_dir());
1251                 cmd.arg("--llvm-bin-dir").arg(llvm_bin_path);
1252
1253                 // If LLD is available, add it to the PATH
1254                 if builder.config.lld_enabled {
1255                     let lld_install_root = builder.ensure(native::Lld {
1256                         target: builder.config.build,
1257                     });
1258
1259                     let lld_bin_path = lld_install_root.join("bin");
1260
1261                     let old_path = env::var_os("PATH").unwrap_or_default();
1262                     let new_path = env::join_paths(std::iter::once(lld_bin_path)
1263                         .chain(env::split_paths(&old_path)))
1264                         .expect("Could not add LLD bin path to PATH");
1265                     cmd.env("PATH", new_path);
1266                 }
1267             }
1268         }
1269
1270         if suite != "run-make-fulldeps" {
1271             cmd.arg("--cc")
1272                 .arg("")
1273                 .arg("--cxx")
1274                 .arg("")
1275                 .arg("--cflags")
1276                 .arg("")
1277                 .arg("--llvm-components")
1278                 .arg("")
1279                 .arg("--llvm-cxxflags")
1280                 .arg("");
1281         }
1282
1283         if builder.remote_tested(target) {
1284             cmd.arg("--remote-test-client")
1285                 .arg(builder.tool_exe(Tool::RemoteTestClient));
1286         }
1287
1288         // Running a C compiler on MSVC requires a few env vars to be set, to be
1289         // sure to set them here.
1290         //
1291         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
1292         // rather than stomp over it.
1293         if target.contains("msvc") {
1294             for &(ref k, ref v) in builder.cc[&target].env() {
1295                 if k != "PATH" {
1296                     cmd.env(k, v);
1297                 }
1298             }
1299         }
1300         cmd.env("RUSTC_BOOTSTRAP", "1");
1301         builder.add_rust_test_threads(&mut cmd);
1302
1303         if builder.config.sanitizers {
1304             cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
1305         }
1306
1307         if builder.config.profiler {
1308             cmd.env("RUSTC_PROFILER_SUPPORT", "1");
1309         }
1310
1311         cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp"));
1312
1313         cmd.arg("--adb-path").arg("adb");
1314         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
1315         if target.contains("android") {
1316             // Assume that cc for this target comes from the android sysroot
1317             cmd.arg("--android-cross-path")
1318                 .arg(builder.cc(target).parent().unwrap().parent().unwrap());
1319         } else {
1320             cmd.arg("--android-cross-path").arg("");
1321         }
1322
1323         if builder.config.cmd.rustfix_coverage() {
1324             cmd.arg("--rustfix-coverage");
1325         }
1326
1327         builder.ci_env.force_coloring_in_ci(&mut cmd);
1328
1329         let _folder = builder.fold_output(|| format!("test_{}", suite));
1330         builder.info(&format!(
1331             "Check compiletest suite={} mode={} ({} -> {})",
1332             suite, mode, &compiler.host, target
1333         ));
1334         let _time = util::timeit(&builder);
1335         try_run(builder, &mut cmd);
1336
1337         if let Some(compare_mode) = compare_mode {
1338             cmd.arg("--compare-mode").arg(compare_mode);
1339             let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode));
1340             builder.info(&format!(
1341                 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
1342                 suite, mode, compare_mode, &compiler.host, target
1343             ));
1344             let _time = util::timeit(&builder);
1345             try_run(builder, &mut cmd);
1346         }
1347     }
1348 }
1349
1350 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1351 struct DocTest {
1352     compiler: Compiler,
1353     path: &'static str,
1354     name: &'static str,
1355     is_ext_doc: bool,
1356 }
1357
1358 impl Step for DocTest {
1359     type Output = ();
1360     const ONLY_HOSTS: bool = true;
1361
1362     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1363         run.never()
1364     }
1365
1366     /// Runs `rustdoc --test` for all documentation in `src/doc`.
1367     ///
1368     /// This will run all tests in our markdown documentation (e.g., the book)
1369     /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
1370     /// `compiler`.
1371     fn run(self, builder: &Builder<'_>) {
1372         let compiler = self.compiler;
1373
1374         builder.ensure(compile::Test {
1375             compiler,
1376             target: compiler.host,
1377         });
1378
1379         // Do a breadth-first traversal of the `src/doc` directory and just run
1380         // tests for all files that end in `*.md`
1381         let mut stack = vec![builder.src.join(self.path)];
1382         let _time = util::timeit(&builder);
1383         let _folder = builder.fold_output(|| format!("test_{}", self.name));
1384
1385         let mut files = Vec::new();
1386         while let Some(p) = stack.pop() {
1387             if p.is_dir() {
1388                 stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
1389                 continue;
1390             }
1391
1392             if p.extension().and_then(|s| s.to_str()) != Some("md") {
1393                 continue;
1394             }
1395
1396             // The nostarch directory in the book is for no starch, and so isn't
1397             // guaranteed to builder. We don't care if it doesn't build, so skip it.
1398             if p.to_str().map_or(false, |p| p.contains("nostarch")) {
1399                 continue;
1400             }
1401
1402             files.push(p);
1403         }
1404
1405         files.sort();
1406
1407         let mut toolstate = ToolState::TestPass;
1408         for file in files {
1409             if !markdown_test(builder, compiler, &file) {
1410                 toolstate = ToolState::TestFail;
1411             }
1412         }
1413         if self.is_ext_doc {
1414             builder.save_toolstate(self.name, toolstate);
1415         }
1416     }
1417 }
1418
1419 macro_rules! test_book {
1420     ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
1421         $(
1422             #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1423             pub struct $name {
1424                 compiler: Compiler,
1425             }
1426
1427             impl Step for $name {
1428                 type Output = ();
1429                 const DEFAULT: bool = $default;
1430                 const ONLY_HOSTS: bool = true;
1431
1432                 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1433                     run.path($path)
1434                 }
1435
1436                 fn make_run(run: RunConfig<'_>) {
1437                     run.builder.ensure($name {
1438                         compiler: run.builder.compiler(run.builder.top_stage, run.host),
1439                     });
1440                 }
1441
1442                 fn run(self, builder: &Builder<'_>) {
1443                     builder.ensure(DocTest {
1444                         compiler: self.compiler,
1445                         path: $path,
1446                         name: $book_name,
1447                         is_ext_doc: !$default,
1448                     });
1449                 }
1450             }
1451         )+
1452     }
1453 }
1454
1455 test_book!(
1456     Nomicon, "src/doc/nomicon", "nomicon", default=false;
1457     Reference, "src/doc/reference", "reference", default=false;
1458     RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
1459     RustcBook, "src/doc/rustc", "rustc", default=true;
1460     RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
1461     EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
1462     TheBook, "src/doc/book", "book", default=false;
1463     UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
1464     EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
1465 );
1466
1467 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1468 pub struct ErrorIndex {
1469     compiler: Compiler,
1470 }
1471
1472 impl Step for ErrorIndex {
1473     type Output = ();
1474     const DEFAULT: bool = true;
1475     const ONLY_HOSTS: bool = true;
1476
1477     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1478         run.path("src/tools/error_index_generator")
1479     }
1480
1481     fn make_run(run: RunConfig<'_>) {
1482         run.builder.ensure(ErrorIndex {
1483             compiler: run.builder.compiler(run.builder.top_stage, run.host),
1484         });
1485     }
1486
1487     /// Runs the error index generator tool to execute the tests located in the error
1488     /// index.
1489     ///
1490     /// The `error_index_generator` tool lives in `src/tools` and is used to
1491     /// generate a markdown file from the error indexes of the code base which is
1492     /// then passed to `rustdoc --test`.
1493     fn run(self, builder: &Builder<'_>) {
1494         let compiler = self.compiler;
1495
1496         builder.ensure(compile::Std {
1497             compiler,
1498             target: compiler.host,
1499         });
1500
1501         let dir = testdir(builder, compiler.host);
1502         t!(fs::create_dir_all(&dir));
1503         let output = dir.join("error-index.md");
1504
1505         let mut tool = tool::ErrorIndex::command(
1506             builder,
1507             builder.compiler(compiler.stage, builder.config.build),
1508         );
1509         tool.arg("markdown")
1510             .arg(&output)
1511             .env("CFG_BUILD", &builder.config.build)
1512             .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
1513
1514         let _folder = builder.fold_output(|| "test_error_index");
1515         builder.info(&format!("Testing error-index stage{}", compiler.stage));
1516         let _time = util::timeit(&builder);
1517         builder.run(&mut tool);
1518         markdown_test(builder, compiler, &output);
1519     }
1520 }
1521
1522 fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
1523     match fs::read_to_string(markdown) {
1524         Ok(contents) => {
1525             if !contents.contains("```") {
1526                 return true;
1527             }
1528         }
1529         Err(_) => {}
1530     }
1531
1532     builder.info(&format!("doc tests for: {}", markdown.display()));
1533     let mut cmd = builder.rustdoc_cmd(compiler);
1534     builder.add_rust_test_threads(&mut cmd);
1535     cmd.arg("--test");
1536     cmd.arg(markdown);
1537     cmd.env("RUSTC_BOOTSTRAP", "1");
1538
1539     let test_args = builder.config.cmd.test_args().join(" ");
1540     cmd.arg("--test-args").arg(test_args);
1541
1542     if builder.config.verbose_tests {
1543         try_run(builder, &mut cmd)
1544     } else {
1545         try_run_quiet(builder, &mut cmd)
1546     }
1547 }
1548
1549 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1550 pub struct CrateLibrustc {
1551     compiler: Compiler,
1552     target: Interned<String>,
1553     test_kind: TestKind,
1554     krate: Interned<String>,
1555 }
1556
1557 impl Step for CrateLibrustc {
1558     type Output = ();
1559     const DEFAULT: bool = true;
1560     const ONLY_HOSTS: bool = true;
1561
1562     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1563         run.krate("rustc-main")
1564     }
1565
1566     fn make_run(run: RunConfig<'_>) {
1567         let builder = run.builder;
1568         let compiler = builder.compiler(builder.top_stage, run.host);
1569
1570         for krate in builder.in_tree_crates("rustc-main") {
1571             if run.path.ends_with(&krate.path) {
1572                 let test_kind = builder.kind.into();
1573
1574                 builder.ensure(CrateLibrustc {
1575                     compiler,
1576                     target: run.target,
1577                     test_kind,
1578                     krate: krate.name,
1579                 });
1580             }
1581         }
1582     }
1583
1584     fn run(self, builder: &Builder<'_>) {
1585         builder.ensure(Crate {
1586             compiler: self.compiler,
1587             target: self.target,
1588             mode: Mode::Rustc,
1589             test_kind: self.test_kind,
1590             krate: self.krate,
1591         });
1592     }
1593 }
1594
1595 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1596 pub struct CrateNotDefault {
1597     compiler: Compiler,
1598     target: Interned<String>,
1599     test_kind: TestKind,
1600     krate: &'static str,
1601 }
1602
1603 impl Step for CrateNotDefault {
1604     type Output = ();
1605
1606     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1607         run.path("src/librustc_asan")
1608             .path("src/librustc_lsan")
1609             .path("src/librustc_msan")
1610             .path("src/librustc_tsan")
1611     }
1612
1613     fn make_run(run: RunConfig<'_>) {
1614         let builder = run.builder;
1615         let compiler = builder.compiler(builder.top_stage, run.host);
1616
1617         let test_kind = builder.kind.into();
1618
1619         builder.ensure(CrateNotDefault {
1620             compiler,
1621             target: run.target,
1622             test_kind,
1623             krate: match run.path {
1624                 _ if run.path.ends_with("src/librustc_asan") => "rustc_asan",
1625                 _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan",
1626                 _ if run.path.ends_with("src/librustc_msan") => "rustc_msan",
1627                 _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan",
1628                 _ => panic!("unexpected path {:?}", run.path),
1629             },
1630         });
1631     }
1632
1633     fn run(self, builder: &Builder<'_>) {
1634         builder.ensure(Crate {
1635             compiler: self.compiler,
1636             target: self.target,
1637             mode: Mode::Std,
1638             test_kind: self.test_kind,
1639             krate: INTERNER.intern_str(self.krate),
1640         });
1641     }
1642 }
1643
1644 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1645 pub struct Crate {
1646     pub compiler: Compiler,
1647     pub target: Interned<String>,
1648     pub mode: Mode,
1649     pub test_kind: TestKind,
1650     pub krate: Interned<String>,
1651 }
1652
1653 impl Step for Crate {
1654     type Output = ();
1655     const DEFAULT: bool = true;
1656
1657     fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1658         let builder = run.builder;
1659         run = run.krate("test");
1660         for krate in run.builder.in_tree_crates("std") {
1661             if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
1662                 run = run.path(krate.local_path(&builder).to_str().unwrap());
1663             }
1664         }
1665         run
1666     }
1667
1668     fn make_run(run: RunConfig<'_>) {
1669         let builder = run.builder;
1670         let compiler = builder.compiler(builder.top_stage, run.host);
1671
1672         let make = |mode: Mode, krate: &CargoCrate| {
1673             let test_kind = builder.kind.into();
1674
1675             builder.ensure(Crate {
1676                 compiler,
1677                 target: run.target,
1678                 mode,
1679                 test_kind,
1680                 krate: krate.name,
1681             });
1682         };
1683
1684         for krate in builder.in_tree_crates("std") {
1685             if run.path.ends_with(&krate.local_path(&builder)) {
1686                 make(Mode::Std, krate);
1687             }
1688         }
1689         for krate in builder.in_tree_crates("test") {
1690             if run.path.ends_with(&krate.local_path(&builder)) {
1691                 make(Mode::Test, krate);
1692             }
1693         }
1694     }
1695
1696     /// Runs all unit tests plus documentation tests for a given crate defined
1697     /// by a `Cargo.toml` (single manifest)
1698     ///
1699     /// This is what runs tests for crates like the standard library, compiler, etc.
1700     /// It essentially is the driver for running `cargo test`.
1701     ///
1702     /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
1703     /// arguments, and those arguments are discovered from `cargo metadata`.
1704     fn run(self, builder: &Builder<'_>) {
1705         let compiler = self.compiler;
1706         let target = self.target;
1707         let mode = self.mode;
1708         let test_kind = self.test_kind;
1709         let krate = self.krate;
1710
1711         builder.ensure(compile::Test { compiler, target });
1712         builder.ensure(RemoteCopyLibs { compiler, target });
1713
1714         // If we're not doing a full bootstrap but we're testing a stage2 version of
1715         // libstd, then what we're actually testing is the libstd produced in
1716         // stage1. Reflect that here by updating the compiler that we're working
1717         // with automatically.
1718         let compiler = if builder.force_use_stage1(compiler, target) {
1719             builder.compiler(1, compiler.host)
1720         } else {
1721             compiler.clone()
1722         };
1723
1724         let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
1725         match mode {
1726             Mode::Std => {
1727                 compile::std_cargo(builder, &compiler, target, &mut cargo);
1728             }
1729             Mode::Test => {
1730                 compile::test_cargo(builder, &compiler, target, &mut cargo);
1731             }
1732             Mode::Rustc => {
1733                 builder.ensure(compile::Rustc { compiler, target });
1734                 compile::rustc_cargo(builder, &mut cargo);
1735             }
1736             _ => panic!("can only test libraries"),
1737         };
1738
1739         // Build up the base `cargo test` command.
1740         //
1741         // Pass in some standard flags then iterate over the graph we've discovered
1742         // in `cargo metadata` with the maps above and figure out what `-p`
1743         // arguments need to get passed.
1744         if test_kind.subcommand() == "test" && !builder.fail_fast {
1745             cargo.arg("--no-fail-fast");
1746         }
1747         match builder.doc_tests {
1748             DocTests::Only => {
1749                 cargo.arg("--doc");
1750             }
1751             DocTests::No => {
1752                 cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
1753             }
1754             DocTests::Yes => {}
1755         }
1756
1757         cargo.arg("-p").arg(krate);
1758
1759         // The tests are going to run with the *target* libraries, so we need to
1760         // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
1761         //
1762         // Note that to run the compiler we need to run with the *host* libraries,
1763         // but our wrapper scripts arrange for that to be the case anyway.
1764         let mut dylib_path = dylib_path();
1765         dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
1766         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
1767
1768         cargo.arg("--");
1769         cargo.args(&builder.config.cmd.test_args());
1770
1771         if !builder.config.verbose_tests {
1772             cargo.arg("--quiet");
1773         }
1774
1775         if target.contains("emscripten") {
1776             cargo.env(
1777                 format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1778                 builder
1779                     .config
1780                     .nodejs
1781                     .as_ref()
1782                     .expect("nodejs not configured"),
1783             );
1784         } else if target.starts_with("wasm32") {
1785             // Warn about running tests without the `wasm_syscall` feature enabled.
1786             // The javascript shim implements the syscall interface so that test
1787             // output can be correctly reported.
1788             if !builder.config.wasm_syscall {
1789                 builder.info(
1790                     "Libstd was built without `wasm_syscall` feature enabled: \
1791                      test output may not be visible."
1792                 );
1793             }
1794
1795             // On the wasm32-unknown-unknown target we're using LTO which is
1796             // incompatible with `-C prefer-dynamic`, so disable that here
1797             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
1798
1799             let node = builder
1800                 .config
1801                 .nodejs
1802                 .as_ref()
1803                 .expect("nodejs not configured");
1804             let runner = format!(
1805                 "{} {}/src/etc/wasm32-shim.js",
1806                 node.display(),
1807                 builder.src.display()
1808             );
1809             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
1810         } else if builder.remote_tested(target) {
1811             cargo.env(
1812                 format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
1813                 format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()),
1814             );
1815         }
1816
1817         let _folder = builder.fold_output(|| {
1818             format!(
1819                 "{}_stage{}-{}",
1820                 test_kind.subcommand(),
1821                 compiler.stage,
1822                 krate
1823             )
1824         });
1825         builder.info(&format!(
1826             "{} {} stage{} ({} -> {})",
1827             test_kind, krate, compiler.stage, &compiler.host, target
1828         ));
1829         let _time = util::timeit(&builder);
1830         try_run(builder, &mut cargo);
1831     }
1832 }
1833
1834 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1835 pub struct CrateRustdoc {
1836     host: Interned<String>,
1837     test_kind: TestKind,
1838 }
1839
1840 impl Step for CrateRustdoc {
1841     type Output = ();
1842     const DEFAULT: bool = true;
1843     const ONLY_HOSTS: bool = true;
1844
1845     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1846         run.paths(&["src/librustdoc", "src/tools/rustdoc"])
1847     }
1848
1849     fn make_run(run: RunConfig<'_>) {
1850         let builder = run.builder;
1851
1852         let test_kind = builder.kind.into();
1853
1854         builder.ensure(CrateRustdoc {
1855             host: run.host,
1856             test_kind,
1857         });
1858     }
1859
1860     fn run(self, builder: &Builder<'_>) {
1861         let test_kind = self.test_kind;
1862
1863         let compiler = builder.compiler(builder.top_stage, self.host);
1864         let target = compiler.host;
1865         builder.ensure(compile::Rustc { compiler, target });
1866
1867         let mut cargo = tool::prepare_tool_cargo(builder,
1868                                                  compiler,
1869                                                  Mode::ToolRustc,
1870                                                  target,
1871                                                  test_kind.subcommand(),
1872                                                  "src/tools/rustdoc",
1873                                                  SourceType::InTree,
1874                                                  &[]);
1875         if test_kind.subcommand() == "test" && !builder.fail_fast {
1876             cargo.arg("--no-fail-fast");
1877         }
1878
1879         cargo.arg("-p").arg("rustdoc:0.0.0");
1880
1881         cargo.arg("--");
1882         cargo.args(&builder.config.cmd.test_args());
1883
1884         if self.host.contains("musl") {
1885             cargo.arg("'-Ctarget-feature=-crt-static'");
1886         }
1887
1888         if !builder.config.verbose_tests {
1889             cargo.arg("--quiet");
1890         }
1891
1892         let _folder = builder
1893             .fold_output(|| format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage));
1894         builder.info(&format!(
1895             "{} rustdoc stage{} ({} -> {})",
1896             test_kind, compiler.stage, &compiler.host, target
1897         ));
1898         let _time = util::timeit(&builder);
1899
1900         try_run(builder, &mut cargo);
1901     }
1902 }
1903
1904 fn envify(s: &str) -> String {
1905     s.chars()
1906         .map(|c| match c {
1907             '-' => '_',
1908             c => c,
1909         })
1910         .flat_map(|c| c.to_uppercase())
1911         .collect()
1912 }
1913
1914 /// Some test suites are run inside emulators or on remote devices, and most
1915 /// of our test binaries are linked dynamically which means we need to ship
1916 /// the standard library and such to the emulator ahead of time. This step
1917 /// represents this and is a dependency of all test suites.
1918 ///
1919 /// Most of the time this is a no-op. For some steps such as shipping data to
1920 /// QEMU we have to build our own tools so we've got conditional dependencies
1921 /// on those programs as well. Note that the remote test client is built for
1922 /// the build target (us) and the server is built for the target.
1923 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1924 pub struct RemoteCopyLibs {
1925     compiler: Compiler,
1926     target: Interned<String>,
1927 }
1928
1929 impl Step for RemoteCopyLibs {
1930     type Output = ();
1931
1932     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1933         run.never()
1934     }
1935
1936     fn run(self, builder: &Builder<'_>) {
1937         let compiler = self.compiler;
1938         let target = self.target;
1939         if !builder.remote_tested(target) {
1940             return;
1941         }
1942
1943         builder.ensure(compile::Test { compiler, target });
1944
1945         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
1946         t!(fs::create_dir_all(builder.out.join("tmp")));
1947
1948         let server = builder.ensure(tool::RemoteTestServer {
1949             compiler: compiler.with_stage(0),
1950             target,
1951         });
1952
1953         // Spawn the emulator and wait for it to come online
1954         let tool = builder.tool_exe(Tool::RemoteTestClient);
1955         let mut cmd = Command::new(&tool);
1956         cmd.arg("spawn-emulator")
1957             .arg(target)
1958             .arg(&server)
1959             .arg(builder.out.join("tmp"));
1960         if let Some(rootfs) = builder.qemu_rootfs(target) {
1961             cmd.arg(rootfs);
1962         }
1963         builder.run(&mut cmd);
1964
1965         // Push all our dylibs to the emulator
1966         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
1967             let f = t!(f);
1968             let name = f.file_name().into_string().unwrap();
1969             if util::is_dylib(&name) {
1970                 builder.run(Command::new(&tool).arg("push").arg(f.path()));
1971             }
1972         }
1973     }
1974 }
1975
1976 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1977 pub struct Distcheck;
1978
1979 impl Step for Distcheck {
1980     type Output = ();
1981
1982     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1983         run.path("distcheck")
1984     }
1985
1986     fn make_run(run: RunConfig<'_>) {
1987         run.builder.ensure(Distcheck);
1988     }
1989
1990     /// Runs "distcheck", a 'make check' from a tarball
1991     fn run(self, builder: &Builder<'_>) {
1992         builder.info("Distcheck");
1993         let dir = builder.out.join("tmp").join("distcheck");
1994         let _ = fs::remove_dir_all(&dir);
1995         t!(fs::create_dir_all(&dir));
1996
1997         // Guarantee that these are built before we begin running.
1998         builder.ensure(dist::PlainSourceTarball);
1999         builder.ensure(dist::Src);
2000
2001         let mut cmd = Command::new("tar");
2002         cmd.arg("-xzf")
2003             .arg(builder.ensure(dist::PlainSourceTarball))
2004             .arg("--strip-components=1")
2005             .current_dir(&dir);
2006         builder.run(&mut cmd);
2007         builder.run(
2008             Command::new("./configure")
2009                 .args(&builder.config.configure_args)
2010                 .arg("--enable-vendor")
2011                 .current_dir(&dir),
2012         );
2013         builder.run(
2014             Command::new(build_helper::make(&builder.config.build))
2015                 .arg("check")
2016                 .current_dir(&dir),
2017         );
2018
2019         // Now make sure that rust-src has all of libstd's dependencies
2020         builder.info("Distcheck rust-src");
2021         let dir = builder.out.join("tmp").join("distcheck-src");
2022         let _ = fs::remove_dir_all(&dir);
2023         t!(fs::create_dir_all(&dir));
2024
2025         let mut cmd = Command::new("tar");
2026         cmd.arg("-xzf")
2027             .arg(builder.ensure(dist::Src))
2028             .arg("--strip-components=1")
2029             .current_dir(&dir);
2030         builder.run(&mut cmd);
2031
2032         let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
2033         builder.run(
2034             Command::new(&builder.initial_cargo)
2035                 .arg("generate-lockfile")
2036                 .arg("--manifest-path")
2037                 .arg(&toml)
2038                 .current_dir(&dir),
2039         );
2040     }
2041 }
2042
2043 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2044 pub struct Bootstrap;
2045
2046 impl Step for Bootstrap {
2047     type Output = ();
2048     const DEFAULT: bool = true;
2049     const ONLY_HOSTS: bool = true;
2050
2051     /// Tests the build system itself.
2052     fn run(self, builder: &Builder<'_>) {
2053         let mut cmd = Command::new(&builder.initial_cargo);
2054         cmd.arg("test")
2055             .current_dir(builder.src.join("src/bootstrap"))
2056             .env("RUSTFLAGS", "-Cdebuginfo=2")
2057             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
2058             .env("RUSTC_BOOTSTRAP", "1")
2059             .env("RUSTC", &builder.initial_rustc);
2060         if let Some(flags) = option_env!("RUSTFLAGS") {
2061             // Use the same rustc flags for testing as for "normal" compilation,
2062             // so that Cargo doesn’t recompile the entire dependency graph every time:
2063             // https://github.com/rust-lang/rust/issues/49215
2064             cmd.env("RUSTFLAGS", flags);
2065         }
2066         if !builder.fail_fast {
2067             cmd.arg("--no-fail-fast");
2068         }
2069         cmd.arg("--").args(&builder.config.cmd.test_args());
2070         // rustbuild tests are racy on directory creation so just run them one at a time.
2071         // Since there's not many this shouldn't be a problem.
2072         cmd.arg("--test-threads=1");
2073         try_run(builder, &mut cmd);
2074     }
2075
2076     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2077         run.path("src/bootstrap")
2078     }
2079
2080     fn make_run(run: RunConfig<'_>) {
2081         run.builder.ensure(Bootstrap);
2082     }
2083 }