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