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