Skip to main content

bootstrap/core/build_steps/
check.rs

1//! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use crate::core::build_steps::compile::{
7    ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
8    std_crates_for_make_run,
9};
10use crate::core::build_steps::tool;
11use crate::core::build_steps::tool::{
12    SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler,
13    prepare_tool_cargo,
14};
15use crate::core::builder::{
16    self, Alias, Builder, Cargo, CommandLineStep, Kind, RunConfig, ShouldRun, Step, StepMetadata,
17    crate_description,
18};
19use crate::core::config::TargetSelection;
20use crate::core::config::flags::Subcommand;
21use crate::utils::build_stamp::{self, BuildStamp};
22use crate::utils::helpers::t;
23use crate::{CodegenBackendKind, Compiler, Mode};
24
25/// Allows individual check-step instances to keep track of whether they
26/// represent `cargo check` or `cargo fix`, independently of [`Builder::kind`].
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28enum CheckKind {
29    Check,
30    Fix,
31}
32
33impl CheckKind {
34    fn to_kind(self) -> Kind {
35        match self {
36            CheckKind::Check => Kind::Check,
37            CheckKind::Fix => Kind::Fix,
38        }
39    }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct Std {
44    /// Compiler that will check this std.
45    pub build_compiler: Compiler,
46    pub target: TargetSelection,
47    /// Whether to build only a subset of crates.
48    ///
49    /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
50    ///
51    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
52    crates: Vec<String>,
53}
54
55impl Std {
56    const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"];
57}
58
59impl CommandLineStep for Std {
60    type Output = BuildStamp;
61
62    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
63        let mut run = run;
64        for c in Std::CRATE_OR_DEPS {
65            run = run.crate_or_deps(c);
66        }
67
68        run.path("library")
69    }
70
71    fn is_default_step(_builder: &Builder<'_>) -> bool {
72        true
73    }
74
75    fn make_run(run: RunConfig<'_>) {
76        if !run.builder.download_rustc() && run.builder.config.skip_std_check_if_no_download_rustc {
77            eprintln!(
78                "WARNING: `--skip-std-check-if-no-download-rustc` flag was passed and `rust.download-rustc` is not available. Skipping."
79            );
80            return;
81        }
82
83        if run.builder.config.compile_time_deps {
84            // libstd doesn't have any important build scripts and can't have any proc macros
85            return;
86        }
87
88        // Explicitly pass -p for all dependencies crates -- this will force cargo
89        // to also check the tests/benches/examples for these crates, rather
90        // than just the leaf crate.
91        let crates = std_crates_for_make_run(&run);
92        run.builder.ensure(Std {
93            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std)
94                .build_compiler(),
95            target: run.target,
96            crates,
97        });
98    }
99
100    fn run(self, builder: &Builder<'_>) -> Self::Output {
101        let build_compiler = self.build_compiler;
102        let target = self.target;
103
104        let mut cargo = builder::Cargo::new(
105            builder,
106            build_compiler,
107            Mode::Std,
108            SourceType::InTree,
109            target,
110            builder.kind,
111        );
112
113        std_cargo(builder, target, &mut cargo, &self.crates);
114        if matches!(builder.config.cmd, Subcommand::Fix) {
115            // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot.
116            cargo.arg("--lib");
117        }
118
119        let _guard = builder.msg(
120            builder.kind,
121            format_args!("library artifacts{}", crate_description(&self.crates)),
122            Mode::Std,
123            build_compiler,
124            target,
125        );
126
127        let check_stamp =
128            build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
129        run_cargo(
130            builder,
131            cargo,
132            builder.config.free_args.clone(),
133            &check_stamp,
134            vec![],
135            ArtifactKeepMode::OnlyRmeta,
136        );
137
138        drop(_guard);
139
140        // don't check test dependencies if we haven't built libtest
141        if !self.crates.iter().any(|krate| krate == "test") {
142            return check_stamp;
143        }
144
145        // Then run cargo again, once we've put the rmeta files for the library
146        // crates into the sysroot. This is needed because e.g., core's tests
147        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
148        // since we initialize with an empty sysroot.
149        //
150        // Currently only the "libtest" tree of crates does this.
151        let mut cargo = builder::Cargo::new(
152            builder,
153            build_compiler,
154            Mode::Std,
155            SourceType::InTree,
156            target,
157            Kind::Check,
158        );
159
160        std_cargo(builder, target, &mut cargo, &self.crates);
161
162        let stamp =
163            build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test");
164        let _guard = builder.msg(
165            Kind::Check,
166            "library test/bench/example targets",
167            Mode::Std,
168            build_compiler,
169            target,
170        );
171        run_cargo(
172            builder,
173            cargo,
174            builder.config.free_args.clone(),
175            &stamp,
176            vec![],
177            ArtifactKeepMode::OnlyRmeta,
178        );
179        check_stamp
180    }
181
182    fn metadata(&self) -> Option<StepMetadata> {
183        Some(StepMetadata::check("std", self.target).built_by(self.build_compiler))
184    }
185}
186
187/// Represents a proof that rustc was **checked**.
188/// Contains directories with .rmeta files generated by checking rustc for a specific
189/// target.
190#[derive(Debug, Clone, PartialEq, Eq, Hash)]
191struct RmetaSysroot {
192    host_dir: PathBuf,
193    target_dir: PathBuf,
194}
195
196impl RmetaSysroot {
197    /// Copy rmeta artifacts from the given `stamp` into a sysroot located at `directory`.
198    fn from_stamp(
199        builder: &Builder<'_>,
200        stamp: BuildStamp,
201        target: TargetSelection,
202        directory: &Path,
203    ) -> Self {
204        let host_dir = directory.join("host");
205        let target_dir = directory.join(target);
206        let _ = fs::remove_dir_all(directory);
207        t!(fs::create_dir_all(directory));
208        add_to_sysroot(builder, &target_dir, &host_dir, &stamp);
209
210        Self { host_dir, target_dir }
211    }
212
213    /// Configure the given cargo invocation so that the compiled crate will be able to use
214    /// rustc .rmeta artifacts that were previously generated.
215    fn configure_cargo(&self, cargo: &mut Cargo) {
216        cargo.append_to_env(
217            "RUSTC_ADDITIONAL_SYSROOT_PATHS",
218            format!("{},{}", self.host_dir.to_str().unwrap(), self.target_dir.to_str().unwrap()),
219            ",",
220        );
221    }
222}
223
224/// Checks rustc using the given `build_compiler` for the given `target`, and produces
225/// a sysroot in the build directory that stores the generated .rmeta files.
226///
227/// This step exists so that we can store the generated .rmeta artifacts into a separate
228/// directory, instead of copying them into the sysroot of `build_compiler`, which would
229/// "pollute" it (that is especially problematic for the external stage0 rustc).
230#[derive(Debug, Clone, PartialEq, Eq, Hash)]
231struct PrepareRustcRmetaSysroot {
232    build_compiler: CompilerForCheck,
233    target: TargetSelection,
234}
235
236impl PrepareRustcRmetaSysroot {
237    fn new(build_compiler: CompilerForCheck, target: TargetSelection) -> Self {
238        Self { build_compiler, target }
239    }
240}
241
242impl Step for PrepareRustcRmetaSysroot {
243    type Output = RmetaSysroot;
244
245    fn run(self, builder: &Builder<'_>) -> Self::Output {
246        // Check rustc
247        let stamp = Rustc::check_rustc_for_preparing_sysroot(builder, &self);
248
249        let build_compiler = self.build_compiler.build_compiler();
250
251        // Copy the generated rmeta artifacts to a separate directory
252        let dir = builder
253            .out
254            .join(build_compiler.host)
255            .join(format!("stage{}-rustc-rmeta-artifacts", build_compiler.stage + 1));
256        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
257    }
258}
259
260/// Checks std using the given `build_compiler` for the given `target`, and produces
261/// a sysroot in the build directory that stores the generated .rmeta files.
262///
263/// This step exists so that we can store the generated .rmeta artifacts into a separate
264/// directory, instead of copying them into the sysroot of `build_compiler`, which would
265/// "pollute" it (that is especially problematic for the external stage0 rustc).
266#[derive(Debug, Clone, PartialEq, Eq, Hash)]
267struct PrepareStdRmetaSysroot {
268    build_compiler: Compiler,
269    target: TargetSelection,
270}
271
272impl PrepareStdRmetaSysroot {
273    fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
274        Self { build_compiler, target }
275    }
276}
277
278impl Step for PrepareStdRmetaSysroot {
279    type Output = RmetaSysroot;
280
281    fn run(self, builder: &Builder<'_>) -> Self::Output {
282        // Check std
283        let stamp = builder.ensure(Std {
284            build_compiler: self.build_compiler,
285            target: self.target,
286            crates: vec![],
287        });
288
289        // Copy the generated rmeta artifacts to a separate directory
290        let dir = builder
291            .out
292            .join(self.build_compiler.host)
293            .join(format!("stage{}-std-rmeta-artifacts", self.build_compiler.stage));
294
295        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
296    }
297}
298
299/// Checks rustc using `build_compiler`.
300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
301pub struct Rustc {
302    check_kind: CheckKind,
303
304    /// Compiler that will check this rustc.
305    build_compiler: CompilerForCheck,
306    target: TargetSelection,
307
308    /// Whether to build only a subset of crates.
309    ///
310    /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
311    ///
312    /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
313    crates: Vec<String>,
314}
315
316impl Rustc {
317    fn check_rustc_for_preparing_sysroot(
318        builder: &Builder<'_>,
319        prepare: &PrepareRustcRmetaSysroot,
320    ) -> BuildStamp {
321        builder.ensure(Rustc {
322            // We specifically want `cargo check`, not the current bootstrap subcommand.
323            check_kind: CheckKind::Check,
324            build_compiler: prepare.build_compiler.clone(),
325            target: prepare.target,
326            crates: vec![],
327        })
328    }
329}
330
331impl CommandLineStep for Rustc {
332    type Output = BuildStamp;
333    const IS_HOST: bool = true;
334
335    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
336        run.crate_or_deps("rustc-main").path("compiler")
337    }
338
339    fn is_default_step(_builder: &Builder<'_>) -> bool {
340        true
341    }
342
343    fn make_run(run: RunConfig<'_>) {
344        let check_kind = match run.builder.kind {
345            Kind::Check => CheckKind::Check,
346            Kind::Fix => CheckKind::Fix,
347            kind => panic!("unexpected kind for `check::Rustc`: {kind:?}"),
348        };
349
350        let target = run.target;
351        let build_compiler = prepare_compiler_for_check(run.builder, target, Mode::Rustc);
352        let crates = run.make_run_crates(Alias::Compiler);
353
354        run.builder.ensure(Rustc { check_kind, build_compiler, target, crates });
355    }
356
357    /// Check the compiler.
358    ///
359    /// This will check the compiler for a particular stage of the build using
360    /// the `compiler` targeting the `target` architecture. The artifacts
361    /// created will also be linked into the sysroot directory.
362    ///
363    /// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
364    fn run(self, builder: &Builder<'_>) -> Self::Output {
365        let build_compiler = self.build_compiler.build_compiler;
366        let target = self.target;
367
368        let mut cargo = builder::Cargo::new(
369            builder,
370            build_compiler,
371            Mode::Rustc,
372            SourceType::InTree,
373            target,
374            self.check_kind.to_kind(),
375        );
376
377        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
378        self.build_compiler.configure_cargo(&mut cargo);
379
380        // Explicitly pass -p for all compiler crates -- this will force cargo
381        // to also check the tests/benches/examples for these crates, rather
382        // than just the leaf crate.
383        for krate in &*self.crates {
384            cargo.arg("-p").arg(krate);
385        }
386
387        let _guard = builder.msg(
388            self.check_kind.to_kind(),
389            format_args!("compiler artifacts{}", crate_description(&self.crates)),
390            Mode::Rustc,
391            self.build_compiler.build_compiler(),
392            target,
393        );
394
395        let stamp =
396            build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check");
397
398        run_cargo(
399            builder,
400            cargo,
401            builder.config.free_args.clone(),
402            &stamp,
403            vec![],
404            ArtifactKeepMode::OnlyRmeta,
405        );
406
407        stamp
408    }
409
410    fn metadata(&self) -> Option<StepMetadata> {
411        let mut metadata = StepMetadata::new("rustc", self.target, self.check_kind.to_kind())
412            .built_by(self.build_compiler.build_compiler());
413        if !self.crates.is_empty() {
414            metadata = metadata.with_metadata(format!("({} crates)", self.crates.len()));
415        }
416        Some(metadata)
417    }
418}
419
420/// Represents a compiler that can check something.
421///
422/// If the compiler was created for `Mode::ToolRustcPrivate` or `Mode::Codegen`, it will also contain
423/// .rmeta artifacts from rustc that was already checked using `build_compiler`.
424///
425/// All steps that use this struct in a "general way" (i.e. they don't know exactly what kind of
426/// thing is being built) should call `configure_cargo` to ensure that the rmeta artifacts are
427/// properly linked, if present.
428#[derive(Debug, Clone, PartialEq, Eq, Hash)]
429pub struct CompilerForCheck {
430    build_compiler: Compiler,
431    rustc_rmeta_sysroot: Option<RmetaSysroot>,
432    std_rmeta_sysroot: Option<RmetaSysroot>,
433}
434
435impl CompilerForCheck {
436    pub fn build_compiler(&self) -> Compiler {
437        self.build_compiler
438    }
439
440    /// If there are any rustc rmeta artifacts available, configure the Cargo invocation
441    /// so that the artifact being built can find them.
442    pub fn configure_cargo(&self, cargo: &mut Cargo) {
443        if let Some(sysroot) = &self.rustc_rmeta_sysroot {
444            sysroot.configure_cargo(cargo);
445        }
446        if let Some(sysroot) = &self.std_rmeta_sysroot {
447            sysroot.configure_cargo(cargo);
448        }
449    }
450}
451
452/// Prepare the standard library for checking something (that requires stdlib) using
453/// `build_compiler`.
454fn prepare_std(
455    builder: &Builder<'_>,
456    build_compiler: Compiler,
457    target: TargetSelection,
458) -> Option<RmetaSysroot> {
459    // We need to build the host stdlib even if we only check, to compile build scripts and proc
460    // macros
461    builder.std(build_compiler, builder.host_target);
462
463    // If we're cross-compiling, we generate the rmeta files for the given target
464    // This check has to be here, because if we generate both .so and .rmeta files, rustc will fail,
465    // as it will have multiple candidates for linking.
466    if builder.host_target != target {
467        Some(builder.ensure(PrepareStdRmetaSysroot::new(build_compiler, target)))
468    } else {
469        None
470    }
471}
472
473/// Prepares a compiler that will check something with the given `mode`.
474pub fn prepare_compiler_for_check(
475    builder: &Builder<'_>,
476    target: TargetSelection,
477    mode: Mode,
478) -> CompilerForCheck {
479    let host = builder.host_target;
480
481    let mut rustc_rmeta_sysroot = None;
482    let mut std_rmeta_sysroot = None;
483    let build_compiler = match mode {
484        Mode::ToolBootstrap => builder.compiler(0, host),
485        // We could also only check std here and use `prepare_std`, but `ToolTarget` is currently
486        // only used for running in-tree Clippy on bootstrap tools, so it does not seem worth it to
487        // optimize it. Therefore, here we build std for the target, instead of just checking it.
488        Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
489        Mode::ToolStd => {
490            if builder.config.compile_time_deps {
491                // When --compile-time-deps is passed, we can't use any rustc
492                // other than the bootstrap compiler. Luckily build scripts and
493                // proc macros for tools are unlikely to need nightly.
494                builder.compiler(0, host)
495            } else {
496                // These tools require the local standard library to be checked
497                let build_compiler = builder.compiler(builder.top_stage, host);
498                std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
499                build_compiler
500            }
501        }
502        Mode::ToolRustcPrivate | Mode::Codegen => {
503            // Check Rustc to produce the required rmeta artifacts for rustc_private, and then
504            // return the build compiler that was used to check rustc.
505            // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
506            // an empty set of crates, which will avoid using `cargo -p`.
507            let compiler_for_rustc = prepare_compiler_for_check(builder, target, Mode::Rustc);
508            rustc_rmeta_sysroot = Some(
509                builder.ensure(PrepareRustcRmetaSysroot::new(compiler_for_rustc.clone(), target)),
510            );
511            let build_compiler = compiler_for_rustc.build_compiler();
512
513            // To check a rustc_private tool, we also need to check std that it will link to
514            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
515            build_compiler
516        }
517        Mode::Rustc => {
518            // This is a horrible hack, because we actually change the compiler stage numbering
519            // here. If you do `x check --stage 1 --host FOO`, we build stage 1 host rustc,
520            // and use that to check stage 1 FOO rustc (which actually makes that stage 2 FOO
521            // rustc).
522            //
523            // FIXME: remove this and either fix cross-compilation check on stage 2 (which has a
524            // myriad of other problems) or disable cross-checking on stage 1.
525            let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage };
526            let build_compiler = builder.compiler(stage, host);
527
528            // To check rustc, we need to check std that it will link to
529            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
530            build_compiler
531        }
532        Mode::Std => {
533            // When checking std stage N, we want to do it with the stage N compiler
534            // Note: we don't need to build the host stdlib here, because when compiling std, the
535            // stage 0 stdlib is used to compile build scripts and proc macros.
536            builder.compiler(builder.top_stage, host)
537        }
538    };
539    CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
540}
541
542/// Check the Cranelift codegen backend.
543#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544pub struct CraneliftCodegenBackend {
545    build_compiler: CompilerForCheck,
546    target: TargetSelection,
547}
548
549impl CommandLineStep for CraneliftCodegenBackend {
550    type Output = ();
551    const IS_HOST: bool = true;
552
553    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
554        run.alias("rustc_codegen_cranelift").alias("cg_clif")
555    }
556
557    fn is_default_step(_builder: &Builder<'_>) -> bool {
558        true
559    }
560
561    fn make_run(run: RunConfig<'_>) {
562        run.builder.ensure(CraneliftCodegenBackend {
563            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
564            target: run.target,
565        });
566    }
567
568    fn run(self, builder: &Builder<'_>) {
569        let build_compiler = self.build_compiler.build_compiler();
570        let target = self.target;
571
572        let mut cargo = builder::Cargo::new(
573            builder,
574            build_compiler,
575            Mode::Codegen,
576            SourceType::InTree,
577            target,
578            builder.kind,
579        );
580
581        cargo
582            .arg("--manifest-path")
583            .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));
584        rustc_cargo_env(builder, &mut cargo, target);
585        self.build_compiler.configure_cargo(&mut cargo);
586
587        let _guard = builder.msg(
588            Kind::Check,
589            "rustc_codegen_cranelift",
590            Mode::Codegen,
591            build_compiler,
592            target,
593        );
594
595        let stamp = build_stamp::codegen_backend_stamp(
596            builder,
597            build_compiler,
598            target,
599            &CodegenBackendKind::Cranelift,
600        )
601        .with_prefix("check");
602
603        run_cargo(
604            builder,
605            cargo,
606            builder.config.free_args.clone(),
607            &stamp,
608            vec![],
609            ArtifactKeepMode::OnlyRmeta,
610        );
611    }
612
613    fn metadata(&self) -> Option<StepMetadata> {
614        Some(
615            StepMetadata::check("rustc_codegen_cranelift", self.target)
616                .built_by(self.build_compiler.build_compiler()),
617        )
618    }
619}
620
621/// Check the GCC codegen backend.
622#[derive(Debug, Clone, PartialEq, Eq, Hash)]
623pub struct GccCodegenBackend {
624    build_compiler: CompilerForCheck,
625    target: TargetSelection,
626}
627
628impl CommandLineStep for GccCodegenBackend {
629    type Output = ();
630    const IS_HOST: bool = true;
631
632    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
633        run.alias("rustc_codegen_gcc").alias("cg_gcc")
634    }
635
636    fn is_default_step(_builder: &Builder<'_>) -> bool {
637        true
638    }
639
640    fn make_run(run: RunConfig<'_>) {
641        run.builder.ensure(GccCodegenBackend {
642            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
643            target: run.target,
644        });
645    }
646
647    fn run(self, builder: &Builder<'_>) {
648        // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved
649        if builder.build.config.vendor {
650            println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
651            return;
652        }
653
654        let build_compiler = self.build_compiler.build_compiler();
655        let target = self.target;
656
657        let mut cargo = builder::Cargo::new(
658            builder,
659            build_compiler,
660            Mode::Codegen,
661            SourceType::InTree,
662            target,
663            builder.kind,
664        );
665
666        cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
667        rustc_cargo_env(builder, &mut cargo, target);
668        self.build_compiler.configure_cargo(&mut cargo);
669
670        let _guard =
671            builder.msg(Kind::Check, "rustc_codegen_gcc", Mode::Codegen, build_compiler, target);
672
673        let stamp = build_stamp::codegen_backend_stamp(
674            builder,
675            build_compiler,
676            target,
677            &CodegenBackendKind::Gcc,
678        )
679        .with_prefix("check");
680
681        run_cargo(
682            builder,
683            cargo,
684            builder.config.free_args.clone(),
685            &stamp,
686            vec![],
687            ArtifactKeepMode::OnlyRmeta,
688        );
689    }
690
691    fn metadata(&self) -> Option<StepMetadata> {
692        Some(
693            StepMetadata::check("rustc_codegen_gcc", self.target)
694                .built_by(self.build_compiler.build_compiler()),
695        )
696    }
697}
698
699macro_rules! tool_check_step {
700    (
701        $name:ident {
702            // The part of this path after the final '/' is also used as a display name.
703            path: $path:literal
704            $(, alt_path: $alt_path:literal )*
705            // `Mode` to use when checking this tool
706            , mode: $mode:expr
707            // Subset of nightly features that are allowed to be used when checking
708            $(, allow_features: $allow_features:expr )?
709            // Features that should be enabled when checking
710            $(, enable_features: [$($enable_features:expr),*] )?
711            $(, default_features: $default_features:expr )?
712            $(, default: $default:literal )?
713            $( , )?
714        }
715    ) => {
716        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
717        pub struct $name {
718            compiler: CompilerForCheck,
719            target: TargetSelection,
720        }
721
722        impl CommandLineStep for $name {
723            type Output = ();
724            const IS_HOST: bool = true;
725
726            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
727                run.multi_path(&[$path $(, $alt_path )*])
728            }
729
730            fn is_default_step(_builder: &Builder<'_>) -> bool {
731                // Most of the tool-checks using this macro are run by default.
732                true $( && const { $default } )?
733            }
734
735            fn make_run(run: RunConfig<'_>) {
736                let target = run.target;
737                let mode: Mode = $mode;
738
739                let compiler = prepare_compiler_for_check(run.builder, target, mode);
740
741                // It doesn't make sense to cross-check bootstrap tools
742                if mode == Mode::ToolBootstrap && target != run.builder.host_target {
743                    println!("WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool", stringify!($path));
744                    return;
745                };
746
747                run.builder.ensure($name { target, compiler });
748            }
749
750            fn run(self, builder: &Builder<'_>) {
751                let Self { target, compiler } = self;
752                let allow_features = {
753                    let mut _value = "";
754                    $( _value = $allow_features; )?
755                    _value
756                };
757                let extra_features: &[&str] = &[$($($enable_features),*)?];
758                let default_features = {
759                    let mut _value = true;
760                    $( _value = $default_features; )?
761                    _value
762                };
763                let mode: Mode = $mode;
764                run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features, default_features);
765            }
766
767            fn metadata(&self) -> Option<StepMetadata> {
768                Some(StepMetadata::check(stringify!($name), self.target).built_by(self.compiler.build_compiler))
769            }
770        }
771    }
772}
773
774/// Used by the implementation of `Step::run` in `tool_check_step!`.
775#[allow(clippy::too_many_arguments)]
776fn run_tool_check_step(
777    builder: &Builder<'_>,
778    compiler: CompilerForCheck,
779    target: TargetSelection,
780    path: &str,
781    mode: Mode,
782    allow_features: &str,
783    extra_features: &[&str],
784    default_features: bool,
785) {
786    let display_name = path.rsplit('/').next().unwrap();
787
788    let build_compiler = compiler.build_compiler();
789
790    let extra_features = extra_features.iter().map(|f| f.to_string()).collect::<Vec<String>>();
791    let mut cargo = prepare_tool_cargo(
792        builder,
793        build_compiler,
794        mode,
795        target,
796        builder.kind,
797        path,
798        // Currently, all of the tools that use this macro/function are in-tree.
799        // If support for out-of-tree tools is re-added in the future, those
800        // steps should probably be marked non-default so that the default
801        // checks aren't affected by toolstate being broken.
802        SourceType::InTree,
803        &extra_features,
804    );
805    cargo.allow_features(allow_features);
806    compiler.configure_cargo(&mut cargo);
807
808    // FIXME: check bootstrap doesn't currently work when multiple targets are checked
809    // FIXME: rust-analyzer does not work with --all-targets
810    if display_name == "rust-analyzer" {
811        cargo.arg("--bins");
812        cargo.arg("--tests");
813        cargo.arg("--benches");
814    } else {
815        cargo.arg("--all-targets");
816    }
817
818    if !default_features {
819        cargo.arg("--no-default-features");
820    }
821
822    let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target))
823        .with_prefix(&format!("{display_name}-check"));
824
825    let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target);
826    run_cargo(
827        builder,
828        cargo,
829        builder.config.free_args.clone(),
830        &stamp,
831        vec![],
832        ArtifactKeepMode::OnlyRmeta,
833    );
834}
835
836tool_check_step!(Rustdoc {
837    path: "src/tools/rustdoc",
838    alt_path: "src/librustdoc",
839    mode: Mode::ToolRustcPrivate
840});
841// Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
842// of a submodule. Since the SourceType only drives the deny-warnings
843// behavior, treat it as in-tree so that any new warnings in clippy will be
844// rejected.
845tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate });
846tool_check_step!(Miri {
847    path: "src/tools/miri",
848    mode: Mode::ToolRustcPrivate,
849    enable_features: ["check_only"],
850});
851tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate });
852tool_check_step!(Priroda { path: "src/tools/miri/priroda", mode: Mode::ToolRustcPrivate });
853tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate });
854tool_check_step!(RustAnalyzer {
855    path: "src/tools/rust-analyzer",
856    mode: Mode::ToolRustcPrivate,
857    allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
858    enable_features: ["in-rust-tree"],
859});
860tool_check_step!(MiroptTestTools {
861    path: "src/tools/miropt-test-tools",
862    mode: Mode::ToolBootstrap
863});
864// We want to test the local std
865tool_check_step!(TestFloatParse {
866    path: "src/tools/test-float-parse",
867    mode: Mode::ToolStd,
868    allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES
869});
870tool_check_step!(FeaturesStatusDump {
871    path: "src/tools/features-status-dump",
872    mode: Mode::ToolBootstrap
873});
874
875tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false });
876
877// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
878// check to make it easier to work on.
879tool_check_step!(RunMakeSupport {
880    path: "src/tools/run-make-support",
881    mode: Mode::ToolBootstrap,
882    default: false
883});
884
885tool_check_step!(CoverageDump {
886    path: "src/tools/coverage-dump",
887    mode: Mode::ToolBootstrap,
888    default: false
889});
890
891// Compiletest is implicitly "checked" when it gets built in order to run tests,
892// so this is mainly for people working on compiletest to run locally.
893tool_check_step!(Compiletest {
894    path: "src/tools/compiletest",
895    mode: Mode::ToolBootstrap,
896    default: false,
897});
898
899// As with compiletest, rustdoc-gui-test is automatically built when running
900// relevant tests. So being able to check it is mainly useful for people
901// working on on rustdoc-gui-test itself, or on its compiletest dependency.
902tool_check_step!(RustdocGuiTest {
903    path: "src/tools/rustdoc-gui-test",
904    mode: Mode::ToolBootstrap,
905    default: false,
906});
907
908tool_check_step!(Linkchecker {
909    path: "src/tools/linkchecker",
910    mode: Mode::ToolBootstrap,
911    default: false
912});
913
914tool_check_step!(BumpStage0 {
915    path: "src/tools/bump-stage0",
916    mode: Mode::ToolBootstrap,
917    default: false
918});
919
920// Tidy is implicitly checked when `./x test tidy` is executed
921// (if you set a pre-push hook, the command is called).
922// So this is mainly for people working on tidy.
923tool_check_step!(Tidy { path: "src/tools/tidy", mode: Mode::ToolBootstrap, default: false });