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