]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/check.rs
Do anonymous lifetimes remapping correctly for nested rpits
[rust.git] / src / bootstrap / check.rs
1 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
3 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
4 use crate::cache::Interned;
5 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
6 use crate::config::TargetSelection;
7 use crate::tool::{prepare_tool_cargo, SourceType};
8 use crate::INTERNER;
9 use crate::{Compiler, Mode, Subcommand};
10 use std::path::{Path, PathBuf};
11
12 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
13 pub struct Std {
14     pub target: TargetSelection,
15 }
16
17 /// Returns args for the subcommand itself (not for cargo)
18 fn args(builder: &Builder<'_>) -> Vec<String> {
19     fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
20         arr.iter().copied().map(String::from)
21     }
22
23     if let Subcommand::Clippy {
24         fix,
25         clippy_lint_allow,
26         clippy_lint_deny,
27         clippy_lint_warn,
28         clippy_lint_forbid,
29         ..
30     } = &builder.config.cmd
31     {
32         // disable the most spammy clippy lints
33         let ignored_lints = vec![
34             "many_single_char_names", // there are a lot in stdarch
35             "collapsible_if",
36             "type_complexity",
37             "missing_safety_doc", // almost 3K warnings
38             "too_many_arguments",
39             "needless_lifetimes", // people want to keep the lifetimes
40             "wrong_self_convention",
41         ];
42         let mut args = vec![];
43         if *fix {
44             #[rustfmt::skip]
45             args.extend(strings(&[
46                 "--fix", "-Zunstable-options",
47                 // FIXME: currently, `--fix` gives an error while checking tests for libtest,
48                 // possibly because libtest is not yet built in the sysroot.
49                 // As a workaround, avoid checking tests and benches when passed --fix.
50                 "--lib", "--bins", "--examples",
51             ]));
52         }
53         args.extend(strings(&["--", "--cap-lints", "warn"]));
54         args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
55         let mut clippy_lint_levels: Vec<String> = Vec::new();
56         clippy_lint_allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
57         clippy_lint_deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
58         clippy_lint_warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
59         clippy_lint_forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
60         args.extend(clippy_lint_levels);
61         args
62     } else {
63         vec![]
64     }
65 }
66
67 fn cargo_subcommand(kind: Kind) -> &'static str {
68     match kind {
69         Kind::Check => "check",
70         Kind::Clippy => "clippy",
71         Kind::Fix => "fix",
72         _ => unreachable!(),
73     }
74 }
75
76 impl Step for Std {
77     type Output = ();
78     const DEFAULT: bool = true;
79
80     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
81         run.all_krates("test").path("library")
82     }
83
84     fn make_run(run: RunConfig<'_>) {
85         run.builder.ensure(Std { target: run.target });
86     }
87
88     fn run(self, builder: &Builder<'_>) {
89         builder.update_submodule(&Path::new("library").join("stdarch"));
90
91         let target = self.target;
92         let compiler = builder.compiler(builder.top_stage, builder.config.build);
93
94         let mut cargo = builder.cargo(
95             compiler,
96             Mode::Std,
97             SourceType::InTree,
98             target,
99             cargo_subcommand(builder.kind),
100         );
101         std_cargo(builder, target, compiler.stage, &mut cargo);
102
103         builder.info(&format!(
104             "Checking stage{} std artifacts ({} -> {})",
105             builder.top_stage, &compiler.host, target
106         ));
107         run_cargo(
108             builder,
109             cargo,
110             args(builder),
111             &libstd_stamp(builder, compiler, target),
112             vec![],
113             true,
114         );
115
116         // We skip populating the sysroot in non-zero stage because that'll lead
117         // to rlib/rmeta conflicts if std gets built during this session.
118         if compiler.stage == 0 {
119             let libdir = builder.sysroot_libdir(compiler, target);
120             let hostdir = builder.sysroot_libdir(compiler, compiler.host);
121             add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
122         }
123
124         // don't run on std twice with x.py clippy
125         if builder.kind == Kind::Clippy {
126             return;
127         }
128
129         // Then run cargo again, once we've put the rmeta files for the library
130         // crates into the sysroot. This is needed because e.g., core's tests
131         // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
132         // since we initialize with an empty sysroot.
133         //
134         // Currently only the "libtest" tree of crates does this.
135         let mut cargo = builder.cargo(
136             compiler,
137             Mode::Std,
138             SourceType::InTree,
139             target,
140             cargo_subcommand(builder.kind),
141         );
142
143         // If we're not in stage 0, tests and examples will fail to compile
144         // from `core` definitions being loaded from two different `libcore`
145         // .rmeta and .rlib files.
146         if compiler.stage == 0 {
147             cargo.arg("--all-targets");
148         }
149
150         std_cargo(builder, target, compiler.stage, &mut cargo);
151
152         // Explicitly pass -p for all dependencies krates -- this will force cargo
153         // to also check the tests/benches/examples for these crates, rather
154         // than just the leaf crate.
155         for krate in builder.in_tree_crates("test", Some(target)) {
156             cargo.arg("-p").arg(krate.name);
157         }
158
159         builder.info(&format!(
160             "Checking stage{} std test/bench/example targets ({} -> {})",
161             builder.top_stage, &compiler.host, target
162         ));
163         run_cargo(
164             builder,
165             cargo,
166             args(builder),
167             &libstd_test_stamp(builder, compiler, target),
168             vec![],
169             true,
170         );
171     }
172 }
173
174 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
175 pub struct Rustc {
176     pub target: TargetSelection,
177 }
178
179 impl Step for Rustc {
180     type Output = ();
181     const ONLY_HOSTS: bool = true;
182     const DEFAULT: bool = true;
183
184     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
185         run.all_krates("rustc-main").path("compiler")
186     }
187
188     fn make_run(run: RunConfig<'_>) {
189         run.builder.ensure(Rustc { target: run.target });
190     }
191
192     /// Builds the compiler.
193     ///
194     /// This will build the compiler for a particular stage of the build using
195     /// the `compiler` targeting the `target` architecture. The artifacts
196     /// created will also be linked into the sysroot directory.
197     fn run(self, builder: &Builder<'_>) {
198         let compiler = builder.compiler(builder.top_stage, builder.config.build);
199         let target = self.target;
200
201         if compiler.stage != 0 {
202             // If we're not in stage 0, then we won't have a std from the beta
203             // compiler around. That means we need to make sure there's one in
204             // the sysroot for the compiler to find. Otherwise, we're going to
205             // fail when building crates that need to generate code (e.g., build
206             // scripts and their dependencies).
207             builder.ensure(crate::compile::Std::new(compiler, compiler.host));
208             builder.ensure(crate::compile::Std::new(compiler, target));
209         } else {
210             builder.ensure(Std { target });
211         }
212
213         let mut cargo = builder.cargo(
214             compiler,
215             Mode::Rustc,
216             SourceType::InTree,
217             target,
218             cargo_subcommand(builder.kind),
219         );
220         rustc_cargo(builder, &mut cargo, target);
221
222         // For ./x.py clippy, don't run with --all-targets because
223         // linting tests and benchmarks can produce very noisy results
224         if builder.kind != Kind::Clippy {
225             cargo.arg("--all-targets");
226         }
227
228         // Explicitly pass -p for all compiler krates -- this will force cargo
229         // to also check the tests/benches/examples for these crates, rather
230         // than just the leaf crate.
231         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
232             cargo.arg("-p").arg(krate.name);
233         }
234
235         builder.info(&format!(
236             "Checking stage{} compiler artifacts ({} -> {})",
237             builder.top_stage, &compiler.host, target
238         ));
239         run_cargo(
240             builder,
241             cargo,
242             args(builder),
243             &librustc_stamp(builder, compiler, target),
244             vec![],
245             true,
246         );
247
248         let libdir = builder.sysroot_libdir(compiler, target);
249         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
250         add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
251     }
252 }
253
254 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
255 pub struct CodegenBackend {
256     pub target: TargetSelection,
257     pub backend: Interned<String>,
258 }
259
260 impl Step for CodegenBackend {
261     type Output = ();
262     const ONLY_HOSTS: bool = true;
263     const DEFAULT: bool = true;
264
265     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
266         run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"])
267     }
268
269     fn make_run(run: RunConfig<'_>) {
270         for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] {
271             run.builder.ensure(CodegenBackend { target: run.target, backend });
272         }
273     }
274
275     fn run(self, builder: &Builder<'_>) {
276         let compiler = builder.compiler(builder.top_stage, builder.config.build);
277         let target = self.target;
278         let backend = self.backend;
279
280         builder.ensure(Rustc { target });
281
282         let mut cargo = builder.cargo(
283             compiler,
284             Mode::Codegen,
285             SourceType::InTree,
286             target,
287             cargo_subcommand(builder.kind),
288         );
289         cargo
290             .arg("--manifest-path")
291             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
292         rustc_cargo_env(builder, &mut cargo, target);
293
294         builder.info(&format!(
295             "Checking stage{} {} artifacts ({} -> {})",
296             builder.top_stage, backend, &compiler.host.triple, target.triple
297         ));
298
299         run_cargo(
300             builder,
301             cargo,
302             args(builder),
303             &codegen_backend_stamp(builder, compiler, target, backend),
304             vec![],
305             true,
306         );
307     }
308 }
309
310 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
311 pub struct RustAnalyzer {
312     pub target: TargetSelection,
313 }
314
315 impl Step for RustAnalyzer {
316     type Output = ();
317     const ONLY_HOSTS: bool = true;
318     const DEFAULT: bool = true;
319
320     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
321         run.path("src/tools/rust-analyzer")
322     }
323
324     fn make_run(run: RunConfig<'_>) {
325         run.builder.ensure(RustAnalyzer { target: run.target });
326     }
327
328     fn run(self, builder: &Builder<'_>) {
329         let compiler = builder.compiler(builder.top_stage, builder.config.build);
330         let target = self.target;
331
332         builder.ensure(Std { target });
333
334         let mut cargo = prepare_tool_cargo(
335             builder,
336             compiler,
337             Mode::ToolStd,
338             target,
339             cargo_subcommand(builder.kind),
340             "src/tools/rust-analyzer",
341             SourceType::InTree,
342             &["rust-analyzer/in-rust-tree".to_owned()],
343         );
344
345         cargo.rustflag(
346             "-Zallow-features=proc_macro_internals,proc_macro_diagnostic,proc_macro_span",
347         );
348
349         // For ./x.py clippy, don't check those targets because
350         // linting tests and benchmarks can produce very noisy results
351         if builder.kind != Kind::Clippy {
352             // can't use `--all-targets` because `--examples` doesn't work well
353             cargo.arg("--bins");
354             cargo.arg("--tests");
355             cargo.arg("--benches");
356         }
357
358         builder.info(&format!(
359             "Checking stage{} {} artifacts ({} -> {})",
360             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
361         ));
362         run_cargo(builder, cargo, args(builder), &stamp(builder, compiler, target), vec![], true);
363
364         /// Cargo's output path in a given stage, compiled by a particular
365         /// compiler for the specified target.
366         fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
367             builder.cargo_out(compiler, Mode::ToolStd, target).join(".rust-analyzer-check.stamp")
368         }
369     }
370 }
371
372 macro_rules! tool_check_step {
373     ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
374         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
375         pub struct $name {
376             pub target: TargetSelection,
377         }
378
379         impl Step for $name {
380             type Output = ();
381             const ONLY_HOSTS: bool = true;
382             // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
383             const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
384
385             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
386                 run.paths(&[ $path, $($alias),* ])
387             }
388
389             fn make_run(run: RunConfig<'_>) {
390                 run.builder.ensure($name { target: run.target });
391             }
392
393             fn run(self, builder: &Builder<'_>) {
394                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
395                 let target = self.target;
396
397                 builder.ensure(Rustc { target });
398
399                 let mut cargo = prepare_tool_cargo(
400                     builder,
401                     compiler,
402                     Mode::ToolRustc,
403                     target,
404                     cargo_subcommand(builder.kind),
405                     $path,
406                     $source_type,
407                     &[],
408                 );
409
410                 // For ./x.py clippy, don't run with --all-targets because
411                 // linting tests and benchmarks can produce very noisy results
412                 if builder.kind != Kind::Clippy {
413                     cargo.arg("--all-targets");
414                 }
415
416                 // Enable internal lints for clippy and rustdoc
417                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
418                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
419                 cargo.rustflag("-Zunstable-options");
420
421                 builder.info(&format!(
422                     "Checking stage{} {} artifacts ({} -> {})",
423                     builder.top_stage,
424                     stringify!($name).to_lowercase(),
425                     &compiler.host.triple,
426                     target.triple
427                 ));
428                 run_cargo(
429                     builder,
430                     cargo,
431                     args(builder),
432                     &stamp(builder, compiler, target),
433                     vec![],
434                     true,
435                 );
436
437                 /// Cargo's output path in a given stage, compiled by a particular
438                 /// compiler for the specified target.
439                 fn stamp(
440                     builder: &Builder<'_>,
441                     compiler: Compiler,
442                     target: TargetSelection,
443                 ) -> PathBuf {
444                     builder
445                         .cargo_out(compiler, Mode::ToolRustc, target)
446                         .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
447                 }
448             }
449         }
450     };
451 }
452
453 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
454 // Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
455 // of a submodule. Since the SourceType only drives the deny-warnings
456 // behavior, treat it as in-tree so that any new warnings in clippy will be
457 // rejected.
458 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
459 // Miri on the other hand is treated as out of tree, since InTree also causes it to
460 // be run as part of `check`, which can fail on platforms which libffi-sys has no support for.
461 tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
462 tool_check_step!(Rls, "src/tools/rls", SourceType::InTree);
463 tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
464
465 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
466
467 /// Cargo's output path for the standard library in a given stage, compiled
468 /// by a particular compiler for the specified target.
469 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
470     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
471 }
472
473 /// Cargo's output path for the standard library in a given stage, compiled
474 /// by a particular compiler for the specified target.
475 fn libstd_test_stamp(
476     builder: &Builder<'_>,
477     compiler: Compiler,
478     target: TargetSelection,
479 ) -> PathBuf {
480     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
481 }
482
483 /// Cargo's output path for librustc in a given stage, compiled by a particular
484 /// compiler for the specified target.
485 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
486     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
487 }
488
489 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
490 /// compiler for the specified target and backend.
491 fn codegen_backend_stamp(
492     builder: &Builder<'_>,
493     compiler: Compiler,
494     target: TargetSelection,
495     backend: Interned<String>,
496 ) -> PathBuf {
497     builder
498         .cargo_out(compiler, Mode::Codegen, target)
499         .join(format!(".librustc_codegen_{}-check.stamp", backend))
500 }