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