From 6fd96ddc3d8eba9b4c1364e1a073a4da040244d4 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 1 Apr 2026 13:47:30 -0500 Subject: [PATCH 01/11] rustdoc_missing_doc_code_examples: lint on macro_rules macros --- src/librustdoc/clean/types.rs | 7 +++ .../passes/check_doc_test_visibility.rs | 3 +- src/librustdoc/passes/strip_hidden.rs | 5 +- tests/rustdoc-ui/lints/check.rs | 12 +++++ tests/rustdoc-ui/lints/check.stderr | 54 ++++++++++++++----- 5 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7d40bc95ec089..4339a4f2f9b89 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -453,6 +453,13 @@ impl Item { self.stability.is_some_and(|x| x.is_unstable()) } + pub(crate) fn is_exported_macro(&self) -> bool { + match self.kind { + ItemKind::MacroItem(..) => find_attr!(&self.attrs.other_attrs, MacroExport { .. }), + _ => false, + } + } + pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { self.item_id .as_def_id() diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index ff7535fea41cb..89caa9399f2bd 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -56,7 +56,8 @@ impl crate::doctest::DocTestVisitor for Tests { } pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { - if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item.item_id.expect_def_id()) + if !(cx.cache.effective_visibilities.is_directly_public(cx.tcx, item.item_id.expect_def_id()) + || item.is_exported_macro()) || matches!( item.kind, clean::StructFieldItem(_) diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index e1feccb13df88..e4c8a7b82a16d 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -3,7 +3,6 @@ use std::mem; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::find_attr; use rustc_middle::ty::TyCtxt; use tracing::debug; @@ -113,9 +112,7 @@ impl DocFolder for Stripper<'_, '_> { clean::ImplItem(..) => true, // If the macro has the `#[macro_export]` attribute, it means it's accessible at the // crate level so it should be handled differently. - clean::MacroItem(..) => { - find_attr!(&i.attrs.other_attrs, MacroExport { .. }) - } + clean::MacroItem(..) => i.is_exported_macro(), _ => false, }; let mut is_hidden = has_doc_hidden; diff --git a/tests/rustdoc-ui/lints/check.rs b/tests/rustdoc-ui/lints/check.rs index 9a4cc96094108..5e5484c01fbba 100644 --- a/tests/rustdoc-ui/lints/check.rs +++ b/tests/rustdoc-ui/lints/check.rs @@ -4,6 +4,7 @@ #![feature(rustdoc_missing_doc_code_examples)] //~ WARN no documentation found for this crate's top-level module //~^ WARN +#![feature(decl_macro)] #![warn(missing_docs)] #![warn(rustdoc::missing_doc_code_examples)] @@ -12,3 +13,14 @@ pub fn foo() {} //~^ WARN //~^^ WARN + +#[macro_export] +macro_rules! bar { +//~^ WARN missing documentation +//~^^ WARN missing code example + () => {}; +} + +pub macro bar_v2() {} +//~^ WARN missing documentation +//~^^ WARN missing code example diff --git a/tests/rustdoc-ui/lints/check.stderr b/tests/rustdoc-ui/lints/check.stderr index 52c8c176084a2..4b009c47a0d0b 100644 --- a/tests/rustdoc-ui/lints/check.stderr +++ b/tests/rustdoc-ui/lints/check.stderr @@ -3,55 +3,81 @@ warning: missing documentation for the crate | LL | / #![feature(rustdoc_missing_doc_code_examples)] LL | | -LL | | -LL | | #![warn(missing_docs)] +LL | | #![feature(decl_macro)] ... | -LL | | pub fn foo() {} - | |_______________^ +LL | | pub macro bar_v2() {} + | |_____________________^ | note: the lint level is defined here - --> $DIR/check.rs:8:9 + --> $DIR/check.rs:9:9 | LL | #![warn(missing_docs)] | ^^^^^^^^^^^^ warning: missing documentation for a function - --> $DIR/check.rs:12:1 + --> $DIR/check.rs:13:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^ +warning: missing documentation for a macro + --> $DIR/check.rs:18:1 + | +LL | macro_rules! bar { + | ^^^^^^^^^^^^^^^^ + +warning: missing documentation for a macro + --> $DIR/check.rs:24:1 + | +LL | pub macro bar_v2() {} + | ^^^^^^^^^^^^^^^^ + warning: no documentation found for this crate's top-level module --> $DIR/check.rs:5:1 | LL | / #![feature(rustdoc_missing_doc_code_examples)] LL | | -LL | | -LL | | #![warn(missing_docs)] +LL | | #![feature(decl_macro)] ... | -LL | | pub fn foo() {} - | |_______________^ +LL | | pub macro bar_v2() {} + | |_____________________^ | = help: The following guide may be of use: https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html note: the lint level is defined here - --> $DIR/check.rs:10:9 + --> $DIR/check.rs:11:9 | LL | #![warn(rustdoc::all)] | ^^^^^^^^^^^^ = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]` warning: missing code example in this documentation - --> $DIR/check.rs:12:1 + --> $DIR/check.rs:13:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/check.rs:9:9 + --> $DIR/check.rs:10:9 | LL | #![warn(rustdoc::missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 4 warnings emitted +warning: missing code example in this documentation + --> $DIR/check.rs:24:1 + | +LL | pub macro bar_v2() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: missing code example in this documentation + --> $DIR/check.rs:18:1 + | +LL | / macro_rules! bar { +LL | | +LL | | +LL | | () => {}; +LL | | } + | |_^ + +warning: 8 warnings emitted From 0f603290db0f8010a58ebae4e8699035f0ad3831 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 27 Mar 2026 21:55:10 +0800 Subject: [PATCH 02/11] Stop compiling when we get load crate failure --- compiler/rustc_metadata/src/creader.rs | 11 +++++++++ compiler/rustc_resolve/src/imports.rs | 4 ++++ ...ssing-extern-crate-cascade-issue-154096.rs | 24 +++++++++++++++++++ ...g-extern-crate-cascade-issue-154096.stderr | 9 +++++++ tests/ui/extern-flag/empty-extern-arg.rs | 3 --- tests/ui/extern-flag/empty-extern-arg.stderr | 9 +------ tests/ui/rust-2018/uniform-paths/deadlock.rs | 1 - .../rust-2018/uniform-paths/deadlock.stderr | 13 ++-------- 8 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.rs create mode 100644 tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.stderr diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 345ee185156ca..411c8111cc92b 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -77,6 +77,9 @@ pub struct CStore { unused_externs: Vec, used_extern_options: FxHashSet, + /// Whether there was a failure in resolving crate, + /// it's used to suppress some diagnostics that would otherwise too noisey. + has_crate_resolve_with_fail: bool, } impl std::fmt::Debug for CStore { @@ -328,6 +331,10 @@ impl CStore { self.has_alloc_error_handler } + pub fn had_extern_crate_load_failure(&self) -> bool { + self.has_crate_resolve_with_fail + } + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { let json_unused_externs = tcx.sess.opts.json_unused_externs; @@ -514,6 +521,7 @@ impl CStore { resolved_externs: UnordMap::default(), unused_externs: Vec::new(), used_extern_options: Default::default(), + has_crate_resolve_with_fail: false, } } @@ -723,6 +731,9 @@ impl CStore { } Err(err) => { debug!("failed to resolve crate {} {:?}", name, dep_kind); + if !tcx.sess.dcx().has_errors().is_some() { + self.has_crate_resolve_with_fail = true; + } let missing_core = self .maybe_resolve_crate( tcx, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6507ee3477379..d51ce9fb7946b 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -674,6 +674,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + if self.cstore().had_extern_crate_load_failure() { + self.tcx.sess.dcx().abort_if_errors(); + } + if !errors.is_empty() { self.throw_unresolved_import_error(errors, glob_error); return; diff --git a/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.rs b/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.rs new file mode 100644 index 0000000000000..5bbaa1980ee67 --- /dev/null +++ b/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.rs @@ -0,0 +1,24 @@ +//@ edition: 2024 + +extern crate missing_154096; +//~^ ERROR can't find crate for `missing_154096` + +mod defs { + pub use missing_154096::Thing; +} + +pub use defs::Thing; + +mod first { + use crate::Thing; + + pub fn take(_: Thing) {} +} + +mod second { + use crate::Thing; + + pub fn take(_: Thing) {} +} + +fn main() {} diff --git a/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.stderr b/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.stderr new file mode 100644 index 0000000000000..4deac6dbcda39 --- /dev/null +++ b/tests/ui/crate-loading/missing-extern-crate-cascade-issue-154096.stderr @@ -0,0 +1,9 @@ +error[E0463]: can't find crate for `missing_154096` + --> $DIR/missing-extern-crate-cascade-issue-154096.rs:3:1 + | +LL | extern crate missing_154096; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/extern-flag/empty-extern-arg.rs b/tests/ui/extern-flag/empty-extern-arg.rs index 10cc3be71135e..db97cee91e507 100644 --- a/tests/ui/extern-flag/empty-extern-arg.rs +++ b/tests/ui/extern-flag/empty-extern-arg.rs @@ -5,6 +5,3 @@ //@ ignore-emscripten missing eh_catch_typeinfo lang item fn main() {} - -//~? ERROR `#[panic_handler]` function required, but not found -//~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 3e0a0d6cd5f86..3ce92522d4195 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -2,12 +2,5 @@ error: extern location for std does not exist: error: cannot resolve a prelude import -error: `#[panic_handler]` function required, but not found - -error: unwinding panics are not supported without std - | - = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding - = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/rust-2018/uniform-paths/deadlock.rs b/tests/ui/rust-2018/uniform-paths/deadlock.rs index d2296c51bdd39..4fab9e9219fab 100644 --- a/tests/ui/rust-2018/uniform-paths/deadlock.rs +++ b/tests/ui/rust-2018/uniform-paths/deadlock.rs @@ -3,6 +3,5 @@ use bar::foo; //~ ERROR can't find crate for `bar` use foo::bar; -//~^^ ERROR unresolved imports `bar::foo`, `foo::bar` fn main() {} diff --git a/tests/ui/rust-2018/uniform-paths/deadlock.stderr b/tests/ui/rust-2018/uniform-paths/deadlock.stderr index c50bc16ac55f3..c3050d6749287 100644 --- a/tests/ui/rust-2018/uniform-paths/deadlock.stderr +++ b/tests/ui/rust-2018/uniform-paths/deadlock.stderr @@ -4,15 +4,6 @@ error[E0463]: can't find crate for `bar` LL | use bar::foo; | ^^^ can't find crate -error[E0432]: unresolved imports `bar::foo`, `foo::bar` - --> $DIR/deadlock.rs:4:5 - | -LL | use bar::foo; - | ^^^^^^^^ -LL | use foo::bar; - | ^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0432, E0463. -For more information about an error, try `rustc --explain E0432`. +For more information about this error, try `rustc --explain E0463`. From f1fbfd4c112cda2392c0d975e82f963f385ecdfe Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 2 Apr 2026 18:58:00 +0800 Subject: [PATCH 03/11] add test case for multiple candidates import --- ...ultiple-candidates-cascade-issue-118130.rs | 20 +++++++++++++++++++ ...ple-candidates-cascade-issue-118130.stderr | 13 ++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.rs create mode 100644 tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.stderr diff --git a/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.rs b/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.rs new file mode 100644 index 0000000000000..1b3814a5e543e --- /dev/null +++ b/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.rs @@ -0,0 +1,20 @@ +//@ aux-build:crateresolve1-1.rs +//@ aux-build:crateresolve1-2.rs +//@ aux-build:crateresolve1-3.rs + +//@ normalize-stderr: "multiple-candidates-cascade-issue-118130\..+/auxiliary/" -> "multiple-candidates-cascade-issue-118130/auxiliary/" +//@ normalize-stderr: "\\\?\\" -> "" +//@ normalize-stderr: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib" + +extern crate crateresolve1; +//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found + +mod defs { + pub use crateresolve1::f; +} + +pub use defs::f; + +fn main() { + let _ = f(); +} diff --git a/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.stderr b/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.stderr new file mode 100644 index 0000000000000..1bd31b924f7f5 --- /dev/null +++ b/tests/ui/crate-loading/multiple-candidates-cascade-issue-118130.stderr @@ -0,0 +1,13 @@ +error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found + --> $DIR/multiple-candidates-cascade-issue-118130.rs:9:1 + | +LL | extern crate crateresolve1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidate #1: $TEST_BUILD_DIR/auxiliary/libcrateresolve1-1.somelib + = note: candidate #2: $TEST_BUILD_DIR/auxiliary/libcrateresolve1-2.somelib + = note: candidate #3: $TEST_BUILD_DIR/auxiliary/libcrateresolve1-3.somelib + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0464`. From e2461cf2add278e00aa30bb0c5935906a5da638b Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Thu, 2 Apr 2026 23:55:05 +0100 Subject: [PATCH 04/11] Add a regression test for the duplicated `crate` keyword in path suggestions --- ...ath-suggestion-duplicated-crate-keyword.rs | 20 ++++++++++++++++ ...suggestion-duplicated-crate-keyword.stderr | 23 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs create mode 100644 tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr diff --git a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs new file mode 100644 index 0000000000000..294885b997da3 --- /dev/null +++ b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.rs @@ -0,0 +1,20 @@ +//! Regression test for . +//! +//! The compiler used to suggest `crate::crate::unix::linux::system::Y` +//! (duplicating the `crate` keyword) instead of `crate::unix::linux::system::Y`. + +pub mod unix { + pub mod linux { + pub mod utils { + pub fn f() { + let _x = crate::linux::system::Y; + //~^ ERROR cannot find `linux` in `crate` + } + } + pub mod system { + pub const Y: u32 = 0; + } + } +} + +fn main() {} diff --git a/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr new file mode 100644 index 0000000000000..49c2db34d2b4d --- /dev/null +++ b/tests/ui/resolve/path-suggestion-duplicated-crate-keyword.stderr @@ -0,0 +1,23 @@ +error[E0433]: cannot find `linux` in `crate` + --> $DIR/path-suggestion-duplicated-crate-keyword.rs:10:33 + | +LL | let _x = crate::linux::system::Y; + | ^^^^^ unresolved import + | +help: a similar path exists + | +LL | let _x = crate::unix::linux::system::Y; + | ++++++ +help: consider importing this module + | +LL + use unix::linux::system; + | +help: if you import `system`, refer to it directly + | +LL - let _x = crate::linux::system::Y; +LL + let _x = system::Y; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. From 8798ba69439d71c4a84635d5dc891e748dec9e4f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:24:33 +0100 Subject: [PATCH 05/11] ci: update upload-artifact action to v7 --- .github/workflows/ci.yml | 2 +- .github/workflows/dependencies.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcdde9c91e8da..fb449197f78bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -254,7 +254,7 @@ jobs: df -h - name: upload artifacts to github - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: # name is set in previous step name: ${{ env.DOC_ARTIFACT_NAME }} diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 7c721c7abeaaf..4d2e2989e834a 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -66,7 +66,7 @@ jobs: run: ./src/tools/update-lockfile.sh - name: upload Cargo.lock artifact for use in PR - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Cargo-lock path: | @@ -75,7 +75,7 @@ jobs: src/tools/rustbook/Cargo.lock retention-days: 1 - name: upload cargo-update log artifact for use in PR - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: cargo-updates path: cargo_update.log From cd9559375576e971a721143af150348955a37007 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 3 Apr 2026 09:16:26 +0800 Subject: [PATCH 06/11] ignore compiler injected crate loading failure --- compiler/rustc_metadata/src/creader.rs | 6 +++++- tests/ui/extern-flag/empty-extern-arg.rs | 3 +++ tests/ui/extern-flag/empty-extern-arg.stderr | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 411c8111cc92b..3c8ea1a9f43d4 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -731,7 +731,11 @@ impl CStore { } Err(err) => { debug!("failed to resolve crate {} {:?}", name, dep_kind); - if !tcx.sess.dcx().has_errors().is_some() { + // crate maybe injrected with `standard_library_imports::inject`, their span is dummy. + // we ignore compiler-injected prelude/sysroot loads here so they don't suppress + // unrelated diagnostics, such as `unsupported targets for std library` etc, + // these maybe helpful for users to resolve crate loading failure. + if !tcx.sess.dcx().has_errors().is_some() && !span.is_dummy() { self.has_crate_resolve_with_fail = true; } let missing_core = self diff --git a/tests/ui/extern-flag/empty-extern-arg.rs b/tests/ui/extern-flag/empty-extern-arg.rs index db97cee91e507..10cc3be71135e 100644 --- a/tests/ui/extern-flag/empty-extern-arg.rs +++ b/tests/ui/extern-flag/empty-extern-arg.rs @@ -5,3 +5,6 @@ //@ ignore-emscripten missing eh_catch_typeinfo lang item fn main() {} + +//~? ERROR `#[panic_handler]` function required, but not found +//~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 3ce92522d4195..3e0a0d6cd5f86 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -2,5 +2,12 @@ error: extern location for std does not exist: error: cannot resolve a prelude import -error: aborting due to 2 previous errors +error: `#[panic_handler]` function required, but not found + +error: unwinding panics are not supported without std + | + = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding + = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem + +error: aborting due to 4 previous errors From 14c7788a167723fe95dd3bf1080508db0e250140 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 3 Apr 2026 12:32:56 +1100 Subject: [PATCH 07/11] Enforce `#![warn(unreachable_pub)]` in compiletest source --- src/tools/compiletest/src/common.rs | 316 +++++++++--------- src/tools/compiletest/src/directives.rs | 204 +++++------ .../compiletest/src/directives/auxiliary.rs | 12 +- src/tools/compiletest/src/edition.rs | 4 +- src/tools/compiletest/src/errors.rs | 20 +- src/tools/compiletest/src/json.rs | 6 +- src/tools/compiletest/src/lib.rs | 5 +- src/tools/compiletest/src/output_capture.rs | 2 +- src/tools/compiletest/src/raise_fd_limit.rs | 4 +- src/tools/compiletest/src/read2.rs | 12 +- src/tools/compiletest/src/runtest.rs | 8 +- .../compiletest/src/runtest/compute_diff.rs | 10 +- src/tools/compiletest/src/runtest/debugger.rs | 10 +- src/tools/compiletest/src/util.rs | 12 +- 14 files changed, 314 insertions(+), 311 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7cac7f5c04940..c167580d99d9a 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -14,7 +14,7 @@ use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] - pub enum TestMode { + pub(crate) enum TestMode { Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", @@ -34,7 +34,7 @@ string_enum! { } impl TestMode { - pub fn aux_dir_disambiguator(self) -> &'static str { + pub(crate) fn aux_dir_disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, // they need to keep their output segregated. match self { @@ -43,7 +43,7 @@ impl TestMode { } } - pub fn output_dir_disambiguator(self) -> &'static str { + pub(crate) fn output_dir_disambiguator(self) -> &'static str { // Coverage tests use the same test files for multiple test modes, // so each mode should have a separate output directory. match self { @@ -56,7 +56,7 @@ impl TestMode { // Note that coverage tests use the same test files for multiple test modes. string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] - pub enum TestSuite { + pub(crate) enum TestSuite { AssemblyLlvm => "assembly-llvm", CodegenLlvm => "codegen-llvm", CodegenUnits => "codegen-units", @@ -83,7 +83,7 @@ string_enum! { string_enum! { #[derive(Clone, Copy, PartialEq, Debug, Hash)] - pub enum PassMode { + pub(crate) enum PassMode { Check => "check", Build => "build", Run => "run", @@ -92,7 +92,7 @@ string_enum! { string_enum! { #[derive(Clone, Copy, PartialEq, Debug, Hash)] - pub enum RunResult { + pub(crate) enum RunResult { Pass => "run-pass", Fail => "run-fail", Crash => "run-crash", @@ -100,7 +100,7 @@ string_enum! { } #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum RunFailMode { +pub(crate) enum RunFailMode { /// Running the program must make it exit with a regular failure exit code /// in the range `1..=127`. If the program is terminated by e.g. a signal /// the test will fail. @@ -117,7 +117,7 @@ pub enum RunFailMode { } #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum FailMode { +pub(crate) enum FailMode { Check, Build, Run(RunFailMode), @@ -125,7 +125,7 @@ pub enum FailMode { string_enum! { #[derive(Clone, Debug, PartialEq)] - pub enum CompareMode { + pub(crate) enum CompareMode { Polonius => "polonius", NextSolver => "next-solver", NextSolverCoherence => "next-solver-coherence", @@ -136,7 +136,7 @@ string_enum! { string_enum! { #[derive(Clone, Copy, Debug, PartialEq)] - pub enum Debugger { + pub(crate) enum Debugger { Cdb => "cdb", Gdb => "gdb", Lldb => "lldb", @@ -145,7 +145,7 @@ string_enum! { #[derive(Clone, Copy, Debug, PartialEq, Default, serde::Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum PanicStrategy { +pub(crate) enum PanicStrategy { #[default] Unwind, Abort, @@ -162,7 +162,7 @@ impl PanicStrategy { #[derive(Clone, Debug, PartialEq, serde::Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum Sanitizer { +pub(crate) enum Sanitizer { Address, Cfi, Dataflow, @@ -180,7 +180,7 @@ pub enum Sanitizer { } #[derive(Clone, Copy, Debug, PartialEq)] -pub enum CodegenBackend { +pub(crate) enum CodegenBackend { Cranelift, Gcc, Llvm, @@ -200,7 +200,7 @@ impl<'a> TryFrom<&'a str> for CodegenBackend { } impl CodegenBackend { - pub fn as_str(self) -> &'static str { + pub(crate) fn as_str(self) -> &'static str { match self { Self::Cranelift => "cranelift", Self::Gcc => "gcc", @@ -208,7 +208,7 @@ impl CodegenBackend { } } - pub fn is_llvm(self) -> bool { + pub(crate) fn is_llvm(self) -> bool { matches!(self, Self::Llvm) } } @@ -235,7 +235,7 @@ impl CodegenBackend { /// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp /// (for changed test detection). #[derive(Debug, Clone)] -pub struct Config { +pub(crate) struct Config { /// Some [`TestMode`]s support [snapshot testing], where a *reference snapshot* of outputs (of /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*. /// @@ -243,17 +243,17 @@ pub struct Config { /// `compiletest` will only try to compare. /// /// [snapshot testing]: https://jestjs.io/docs/snapshot-testing - pub bless: bool, + pub(crate) bless: bool, /// Attempt to stop as soon as possible after any test fails. We may still run a few more tests /// before stopping when multiple test threads are used. - pub fail_fast: bool, + pub(crate) fail_fast: bool, /// Path to libraries needed to run the *staged* `rustc`-under-test on the **host** platform. /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/bin/lib` - pub host_compile_lib_path: Utf8PathBuf, + pub(crate) host_compile_lib_path: Utf8PathBuf, /// Path to libraries needed to run the compiled executable for the **target** platform. This /// corresponds to the **target** sysroot libraries, including the **target** standard library. @@ -264,7 +264,7 @@ pub struct Config { /// FIXME: this is very under-documented in conjunction with the `remote-test-client` scheme and /// `RUNNER` scheme to actually run the target executable under the target platform environment, /// cf. [`Self::remote_test_client`] and [`Self::runner`]. - pub target_run_lib_path: Utf8PathBuf, + pub(crate) target_run_lib_path: Utf8PathBuf, /// Path to the `rustc`-under-test. /// @@ -283,7 +283,7 @@ pub struct Config { /// /// It is possible for this `rustc` to be a stage 0 `rustc` if explicitly configured with the /// bootstrap option `build.compiletest-allow-stage0=true` and specifying `--stage=0`. - pub rustc_path: Utf8PathBuf, + pub(crate) rustc_path: Utf8PathBuf, /// Path to a *staged* **host** platform cargo executable (unless stage 0 is forced). This /// staged `cargo` is only used within `run-make` test recipes during recipe run time (and is @@ -294,14 +294,14 @@ pub struct Config { /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1-tools-bin/cargo` /// /// FIXME: maybe rename this to reflect that this is a *staged* host cargo. - pub cargo_path: Option, + pub(crate) cargo_path: Option, /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with /// [`Self::rustc_path`]. /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc` - pub stage0_rustc_path: Option, + pub(crate) stage0_rustc_path: Option, /// Path to the stage 1 or higher `rustc` used to obtain target information via /// `--print=all-target-specs-json` and similar queries. @@ -310,35 +310,35 @@ pub struct Config { /// But when running "stage 1" ui-fulldeps tests, `rustc_path` is a stage 0 /// compiler, whereas target specs must be obtained from a stage 1+ compiler /// (in case the JSON format has changed since the last bootstrap bump). - pub query_rustc_path: Option, + pub(crate) query_rustc_path: Option, /// Path to the `rustdoc`-under-test. Like [`Self::rustc_path`], this `rustdoc` is *staged*. - pub rustdoc_path: Option, + pub(crate) rustdoc_path: Option, /// Path to the `src/tools/coverage-dump/` bootstrap tool executable. - pub coverage_dump_path: Option, + pub(crate) coverage_dump_path: Option, /// Path to the Python 3 executable to use for htmldocck and some run-make tests. - pub python: String, + pub(crate) python: String, /// Path to the `src/tools/jsondocck/` bootstrap tool executable. - pub jsondocck_path: Option, + pub(crate) jsondocck_path: Option, /// Path to the `src/tools/jsondoclint/` bootstrap tool executable. - pub jsondoclint_path: Option, + pub(crate) jsondoclint_path: Option, /// Path to a host LLVM `FileCheck` executable. - pub llvm_filecheck: Option, + pub(crate) llvm_filecheck: Option, /// Path to a host LLVM bintools directory. /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/llvm/bin` - pub llvm_bin_dir: Option, + pub(crate) llvm_bin_dir: Option, /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`, /// then these tests will be ignored. - pub run_clang_based_tests_with: Option, + pub(crate) run_clang_based_tests_with: Option, /// Path to the directory containing the sources. This corresponds to the root folder of a /// `rust-lang/rust` checkout. @@ -348,27 +348,27 @@ pub struct Config { /// /// FIXME: this name is confusing, because this is actually `$checkout_root`, **not** the /// `$checkout_root/src/` folder. - pub src_root: Utf8PathBuf, + pub(crate) src_root: Utf8PathBuf, /// Absolute path to the test suite directory. /// /// For example: /// - `/home/ferris/rust/tests/ui` /// - `/home/ferris/rust/tests/coverage` - pub src_test_suite_root: Utf8PathBuf, + pub(crate) src_test_suite_root: Utf8PathBuf, /// Path to the top-level build directory used by bootstrap. /// /// For example: /// - `/home/ferris/rust/build` - pub build_root: Utf8PathBuf, + pub(crate) build_root: Utf8PathBuf, /// Path to the build directory used by the current test suite. /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/test/ui` /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/test/coverage` - pub build_test_suite_root: Utf8PathBuf, + pub(crate) build_test_suite_root: Utf8PathBuf, /// Path to the directory containing the sysroot of the `rustc`-under-test. /// @@ -384,21 +384,21 @@ pub struct Config { /// stage 0 is forced and no custom stage 0 `rustc` was otherwise specified (so that it /// *happens* to run against the bootstrap `rustc`, but this non-custom bootstrap `rustc` case /// is not really supported). - pub sysroot_base: Utf8PathBuf, + pub(crate) sysroot_base: Utf8PathBuf, /// The number of the stage under test. - pub stage: u32, + pub(crate) stage: u32, /// The id of the stage under test (stage1-xxx, etc). /// /// FIXME: reconsider this string; this is hashed for test build stamp. - pub stage_id: String, + pub(crate) stage_id: String, /// The [`TestMode`]. E.g. [`TestMode::Ui`]. Each test mode can correspond to one or more test /// suites. /// /// FIXME: stop using stringly-typed test suites! - pub mode: TestMode, + pub(crate) mode: TestMode, /// The test suite. /// @@ -408,7 +408,7 @@ pub struct Config { /// Note that the same test suite (e.g. `tests/coverage/`) may correspond to multiple test /// modes, e.g. `tests/coverage/` can be run under both [`TestMode::CoverageRun`] and /// [`TestMode::CoverageMap`]. - pub suite: TestSuite, + pub(crate) suite: TestSuite, /// When specified, **only** the specified [`Debugger`] will be used to run against the /// `tests/debuginfo` test suite. When unspecified, `compiletest` will attempt to find all three @@ -420,30 +420,30 @@ pub struct Config { /// should have `bootstrap` allow the user to *explicitly* configure the debuggers, and *not* /// try to implicitly discover some random debugger from the user environment. This makes the /// debuginfo test suite particularly hard to work with. - pub debugger: Option, + pub(crate) debugger: Option, /// Run ignored tests *unconditionally*, overriding their ignore reason. /// /// FIXME: this is wired up through the test execution logic, but **not** accessible from /// `bootstrap` directly; `compiletest` exposes this as `--ignored`. I.e. you'd have to use `./x /// test $test_suite -- --ignored=true`. - pub run_ignored: bool, + pub(crate) run_ignored: bool, /// Whether *staged* `rustc`-under-test was built with debug assertions. /// /// FIXME: make it clearer that this refers to the staged `rustc`-under-test, not stage 0 /// `rustc`. - pub with_rustc_debug_assertions: bool, + pub(crate) with_rustc_debug_assertions: bool, /// Whether *staged* `std` was built with debug assertions. /// /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. - pub with_std_debug_assertions: bool, + pub(crate) with_std_debug_assertions: bool, /// Whether *staged* `std` was built with remapping of debuginfo. /// /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. - pub with_std_remap_debuginfo: bool, + pub(crate) with_std_remap_debuginfo: bool, /// Only run tests that match these filters (using `libtest` "test name contains" filter logic). /// @@ -452,25 +452,25 @@ pub struct Config { /// but this is often not intuitive. We should consider changing that behavior with an MCP to do /// test path *prefix* matching which better corresponds to how `compiletest` `tests/` are /// organized, and how users would intuitively expect the filtering logic to work like. - pub filters: Vec, + pub(crate) filters: Vec, /// Skip tests matching these substrings. The matching logic exactly corresponds to /// [`Self::filters`] but inverted. /// /// FIXME(#139660): ditto on test matching behavior. - pub skip: Vec, + pub(crate) skip: Vec, /// Exactly match the filter, rather than a substring. /// /// FIXME(#139660): ditto on test matching behavior. - pub filter_exact: bool, + pub(crate) filter_exact: bool, /// Force the pass mode of a check/build/run test to instead use this mode instead. /// /// FIXME: make it even more obvious (especially in PR CI where `--pass=check` is used) when a /// pass mode is forced when the test fails, because it can be very non-obvious when e.g. an /// error is emitted only when `//@ build-pass` but not `//@ check-pass`. - pub force_pass_mode: Option, + pub(crate) force_pass_mode: Option, /// Explicitly enable or disable running of the target test binary. /// @@ -480,7 +480,7 @@ pub struct Config { /// FIXME: Currently `--run` is a tri-state, it can be `--run={auto,always,never}`, and when /// `--run=auto` is specified, it's run if the platform doesn't end with `-fuchsia`. See /// [`Config::run_enabled`]. - pub run: Option, + pub(crate) run: Option, /// A command line to prefix target program execution with, for running under valgrind for /// example, i.e. `$runner target.exe [args..]`. Similar to `CARGO_*_RUNNER` configuration. @@ -489,45 +489,45 @@ pub struct Config { /// scheme. /// /// FIXME: the runner scheme is very under-documented. - pub runner: Option, + pub(crate) runner: Option, /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **host** /// platform. - pub host_rustcflags: Vec, + pub(crate) host_rustcflags: Vec, /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **target** /// platform. - pub target_rustcflags: Vec, + pub(crate) target_rustcflags: Vec, /// Whether the *staged* `rustc`-under-test and the associated *staged* `std` has been built /// with randomized struct layouts. - pub rust_randomized_layout: bool, + pub(crate) rust_randomized_layout: bool, /// Whether tests should be optimized by default (`-O`). Individual test suites and test files /// may override this setting. /// /// FIXME: this flag / config option is somewhat misleading. For instance, in ui tests, it's /// *only* applied to the [`PassMode::Run`] test crate and not its auxiliaries. - pub optimize_tests: bool, + pub(crate) optimize_tests: bool, /// Target platform tuple. - pub target: String, + pub(crate) target: String, /// Host platform tuple. - pub host: String, + pub(crate) host: String, /// Path to / name of the Microsoft Console Debugger (CDB) executable. /// /// FIXME: this is an *opt-in* "override" option. When this isn't provided, we try to conjure a /// cdb by looking at the user's program files on Windows... See `debuggers::find_cdb`. - pub cdb: Option, + pub(crate) cdb: Option, /// Version of CDB. /// /// FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! /// /// FIXME: audit cdb version gating. - pub cdb_version: Option<[u16; 4]>, + pub(crate) cdb_version: Option<[u16; 4]>, /// Path to / name of the GDB executable. /// @@ -536,7 +536,7 @@ pub struct Config { /// /// FIXME: we are propagating a python from `PYTHONPATH`, not from an explicit config for gdb /// debugger script. - pub gdb: Option, + pub(crate) gdb: Option, /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch /// @@ -547,24 +547,24 @@ pub struct Config { /// purposes of debuginfo tests? /// /// FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! - pub gdb_version: Option, + pub(crate) gdb_version: Option, /// Path to or name of the LLDB executable to use for debuginfo tests. - pub lldb: Option, + pub(crate) lldb: Option, /// Version of LLDB. /// /// FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! - pub lldb_version: Option, + pub(crate) lldb_version: Option, /// Version of LLVM. /// /// FIXME: Audit the fallback derivation of /// [`crate::directives::extract_llvm_version_from_binary`], that seems very questionable? - pub llvm_version: Option, + pub(crate) llvm_version: Option, /// Is LLVM a system LLVM. - pub system_llvm: bool, + pub(crate) system_llvm: bool, /// Path to the android tools. /// @@ -572,7 +572,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub android_cross_path: Option, + pub(crate) android_cross_path: Option, /// Extra parameter to run adb on `arm-linux-androideabi`. /// @@ -581,7 +581,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_path: Option, + pub(crate) adb_path: Option, /// Extra parameter to run test suite on `arm-linux-androideabi`. /// @@ -590,18 +590,18 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_test_dir: Option, + pub(crate) adb_test_dir: Option, /// Status whether android device available or not. When unavailable, this will cause tests to /// panic when the test binary is attempted to be run. /// /// FIXME: take a look at this; this also influences adb in gdb code paths in a strange way. - pub adb_device_status: bool, + pub(crate) adb_device_status: bool, /// Verbose dump a lot of info. /// /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. - pub verbose: bool, + pub(crate) verbose: bool, /// Where to find the remote test client process, if we're using it. /// @@ -611,67 +611,67 @@ pub struct Config { /// Note: this is not to be confused with [`Self::runner`], which is a different scheme. /// /// FIXME: the `remote_test_client` scheme is very under-documented. - pub remote_test_client: Option, + pub(crate) remote_test_client: Option, /// [`CompareMode`] describing what file the actual ui output will be compared to. /// /// FIXME: currently, [`CompareMode`] is a mishmash of lot of things (different borrow-checker /// model, different trait solver, different debugger, etc.). - pub compare_mode: Option, + pub(crate) compare_mode: Option, /// If true, this will generate a coverage file with UI test files that run `MachineApplicable` /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is /// created in `$test_suite_build_root/rustfix_missing_coverage.txt` - pub rustfix_coverage: bool, + pub(crate) rustfix_coverage: bool, /// Whether to run `enzyme` autodiff tests. - pub has_enzyme: bool, + pub(crate) has_enzyme: bool, /// Whether to run `offload` autodiff tests. - pub has_offload: bool, + pub(crate) has_offload: bool, /// The current Rust channel info. /// /// FIXME: treat this more carefully; "stable", "beta" and "nightly" are definitely valid, but /// channel might also be "dev" or such, which should be treated as "nightly". - pub channel: String, + pub(crate) channel: String, /// Whether adding git commit information such as the commit hash has been enabled for building. /// /// FIXME: `compiletest` cannot trust `bootstrap` for this information, because `bootstrap` can /// have bugs and had bugs on that logic. We need to figure out how to obtain this e.g. directly /// from CI or via git locally. - pub git_hash: bool, + pub(crate) git_hash: bool, /// The default Rust edition. - pub edition: Option, + pub(crate) edition: Option, // Configuration for various run-make tests frobbing things like C compilers or querying about // various LLVM component information. // // FIXME: this really should be better packaged together. // FIXME: these need better docs, e.g. for *host*, or for *target*? - pub cc: String, - pub cxx: String, - pub cflags: String, - pub cxxflags: String, - pub ar: String, - pub target_linker: Option, - pub host_linker: Option, - pub llvm_components: String, + pub(crate) cc: String, + pub(crate) cxx: String, + pub(crate) cflags: String, + pub(crate) cxxflags: String, + pub(crate) ar: String, + pub(crate) target_linker: Option, + pub(crate) host_linker: Option, + pub(crate) llvm_components: String, /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests. - pub nodejs: Option, + pub(crate) nodejs: Option, /// Whether to rerun tests even if the inputs are unchanged. - pub force_rerun: bool, + pub(crate) force_rerun: bool, /// Only rerun the tests that result has been modified according to `git status`. /// /// FIXME: this is undocumented. /// /// FIXME: how does this interact with [`Self::force_rerun`]? - pub only_modified: bool, + pub(crate) only_modified: bool, // FIXME: these are really not "config"s, but rather are information derived from // `rustc`-under-test. This poses an interesting conundrum: if we're testing the @@ -684,72 +684,72 @@ pub struct Config { // from print requests produced by the `rustc`-under-test. // // FIXME: move them out from `Config`, because they are *not* configs. - pub target_cfgs: OnceLock, - pub builtin_cfg_names: OnceLock>, - pub supported_crate_types: OnceLock>, + pub(crate) target_cfgs: OnceLock, + pub(crate) builtin_cfg_names: OnceLock>, + pub(crate) supported_crate_types: OnceLock>, /// Should we capture console output that would be printed by test runners via their `stdout` /// and `stderr` trait objects, or via the custom panic hook. /// /// The default is `true`. This can be disabled via the compiletest cli flag `--no-capture` /// (which mirrors the libtest `--no-capture` flag). - pub capture: bool, + pub(crate) capture: bool, /// Needed both to construct [`build_helper::git::GitConfig`]. - pub nightly_branch: String, - pub git_merge_commit_email: String, + pub(crate) nightly_branch: String, + pub(crate) git_merge_commit_email: String, /// True if the profiler runtime is enabled for this target. Used by the /// `needs-profiler-runtime` directive in test files. - pub profiler_runtime: bool, + pub(crate) profiler_runtime: bool, /// Command for visual diff display, e.g. `diff-tool --color=always`. - pub diff_command: Option, + pub(crate) diff_command: Option, /// Path to minicore aux library (`tests/auxiliary/minicore.rs`), used for `no_core` tests that /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to /// `-Zbuild-std`. Used in e.g. ABI tests. - pub minicore_path: Utf8PathBuf, + pub(crate) minicore_path: Utf8PathBuf, /// Current codegen backend used. - pub default_codegen_backend: CodegenBackend, + pub(crate) default_codegen_backend: CodegenBackend, /// Name/path of the backend to use instead of `default_codegen_backend`. - pub override_codegen_backend: Option, + pub(crate) override_codegen_backend: Option, /// Whether to ignore `//@ ignore-backends`. - pub bypass_ignore_backends: bool, + pub(crate) bypass_ignore_backends: bool, /// Number of parallel jobs configured for the build. /// /// This is forwarded from bootstrap's `jobs` configuration. - pub jobs: u32, + pub(crate) jobs: u32, /// Number of parallel threads to use for the frontend when building test artifacts. - pub parallel_frontend_threads: u32, + pub(crate) parallel_frontend_threads: u32, /// Number of times to execute each test. - pub iteration_count: u32, + pub(crate) iteration_count: u32, } impl Config { - pub const DEFAULT_PARALLEL_FRONTEND_THREADS: u32 = 1; - pub const DEFAULT_ITERATION_COUNT: u32 = 1; + pub(crate) const DEFAULT_PARALLEL_FRONTEND_THREADS: u32 = 1; + pub(crate) const DEFAULT_ITERATION_COUNT: u32 = 1; /// FIXME: this run scheme is... confusing. - pub fn run_enabled(&self) -> bool { + pub(crate) fn run_enabled(&self) -> bool { self.run.unwrap_or_else(|| { // Auto-detect whether to run based on the platform. !self.target.ends_with("-fuchsia") }) } - pub fn target_cfgs(&self) -> &TargetCfgs { + pub(crate) fn target_cfgs(&self) -> &TargetCfgs { self.target_cfgs.get_or_init(|| TargetCfgs::new(self)) } - pub fn target_cfg(&self) -> &TargetCfg { + pub(crate) fn target_cfg(&self) -> &TargetCfg { &self.target_cfgs().current } - pub fn matches_arch(&self, arch: &str) -> bool { + pub(crate) fn matches_arch(&self, arch: &str) -> bool { self.target_cfg().arch == arch || { // Matching all the thumb variants as one can be convenient. @@ -759,15 +759,15 @@ impl Config { || (arch == "i586" && self.target.starts_with("i586-")) } - pub fn matches_os(&self, os: &str) -> bool { + pub(crate) fn matches_os(&self, os: &str) -> bool { self.target_cfg().os == os } - pub fn matches_env(&self, env: &str) -> bool { + pub(crate) fn matches_env(&self, env: &str) -> bool { self.target_cfg().env == env } - pub fn matches_abi(&self, abi: &str) -> bool { + pub(crate) fn matches_abi(&self, abi: &str) -> bool { self.target_cfg().abi == abi } @@ -776,29 +776,29 @@ impl Config { self.target_cfg().families.iter().any(|f| f == family) } - pub fn is_big_endian(&self) -> bool { + pub(crate) fn is_big_endian(&self) -> bool { self.target_cfg().endian == Endian::Big } - pub fn get_pointer_width(&self) -> u32 { + pub(crate) fn get_pointer_width(&self) -> u32 { *&self.target_cfg().pointer_width } - pub fn can_unwind(&self) -> bool { + pub(crate) fn can_unwind(&self) -> bool { self.target_cfg().panic == PanicStrategy::Unwind } /// Get the list of builtin, 'well known' cfg names - pub fn builtin_cfg_names(&self) -> &HashSet { + pub(crate) fn builtin_cfg_names(&self) -> &HashSet { self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self)) } /// Get the list of crate types that the target platform supports. - pub fn supported_crate_types(&self) -> &HashSet { + pub(crate) fn supported_crate_types(&self) -> &HashSet { self.supported_crate_types.get_or_init(|| supported_crate_types(self)) } - pub fn has_threads(&self) -> bool { + pub(crate) fn has_threads(&self) -> bool { // Wasm targets don't have threads unless `-threads` is in the target // name, such as `wasm32-wasip1-threads`. if self.target.starts_with("wasm") { @@ -807,7 +807,7 @@ impl Config { true } - pub fn has_asm_support(&self) -> bool { + pub(crate) fn has_asm_support(&self) -> bool { // This should match the stable list in `LoweringContext::lower_inline_asm`. static ASM_SUPPORTED_ARCHS: &[&str] = &[ "x86", @@ -826,14 +826,14 @@ impl Config { ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str()) } - pub fn git_config(&self) -> GitConfig<'_> { + pub(crate) fn git_config(&self) -> GitConfig<'_> { GitConfig { nightly_branch: &self.nightly_branch, git_merge_commit_email: &self.git_merge_commit_email, } } - pub fn has_subprocess_support(&self) -> bool { + pub(crate) fn has_subprocess_support(&self) -> bool { // FIXME(#135928): compiletest is always a **host** tool. Building and running an // capability detection executable against the **target** is not trivial. The short term // solution here is to hard-code some targets to allow/deny, unfortunately. @@ -851,26 +851,26 @@ impl Config { /// But we treat it as the parallel frontend being enabled in this case. /// - `1` means single-threaded (parallel frontend disabled). /// - `>1` means an explicitly configured thread count. - pub fn parallel_frontend_enabled(&self) -> bool { + pub(crate) fn parallel_frontend_enabled(&self) -> bool { self.parallel_frontend_threads != 1 } } /// Known widths of `target_has_atomic`. -pub const KNOWN_TARGET_HAS_ATOMIC_WIDTHS: &[&str] = &["8", "16", "32", "64", "128", "ptr"]; +pub(crate) const KNOWN_TARGET_HAS_ATOMIC_WIDTHS: &[&str] = &["8", "16", "32", "64", "128", "ptr"]; #[derive(Debug, Clone)] -pub struct TargetCfgs { - pub current: TargetCfg, - pub all_targets: HashSet, - pub all_archs: HashSet, - pub all_oses: HashSet, - pub all_oses_and_envs: HashSet, - pub all_envs: HashSet, - pub all_abis: HashSet, - pub all_families: HashSet, - pub all_pointer_widths: HashSet, - pub all_rustc_abis: HashSet, +pub(crate) struct TargetCfgs { + pub(crate) current: TargetCfg, + pub(crate) all_targets: HashSet, + pub(crate) all_archs: HashSet, + pub(crate) all_oses: HashSet, + pub(crate) all_oses_and_envs: HashSet, + pub(crate) all_envs: HashSet, + pub(crate) all_abis: HashSet, + pub(crate) all_families: HashSet, + pub(crate) all_pointer_widths: HashSet, + pub(crate) all_rustc_abis: HashSet, } impl TargetCfgs { @@ -1017,7 +1017,7 @@ impl TargetCfgs { #[derive(Clone, Debug, serde::Deserialize)] #[serde(rename_all = "kebab-case")] -pub struct TargetCfg { +pub(crate) struct TargetCfg { pub(crate) arch: String, #[serde(default = "default_os")] pub(crate) os: String, @@ -1080,7 +1080,7 @@ fn default_binary_format_elf() -> Cow<'static, str> { #[derive(Eq, PartialEq, Clone, Debug, Default, serde::Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum Endian { +pub(crate) enum Endian { #[default] Little, Big, @@ -1114,7 +1114,7 @@ fn extract_cfg_name(check_cfg_line: &str) -> Result<&str, &'static str> { Ok(inner[..first_comma].trim()) } -pub const KNOWN_CRATE_TYPES: &[&str] = +pub(crate) const KNOWN_CRATE_TYPES: &[&str] = &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]; fn supported_crate_types(config: &Config) -> HashSet { @@ -1196,7 +1196,7 @@ pub(crate) struct TestPaths { } /// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`. -pub fn expected_output_path( +pub(crate) fn expected_output_path( testpaths: &TestPaths, revision: Option<&str>, compare_mode: &Option, @@ -1217,7 +1217,7 @@ pub fn expected_output_path( testpaths.file.with_extension(extension) } -pub const UI_EXTENSIONS: &[&str] = &[ +pub(crate) const UI_EXTENSIONS: &[&str] = &[ UI_STDERR, UI_SVG, UI_WINDOWS_SVG, @@ -1231,18 +1231,18 @@ pub const UI_EXTENSIONS: &[&str] = &[ UI_COVERAGE, UI_COVERAGE_MAP, ]; -pub const UI_STDERR: &str = "stderr"; -pub const UI_SVG: &str = "svg"; -pub const UI_WINDOWS_SVG: &str = "windows.svg"; -pub const UI_STDOUT: &str = "stdout"; -pub const UI_FIXED: &str = "fixed"; -pub const UI_RUN_STDERR: &str = "run.stderr"; -pub const UI_RUN_STDOUT: &str = "run.stdout"; -pub const UI_STDERR_64: &str = "64bit.stderr"; -pub const UI_STDERR_32: &str = "32bit.stderr"; -pub const UI_STDERR_16: &str = "16bit.stderr"; -pub const UI_COVERAGE: &str = "coverage"; -pub const UI_COVERAGE_MAP: &str = "cov-map"; +pub(crate) const UI_STDERR: &str = "stderr"; +pub(crate) const UI_SVG: &str = "svg"; +pub(crate) const UI_WINDOWS_SVG: &str = "windows.svg"; +pub(crate) const UI_STDOUT: &str = "stdout"; +pub(crate) const UI_FIXED: &str = "fixed"; +pub(crate) const UI_RUN_STDERR: &str = "run.stderr"; +pub(crate) const UI_RUN_STDOUT: &str = "run.stdout"; +pub(crate) const UI_STDERR_64: &str = "64bit.stderr"; +pub(crate) const UI_STDERR_32: &str = "32bit.stderr"; +pub(crate) const UI_STDERR_16: &str = "16bit.stderr"; +pub(crate) const UI_COVERAGE: &str = "coverage"; +pub(crate) const UI_COVERAGE_MAP: &str = "cov-map"; /// Absolute path to the directory where all output for all tests in the given `relative_dir` group /// should reside. Example: @@ -1252,12 +1252,12 @@ pub const UI_COVERAGE_MAP: &str = "cov-map"; /// ``` /// /// This is created early when tests are collected to avoid race conditions. -pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf { +pub(crate) fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf { config.build_test_suite_root.join(relative_dir) } /// Generates a unique name for the test, such as `testname.revision.mode`. -pub fn output_testname_unique( +pub(crate) fn output_testname_unique( config: &Config, testpaths: &TestPaths, revision: Option<&str>, @@ -1274,7 +1274,7 @@ pub fn output_testname_unique( /// Absolute path to the directory where all output for the given /// test/revision should reside. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/ -pub fn output_base_dir( +pub(crate) fn output_base_dir( config: &Config, testpaths: &TestPaths, revision: Option<&str>, @@ -1286,7 +1286,7 @@ pub fn output_base_dir( /// Absolute path to the base filename used as output for the given /// test/revision. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname -pub fn output_base_name( +pub(crate) fn output_base_name( config: &Config, testpaths: &TestPaths, revision: Option<&str>, @@ -1296,7 +1296,7 @@ pub fn output_base_name( /// Absolute path to the directory to use for incremental compilation. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc -pub fn incremental_dir( +pub(crate) fn incremental_dir( config: &Config, testpaths: &TestPaths, revision: Option<&str>, diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index b6a9a5b1b9f5f..036495130f819 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -36,7 +36,7 @@ mod needs; #[cfg(test)] mod tests; -pub struct DirectivesCache { +pub(crate) struct DirectivesCache { /// "Conditions" used by `ignore-*` and `only-*` directives, prepared in /// advance so that they don't have to be evaluated repeatedly. cfg_conditions: cfg::PreparedConditions, @@ -44,7 +44,7 @@ pub struct DirectivesCache { } impl DirectivesCache { - pub fn load(config: &Config) -> Self { + pub(crate) fn load(config: &Config) -> Self { Self { cfg_conditions: cfg::prepare_conditions(config), needs: CachedNeedsConditions::load(config), @@ -82,68 +82,68 @@ impl EarlyProps { #[derive(Clone, Debug)] pub(crate) struct TestProps { // Lines that should be expected, in order, on standard out - pub error_patterns: Vec, + pub(crate) error_patterns: Vec, // Regexes that should be expected, in order, on standard out - pub regex_error_patterns: Vec, + pub(crate) regex_error_patterns: Vec, /// Edition selected by an `//@ edition` directive, if any. /// /// Automatically added to `compile_flags` during directive processing. - pub edition: Option, + pub(crate) edition: Option, // Extra flags to pass to the compiler - pub compile_flags: Vec, + pub(crate) compile_flags: Vec, // Extra flags to pass when the compiled code is run (such as --bench) - pub run_flags: Vec, + pub(crate) run_flags: Vec, /// Extra flags to pass to rustdoc but not the compiler. - pub doc_flags: Vec, + pub(crate) doc_flags: Vec, // If present, the name of a file that this test should match when // pretty-printed - pub pp_exact: Option, + pub(crate) pp_exact: Option, /// Auxiliary crates that should be built and made available to this test. pub(crate) aux: AuxProps, // Environment settings to use for compiling - pub rustc_env: Vec<(String, String)>, + pub(crate) rustc_env: Vec<(String, String)>, // Environment variables to unset prior to compiling. // Variables are unset before applying 'rustc_env'. - pub unset_rustc_env: Vec, + pub(crate) unset_rustc_env: Vec, // Environment settings to use during execution - pub exec_env: Vec<(String, String)>, + pub(crate) exec_env: Vec<(String, String)>, // Environment variables to unset prior to execution. // Variables are unset before applying 'exec_env' - pub unset_exec_env: Vec, + pub(crate) unset_exec_env: Vec, // Build documentation for all specified aux-builds as well - pub build_aux_docs: bool, + pub(crate) build_aux_docs: bool, /// Build the documentation for each crate in a unique output directory. /// Uses `/docs//doc`. - pub unique_doc_out_dir: bool, + pub(crate) unique_doc_out_dir: bool, // Flag to force a crate to be built with the host architecture - pub force_host: bool, + pub(crate) force_host: bool, // Check stdout for error-pattern output as well as stderr - pub check_stdout: bool, + pub(crate) check_stdout: bool, // Check stdout & stderr for output of run-pass test - pub check_run_results: bool, + pub(crate) check_run_results: bool, // For UI tests, allows compiler to generate arbitrary output to stdout - pub dont_check_compiler_stdout: bool, + pub(crate) dont_check_compiler_stdout: bool, // For UI tests, allows compiler to generate arbitrary output to stderr - pub dont_check_compiler_stderr: bool, + pub(crate) dont_check_compiler_stderr: bool, // Don't force a --crate-type=dylib flag on the command line // // Set this for example if you have an auxiliary test file that contains // a proc-macro and needs `#![crate_type = "proc-macro"]`. This ensures // that the aux file is compiled as a `proc-macro` and not as a `dylib`. - pub no_prefer_dynamic: bool, + pub(crate) no_prefer_dynamic: bool, // Which pretty mode are we testing with, default to 'normal' - pub pretty_mode: String, + pub(crate) pretty_mode: String, // Only compare pretty output and don't try compiling - pub pretty_compare_only: bool, + pub(crate) pretty_compare_only: bool, // Patterns which must not appear in the output of a cfail test. - pub forbid_output: Vec, + pub(crate) forbid_output: Vec, // Revisions to test for incremental compilation. - pub revisions: Vec, + pub(crate) revisions: Vec, // Directory (if any) to use for incremental compilation. This is // not set by end-users; rather it is set by the incremental // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) - pub incremental_dir: Option, + pub(crate) incremental_dir: Option, // If `true`, this test will use incremental compilation. // // This can be set manually with the `incremental` directive, or implicitly @@ -158,113 +158,113 @@ pub(crate) struct TestProps { // Compiletest will create the incremental directory, and ensure it is // empty before the test starts. Incremental mode tests will reuse the // incremental directory between passes in the same test. - pub incremental: bool, + pub(crate) incremental: bool, // If `true`, this test is a known bug. // // When set, some requirements are relaxed. Currently, this only means no // error annotations are needed, but this may be updated in the future to // include other relaxations. - pub known_bug: bool, + pub(crate) known_bug: bool, // How far should the test proceed while still passing. pass_mode: Option, // Ignore `--pass` overrides from the command line for this test. ignore_pass: bool, // How far this test should proceed to start failing. - pub fail_mode: Option, + pub(crate) fail_mode: Option, // rustdoc will test the output of the `--test` option - pub check_test_line_numbers_match: bool, + pub(crate) check_test_line_numbers_match: bool, // customized normalization rules - pub normalize_stdout: Vec<(String, String)>, - pub normalize_stderr: Vec<(String, String)>, - pub failure_status: Option, + pub(crate) normalize_stdout: Vec<(String, String)>, + pub(crate) normalize_stderr: Vec<(String, String)>, + pub(crate) failure_status: Option, // For UI tests, allows compiler to exit with arbitrary failure status - pub dont_check_failure_status: bool, + pub(crate) dont_check_failure_status: bool, // Whether or not `rustfix` should apply the `CodeSuggestion`s of this test and compile the // resulting Rust code. - pub run_rustfix: bool, + pub(crate) run_rustfix: bool, // If true, `rustfix` will only apply `MachineApplicable` suggestions. - pub rustfix_only_machine_applicable: bool, - pub assembly_output: Option, + pub(crate) rustfix_only_machine_applicable: bool, + pub(crate) assembly_output: Option, // If true, the test is expected to ICE - pub should_ice: bool, + pub(crate) should_ice: bool, // If true, the stderr is expected to be different across bit-widths. - pub stderr_per_bitwidth: bool, + pub(crate) stderr_per_bitwidth: bool, // The MIR opt to unit test, if any - pub mir_unit_test: Option, + pub(crate) mir_unit_test: Option, // Whether to tell `rustc` to remap the "src base" directory to a fake // directory. - pub remap_src_base: bool, + pub(crate) remap_src_base: bool, /// Extra flags to pass to `llvm-cov` when producing coverage reports. /// Only used by the "coverage-run" test mode. - pub llvm_cov_flags: Vec, + pub(crate) llvm_cov_flags: Vec, /// Extra flags to pass to LLVM's `filecheck` tool, in tests that use it. - pub filecheck_flags: Vec, + pub(crate) filecheck_flags: Vec, /// Don't automatically insert any `--check-cfg` args - pub no_auto_check_cfg: bool, + pub(crate) no_auto_check_cfg: bool, /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios /// that don't otherwise want/need `-Z build-std`. - pub add_minicore: bool, + pub(crate) add_minicore: bool, /// Add these flags to the build of `minicore`. - pub minicore_compile_flags: Vec, + pub(crate) minicore_compile_flags: Vec, /// Whether line annotations are required for the given error kind. - pub dont_require_annotations: HashSet, + pub(crate) dont_require_annotations: HashSet, /// Whether pretty printers should be disabled in gdb. - pub disable_gdb_pretty_printers: bool, + pub(crate) disable_gdb_pretty_printers: bool, /// Compare the output by lines, rather than as a single string. - pub compare_output_by_lines: bool, + pub(crate) compare_output_by_lines: bool, } mod directives { - pub const ERROR_PATTERN: &'static str = "error-pattern"; - pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern"; - pub const COMPILE_FLAGS: &'static str = "compile-flags"; - pub const RUN_FLAGS: &'static str = "run-flags"; - pub const DOC_FLAGS: &'static str = "doc-flags"; - pub const SHOULD_ICE: &'static str = "should-ice"; - pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs"; - pub const UNIQUE_DOC_OUT_DIR: &'static str = "unique-doc-out-dir"; - pub const FORCE_HOST: &'static str = "force-host"; - pub const CHECK_STDOUT: &'static str = "check-stdout"; - pub const CHECK_RUN_RESULTS: &'static str = "check-run-results"; - pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout"; - pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr"; - pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations"; - pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic"; - pub const PRETTY_MODE: &'static str = "pretty-mode"; - pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only"; - pub const AUX_BIN: &'static str = "aux-bin"; - pub const AUX_BUILD: &'static str = "aux-build"; - pub const AUX_CRATE: &'static str = "aux-crate"; - pub const PROC_MACRO: &'static str = "proc-macro"; - pub const AUX_CODEGEN_BACKEND: &'static str = "aux-codegen-backend"; - pub const EXEC_ENV: &'static str = "exec-env"; - pub const RUSTC_ENV: &'static str = "rustc-env"; - pub const UNSET_EXEC_ENV: &'static str = "unset-exec-env"; - pub const UNSET_RUSTC_ENV: &'static str = "unset-rustc-env"; - pub const FORBID_OUTPUT: &'static str = "forbid-output"; - pub const CHECK_TEST_LINE_NUMBERS_MATCH: &'static str = "check-test-line-numbers-match"; - pub const IGNORE_PASS: &'static str = "ignore-pass"; - pub const FAILURE_STATUS: &'static str = "failure-status"; - pub const DONT_CHECK_FAILURE_STATUS: &'static str = "dont-check-failure-status"; - pub const RUN_RUSTFIX: &'static str = "run-rustfix"; - pub const RUSTFIX_ONLY_MACHINE_APPLICABLE: &'static str = "rustfix-only-machine-applicable"; - pub const ASSEMBLY_OUTPUT: &'static str = "assembly-output"; - pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth"; - pub const INCREMENTAL: &'static str = "incremental"; - pub const KNOWN_BUG: &'static str = "known-bug"; - pub const TEST_MIR_PASS: &'static str = "test-mir-pass"; - pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; - pub const LLVM_COV_FLAGS: &'static str = "llvm-cov-flags"; - pub const FILECHECK_FLAGS: &'static str = "filecheck-flags"; - pub const NO_AUTO_CHECK_CFG: &'static str = "no-auto-check-cfg"; - pub const ADD_MINICORE: &'static str = "add-minicore"; - pub const MINICORE_COMPILE_FLAGS: &'static str = "minicore-compile-flags"; - pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers"; - pub const COMPARE_OUTPUT_BY_LINES: &'static str = "compare-output-by-lines"; + pub(crate) const ERROR_PATTERN: &str = "error-pattern"; + pub(crate) const REGEX_ERROR_PATTERN: &str = "regex-error-pattern"; + pub(crate) const COMPILE_FLAGS: &str = "compile-flags"; + pub(crate) const RUN_FLAGS: &str = "run-flags"; + pub(crate) const DOC_FLAGS: &str = "doc-flags"; + pub(crate) const SHOULD_ICE: &str = "should-ice"; + pub(crate) const BUILD_AUX_DOCS: &str = "build-aux-docs"; + pub(crate) const UNIQUE_DOC_OUT_DIR: &str = "unique-doc-out-dir"; + pub(crate) const FORCE_HOST: &str = "force-host"; + pub(crate) const CHECK_STDOUT: &str = "check-stdout"; + pub(crate) const CHECK_RUN_RESULTS: &str = "check-run-results"; + pub(crate) const DONT_CHECK_COMPILER_STDOUT: &str = "dont-check-compiler-stdout"; + pub(crate) const DONT_CHECK_COMPILER_STDERR: &str = "dont-check-compiler-stderr"; + pub(crate) const DONT_REQUIRE_ANNOTATIONS: &str = "dont-require-annotations"; + pub(crate) const NO_PREFER_DYNAMIC: &str = "no-prefer-dynamic"; + pub(crate) const PRETTY_MODE: &str = "pretty-mode"; + pub(crate) const PRETTY_COMPARE_ONLY: &str = "pretty-compare-only"; + pub(crate) const AUX_BIN: &str = "aux-bin"; + pub(crate) const AUX_BUILD: &str = "aux-build"; + pub(crate) const AUX_CRATE: &str = "aux-crate"; + pub(crate) const PROC_MACRO: &str = "proc-macro"; + pub(crate) const AUX_CODEGEN_BACKEND: &str = "aux-codegen-backend"; + pub(crate) const EXEC_ENV: &str = "exec-env"; + pub(crate) const RUSTC_ENV: &str = "rustc-env"; + pub(crate) const UNSET_EXEC_ENV: &str = "unset-exec-env"; + pub(crate) const UNSET_RUSTC_ENV: &str = "unset-rustc-env"; + pub(crate) const FORBID_OUTPUT: &str = "forbid-output"; + pub(crate) const CHECK_TEST_LINE_NUMBERS_MATCH: &str = "check-test-line-numbers-match"; + pub(crate) const IGNORE_PASS: &str = "ignore-pass"; + pub(crate) const FAILURE_STATUS: &str = "failure-status"; + pub(crate) const DONT_CHECK_FAILURE_STATUS: &str = "dont-check-failure-status"; + pub(crate) const RUN_RUSTFIX: &str = "run-rustfix"; + pub(crate) const RUSTFIX_ONLY_MACHINE_APPLICABLE: &str = "rustfix-only-machine-applicable"; + pub(crate) const ASSEMBLY_OUTPUT: &str = "assembly-output"; + pub(crate) const STDERR_PER_BITWIDTH: &str = "stderr-per-bitwidth"; + pub(crate) const INCREMENTAL: &str = "incremental"; + pub(crate) const KNOWN_BUG: &str = "known-bug"; + pub(crate) const TEST_MIR_PASS: &str = "test-mir-pass"; + pub(crate) const REMAP_SRC_BASE: &str = "remap-src-base"; + pub(crate) const LLVM_COV_FLAGS: &str = "llvm-cov-flags"; + pub(crate) const FILECHECK_FLAGS: &str = "filecheck-flags"; + pub(crate) const NO_AUTO_CHECK_CFG: &str = "no-auto-check-cfg"; + pub(crate) const ADD_MINICORE: &str = "add-minicore"; + pub(crate) const MINICORE_COMPILE_FLAGS: &str = "minicore-compile-flags"; + pub(crate) const DISABLE_GDB_PRETTY_PRINTERS: &str = "disable-gdb-pretty-printers"; + pub(crate) const COMPARE_OUTPUT_BY_LINES: &str = "compare-output-by-lines"; } impl TestProps { - pub fn new() -> Self { + pub(crate) fn new() -> Self { TestProps { error_patterns: vec![], regex_error_patterns: vec![], @@ -322,7 +322,7 @@ impl TestProps { } } - pub fn from_aux_file( + pub(crate) fn from_aux_file( &self, testfile: &Utf8Path, revision: Option<&str>, @@ -338,7 +338,7 @@ impl TestProps { props } - pub fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self { + pub(crate) fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self { let mut props = TestProps::new(); props.load_from(testfile, revision, config); props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string())); @@ -475,7 +475,7 @@ impl TestProps { } } - pub fn pass_mode(&self, config: &Config) -> Option { + pub(crate) fn pass_mode(&self, config: &Config) -> Option { if !self.ignore_pass && self.fail_mode.is_none() { if let mode @ Some(_) = config.force_pass_mode { return mode; @@ -485,7 +485,7 @@ impl TestProps { } // does not consider CLI override for pass mode - pub fn local_pass_mode(&self) -> Option { + pub(crate) fn local_pass_mode(&self) -> Option { self.pass_mode } @@ -872,7 +872,7 @@ fn parse_normalize_rule(raw_value: &str) -> Option<(String, String)> { /// error handling strategy. /// /// FIXME(jieyouxu): improve error handling -pub fn extract_llvm_version(version: &str) -> Version { +pub(crate) fn extract_llvm_version(version: &str) -> Version { // The version substring we're interested in usually looks like the `1.2.3`, without any of the // fancy suffix like `-rc1` or `meow`. let version = version.trim(); @@ -895,7 +895,7 @@ pub fn extract_llvm_version(version: &str) -> Version { } } -pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { +pub(crate) fn extract_llvm_version_from_binary(binary_path: &str) -> Option { let output = Command::new(binary_path).arg("--version").output().ok()?; if !output.status.success() { return None; diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 0e7e370adbd41..b88ddc00a535a 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -13,16 +13,16 @@ mod tests; /// The value of an `aux-crate` directive. #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct AuxCrate { +pub(crate) struct AuxCrate { /// Contains `--extern` modifiers, if any. See the tracking issue for more /// info: /// With `aux-crate: noprelude:foo=bar.rs` this will be `noprelude`. - pub extern_modifiers: Option, + pub(crate) extern_modifiers: Option, /// With `aux-crate: foo=bar.rs` this will be `foo`. /// With `aux-crate: noprelude:foo=bar.rs` this will be `foo`. - pub name: String, + pub(crate) name: String, /// With `aux-crate: foo=bar.rs` this will be `bar.rs`. - pub path: String, + pub(crate) path: String, } /// The value of a `proc-macro` directive. @@ -31,9 +31,9 @@ pub(crate) struct ProcMacro { /// Contains `--extern` modifiers, if any. See the tracking issue for more /// info: /// With `proc-macro: noprelude:bar.rs` this will be `noprelude`. - pub extern_modifiers: Option, + pub(crate) extern_modifiers: Option, /// With `proc-macro: bar.rs` this will be `bar.rs`. - pub path: String, + pub(crate) path: String, } /// Properties parsed from `aux-*` test directives. diff --git a/src/tools/compiletest/src/edition.rs b/src/tools/compiletest/src/edition.rs index 36550cf5b2b95..2f5b92ee29a65 100644 --- a/src/tools/compiletest/src/edition.rs +++ b/src/tools/compiletest/src/edition.rs @@ -1,7 +1,7 @@ use crate::fatal; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum Edition { +pub(crate) enum Edition { // Note that the ordering here is load-bearing, as we want the future edition to be greater than // any year-based edition. Year(u32), @@ -23,7 +23,7 @@ impl From for Edition { } } -pub fn parse_edition(mut input: &str) -> Edition { +pub(crate) fn parse_edition(mut input: &str) -> Edition { input = input.trim(); if input == "future" { Edition::Future diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 9fa26305f6b0b..81513afc9a2d2 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -9,7 +9,7 @@ use regex::Regex; use tracing::*; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ErrorKind { +pub(crate) enum ErrorKind { Help, Error, Note, @@ -21,7 +21,7 @@ pub enum ErrorKind { } impl ErrorKind { - pub fn from_compiler_str(s: &str) -> ErrorKind { + pub(crate) fn from_compiler_str(s: &str) -> ErrorKind { match s { "help" => ErrorKind::Help, "error" | "error: internal compiler error" => ErrorKind::Error, @@ -45,7 +45,7 @@ impl ErrorKind { }) } - pub fn expect_from_user_str(s: &str) -> ErrorKind { + pub(crate) fn expect_from_user_str(s: &str) -> ErrorKind { ErrorKind::from_user_str(s).unwrap_or_else(|| { panic!( "unexpected diagnostic kind `{s}`, expected \ @@ -70,16 +70,16 @@ impl fmt::Display for ErrorKind { } #[derive(Debug)] -pub struct Error { - pub line_num: Option, - pub column_num: Option, +pub(crate) struct Error { + pub(crate) line_num: Option, + pub(crate) column_num: Option, /// What kind of message we expect (e.g., warning, error, suggestion). - pub kind: ErrorKind, - pub msg: String, + pub(crate) kind: ErrorKind, + pub(crate) msg: String, /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations /// are not mandatory, even if they would otherwise be mandatory for primary errors. /// Only makes sense for "actual" errors, not for "expected" errors. - pub require_annotation: bool, + pub(crate) require_annotation: bool, } /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" @@ -92,7 +92,7 @@ pub struct Error { /// /// If revision is not None, then we look /// for `//[X]~` instead, where `X` is the current revision. -pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec { +pub(crate) fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec { let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap()); // `last_nonfollow_error` tracks the most recently seen diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index a8e6416e56c84..cf24d1140dd71 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -83,14 +83,14 @@ struct DiagnosticCode { code: String, } -pub fn rustfix_diagnostics_only(output: &str) -> String { +pub(crate) fn rustfix_diagnostics_only(output: &str) -> String { output .lines() .filter(|line| line.starts_with('{') && serde_json::from_str::(line).is_ok()) .collect() } -pub fn extract_rendered(output: &str) -> String { +pub(crate) fn extract_rendered(output: &str) -> String { output .lines() .filter_map(|line| { @@ -137,7 +137,7 @@ pub fn extract_rendered(output: &str) -> String { .collect() } -pub fn parse_output(file_name: &str, output: &str) -> Vec { +pub(crate) fn parse_output(file_name: &str, output: &str) -> Vec { let mut errors = Vec::new(); for line in output.lines() { // Compiler can emit non-json lines in non-`--error-format=json` modes, diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 6dae2ca0b4759..a23e3bb9a90e4 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,9 +1,13 @@ #![crate_name = "compiletest"] +#![warn(unreachable_pub)] #[cfg(test)] mod tests; +// Public modules needed by the compiletest binary or by `rustdoc-gui-test`. pub mod cli; +pub mod rustdoc_gui_test; + mod common; mod debuggers; mod diagnostics; @@ -17,7 +21,6 @@ mod panic_hook; mod raise_fd_limit; mod read2; mod runtest; -pub mod rustdoc_gui_test; mod util; use core::panic; diff --git a/src/tools/compiletest/src/output_capture.rs b/src/tools/compiletest/src/output_capture.rs index de1aea11ade9b..4956c47b16deb 100644 --- a/src/tools/compiletest/src/output_capture.rs +++ b/src/tools/compiletest/src/output_capture.rs @@ -2,7 +2,7 @@ use std::fmt; use std::panic::RefUnwindSafe; use std::sync::Mutex; -pub trait ConsoleOut: fmt::Debug + RefUnwindSafe { +pub(crate) trait ConsoleOut: fmt::Debug + RefUnwindSafe { fn write_fmt(&self, args: fmt::Arguments<'_>); } diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index 653b125a6b413..1c86eaf7c7c98 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -7,7 +7,7 @@ #[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] // FIXME(#139616): document caller contract. -pub unsafe fn raise_fd_limit() { +pub(crate) unsafe fn raise_fd_limit() { use std::ptr::null_mut; use std::{cmp, io}; @@ -54,4 +54,4 @@ pub unsafe fn raise_fd_limit() { } #[cfg(not(target_vendor = "apple"))] -pub unsafe fn raise_fd_limit() {} +pub(crate) unsafe fn raise_fd_limit() {} diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 2213dd07160a7..e5d1b0ade6eaf 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -7,15 +7,15 @@ mod tests; use std::io::{self, Write}; use std::process::{Child, Output}; -pub use self::imp::read2; +use self::imp::read2; #[derive(Copy, Clone, Debug)] -pub enum Truncated { +pub(crate) enum Truncated { Yes, No, } -pub fn read2_abbreviated( +pub(crate) fn read2_abbreviated( mut child: Child, filter_paths_from_len: &[String], ) -> io::Result<(Output, Truncated)> { @@ -138,7 +138,7 @@ mod imp { use std::io::{self, Read}; use std::process::{ChildStderr, ChildStdout}; - pub fn read2( + pub(crate) fn read2( out_pipe: ChildStdout, err_pipe: ChildStderr, data: &mut dyn FnMut(bool, &mut Vec, bool), @@ -160,7 +160,7 @@ mod imp { use std::process::{ChildStderr, ChildStdout}; use std::{io, mem}; - pub fn read2( + pub(crate) fn read2( mut out_pipe: ChildStdout, mut err_pipe: ChildStderr, data: &mut dyn FnMut(bool, &mut Vec, bool), @@ -247,7 +247,7 @@ mod imp { done: bool, } - pub fn read2( + pub(crate) fn read2( out_pipe: ChildStdout, err_pipe: ChildStderr, data: &mut dyn FnMut(bool, &mut Vec, bool), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index da4ec440bb443..53599179cfce0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -106,7 +106,7 @@ fn dylib_name(name: &str) -> String { format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) } -pub fn run( +pub(crate) fn run( config: &Config, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut, @@ -181,7 +181,7 @@ pub fn run( cx.create_stamp(); } -pub fn compute_stamp_hash(config: &Config) -> String { +pub(crate) fn compute_stamp_hash(config: &Config) -> String { let mut hash = DefaultHasher::new(); config.stage_id.hash(&mut hash); config.run.hash(&mut hash); @@ -2985,7 +2985,7 @@ struct ProcArgs { } #[derive(Debug)] -pub struct ProcRes { +pub(crate) struct ProcRes { status: ExitStatus, stdout: String, stderr: String, @@ -2995,7 +2995,7 @@ pub struct ProcRes { impl ProcRes { #[must_use] - pub fn format_info(&self) -> String { + pub(crate) fn format_info(&self) -> String { fn render(name: &str, contents: &str) -> String { let contents = json::extract_rendered(contents); let contents = contents.trim_end(); diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs index 8418dcbaf9639..97ccdb989d437 100644 --- a/src/tools/compiletest/src/runtest/compute_diff.rs +++ b/src/tools/compiletest/src/runtest/compute_diff.rs @@ -1,16 +1,16 @@ use std::collections::VecDeque; #[derive(Debug, PartialEq)] -pub enum DiffLine { +pub(crate) enum DiffLine { Context(String), Expected(String), Resulting(String), } #[derive(Debug, PartialEq)] -pub struct Mismatch { - pub line_number: u32, - pub lines: Vec, +pub(crate) struct Mismatch { + pub(crate) line_number: u32, + pub(crate) lines: Vec, } impl Mismatch { @@ -20,7 +20,7 @@ impl Mismatch { } // Produces a diff between the expected output and actual output. -pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { +pub(crate) fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { let mut line_number = 1; let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); let mut lines_since_mismatch = context_size + 1; diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 70996004a3366..a28e38a7db5d7 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -8,11 +8,11 @@ use crate::directives::{LineNumber, line_directive}; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output -pub(super) struct DebuggerCommands { +pub(crate) struct DebuggerCommands { /// Commands for the debuuger - pub commands: Vec, + pub(crate) commands: Vec, /// Lines to insert breakpoints at - pub breakpoint_lines: Vec, + pub(crate) breakpoint_lines: Vec, /// Contains the source line number to check and the line itself check_lines: Vec<(LineNumber, String)>, /// Source file name @@ -22,7 +22,7 @@ pub(super) struct DebuggerCommands { } impl DebuggerCommands { - pub fn parse_from( + pub(crate) fn parse_from( file: &Utf8Path, debugger_prefix: &str, test_revision: Option<&str>, @@ -75,7 +75,7 @@ impl DebuggerCommands { /// Given debugger output and lines to check, ensure that every line is /// contained in the debugger output. The check lines need to be found in /// order, but there can be extra lines between. - pub fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String> { + pub(crate) fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String> { // (src_lineno, ck_line) that we did find let mut found = vec![]; // (src_lineno, ck_line) that we couldn't find diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index a189c1d1c2dfc..26d2edaedbbe2 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -6,7 +6,7 @@ use camino::{Utf8Path, Utf8PathBuf}; #[cfg(test)] mod tests; -pub fn make_new_path(path: &str) -> String { +pub(crate) fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to // maintain the current value while adding our own @@ -16,14 +16,14 @@ pub fn make_new_path(path: &str) -> String { } } -pub fn lib_path_env_var() -> &'static str { +pub(crate) fn lib_path_env_var() -> &'static str { "PATH" } fn path_div() -> &'static str { ";" } -pub trait Utf8PathBufExt { +pub(crate) trait Utf8PathBufExt { /// Append an extension to the path, even if it already has one. fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf; } @@ -44,7 +44,7 @@ impl Utf8PathBufExt for Utf8PathBuf { } /// The name of the environment variable that holds dynamic library locations. -pub fn dylib_env_var() -> &'static str { +pub(crate) fn dylib_env_var() -> &'static str { if cfg!(any(windows, target_os = "cygwin")) { "PATH" } else if cfg!(target_vendor = "apple") { @@ -60,7 +60,7 @@ pub fn dylib_env_var() -> &'static str { /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. /// If the dylib_path_var is already set for this cmd, the old value will be overwritten! -pub fn add_dylib_path( +pub(crate) fn add_dylib_path( cmd: &mut Command, paths: impl Iterator>, ) { @@ -70,7 +70,7 @@ pub fn add_dylib_path( cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap()); } -pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> { +pub(crate) fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> { std::fs::create_dir_all(dst.as_std_path())?; for entry in std::fs::read_dir(src.as_std_path())? { let entry = entry?; From b651ab0d6c931665b52e0b8caedcbb2ddea4991d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Mar 2026 10:55:27 +1100 Subject: [PATCH 08/11] Add a useful comment. I previously tried to remove this field because it seemed useless. --- compiler/rustc_macros/src/query.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 75be5a1686035..950f4565a3dae 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -128,6 +128,7 @@ impl Parse for List { } struct Desc { + // This ident is always `desc` but we need it for its span, for `crate::query::modifiers`. modifier: Ident, expr_list: Punctuated, } From aebce4c73f1321d6ef30dfc74d4c99ccae174c11 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 2 Apr 2026 11:24:03 +1100 Subject: [PATCH 09/11] Process query modifiers in alphabetical order everywhere. --- compiler/rustc_macros/src/query.rs | 43 ++++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 950f4565a3dae..a44efc97dc8ff 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -149,15 +149,17 @@ struct QueryModifiers { } fn parse_query_modifiers(input: ParseStream<'_>) -> Result { + // tidy-alphabetical-start let mut arena_cache = None; let mut cache_on_disk = None; + let mut depth_limit = None; let mut desc = None; + let mut eval_always = None; + let mut feedable = None; let mut no_force = None; let mut no_hash = None; - let mut eval_always = None; - let mut depth_limit = None; let mut separate_provide_extern = None; - let mut feedable = None; + // tidy-alphabetical-end while !input.is_empty() { let modifier: Ident = input.parse()?; @@ -171,29 +173,29 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { }; } - if modifier == "desc" { + if modifier == "arena_cache" { + try_insert!(arena_cache = modifier); + } else if modifier == "cache_on_disk" { + try_insert!(cache_on_disk = modifier); + } else if modifier == "depth_limit" { + try_insert!(depth_limit = modifier); + } else if modifier == "desc" { // Parse a description modifier like: // `desc { "foo {}", tcx.item_path(key) }` let attr_content; braced!(attr_content in input); let expr_list = attr_content.parse_terminated(Expr::parse, Token![,])?; try_insert!(desc = Desc { modifier, expr_list }); - } else if modifier == "cache_on_disk" { - try_insert!(cache_on_disk = modifier); - } else if modifier == "arena_cache" { - try_insert!(arena_cache = modifier); + } else if modifier == "eval_always" { + try_insert!(eval_always = modifier); + } else if modifier == "feedable" { + try_insert!(feedable = modifier); } else if modifier == "no_force" { try_insert!(no_force = modifier); } else if modifier == "no_hash" { try_insert!(no_hash = modifier); - } else if modifier == "eval_always" { - try_insert!(eval_always = modifier); - } else if modifier == "depth_limit" { - try_insert!(depth_limit = modifier); } else if modifier == "separate_provide_extern" { try_insert!(separate_provide_extern = modifier); - } else if modifier == "feedable" { - try_insert!(feedable = modifier); } else { return Err(Error::new(modifier.span(), "unknown query modifier")); } @@ -202,15 +204,17 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { return Err(input.error("no description provided")); }; Ok(QueryModifiers { + // tidy-alphabetical-start arena_cache, cache_on_disk, + depth_limit, desc, + eval_always, + feedable, no_force, no_hash, - eval_always, - depth_limit, separate_provide_extern, - feedable, + // tidy-alphabetical-end }) } @@ -248,15 +252,18 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { // tidy-alphabetical-end } = &query.modifiers; + // tidy-alphabetical-start let arena_cache = arena_cache.is_some(); let cache_on_disk = cache_on_disk.is_some(); let depth_limit = depth_limit.is_some(); + // `desc` is not handled here let eval_always = eval_always.is_some(); let feedable = feedable.is_some(); let no_force = no_force.is_some(); let no_hash = no_hash.is_some(); let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty); let separate_provide_extern = separate_provide_extern.is_some(); + // tidy-alphabetical-end // Giving an input span to the modifier names in the modifier list seems // to give slightly more helpful errors when one of the callback macros @@ -269,6 +276,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { arena_cache: #arena_cache, cache_on_disk: #cache_on_disk, depth_limit: #depth_limit, + // `desc` is not handled here eval_always: #eval_always, feedable: #feedable, no_force: #no_force, @@ -367,6 +375,7 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke arena_cache, cache_on_disk, depth_limit, + // `desc` is handled above eval_always, feedable, no_force, From d9137667574db8fd54e0766f492ff5eff236ab44 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 16 Mar 2026 19:17:58 +1100 Subject: [PATCH 10/11] Remove the `_description_fns` module. `rustc_queries` generates a macro and two modules. One of the modules looks like this: ``` mod _description_fns { ... #[allow(unused_variables)] pub fn hir_module_items<'tcx>(tcx: TyCtxt<'tcx>, key: LocalModDefId) -> String { format!("getting HIR module items in `{}`", tcx.def_path_str(key)) } ... } ``` Members of this module are then used in `TaggedQueryKey::description`. This commit removes the `_description_fns` module entirely. For each query we now instead generate a description closure that is used instead. This closure is passed in the modifiers list. This change simplifies `rustc_queries` quite a bit. It requires adding another query modifier, but query modifiers are how other query-specific details are already passed to the declarative macros, so it's more consistent. --- compiler/rustc_macros/src/query.rs | 63 +++++-------------- compiler/rustc_middle/src/query/plumbing.rs | 4 +- .../rustc_query_impl/src/dep_kind_vtables.rs | 1 + compiler/rustc_query_impl/src/query_impl.rs | 1 + 4 files changed, 18 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index a44efc97dc8ff..6960920367ffe 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -243,7 +243,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { arena_cache, cache_on_disk, depth_limit, - desc: _, + desc, eval_always, feedable, no_force, @@ -256,7 +256,18 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { let arena_cache = arena_cache.is_some(); let cache_on_disk = cache_on_disk.is_some(); let depth_limit = depth_limit.is_some(); - // `desc` is not handled here + let desc = { + // Put a description closure in the `desc` modifier. + let key_pat = &query.key_pat; + let key_ty = &query.key_ty; + let desc_expr_list = &desc.expr_list; + quote! { + { + #[allow(unused_variables)] + |tcx: TyCtxt<'tcx>, #key_pat: #key_ty| format!(#desc_expr_list) + } + } + }; let eval_always = eval_always.is_some(); let feedable = feedable.is_some(); let no_force = no_force.is_some(); @@ -276,7 +287,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { arena_cache: #arena_cache, cache_on_disk: #cache_on_disk, depth_limit: #depth_limit, - // `desc` is not handled here + desc: #desc, eval_always: #eval_always, feedable: #feedable, no_force: #no_force, @@ -314,37 +325,6 @@ fn doc_comment_from_desc(list: &Punctuated) -> Result(tcx: TyCtxt<'tcx>, #key_pat: #key_ty) -> String { - format!(#expr_list) - } - }; - - streams.description_fns_stream.extend(quote! { - #desc - }); -} - /// Add hints for rust-analyzer fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::TokenStream) { // Add links to relevant modifiers @@ -419,7 +399,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut non_query_stream = quote! {}; - let mut helpers = HelperTokenStreams::default(); let mut analyzer_stream = quote! {}; let mut errors = quote! {}; @@ -472,11 +451,8 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } add_to_analyzer_stream(&query, &mut analyzer_stream); - make_helpers_for_query(&query, &mut helpers); } - let HelperTokenStreams { description_fns_stream } = helpers; - TokenStream::from(quote! { /// Higher-order macro that invokes the specified macro with (a) a list of all query /// signatures (including modifiers), and (b) a list of non-query names. This allows @@ -500,17 +476,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { #analyzer_stream } - /// Functions that format a human-readable description of each query - /// and its key, as specified by the `desc` query modifier. - /// - /// (The leading `_` avoids collisions with actual query names when - /// expanded in `rustc_middle::queries`, and makes this macro-generated - /// module easier to search for.) - pub mod _description_fns { - use super::*; - #description_fns_stream - } - #errors }) } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 2e1e614b8fb4c..11f66f10cd549 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -301,6 +301,7 @@ macro_rules! define_callbacks { arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, depth_limit: $depth_limit:literal, + desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, no_force: $no_force:literal, @@ -435,8 +436,7 @@ macro_rules! define_callbacks { pub fn description(&self, tcx: TyCtxt<'tcx>) -> String { let (name, description) = ty::print::with_no_queries!(match self { $( - TaggedQueryKey::$name(key) => - (stringify!($name), _description_fns::$name(tcx, *key)), + TaggedQueryKey::$name(key) => (stringify!($name), ($desc)(tcx, *key)), )* }); if tcx.sess.verbose_internals() { diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index b70fe3008cb10..e0d3575863674 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -135,6 +135,7 @@ macro_rules! define_dep_kind_vtables { arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, depth_limit: $depth_limit:literal, + desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, no_force: $no_force:literal, diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs index 2d3dae04181e5..c1e7f3ef3cdb6 100644 --- a/compiler/rustc_query_impl/src/query_impl.rs +++ b/compiler/rustc_query_impl/src/query_impl.rs @@ -19,6 +19,7 @@ macro_rules! define_queries { arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, depth_limit: $depth_limit:literal, + desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, no_force: $no_force:literal, From 15c6e6e0925aea95e21adad02a992f070dca0002 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Apr 2026 22:01:00 +1100 Subject: [PATCH 11/11] Add a `handle_cycle_error` query modifier. This modifier indicates that a query has a custom handler for cycles. That custom handler must be found at `rustc_query_impl::handle_cycle_error::$name`. This eliminates the need for `specialize_query_vtables`, which is the current hack to install custom handlers. It's more lines of code in total, but indicating special treatment of a query via a modifier in `queries.rs` is more consistent with how other aspects of queries are handled. --- compiler/rustc_macros/src/query.rs | 9 +++ compiler/rustc_middle/src/queries.rs | 5 ++ compiler/rustc_middle/src/query/modifiers.rs | 8 +++ compiler/rustc_middle/src/query/plumbing.rs | 1 + .../rustc_query_impl/src/dep_kind_vtables.rs | 1 + .../src/handle_cycle_error.rs | 71 +++++++++++-------- compiler/rustc_query_impl/src/lib.rs | 4 +- compiler/rustc_query_impl/src/query_impl.rs | 12 ++-- 8 files changed, 74 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 6960920367ffe..3880894572c93 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -142,6 +142,7 @@ struct QueryModifiers { desc: Desc, eval_always: Option, feedable: Option, + handle_cycle_error: Option, no_force: Option, no_hash: Option, separate_provide_extern: Option, @@ -156,6 +157,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut desc = None; let mut eval_always = None; let mut feedable = None; + let mut handle_cycle_error = None; let mut no_force = None; let mut no_hash = None; let mut separate_provide_extern = None; @@ -190,6 +192,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(eval_always = modifier); } else if modifier == "feedable" { try_insert!(feedable = modifier); + } else if modifier == "handle_cycle_error" { + try_insert!(handle_cycle_error = modifier); } else if modifier == "no_force" { try_insert!(no_force = modifier); } else if modifier == "no_hash" { @@ -211,6 +215,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { desc, eval_always, feedable, + handle_cycle_error, no_force, no_hash, separate_provide_extern, @@ -246,6 +251,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { desc, eval_always, feedable, + handle_cycle_error, no_force, no_hash, separate_provide_extern, @@ -270,6 +276,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { }; let eval_always = eval_always.is_some(); let feedable = feedable.is_some(); + let handle_cycle_error = handle_cycle_error.is_some(); let no_force = no_force.is_some(); let no_hash = no_hash.is_some(); let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty); @@ -290,6 +297,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { desc: #desc, eval_always: #eval_always, feedable: #feedable, + handle_cycle_error: #handle_cycle_error, no_force: #no_force, no_hash: #no_hash, returns_error_guaranteed: #returns_error_guaranteed, @@ -358,6 +366,7 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke // `desc` is handled above eval_always, feedable, + handle_cycle_error, no_force, no_hash, separate_provide_extern, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 35e33fd2d5457..63be8a63e9f27 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -583,6 +583,7 @@ rustc_queries! { // messages about cycles that then abort.) query check_representability(key: LocalDefId) { desc { "checking if `{}` is representable", tcx.def_path_str(key) } + handle_cycle_error // We don't want recursive representability calls to be forced with // incremental compilation because, if a cycle occurs, we need the // entire cycle to be in memory for diagnostics. @@ -593,6 +594,7 @@ rustc_queries! { /// details, particularly on the modifiers. query check_representability_adt_ty(key: Ty<'tcx>) { desc { "checking if `{}` is representable", key } + handle_cycle_error no_force } @@ -1032,6 +1034,7 @@ rustc_queries! { query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { desc { "computing the variances of `{}`", tcx.def_path_str(def_id) } cache_on_disk + handle_cycle_error separate_provide_extern } @@ -1164,6 +1167,7 @@ rustc_queries! { query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { desc { "computing function signature of `{}`", tcx.def_path_str(key) } cache_on_disk + handle_cycle_error separate_provide_extern } @@ -1756,6 +1760,7 @@ rustc_queries! { ) -> Result, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } + handle_cycle_error } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 2d22a548b7351..4fd91caa94cd7 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -58,6 +58,14 @@ pub(crate) struct eval_always; /// Generate a `feed` method to set the query's value from another query. pub(crate) struct feedable; +/// # `handle_cycle_error` query modifier +/// +/// The default behaviour for a query cycle is to emit a cycle error and halt +/// compilation. Queries with this modifier will instead use a custom handler, +/// which must be provided at `rustc_query_impl::handle_cycle_error::$name`, +/// where `$name` is the query name. +pub(crate) struct handle_cycle_error; + /// # `no_force` query modifier /// /// Dep nodes of queries with this modifier will never be "forced" when trying diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 11f66f10cd549..6b207be245ba7 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -304,6 +304,7 @@ macro_rules! define_callbacks { desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, + handle_cycle_error: $handle_cycle_error:literal, no_force: $no_force:literal, no_hash: $no_hash:literal, returns_error_guaranteed: $returns_error_guaranteed:literal, diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index e0d3575863674..d12db3784f711 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -138,6 +138,7 @@ macro_rules! define_dep_kind_vtables { desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, + handle_cycle_error: $handle_cycle_error:literal, no_force: $no_force:literal, no_hash: $no_hash:literal, returns_error_guaranteed: $returns_error_guaranteed:literal, diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs index 22f8ac9837f6d..07565254969c8 100644 --- a/compiler/rustc_query_impl/src/handle_cycle_error.rs +++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs @@ -9,48 +9,29 @@ use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_e use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::bug; -use rustc_middle::queries::{QueryVTables, TaggedQueryKey}; +use rustc_middle::queries::TaggedQueryKey; use rustc_middle::query::Cycle; -use rustc_middle::query::erase::erase_val; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; use crate::job::create_cycle_error; -pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { - vtables.fn_sig.handle_cycle_error_fn = |tcx, key, _, err| { - let guar = err.delay_as_bug(); - erase_val(fn_sig(tcx, key, guar)) - }; - - vtables.check_representability.handle_cycle_error_fn = - |tcx, _, cycle, _err| check_representability(tcx, cycle); - - vtables.check_representability_adt_ty.handle_cycle_error_fn = - |tcx, _, cycle, _err| check_representability(tcx, cycle); - - vtables.variances_of.handle_cycle_error_fn = |tcx, key, _, err| { - let _guar = err.delay_as_bug(); - erase_val(variances_of(tcx, key)) - }; - - vtables.layout_of.handle_cycle_error_fn = |tcx, _, cycle, err| { - let _guar = err.delay_as_bug(); - erase_val(Err(layout_of(tcx, cycle))) - } -} - +// Default cycle handler used for all queries that don't use the `handle_cycle_error` query +// modifier. pub(crate) fn default(err: Diag<'_>) -> ! { let guar = err.emit(); guar.raise_fatal() } -fn fn_sig<'tcx>( +pub(crate) fn fn_sig<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - guar: ErrorGuaranteed, + _: Cycle<'tcx>, + err: Diag<'_>, ) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { + let guar = err.delay_as_bug(); + let err = Ty::new_error(tcx, guar); let arity = if let Some(node) = tcx.hir_get_if_local(def_id) @@ -71,7 +52,25 @@ fn fn_sig<'tcx>( ))) } -fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! { +pub(crate) fn check_representability<'tcx>( + tcx: TyCtxt<'tcx>, + _key: LocalDefId, + cycle: Cycle<'tcx>, + _err: Diag<'_>, +) { + check_representability_inner(tcx, cycle); +} + +pub(crate) fn check_representability_adt_ty<'tcx>( + tcx: TyCtxt<'tcx>, + _key: Ty<'tcx>, + cycle: Cycle<'tcx>, + _err: Diag<'_>, +) { + check_representability_inner(tcx, cycle); +} + +fn check_representability_inner<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for frame in &cycle.frames { @@ -102,7 +101,13 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! { guar.raise_fatal() } -fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] { +pub(crate) fn variances_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + _cycle: Cycle<'tcx>, + err: Diag<'_>, +) -> &'tcx [ty::Variance] { + let _guar = err.delay_as_bug(); let n = tcx.generics_of(def_id).own_params.len(); tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n)) } @@ -126,7 +131,13 @@ fn search_for_cycle_permutation( otherwise() } -fn layout_of<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> &'tcx ty::layout::LayoutError<'tcx> { +pub(crate) fn layout_of<'tcx>( + tcx: TyCtxt<'tcx>, + _key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, + cycle: Cycle<'tcx>, + err: Diag<'_>, +) -> Result, &'tcx ty::layout::LayoutError<'tcx>> { + let _guar = err.delay_as_bug(); let diag = search_for_cycle_permutation( &cycle.frames, |frames| { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index de03b48394b10..27bfe1451f64f 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -48,11 +48,9 @@ pub fn query_system<'tcx>( on_disk_cache: Option, incremental: bool, ) -> QuerySystem<'tcx> { - let mut query_vtables = query_impl::make_query_vtables(incremental); - handle_cycle_error::specialize_query_vtables(&mut query_vtables); QuerySystem { arenas: Default::default(), - query_vtables, + query_vtables: query_impl::make_query_vtables(incremental), side_effects: Default::default(), on_disk_cache, local_providers, diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs index c1e7f3ef3cdb6..101bf2c4e80f7 100644 --- a/compiler/rustc_query_impl/src/query_impl.rs +++ b/compiler/rustc_query_impl/src/query_impl.rs @@ -22,6 +22,7 @@ macro_rules! define_queries { desc: $desc:expr, eval_always: $eval_always:literal, feedable: $feedable:literal, + handle_cycle_error: $handle_cycle_error:literal, no_force: $no_force:literal, no_hash: $no_hash:literal, returns_error_guaranteed: $returns_error_guaranteed:literal, @@ -144,7 +145,6 @@ macro_rules! define_queries { -> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>> { use rustc_middle::queries::$name::Value; - QueryVTable { name: stringify!($name), eval_always: $eval_always, @@ -177,9 +177,13 @@ macro_rules! define_queries { #[cfg(not($cache_on_disk))] try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None, - // The default just emits `err` and then aborts. - // `handle_cycle_error::specialize_query_vtables` overwrites this default - // for certain queries. + #[cfg($handle_cycle_error)] + handle_cycle_error_fn: |tcx, key, cycle, err| { + use rustc_middle::query::erase::erase_val; + + erase_val($crate::handle_cycle_error::$name(tcx, key, cycle, err)) + }, + #[cfg(not($handle_cycle_error))] handle_cycle_error_fn: |_tcx, _key, _cycle, err| { $crate::handle_cycle_error::default(err) },