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