2 use crate::config
::{Config, TargetSelection}
;
5 fn configure(cmd
: &str, host
: &[&str], target
: &[&str]) -> Config
{
6 configure_with_args(&[cmd
.to_owned()], host
, target
)
9 fn configure_with_args(cmd
: &[String
], host
: &[&str], target
: &[&str]) -> Config
{
10 let mut config
= Config
::parse(cmd
);
11 // don't save toolstates
12 config
.save_toolstates
= None
;
13 config
.dry_run
= true;
15 // Ignore most submodules, since we don't need them for a dry run.
16 // But make sure to check out the `doc` and `rust-analyzer` submodules, since some steps need them
17 // just to know which commands to run.
18 let submodule_build
= Build
::new(Config
{
19 // don't include LLVM, so CI doesn't require ninja/cmake to be installed
20 rust_codegen_backends
: vec
![],
21 ..Config
::parse(&["check".to_owned()])
23 submodule_build
.update_submodule(Path
::new("src/doc/book"));
24 submodule_build
.update_submodule(Path
::new("src/tools/rust-analyzer"));
25 config
.submodules
= Some(false);
27 config
.ninja_in_file
= false;
28 // try to avoid spurious failures in dist where we create/delete each others file
29 // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
30 let dir
= Path
::new(env
!("OUT_DIR"))
31 .join("tmp-rustbuild-tests")
32 .join(&thread
::current().name().unwrap_or("unknown").replace(":", "-"));
33 t
!(fs
::create_dir_all(&dir
));
35 config
.build
= TargetSelection
::from_user("A");
36 config
.hosts
= host
.iter().map(|s
| TargetSelection
::from_user(s
)).collect();
37 config
.targets
= target
.iter().map(|s
| TargetSelection
::from_user(s
)).collect();
41 fn first
<A
, B
>(v
: Vec
<(A
, B
)>) -> Vec
<A
> {
42 v
.into_iter().map(|(a
, _
)| a
).collect
::<Vec
<_
>>()
45 fn run_build(paths
: &[PathBuf
], config
: Config
) -> Cache
{
46 let kind
= config
.cmd
.kind();
47 let build
= Build
::new(config
);
48 let builder
= Builder
::new(&build
);
49 builder
.run_step_descriptions(&Builder
::get_step_descriptions(kind
), paths
);
53 fn check_cli
<const N
: usize>(paths
: [&str; N
]) {
55 &paths
.map(PathBuf
::from
),
56 configure_with_args(&paths
.map(String
::from
), &["A"], &["A"]),
62 // make sure multi suite paths are accepted
63 check_cli(["test", "src/test/ui/attr-start.rs", "src/test/ui/attr-shebang.rs"]);
69 // make sure that invalid paths are caught, even when combined with valid paths
70 check_cli(["test", "library/std", "x"]);
74 fn test_intersection() {
75 let set
= PathSet
::Set(
76 ["library/core", "library/alloc", "library/std"].into_iter().map(TaskPath
::parse
).collect(),
78 let mut command_paths
=
79 vec
![Path
::new("library/core"), Path
::new("library/alloc"), Path
::new("library/stdarch")];
80 let subset
= set
.intersection_removing_matches(&mut command_paths
, None
);
83 PathSet
::Set(["library/core", "library/alloc"].into_iter().map(TaskPath
::parse
).collect())
85 assert_eq
!(command_paths
, vec
![Path
::new("library/stdarch")]);
90 let mut config
= configure("test", &["A"], &["A"]);
91 config
.exclude
= vec
![TaskPath
::parse("src/tools/tidy")];
92 let cache
= run_build(&[], config
);
94 // Ensure we have really excluded tidy
95 assert
!(!cache
.contains
::<test
::Tidy
>());
97 // Ensure other tests are not affected.
98 assert
!(cache
.contains
::<test
::RustdocUi
>());
102 fn test_exclude_kind() {
103 let path
= PathBuf
::from("src/tools/cargotest");
104 let exclude
= TaskPath
::parse("test::src/tools/cargotest");
105 assert_eq
!(exclude
, TaskPath { kind: Some(Kind::Test), path: path.clone() }
);
107 let mut config
= configure("test", &["A"], &["A"]);
108 // Ensure our test is valid, and `test::Cargotest` would be run without the exclude.
109 assert
!(run_build(&[path
.clone()], config
.clone()).contains
::<test
::Cargotest
>());
110 // Ensure tests for cargotest are skipped.
111 config
.exclude
= vec
![exclude
.clone()];
112 assert
!(!run_build(&[path
.clone()], config
).contains
::<test
::Cargotest
>());
114 // Ensure builds for cargotest are not skipped.
115 let mut config
= configure("build", &["A"], &["A"]);
116 config
.exclude
= vec
![exclude
];
117 assert
!(run_build(&[path
], config
).contains
::<tool
::CargoTest
>());
121 use super::{configure, first, run_build}
;
122 use crate::builder
::*;
124 use pretty_assertions
::assert_eq
;
128 let mut cache
= run_build(&[], configure("build", &["A"], &["A"]));
130 let a
= TargetSelection
::from_user("A");
132 first(cache
.all
::<compile
::Std
>()),
134 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
135 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
138 assert
!(!cache
.all
::<compile
::Assemble
>().is_empty());
139 // Make sure rustdoc is only built once.
141 first(cache
.all
::<tool
::Rustdoc
>()),
142 // Recall that rustdoc stages are off-by-one
143 // - this is the compiler it's _linked_ to, not built with.
144 &[tool
::Rustdoc { compiler: Compiler { host: a, stage: 1 }
}],
147 first(cache
.all
::<compile
::Rustc
>()),
148 &[compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: a
},]
154 let config
= Config { stage: 0, ..configure("build", &["A"], &["A"]) }
;
155 let mut cache
= run_build(&[], config
);
157 let a
= TargetSelection
::from_user("A");
159 first(cache
.all
::<compile
::Std
>()),
160 &[compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},]
162 assert
!(!cache
.all
::<compile
::Assemble
>().is_empty());
164 first(cache
.all
::<tool
::Rustdoc
>()),
165 // This is the beta rustdoc.
166 // Add an assert here to make sure this is the only rustdoc built.
167 &[tool
::Rustdoc { compiler: Compiler { host: a, stage: 0 }
}],
169 assert
!(cache
.all
::<compile
::Rustc
>().is_empty());
173 fn build_cross_compile() {
174 let config
= Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) }
;
175 let mut cache
= run_build(&[], config
);
177 let a
= TargetSelection
::from_user("A");
178 let b
= TargetSelection
::from_user("B");
180 // Ideally, this build wouldn't actually have `target: a`
181 // rustdoc/rustcc/std here (the user only requested a host=B build, so
182 // there's not really a need for us to build for target A in this case
183 // (since we're producing stage 1 libraries/binaries). But currently
184 // rustbuild is just a bit buggy here; this should be fixed though.
186 first(cache
.all
::<compile
::Std
>()),
188 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
189 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
190 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: b
},
191 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
195 first(cache
.all
::<compile
::Assemble
>()),
197 compile
::Assemble { target_compiler: Compiler { host: a, stage: 0 }
},
198 compile
::Assemble { target_compiler: Compiler { host: a, stage: 1 }
},
199 compile
::Assemble { target_compiler: Compiler { host: b, stage: 1 }
},
203 first(cache
.all
::<tool
::Rustdoc
>()),
205 tool
::Rustdoc { compiler: Compiler { host: a, stage: 1 }
},
206 tool
::Rustdoc { compiler: Compiler { host: b, stage: 1 }
},
210 first(cache
.all
::<compile
::Rustc
>()),
212 compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
213 compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: b
},
220 let mut config
= configure("doc", &["A"], &["A"]);
221 config
.compiler_docs
= true;
222 config
.cmd
= Subcommand
::Doc { paths: Vec::new(), open: false }
;
223 let mut cache
= run_build(&[], config
);
224 let a
= TargetSelection
::from_user("A");
226 // error_index_generator uses stage 0 to share rustdoc artifacts with the
228 assert_eq
!(first(cache
.all
::<doc
::ErrorIndex
>()), &[doc
::ErrorIndex { target: a }
,]);
230 first(cache
.all
::<tool
::ErrorIndex
>()),
231 &[tool
::ErrorIndex { compiler: Compiler { host: a, stage: 0 }
}]
233 // docs should be built with the beta compiler, not with the stage0 artifacts.
234 // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
235 // not the one it was built by.
237 first(cache
.all
::<tool
::Rustdoc
>()),
238 &[tool
::Rustdoc { compiler: Compiler { host: a, stage: 0 }
},]
244 use super::{first, run_build, Config}
;
245 use crate::builder
::*;
246 use pretty_assertions
::assert_eq
;
248 fn configure(host
: &[&str], target
: &[&str]) -> Config
{
249 Config { stage: 2, ..super::configure("dist", host, target) }
254 let mut cache
= run_build(&[], configure(&["A"], &["A"]));
256 let a
= TargetSelection
::from_user("A");
258 assert_eq
!(first(cache
.all
::<dist
::Docs
>()), &[dist
::Docs { host: a }
,]);
259 assert_eq
!(first(cache
.all
::<dist
::Mingw
>()), &[dist
::Mingw { host: a }
,]);
261 first(cache
.all
::<dist
::Rustc
>()),
262 &[dist
::Rustc { compiler: Compiler { host: a, stage: 2 }
},]
265 first(cache
.all
::<dist
::Std
>()),
266 &[dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},]
268 assert_eq
!(first(cache
.all
::<dist
::Src
>()), &[dist
::Src
]);
269 // Make sure rustdoc is only built once.
271 first(cache
.all
::<tool
::Rustdoc
>()),
272 &[tool
::Rustdoc { compiler: Compiler { host: a, stage: 2 }
},]
277 fn dist_with_targets() {
278 let mut cache
= run_build(&[], configure(&["A"], &["A", "B"]));
280 let a
= TargetSelection
::from_user("A");
281 let b
= TargetSelection
::from_user("B");
284 first(cache
.all
::<dist
::Docs
>()),
285 &[dist
::Docs { host: a }
, dist
::Docs { host: b }
,]
288 first(cache
.all
::<dist
::Mingw
>()),
289 &[dist
::Mingw { host: a }
, dist
::Mingw { host: b }
,]
292 first(cache
.all
::<dist
::Rustc
>()),
293 &[dist
::Rustc { compiler: Compiler { host: a, stage: 2 }
},]
296 first(cache
.all
::<dist
::Std
>()),
298 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
299 dist
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: b
},
302 assert_eq
!(first(cache
.all
::<dist
::Src
>()), &[dist
::Src
]);
306 fn dist_with_hosts() {
307 let mut cache
= run_build(&[], configure(&["A", "B"], &["A", "B"]));
309 let a
= TargetSelection
::from_user("A");
310 let b
= TargetSelection
::from_user("B");
313 first(cache
.all
::<dist
::Docs
>()),
314 &[dist
::Docs { host: a }
, dist
::Docs { host: b }
,]
317 first(cache
.all
::<dist
::Mingw
>()),
318 &[dist
::Mingw { host: a }
, dist
::Mingw { host: b }
,]
321 first(cache
.all
::<dist
::Rustc
>()),
323 dist
::Rustc { compiler: Compiler { host: a, stage: 2 }
},
324 dist
::Rustc { compiler: Compiler { host: b, stage: 2 }
},
328 first(cache
.all
::<dist
::Std
>()),
330 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
331 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
335 first(cache
.all
::<compile
::Std
>()),
337 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
338 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
339 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: a
},
340 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
341 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: b
},
344 assert_eq
!(first(cache
.all
::<dist
::Src
>()), &[dist
::Src
]);
348 fn dist_only_cross_host() {
349 let a
= TargetSelection
::from_user("A");
350 let b
= TargetSelection
::from_user("B");
351 let mut config
= configure(&["A", "B"], &["A", "B"]);
353 config
.extended
= true;
354 config
.hosts
= vec
![b
];
355 let mut cache
= run_build(&[], config
);
358 first(cache
.all
::<dist
::Rustc
>()),
359 &[dist
::Rustc { compiler: Compiler { host: b, stage: 2 }
},]
362 first(cache
.all
::<compile
::Rustc
>()),
364 compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
365 compile
::Rustc { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
371 fn dist_with_targets_and_hosts() {
372 let mut cache
= run_build(&[], configure(&["A", "B"], &["A", "B", "C"]));
374 let a
= TargetSelection
::from_user("A");
375 let b
= TargetSelection
::from_user("B");
376 let c
= TargetSelection
::from_user("C");
379 first(cache
.all
::<dist
::Docs
>()),
380 &[dist
::Docs { host: a }
, dist
::Docs { host: b }
, dist
::Docs { host: c }
,]
383 first(cache
.all
::<dist
::Mingw
>()),
384 &[dist
::Mingw { host: a }
, dist
::Mingw { host: b }
, dist
::Mingw { host: c }
,]
387 first(cache
.all
::<dist
::Rustc
>()),
389 dist
::Rustc { compiler: Compiler { host: a, stage: 2 }
},
390 dist
::Rustc { compiler: Compiler { host: b, stage: 2 }
},
394 first(cache
.all
::<dist
::Std
>()),
396 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
397 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
398 dist
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: c
},
401 assert_eq
!(first(cache
.all
::<dist
::Src
>()), &[dist
::Src
]);
405 fn dist_with_empty_host() {
406 let config
= configure(&[], &["C"]);
407 let mut cache
= run_build(&[], config
);
409 let a
= TargetSelection
::from_user("A");
410 let c
= TargetSelection
::from_user("C");
412 assert_eq
!(first(cache
.all
::<dist
::Docs
>()), &[dist
::Docs { host: c }
,]);
413 assert_eq
!(first(cache
.all
::<dist
::Mingw
>()), &[dist
::Mingw { host: c }
,]);
415 first(cache
.all
::<dist
::Std
>()),
416 &[dist
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: c
},]
421 fn dist_with_same_targets_and_hosts() {
422 let mut cache
= run_build(&[], configure(&["A", "B"], &["A", "B"]));
424 let a
= TargetSelection
::from_user("A");
425 let b
= TargetSelection
::from_user("B");
428 first(cache
.all
::<dist
::Docs
>()),
429 &[dist
::Docs { host: a }
, dist
::Docs { host: b }
,]
432 first(cache
.all
::<dist
::Mingw
>()),
433 &[dist
::Mingw { host: a }
, dist
::Mingw { host: b }
,]
436 first(cache
.all
::<dist
::Rustc
>()),
438 dist
::Rustc { compiler: Compiler { host: a, stage: 2 }
},
439 dist
::Rustc { compiler: Compiler { host: b, stage: 2 }
},
443 first(cache
.all
::<dist
::Std
>()),
445 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
446 dist
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
449 assert_eq
!(first(cache
.all
::<dist
::Src
>()), &[dist
::Src
]);
451 first(cache
.all
::<compile
::Std
>()),
453 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
454 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
455 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: a
},
456 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
457 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: b
},
461 first(cache
.all
::<compile
::Assemble
>()),
463 compile
::Assemble { target_compiler: Compiler { host: a, stage: 0 }
},
464 compile
::Assemble { target_compiler: Compiler { host: a, stage: 1 }
},
465 compile
::Assemble { target_compiler: Compiler { host: a, stage: 2 }
},
466 compile
::Assemble { target_compiler: Compiler { host: b, stage: 2 }
},
473 let build
= Build
::new(configure(&["A", "B"], &["A", "B", "C"]));
474 let mut builder
= Builder
::new(&build
);
475 builder
.run_step_descriptions(
476 &Builder
::get_step_descriptions(Kind
::Build
),
477 &["compiler/rustc".into(), "library/std".into()],
480 let a
= TargetSelection
::from_user("A");
481 let b
= TargetSelection
::from_user("B");
482 let c
= TargetSelection
::from_user("C");
485 first(builder
.cache
.all
::<compile
::Std
>()),
487 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
488 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
489 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: a
},
490 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
491 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: b
},
492 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: c
},
495 assert
!(!builder
.cache
.all
::<compile
::Assemble
>().is_empty());
497 first(builder
.cache
.all
::<compile
::Rustc
>()),
499 compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
500 compile
::Rustc { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
501 compile
::Rustc { compiler: Compiler { host: a, stage: 2 }
, target
: a
},
502 compile
::Rustc { compiler: Compiler { host: a, stage: 1 }
, target
: b
},
503 compile
::Rustc { compiler: Compiler { host: a, stage: 2 }
, target
: b
},
509 fn build_with_empty_host() {
510 let config
= configure(&[], &["C"]);
511 let build
= Build
::new(config
);
512 let mut builder
= Builder
::new(&build
);
513 builder
.run_step_descriptions(&Builder
::get_step_descriptions(Kind
::Build
), &[]);
515 let a
= TargetSelection
::from_user("A");
516 let c
= TargetSelection
::from_user("C");
519 first(builder
.cache
.all
::<compile
::Std
>()),
521 compile
::Std { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
522 compile
::Std { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
523 compile
::Std { compiler: Compiler { host: a, stage: 2 }
, target
: c
},
527 first(builder
.cache
.all
::<compile
::Assemble
>()),
529 compile
::Assemble { target_compiler: Compiler { host: a, stage: 0 }
},
530 compile
::Assemble { target_compiler: Compiler { host: a, stage: 1 }
},
531 compile
::Assemble { target_compiler: Compiler { host: a, stage: 2 }
},
535 first(builder
.cache
.all
::<compile
::Rustc
>()),
537 compile
::Rustc { compiler: Compiler { host: a, stage: 0 }
, target
: a
},
538 compile
::Rustc { compiler: Compiler { host: a, stage: 1 }
, target
: a
},
544 fn test_with_no_doc_stage0() {
545 let mut config
= configure(&["A"], &["A"]);
547 config
.cmd
= Subcommand
::Test
{
548 paths
: vec
!["library/std".into()],
553 doc_tests
: DocTests
::No
,
557 rustfix_coverage
: false,
562 let build
= Build
::new(config
);
563 let mut builder
= Builder
::new(&build
);
565 let host
= TargetSelection
::from_user("A");
567 builder
.run_step_descriptions(
568 &[StepDescription
::from
::<test
::Crate
>(Kind
::Test
)],
569 &["library/std".into()],
572 // Ensure we don't build any compiler artifacts.
573 assert
!(!builder
.cache
.contains
::<compile
::Rustc
>());
575 first(builder
.cache
.all
::<test
::Crate
>()),
577 compiler
: Compiler { host, stage: 0 }
,
580 test_kind
: test
::TestKind
::Test
,
581 crates
: vec
![INTERNER
.intern_str("std")],
588 let mut config
= configure(&["A"], &["A"]);
589 config
.compiler_docs
= true;
590 config
.cmd
= Subcommand
::Doc { paths: Vec::new(), open: false }
;
591 let build
= Build
::new(config
);
592 let mut builder
= Builder
::new(&build
);
593 builder
.run_step_descriptions(&Builder
::get_step_descriptions(Kind
::Doc
), &[]);
594 let a
= TargetSelection
::from_user("A");
596 // error_index_generator uses stage 1 to share rustdoc artifacts with the
599 first(builder
.cache
.all
::<doc
::ErrorIndex
>()),
600 &[doc
::ErrorIndex { target: a }
,]
603 first(builder
.cache
.all
::<tool
::ErrorIndex
>()),
604 &[tool
::ErrorIndex { compiler: Compiler { host: a, stage: 1 }
}]
606 // This is actually stage 1, but Rustdoc::run swaps out the compiler with
607 // stage minus 1 if --stage is not 0. Very confusing!
609 first(builder
.cache
.all
::<tool
::Rustdoc
>()),
610 &[tool
::Rustdoc { compiler: Compiler { host: a, stage: 2 }
},]
616 // Behavior of `x.py test` doing various documentation tests.
617 let mut config
= configure(&["A"], &["A"]);
618 config
.cmd
= Subcommand
::Test
{
624 doc_tests
: DocTests
::Yes
,
628 rustfix_coverage
: false,
632 // Make sure rustfmt binary not being found isn't an error.
633 config
.channel
= "beta".to_string();
634 let build
= Build
::new(config
);
635 let mut builder
= Builder
::new(&build
);
637 builder
.run_step_descriptions(&Builder
::get_step_descriptions(Kind
::Test
), &[]);
638 let a
= TargetSelection
::from_user("A");
640 // error_index_generator uses stage 1 to share rustdoc artifacts with the
643 first(builder
.cache
.all
::<doc
::ErrorIndex
>()),
644 &[doc
::ErrorIndex { target: a }
,]
647 first(builder
.cache
.all
::<tool
::ErrorIndex
>()),
648 &[tool
::ErrorIndex { compiler: Compiler { host: a, stage: 1 }
}]
650 // Unfortunately rustdoc is built twice. Once from stage1 for compiletest
651 // (and other things), and once from stage0 for std crates. Ideally it
652 // would only be built once. If someone wants to fix this, it might be
653 // worth investigating if it would be possible to test std from stage1.
654 // Note that the stages here are +1 than what they actually are because
655 // Rustdoc::run swaps out the compiler with stage minus 1 if --stage is
658 // The stage 0 copy is the one downloaded for bootstrapping. It is
659 // (currently) needed to run "cargo test" on the linkchecker, and
660 // should be relatively "free".
662 first(builder
.cache
.all
::<tool
::Rustdoc
>()),
664 tool
::Rustdoc { compiler: Compiler { host: a, stage: 0 }
},
665 tool
::Rustdoc { compiler: Compiler { host: a, stage: 1 }
},
666 tool
::Rustdoc { compiler: Compiler { host: a, stage: 2 }
},