From 7668154418edb8e61c1cec5e5ff05e5430f73d34 Mon Sep 17 00:00:00 2001 From: Aaryan Agrawal Date: Fri, 2 Jan 2026 14:09:39 +0530 Subject: [PATCH 01/25] triagebot: add autolabel for rustdoc JS files --- triagebot.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index fb6660b9dd038..b17c76adf33b0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -332,6 +332,14 @@ trigger_labels = [ "A-type-based-search", ] +[autolabel."A-rustdoc-js"] +trigger_files = [ + "src/librustdoc/html/static/js/", + "src/librustdoc/html/static/css/", + "tests/rustdoc-js/", + "tests/rustdoc-js-std/", +] + [autolabel."T-compiler"] trigger_files = [ # Source code From 9c4ead681480427806416cb09ea1f667bd6052b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 16:44:51 +0100 Subject: [PATCH 02/25] Remove legacy homu `try` and `auto` branch mentions --- .github/workflows/ci.yml | 19 +++++++++---------- src/ci/citool/src/main.rs | 6 ++---- src/ci/scripts/verify-channel.sh | 3 +-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb6bc325a3bb7..5d26d617ba88c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,11 +11,9 @@ name: CI on: push: branches: - - auto - - try - - try-perf - - automation/bors/try - automation/bors/auto + - automation/bors/try + - try-perf pull_request: branches: - "**" @@ -33,9 +31,10 @@ defaults: concurrency: # For a given workflow, if we push to the same branch, cancel all previous builds on that branch. - # We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which - # are all triggered on the same branch, but which should be able to run concurrently. - group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }} + # We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds + # (try-perf), which are all triggered on the same branch, but which should be able to run + # concurrently. + group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }} cancel-in-progress: true env: TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" @@ -57,7 +56,7 @@ jobs: - name: Test citool # Only test citool on the auto branch, to reduce latency of the calculate matrix job # on PR/try builds. - if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }} + if: ${{ github.ref == 'refs/heads/automation/bors/auto' }} run: | cd src/ci/citool CARGO_INCREMENTAL=0 cargo test @@ -80,7 +79,7 @@ jobs: # access the environment. # # We only enable the environment for the rust-lang/rust repository, so that CI works on forks. - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} env: CI_JOB_NAME: ${{ matrix.name }} CI_JOB_DOC_URL: ${{ matrix.doc_url }} @@ -314,7 +313,7 @@ jobs: needs: [ calculate_matrix, job ] # !cancelled() executes the job regardless of whether the previous jobs passed or failed if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} steps: - name: checkout the source code uses: actions/checkout@v5 diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index d7b491d38f41f..01c0650b3c98f 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -41,14 +41,12 @@ impl GitHubContext { match (self.event_name.as_str(), self.branch_ref.as_str()) { ("pull_request", _) => Some(RunType::PullRequest), ("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }), - ("push", "refs/heads/try" | "refs/heads/automation/bors/try") => { + ("push", "refs/heads/automation/bors/try") => { let patterns = self.get_try_job_patterns(); let patterns = if !patterns.is_empty() { Some(patterns) } else { None }; Some(RunType::TryJob { job_patterns: patterns }) } - ("push", "refs/heads/auto" | "refs/heads/automation/bors/auto") => { - Some(RunType::AutoJob) - } + ("push", "refs/heads/automation/bors/auto") => Some(RunType::AutoJob), ("push", "refs/heads/main") => Some(RunType::MainJob), _ => None, } diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh index cac8ba332ed19..286869e8a411b 100755 --- a/src/ci/scripts/verify-channel.sh +++ b/src/ci/scripts/verify-channel.sh @@ -8,8 +8,7 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isCiBranch auto || isCiBranch try || isCiBranch try-perf || \ - isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then +if isCiBranch try-perf || isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then echo "channel verification is only executed on PR builds" exit fi From 291d0a9a4b175b61b7c499551751ad5023b38bbc Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 6 Jan 2026 16:08:10 -0500 Subject: [PATCH 03/25] diagnostics: make implicit Sized bounds explicit in E0277 When a trait parameter depends upon Sized, the error message only referred to the full trait itself and didn't mention Sized. This makes the failure to implement Sized explicit. It also notes when the Sized trait bound is explicit or implicit. --- .../src/error_reporting/traits/suggestions.rs | 57 +++++++++++--- .../substs-ppaux.normal.stderr | 2 +- .../substs-ppaux.verbose.stderr | 2 +- tests/ui/error-codes/E0277-4.rs | 50 ++++++++++++ tests/ui/error-codes/E0277-4.stderr | 77 +++++++++++++++++++ tests/ui/recursion/issue-23122-2.stderr | 2 +- tests/ui/suggestions/slice-issue-87994.stderr | 10 +-- ...-iterator-deref-in-for-loop.current.stderr | 4 +- ...dyn-iterator-deref-in-for-loop.next.stderr | 4 +- tests/ui/traits/issue-18400.stderr | 2 +- 10 files changed, 186 insertions(+), 24 deletions(-) create mode 100644 tests/ui/error-codes/E0277-4.rs create mode 100644 tests/ui/error-codes/E0277-4.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f60..08a3fd4a0bb30 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1391,25 +1391,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // return early in the caller. let mut label = || { + // Special case `Sized` as `old_pred` will be the trait itself instead of + // `Sized` when the trait bound is the source of the error. + let is_sized = match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) + } + _ => false, + }; + let msg = format!( "the trait bound `{}` is not satisfied", self.tcx.short_string(old_pred, err.long_ty_path()), ); - let self_ty_str = - self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); + let self_ty_str = self.tcx.short_string(old_pred.self_ty(), err.long_ty_path()); let trait_path = self .tcx .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path()); if has_custom_message { + let msg = if is_sized { + "the trait bound `Sized` is not satisfied".into() + } else { + msg + }; err.note(msg); } else { err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; } - err.span_label( - span, - format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), - ); + if is_sized { + err.span_label( + span, + format!("the trait `Sized` is not implemented for `{self_ty_str}`"), + ); + } else { + err.span_label( + span, + format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), + ); + } }; let mut sugg_prefixes = vec![]; @@ -3578,10 +3598,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "unsatisfied trait bound introduced in this `derive` macro", ); } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) { - spans.push_span_label( - data.span, - "unsatisfied trait bound introduced here", - ); + // `Sized` may be an explicit or implicit trait bound. If it is + // implicit, mention it as such. + if let Some(pred) = predicate.as_trait_clause() + && self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) + && self + .tcx + .generics_of(data.impl_or_alias_def_id) + .own_params + .iter() + .any(|param| self.tcx.def_span(param.def_id) == data.span) + { + spans.push_span_label( + data.span, + "unsatisfied trait bound implicitly introduced here", + ); + } else { + spans.push_span_label( + data.span, + "unsatisfied trait bound introduced here", + ); + } } err.span_note(spans, msg); point_at_assoc_type_restriction( diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr index aa2aca7426e1a..b1c9ce3f22b6a 100644 --- a/tests/ui/associated-types/substs-ppaux.normal.stderr +++ b/tests/ui/associated-types/substs-ppaux.normal.stderr @@ -88,7 +88,7 @@ note: required for `str` to implement `Foo<'_, '_, u8>` LL | impl<'a, 'b, T, S> Foo<'a, 'b, S> for T {} | - ^^^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here error: aborting due to 5 previous errors diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr index 23cf222a1d37e..46cae5db56fdd 100644 --- a/tests/ui/associated-types/substs-ppaux.verbose.stderr +++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr @@ -88,7 +88,7 @@ note: required for `str` to implement `Foo<'?0, '?1, u8>` LL | impl<'a, 'b, T, S> Foo<'a, 'b, S> for T {} | - ^^^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here error: aborting due to 5 previous errors diff --git a/tests/ui/error-codes/E0277-4.rs b/tests/ui/error-codes/E0277-4.rs new file mode 100644 index 0000000000000..ead57f00dde50 --- /dev/null +++ b/tests/ui/error-codes/E0277-4.rs @@ -0,0 +1,50 @@ +use std::fmt::Display; + +trait ImplicitTrait { + fn foo(&self); +} + +trait ExplicitTrait { + fn foo(&self); +} + +trait DisplayTrait { + fn foo(&self); +} + +trait UnimplementedTrait { + fn foo(&self); +} + +// Implicitly requires `T: Sized`. +impl ImplicitTrait for T { + fn foo(&self) {} +} + +// Explicitly requires `T: Sized`. +impl ExplicitTrait for T { + fn foo(&self) {} +} + +// Requires `T: Display`. +impl DisplayTrait for T { + fn foo(&self) {} +} + +fn main() { + // `[u8]` does not implement `Sized`. + let x: &[u8] = &[]; + ImplicitTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: ImplicitTrait` is not satisfied [E0277] + ExplicitTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: ExplicitTrait` is not satisfied [E0277] + + // `UnimplementedTrait` has no implementations. + UnimplementedTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: UnimplementedTrait` is not satisfied [E0277] + + // `[u8; 0]` implements `Sized` but not `Display`. + let x: &[u8; 0] = &[]; + DisplayTrait::foo(x); + //~^ ERROR: the trait bound `[u8; 0]: DisplayTrait` is not satisfied [E0277] +} diff --git a/tests/ui/error-codes/E0277-4.stderr b/tests/ui/error-codes/E0277-4.stderr new file mode 100644 index 0000000000000..f38b8146a63d2 --- /dev/null +++ b/tests/ui/error-codes/E0277-4.stderr @@ -0,0 +1,77 @@ +error[E0277]: the trait bound `[u8]: ImplicitTrait` is not satisfied + --> $DIR/E0277-4.rs:37:24 + | +LL | ImplicitTrait::foo(x); + | ------------------ ^ the trait `Sized` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +note: required for `[u8]` to implement `ImplicitTrait` + --> $DIR/E0277-4.rs:20:9 + | +LL | impl ImplicitTrait for T { + | - ^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound implicitly introduced here +help: consider borrowing here + | +LL | ImplicitTrait::foo(&x); + | + +LL | ImplicitTrait::foo(&mut x); + | ++++ + +error[E0277]: the trait bound `[u8]: ExplicitTrait` is not satisfied + --> $DIR/E0277-4.rs:39:24 + | +LL | ExplicitTrait::foo(x); + | ------------------ ^ the trait `Sized` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +note: required for `[u8]` to implement `ExplicitTrait` + --> $DIR/E0277-4.rs:25:16 + | +LL | impl ExplicitTrait for T { + | ----- ^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider borrowing here + | +LL | ExplicitTrait::foo(&x); + | + +LL | ExplicitTrait::foo(&mut x); + | ++++ + +error[E0277]: the trait bound `[u8]: UnimplementedTrait` is not satisfied + --> $DIR/E0277-4.rs:43:29 + | +LL | UnimplementedTrait::foo(x); + | ----------------------- ^ the trait `UnimplementedTrait` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/E0277-4.rs:15:1 + | +LL | trait UnimplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `[u8; 0]: DisplayTrait` is not satisfied + --> $DIR/E0277-4.rs:48:23 + | +LL | DisplayTrait::foo(x); + | ----------------- ^ the trait `std::fmt::Display` is not implemented for `[u8; 0]` + | | + | required by a bound introduced by this call + | +note: required for `[u8; 0]` to implement `DisplayTrait` + --> $DIR/E0277-4.rs:30:18 + | +LL | impl DisplayTrait for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/recursion/issue-23122-2.stderr b/tests/ui/recursion/issue-23122-2.stderr index de402d65e6d6a..39cd0eb35a630 100644 --- a/tests/ui/recursion/issue-23122-2.stderr +++ b/tests/ui/recursion/issue-23122-2.stderr @@ -11,7 +11,7 @@ note: required for `GetNext<<<<... as Next>::Next as Next>::Next as Next>::Next> LL | impl Next for GetNext { | - ^^^^ ^^^^^^^^^^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-23122-2.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/suggestions/slice-issue-87994.stderr b/tests/ui/suggestions/slice-issue-87994.stderr index 22ad5d352120d..dd5c00af90b22 100644 --- a/tests/ui/suggestions/slice-issue-87994.stderr +++ b/tests/ui/suggestions/slice-issue-87994.stderr @@ -17,11 +17,10 @@ error[E0277]: `[i32]` is not an iterator --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ the trait `IntoIterator` is not implemented for `[i32]` + | ^^^^^^ the trait `Sized` is not implemented for `[i32]` | - = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `[i32]` to implement `IntoIterator` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider borrowing here | LL | for _ in &v[1..] { @@ -48,11 +47,10 @@ error[E0277]: `[K]` is not an iterator --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `[K]` + | ^^^^^^^ the trait `Sized` is not implemented for `[K]` | - = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `[K]` to implement `IntoIterator` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider borrowing here | LL | for i2 in &v2[1..] { diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr index b5a9b82a93a3e..0dd2ffffdfeaf 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr @@ -2,9 +2,9 @@ error[E0277]: `dyn Iterator` is not an iterator --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | LL | for item in *things { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` + | ^^^^^^^ the trait `Sized` is not implemented for `dyn Iterator` | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr index b5a9b82a93a3e..0dd2ffffdfeaf 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr @@ -2,9 +2,9 @@ error[E0277]: `dyn Iterator` is not an iterator --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | LL | for item in *things { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` + | ^^^^^^^ the trait `Sized` is not implemented for `dyn Iterator` | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | diff --git a/tests/ui/traits/issue-18400.stderr b/tests/ui/traits/issue-18400.stderr index 146ba16397a20..af5519a15c23d 100644 --- a/tests/ui/traits/issue-18400.stderr +++ b/tests/ui/traits/issue-18400.stderr @@ -11,7 +11,7 @@ note: required for `{integer}` to implement `Set<&[_]>` LL | impl<'a, T, S> Set<&'a [T]> for S where | - ^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here = note: 128 redundant requirements hidden = note: required for `{integer}` to implement `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` From b57c2493339dd2d0dd4a8df6ed7ee81b81e84816 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:42:00 -0500 Subject: [PATCH 04/25] fix: make `Type::of` supported unsized types --- library/core/src/mem/type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7938e2b52ed02..6b16bfadc233a 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -31,7 +31,7 @@ impl Type { #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] // FIXME(reflection): don't require the 'static bound - pub const fn of() -> Self { + pub const fn of() -> Self { const { TypeId::of::().info() } } } From 1bde2f4705d351e24eb556604c0da5511a277e15 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:43:21 -0500 Subject: [PATCH 05/25] chore: test `Type::of` on unsized types I chose to simply extend `dump.rs`, rather than create a new UI test. --- tests/ui/reflection/dump.rs | 2 ++ tests/ui/reflection/dump.run.stdout | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 3bf4f32b6641d..efc3024a84e9f 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -27,4 +27,6 @@ fn main() { println!("{:#?}", const { Type::of::<&Unsized>() }.kind); println!("{:#?}", const { Type::of::<&str>() }.kind); println!("{:#?}", const { Type::of::<&[u8]>() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::<[u8]>() }.kind); } diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout index 71fd80b466580..e9db772e8ebac 100644 --- a/tests/ui/reflection/dump.run.stdout +++ b/tests/ui/reflection/dump.run.stdout @@ -21,3 +21,5 @@ Other Other Other Other +Other +Other From feb44c3f4806069c76b8a06e4393ecb722dd17a1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 8 Jan 2026 22:06:45 +0100 Subject: [PATCH 06/25] Make `--print=check-cfg` output compatible `--check-cfg` arguments --- compiler/rustc_driver_impl/src/lib.rs | 35 +++++----- .../src/compiler-flags/print-check-cfg.md | 29 ++++---- tests/run-make/print-check-cfg/rmake.rs | 66 ++++++++++--------- 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7820198f2dcf2..a328298d3b153 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -765,30 +765,35 @@ fn print_crate_info( for (name, expected_values) in &sess.psess.check_config.expecteds { use crate::config::ExpectedValues; match expected_values { - ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")), + ExpectedValues::Any => { + check_cfgs.push(format!("cfg({name}, values(any()))")) + } ExpectedValues::Some(values) => { - if !values.is_empty() { - check_cfgs.extend(values.iter().map(|value| { + let mut values: Vec<_> = values + .iter() + .map(|value| { if let Some(value) = value { - format!("{name}=\"{value}\"") + format!("\"{value}\"") } else { - name.to_string() + "none()".to_string() } - })) - } else { - check_cfgs.push(format!("{name}=")) - } + }) + .collect(); + + values.sort_unstable(); + + let values = values.join(", "); + + check_cfgs.push(format!("cfg({name}, values({values}))")) } } } check_cfgs.sort_unstable(); - if !sess.psess.check_config.exhaustive_names { - if !sess.psess.check_config.exhaustive_values { - println_info!("any()=any()"); - } else { - println_info!("any()"); - } + if !sess.psess.check_config.exhaustive_names + && sess.psess.check_config.exhaustive_values + { + println_info!("cfg(any())"); } for check_cfg in check_cfgs { println_info!("{check_cfg}"); diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md index 8d314aa62d4cc..1b41a0cd728fc 100644 --- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -9,18 +9,20 @@ This option of the `--print` flag print the list of all the expected cfgs. This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected names and values. -This print option works similarly to `--print=cfg` (modulo check-cfg specifics). - -| `--check-cfg` | `--print=check-cfg` | -|-----------------------------------|-----------------------------| -| `cfg(foo)` | `foo` | -| `cfg(foo, values("bar"))` | `foo="bar"` | -| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"` | -| | *check-cfg specific syntax* | -| `cfg(foo, values(any())` | `foo=any()` | -| `cfg(foo, values())` | `foo=` | -| `cfg(any())` | `any()` | -| *none* | `any()=any()` | +This print option outputs compatible `--check-cfg` arguments with a reduced syntax where all the +expected values are on the same line and `values(...)` is always explicit. + +| `--check-cfg` | `--print=check-cfg` | +|-----------------------------------|-----------------------------------| +| `cfg(foo)` | `cfg(foo, values(none())) | +| `cfg(foo, values("bar"))` | `cfg(foo, values("bar"))` | +| `cfg(foo, values(none(), "bar"))` | `cfg(foo, values(none(), "bar"))` | +| `cfg(foo, values(any())` | `cfg(foo, values(any())` | +| `cfg(foo, values())` | `cfg(foo, values())` | +| `cfg(any())` | `cfg(any())` | +| *nothing* | *nothing* | + +The print option includes well known cfgs. To be used like this: @@ -28,4 +30,7 @@ To be used like this: rustc --print=check-cfg -Zunstable-options lib.rs ``` +> **Note:** Users should be resilient when parsing, in particular against new predicates that +may be added in the future. + [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index f6f7f7cece6e7..e102d2904a80f 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -14,51 +14,55 @@ struct CheckCfg { enum Contains { Some { contains: &'static [&'static str], doesnt_contain: &'static [&'static str] }, - Only(&'static str), + Nothing, } fn main() { - check(CheckCfg { args: &[], contains: Contains::Only("any()=any()") }); + check(CheckCfg { args: &[], contains: Contains::Nothing }); check(CheckCfg { args: &["--check-cfg=cfg()"], contains: Contains::Some { - contains: &["unix", "miri"], - doesnt_contain: &["any()", "any()=any()"], + contains: &["cfg(unix, values(none()))", "cfg(miri, values(none()))"], + doesnt_contain: &["cfg(any())"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(any())"], contains: Contains::Some { - contains: &["any()", "unix", r#"target_feature="crt-static""#], + contains: &["cfg(any())", "cfg(unix, values(none()))"], doesnt_contain: &["any()=any()"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature)"], contains: Contains::Some { - contains: &["unix", "miri", "feature"], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &[ + "cfg(unix, values(none()))", + "cfg(miri, values(none()))", + "cfg(feature, values(none()))", + ], + doesnt_contain: &["cfg(any())", "cfg(feature)"], }, }); check(CheckCfg { args: &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], contains: Contains::Some { - contains: &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &[r#"cfg(feature, values("", "lol", "test", none()))"#], + doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature, values())"], contains: Contains::Some { - contains: &["feature="], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature"], + contains: &["cfg(feature, values())"], + doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature, values())", "--check-cfg=cfg(feature, values(none()))"], contains: Contains::Some { - contains: &["feature"], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &["cfg(feature, values(none()))"], + doesnt_contain: &["cfg(any())", "cfg(feature, values())"], }, }); check(CheckCfg { @@ -67,8 +71,8 @@ fn main() { r#"--check-cfg=cfg(feature, values("tmp"))"#, ], contains: Contains::Some { - contains: &["unix", "miri", "feature=any()"], - doesnt_contain: &["any()", "any()=any()", "feature", "feature=", "feature=\"tmp\""], + contains: &["cfg(feature, values(any()))"], + doesnt_contain: &["cfg(any())", r#"cfg(feature, values("tmp"))"#], }, }); check(CheckCfg { @@ -78,8 +82,12 @@ fn main() { r#"--check-cfg=cfg(feature, values("tmp"))"#, ], contains: Contains::Some { - contains: &["has_foo", "has_bar", "feature=\"tmp\""], - doesnt_contain: &["any()", "any()=any()", "feature"], + contains: &[ + "cfg(has_foo, values(none()))", + "cfg(has_bar, values(none()))", + r#"cfg(feature, values("tmp"))"#, + ], + doesnt_contain: &["cfg(any())", "cfg(feature)"], }, }); } @@ -94,16 +102,15 @@ fn check(CheckCfg { args, contains }: CheckCfg) { for l in stdout.lines() { assert!(l == l.trim()); - if let Some((left, right)) = l.split_once('=') { - if right != "any()" && right != "" { - assert!(right.starts_with("\"")); - assert!(right.ends_with("\"")); - } - assert!(!left.contains("\"")); - } else { - assert!(!l.contains("\"")); - } - assert!(found.insert(l.to_string()), "{}", &l); + assert!(l.starts_with("cfg("), "{l}"); + assert!(l.ends_with(")"), "{l}"); + assert_eq!( + l.chars().filter(|c| *c == '(').count(), + l.chars().filter(|c| *c == ')').count(), + "{l}" + ); + assert!(l.chars().filter(|c| *c == '"').count() % 2 == 0, "{l}"); + assert!(found.insert(l.to_string()), "{l}"); } match contains { @@ -131,9 +138,8 @@ fn check(CheckCfg { args, contains }: CheckCfg) { ); } } - Contains::Only(only) => { - assert!(found.contains(&only.to_string()), "{:?} != {:?}", &only, &found); - assert!(found.len() == 1, "len: {}, instead of 1", found.len()); + Contains::Nothing => { + assert!(found.len() == 0, "len: {}, instead of 0", found.len()); } } } From dd2b0a8e9299512a2c8866edf8f67e301aa6d988 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 8 Jan 2026 22:07:24 +0100 Subject: [PATCH 07/25] Update compiletest for new `--print=check-cfg` output --- src/tools/compiletest/src/common.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 450fde3bbc38e..d2abc9dab1488 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1065,11 +1065,27 @@ fn builtin_cfg_names(config: &Config) -> HashSet { Default::default(), ) .lines() - .map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() }) + .map(|l| extract_cfg_name(&l).unwrap().to_string()) .chain(std::iter::once(String::from("test"))) .collect() } +/// Extract the cfg name from `cfg(name, values(...))` lines +fn extract_cfg_name(check_cfg_line: &str) -> Result<&str, &'static str> { + let trimmed = check_cfg_line.trim(); + + #[rustfmt::skip] + let inner = trimmed + .strip_prefix("cfg(") + .ok_or("missing cfg(")? + .strip_suffix(")") + .ok_or("missing )")?; + + let first_comma = inner.find(',').ok_or("no comma found")?; + + Ok(inner[..first_comma].trim()) +} + pub const KNOWN_CRATE_TYPES: &[&str] = &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]; From d697b4d7abf5573d63a9e3e5d7f84479eb554e67 Mon Sep 17 00:00:00 2001 From: KaiTomotake Date: Mon, 5 Jan 2026 01:32:34 +0900 Subject: [PATCH 08/25] Improve std::path::Path::join documentation Adapt `PathBuf::push` documentation for `Path::join` and add it to `join`'s docs Fix to comply with tidy Remove unnecessary whitespace --- library/std/src/path.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e8eda3c5f76bb..25bd7005b9942 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2972,6 +2972,15 @@ impl Path { /// /// If `path` is absolute, it replaces the current path. /// + /// On Windows: + /// + /// * if `path` has a root but no prefix (e.g., `\windows`), it + /// replaces and returns everything except for the prefix (if any) of `self`. + /// * if `path` has a prefix but no root, `self` is ignored and `path` is returned. + /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) + /// and `path` is not empty, the new path is normalized: all references + /// to `.` and `..` are removed. + /// /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// /// # Examples From e5dbb3b1a2234c49f7134b3a305ca004b993536b Mon Sep 17 00:00:00 2001 From: Marco Trevisan Date: Tue, 13 Jan 2026 04:01:45 +0100 Subject: [PATCH 09/25] armv7-unknown-linux-uclibceabihf.md: Fix build-toml syntax With the suggested value we were getting instead: ``` ERROR: Failed to parse '/tmp/rust/bootstrap.toml': unknown field `stage`, expected one of `build`, `description`, `host`, `target`, `build-dir`, `cargo`, `rustc`, `rustfmt`, `cargo-clippy`, `docs`, `compiler-docs`, `library-docs-private-items`, `docs-minification`, `submodules`, `gdb`, `lldb`, `nodejs`, `npm`, `yarn`, `python`, `windows-rc`, `reuse`, `locked-deps`, `vendor`, `full-bootstrap`, `bootstrap-cache-path`, `extended`, `tools`, `tool`, `verbose`, `sanitizers`, `profiler`, `cargo-native-static`, `low-priority`, `configure-args`, `local-rebuild`, `print-step-timings`, `print-step-rusage`, `check-stage`, `doc-stage`, `build-stage`, `test-stage`, `install-stage`, `dist-stage`, `bench-stage`, `patch-binaries-for-nix`, `metrics`, `android-ndk`, `optimized-compiler-builtins`, `jobs`, `compiletest-diff-tool`, `compiletest-allow-stage0`, `compiletest-use-stage0-libtest`, `tidy-extra-checks`, `ccache`, `exclude` for key `build` ``` --- .../src/platform-support/armv7-unknown-linux-uclibceabihf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 9fb24906b4fc3..249c8fc23a0c0 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -30,7 +30,7 @@ The target can be built by enabling it for a `rustc` build, by placing the follo ```toml [build] target = ["armv7-unknown-linux-uclibceabihf"] -stage = 2 +build-stage = 2 [target.armv7-unknown-linux-uclibceabihf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN From 1e6909140356a20c9301523a03176b38325cd7eb Mon Sep 17 00:00:00 2001 From: Marco Trevisan Date: Tue, 13 Jan 2026 04:17:51 +0100 Subject: [PATCH 10/25] armv7-unknown-linux-uclibceabihf.md: Update toolchain download link The old toolchain is not working with recent rustc, as it does not defining `getauxval` --- .../src/platform-support/armv7-unknown-linux-uclibceabihf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 249c8fc23a0c0..d2635f12db21b 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -21,7 +21,7 @@ This target is cross compiled, and requires a cross toolchain. You can find sui Compiling rust for this target has been tested on `x86_64` linux hosts. Other host types have not been tested, but may work, if you can find a suitable cross compilation toolchain for them. -If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2021.11-1.tar.bz2), and unpack it into a directory. +If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2025.08-1.tar.xz), and unpack it into a directory. ### Configure rust From c263d36539d2859b9fd6f433e6a23a99a3d09d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 13 Jan 2026 07:35:24 +0100 Subject: [PATCH 11/25] Fix citool tests --- src/ci/citool/tests/jobs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs index 5231d4616e049..6787f00d9af83 100644 --- a/src/ci/citool/tests/jobs.rs +++ b/src/ci/citool/tests/jobs.rs @@ -4,7 +4,7 @@ const TEST_JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/tes #[test] fn auto_jobs() { - let stdout = get_matrix("push", "commit", "refs/heads/auto"); + let stdout = get_matrix("push", "commit", "refs/heads/automation/bors/auto"); insta::assert_snapshot!(stdout, @r#" jobs=[{"name":"aarch64-gnu","full_name":"auto - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"x86_64-gnu-llvm-18-1","full_name":"auto - x86_64-gnu-llvm-18-1","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DOCKER_SCRIPT":"stage_2_test_set1.sh","IMAGE":"x86_64-gnu-llvm-18","READ_ONLY_SRC":"0","RUST_BACKTRACE":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"aarch64-apple","full_name":"auto - aarch64-apple","os":"macos-14","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","MACOSX_DEPLOYMENT_TARGET":11.0,"MACOSX_STD_DEPLOYMENT_TARGET":11.0,"NO_DEBUG_ASSERTIONS":1,"NO_LLVM_ASSERTIONS":1,"NO_OVERFLOW_CHECKS":1,"RUSTC_RETRY_LINKER_ON_SEGFAULT":1,"RUST_CONFIGURE_ARGS":"--enable-sanitizers --enable-profiler --set rust.jemalloc","SCRIPT":"./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin","SELECT_XCODE":"/Applications/Xcode_15.4.app","TOOLSTATE_PUBLISH":1,"USE_XCODE_CLANG":1}},{"name":"dist-i686-msvc","full_name":"auto - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}},{"name":"pr-check-1","full_name":"auto - pr-check-1","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true},{"name":"pr-check-2","full_name":"auto - pr-check-2","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true},{"name":"tidy","full_name":"auto - tidy","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true,"doc_url":"https://foo.bar"}] run_type=auto @@ -13,7 +13,7 @@ fn auto_jobs() { #[test] fn try_jobs() { - let stdout = get_matrix("push", "commit", "refs/heads/try"); + let stdout = get_matrix("push", "commit", "refs/heads/automation/bors/try"); insta::assert_snapshot!(stdout, @r###" jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}] run_type=try @@ -28,7 +28,7 @@ fn try_custom_jobs() { try-job: aarch64-gnu try-job: dist-i686-msvc"#, - "refs/heads/try", + "refs/heads/automation/bors/try", ); insta::assert_snapshot!(stdout, @r###" jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] From ef9cbadc433ede9334ae9a9461e65fed4e90f9c2 Mon Sep 17 00:00:00 2001 From: vsriram Date: Tue, 13 Jan 2026 13:31:54 +0530 Subject: [PATCH 12/25] ui: add regression test for macro resolution ICE --- tests/ui/resolve/decl-macro-use-no-ice.rs | 20 ++++++++ tests/ui/resolve/decl-macro-use-no-ice.stderr | 47 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/ui/resolve/decl-macro-use-no-ice.rs create mode 100644 tests/ui/resolve/decl-macro-use-no-ice.stderr diff --git a/tests/ui/resolve/decl-macro-use-no-ice.rs b/tests/ui/resolve/decl-macro-use-no-ice.rs new file mode 100644 index 0000000000000..39b9cb03fea0d --- /dev/null +++ b/tests/ui/resolve/decl-macro-use-no-ice.rs @@ -0,0 +1,20 @@ +//@ edition: 2024 +#![feature(decl_macro)] + +// Regression test for issue +// The compiler previously ICE'd during identifier resolution +// involving `macro` items and `use` inside a public macro. + + +mod foo { + macro f() {} + + pub macro m() { + use f; //~ ERROR `f` is private, and cannot be re-exported + f!(); //~ ERROR macro import `f` is private + } +} + +fn main() { + foo::m!(); +} diff --git a/tests/ui/resolve/decl-macro-use-no-ice.stderr b/tests/ui/resolve/decl-macro-use-no-ice.stderr new file mode 100644 index 0000000000000..9fb75b48b428c --- /dev/null +++ b/tests/ui/resolve/decl-macro-use-no-ice.stderr @@ -0,0 +1,47 @@ +error[E0364]: `f` is private, and cannot be re-exported + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation + | +note: consider marking `f` as `pub` in the imported module + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0603]: macro import `f` is private + --> $DIR/decl-macro-use-no-ice.rs:14:9 + | +LL | f!(); + | ^ private macro import +... +LL | foo::m!(); + | --------- in this macro invocation + | +note: the macro import `f` is defined here... + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation +note: ...and refers to the macro `f` which is defined here + --> $DIR/decl-macro-use-no-ice.rs:10:5 + | +LL | macro f() {} + | ^^^^^^^^^ + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0364, E0603. +For more information about an error, try `rustc --explain E0364`. From 62849e64412e3dd9f7fba08881a6fab92aadadc3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Jan 2026 10:22:34 +0100 Subject: [PATCH 13/25] Reduce flakyness for `tests/rustdoc-gui/notable-trait.goml` --- tests/rustdoc-gui/notable-trait.goml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 839988021fce5..8e4c180e0ef17 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -250,7 +250,7 @@ set-window-size: (1100, 600) reload: assert-count: ("//*[@class='tooltip popover']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) +wait-for-count: ("//*[@class='tooltip popover']", 1) call-function: ("open-settings-menu", {}) -assert-count: ("//*[@class='tooltip popover']", 0) +wait-for-count: ("//*[@class='tooltip popover']", 0) assert-false: "#method\.create_an_iterator_from_read .tooltip:focus" From 1d968067881c968c3e79558472988ab117eaf8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 10:54:31 +0100 Subject: [PATCH 14/25] type params on eii --- tests/ui/eii/type_checking/type_params_149983.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/ui/eii/type_checking/type_params_149983.rs diff --git a/tests/ui/eii/type_checking/type_params_149983.rs b/tests/ui/eii/type_checking/type_params_149983.rs new file mode 100644 index 0000000000000..a0314657bb1d6 --- /dev/null +++ b/tests/ui/eii/type_checking/type_params_149983.rs @@ -0,0 +1,7 @@ +//@ check-fail +// Check that type parameters on EIIs are properly rejected. +// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983. +#![feature(extern_item_impls)] + +#[eii] +fn foo() {} From d25f4718adf1f2358c63299af16c1c4c0519bb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 16:00:46 +0100 Subject: [PATCH 15/25] deduplicate error message when EII has generics --- compiler/rustc_hir_analysis/messages.ftl | 4 ---- .../rustc_hir_analysis/src/check/check.rs | 9 +++++++- .../src/check/compare_eii.rs | 23 +------------------ compiler/rustc_hir_analysis/src/errors.rs | 10 -------- 4 files changed, 9 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 416a6b19edfc8..9ead1225d5f57 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -165,10 +165,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here -hir_analysis_eii_with_generics = - #[{$eii_name}] cannot have generic parameters other than lifetimes - .label = required by this attribute - hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4664bfcce853a..c37611ab2ee70 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -974,12 +974,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), (0, _) => ("const", "consts", None), _ => ("type or const", "types or consts", None), }; + let name = + if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiForeignItem) { + "externally implementable items" + } else { + "foreign items" + }; + let span = tcx.def_span(def_id); struct_span_code_err!( tcx.dcx(), span, E0044, - "foreign items may not have {kinds} parameters", + "{name} may not have {kinds} parameters", ) .with_span_label(span, format!("can't have {kinds} parameters")) .with_help( diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index d8afee9aafc98..c2a9b1fbdee0a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -24,7 +24,7 @@ use super::potentially_plural_count; use crate::check::compare_impl_item::{ CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, }; -use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; +use crate::errors::LifetimesOrBoundsMismatchOnEii; /// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible @@ -154,32 +154,11 @@ fn check_is_structurally_compatible<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } -/// externally implementable items can't have generics -fn check_no_generics<'tcx>( - tcx: TyCtxt<'tcx>, - external_impl: LocalDefId, - _declaration: DefId, - eii_name: Symbol, - eii_attr_span: Span, -) -> Result<(), ErrorGuaranteed> { - let generics = tcx.generics_of(external_impl); - if generics.own_requires_monomorphization() { - tcx.dcx().emit_err(EiiWithGenerics { - span: tcx.def_span(external_impl), - attr: eii_attr_span, - eii_name, - }); - } - - Ok(()) -} - fn check_early_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index b388396ac4fcd..7d4f65434dc42 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1652,13 +1652,3 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii { pub bounds_span: Vec, pub ident: Symbol, } - -#[derive(Diagnostic)] -#[diag(hir_analysis_eii_with_generics)] -pub(crate) struct EiiWithGenerics { - #[primary_span] - pub span: Span, - #[label] - pub attr: Span, - pub eii_name: Symbol, -} From b64a9be97ebe4195e55768e98f6eb4dcdd9220a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 16:52:46 +0100 Subject: [PATCH 16/25] bless the tests --- tests/ui/eii/type_checking/type_params_149983.rs | 3 +++ tests/ui/eii/type_checking/type_params_149983.stderr | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/ui/eii/type_checking/type_params_149983.stderr diff --git a/tests/ui/eii/type_checking/type_params_149983.rs b/tests/ui/eii/type_checking/type_params_149983.rs index a0314657bb1d6..6dc9b309712e1 100644 --- a/tests/ui/eii/type_checking/type_params_149983.rs +++ b/tests/ui/eii/type_checking/type_params_149983.rs @@ -5,3 +5,6 @@ #[eii] fn foo() {} +//~^ ERROR externally implementable items may not have type parameters + +fn main() {} diff --git a/tests/ui/eii/type_checking/type_params_149983.stderr b/tests/ui/eii/type_checking/type_params_149983.stderr new file mode 100644 index 0000000000000..11f06e6c88e20 --- /dev/null +++ b/tests/ui/eii/type_checking/type_params_149983.stderr @@ -0,0 +1,11 @@ +error[E0044]: externally implementable items may not have type parameters + --> $DIR/type_params_149983.rs:7:1 + | +LL | fn foo() {} + | ^^^^^^^^^^^ can't have type parameters + | + = help: replace the type parameters with concrete types like `u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0044`. From b454f76bd1ddf5c7459238f295647561a7895cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 17:45:50 +0100 Subject: [PATCH 17/25] ensure generics are still properly reported on EII *implementations*, and test this --- compiler/rustc_hir_analysis/messages.ftl | 5 +++ .../src/check/compare_eii.rs | 38 ++++++++++++++++++- compiler/rustc_hir_analysis/src/errors.rs | 12 ++++++ .../type_checking/generic_implementation.rs | 13 +++++++ .../generic_implementation.stderr | 12 ++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/ui/eii/type_checking/generic_implementation.rs create mode 100644 tests/ui/eii/type_checking/generic_implementation.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 9ead1225d5f57..fa3c4cb05f961 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here +hir_analysis_eii_with_generics = + `{$impl_name}` cannot have generic parameters other than lifetimes + .label = required by this attribute + .help = `#[{$eii_name}]` marks the implementation of an "externally implementable item" + hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index c2a9b1fbdee0a..2beb7eb09c119 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -8,8 +8,9 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0806, struct_span_code_err}; +use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; +use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -24,7 +25,7 @@ use super::potentially_plural_count; use crate::check::compare_impl_item::{ CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, }; -use crate::errors::LifetimesOrBoundsMismatchOnEii; +use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; /// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible @@ -154,11 +155,44 @@ fn check_is_structurally_compatible<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } +/// externally implementable items can't have generics +fn check_no_generics<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + _declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let generics = tcx.generics_of(external_impl); + if generics.own_requires_monomorphization() + // When an EII implementation is automatically generated by the `#[eii]` macro, + // it will directly refer to the foreign item, not through a macro. + // We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro, + // since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics. + // So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's + // not generated as part of the declaration. + && find_attr!( + tcx.get_all_attrs(external_impl), + AttributeKind::EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_))) + ) + { + tcx.dcx().emit_err(EiiWithGenerics { + span: tcx.def_span(external_impl), + attr: eii_attr_span, + eii_name, + impl_name: tcx.item_name(external_impl), + }); + } + + Ok(()) +} + fn check_early_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7d4f65434dc42..185a822bdfa6a 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1652,3 +1652,15 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii { pub bounds_span: Vec, pub ident: Symbol, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_eii_with_generics)] +#[help] +pub(crate) struct EiiWithGenerics { + #[primary_span] + pub span: Span, + #[label] + pub attr: Span, + pub eii_name: Symbol, + pub impl_name: Symbol, +} diff --git a/tests/ui/eii/type_checking/generic_implementation.rs b/tests/ui/eii/type_checking/generic_implementation.rs new file mode 100644 index 0000000000000..489fd2e645d84 --- /dev/null +++ b/tests/ui/eii/type_checking/generic_implementation.rs @@ -0,0 +1,13 @@ +//@ check-fail +// Check that type parameters on EIIs are properly rejected. +// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983. +#![feature(extern_item_impls)] + +#[eii] +fn foo(); + +#[foo] +fn foo_impl() {} +//~^ ERROR `foo_impl` cannot have generic parameters other than lifetimes + +fn main() {} diff --git a/tests/ui/eii/type_checking/generic_implementation.stderr b/tests/ui/eii/type_checking/generic_implementation.stderr new file mode 100644 index 0000000000000..17a71998423d7 --- /dev/null +++ b/tests/ui/eii/type_checking/generic_implementation.stderr @@ -0,0 +1,12 @@ +error: `foo_impl` cannot have generic parameters other than lifetimes + --> $DIR/generic_implementation.rs:10:1 + | +LL | #[foo] + | ------ required by this attribute +LL | fn foo_impl() {} + | ^^^^^^^^^^^^^^^^ + | + = help: `#[foo]` marks the implementation of an "externally implementable item" + +error: aborting due to 1 previous error + From d616e6cb189c762789a8179cb00e065fcc7f9992 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 13 Jan 2026 21:36:53 +0900 Subject: [PATCH 18/25] Emit error instead of delayed bug when meeting mismatch type for const array --- .../src/hir_ty_lowering/mod.rs | 9 ++++---- ...array-expr-type-mismatch-in-where-bound.rs | 21 +++++++++++++++++++ ...y-expr-type-mismatch-in-where-bound.stderr | 15 +++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d2cbf89336d8b..a66a521975c53 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2415,11 +2415,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let ty::Array(elem_ty, _) = ty.kind() else { - return Const::new_error_with_message( - tcx, - array_expr.span, - "const array must have an array type", - ); + let e = tcx + .dcx() + .span_err(array_expr.span, format!("expected `{}`, found const array", ty)); + return Const::new_error(tcx, e); }; let elems = array_expr diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs new file mode 100644 index 0000000000000..cda519b96d4d8 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs @@ -0,0 +1,21 @@ +//! regression test for +#![feature(min_generic_const_args)] +#![feature(adt_const_params)] +#![expect(incomplete_features)] + +trait Trait1 {} +trait Trait2 {} + +fn foo() +where + T: Trait1<{ [] }>, //~ ERROR: expected `usize`, found const array +{ +} + +fn bar() +where + T: Trait2<3>, //~ ERROR: mismatched types +{ +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr new file mode 100644 index 0000000000000..be40e44742267 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr @@ -0,0 +1,15 @@ +error: expected `usize`, found const array + --> $DIR/array-expr-type-mismatch-in-where-bound.rs:11:17 + | +LL | T: Trait1<{ [] }>, + | ^^ + +error[E0308]: mismatched types + --> $DIR/array-expr-type-mismatch-in-where-bound.rs:17:15 + | +LL | T: Trait2<3>, + | ^ expected `[u8; 3]`, found integer + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 84d59d073170aecbb15de9c1cdcf542bf7443673 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:39:34 +0100 Subject: [PATCH 19/25] Port `#[rustc_dump_user_args]` --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/rustc_dump.rs | 17 +++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_typeck/src/writeback.rs | 9 +++++---- compiler/rustc_passes/src/check_attr.rs | 2 +- 7 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index e02d71a261581..26db2992d8af3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -57,6 +57,7 @@ pub(crate) mod pin_v2; pub(crate) mod proc_macro_attrs; pub(crate) mod prototype; pub(crate) mod repr; +pub(crate) mod rustc_dump; pub(crate) mod rustc_internal; pub(crate) mod semantics; pub(crate) mod stability; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs new file mode 100644 index 0000000000000..d5593a7e02f39 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -0,0 +1,17 @@ +use rustc_hir::Target; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; + +use crate::attributes::prelude::Allow; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; +use crate::target_checking::AllowedTargets; + +pub(crate) struct RustcDumpUserArgs; + +impl NoArgsAttributeParser for RustcDumpUserArgs { + const PATH: &[Symbol] = &[sym::rustc_dump_user_args]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6b1b1d484283f..4ba1936086a25 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,6 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; +use crate::attributes::rustc_dump::RustcDumpUserArgs; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -267,6 +268,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8d18d335b355b..42575f712d4a2 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -906,6 +906,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_dump_user_args]` + RustcDumpUserArgs, + /// Represents `#[rustc_has_incoherent_inherent_impls]` RustcHasIncoherentInherentImpls, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 33655f4f00635..07dd9f8e3e065 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -97,6 +97,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 960a8497a2668..0078cd9d06833 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -14,9 +14,10 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{E0720, ErrorGuaranteed}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{self as hir, AmbigArg, HirId}; +use rustc_hir::{self as hir, AmbigArg, HirId, find_attr}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -25,7 +26,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, fold_regions, }; -use rustc_span::{Span, sym}; +use rustc_span::Span; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::opaque_types::opaque_type_has_defining_use_args; use rustc_trait_selection::solve; @@ -45,8 +46,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_args = - self.has_rustc_attrs && self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args); + let rustc_dump_user_args = self.has_rustc_attrs + && find_attr!(self.tcx.get_all_attrs(item_def_id), AttributeKind::RustcDumpUserArgs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args); for param in body.params { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8f80822a81ab1..f088bd5b5119a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -309,6 +309,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::CfiEncoding { .. } | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } + | AttributeKind::RustcDumpUserArgs ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -379,7 +380,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_variance_of_opaques | sym::rustc_hidden_type_of_opaques | sym::rustc_mir - | sym::rustc_dump_user_args | sym::rustc_effective_visibility | sym::rustc_outlives | sym::rustc_symbol_name From cf4d480eff238667a779c56938ebc51956f586d4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:43:31 +0100 Subject: [PATCH 20/25] Port `#[rustc_dump_def_parents]` --- compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 5 +++-- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index d5593a7e02f39..86cc88fe26e6a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -15,3 +15,12 @@ impl NoArgsAttributeParser for RustcDumpUserArgs { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs; } + +pub(crate) struct RustcDumpDefParents; + +impl NoArgsAttributeParser for RustcDumpDefParents { + const PATH: &[Symbol] = &[sym::rustc_dump_def_parents]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4ba1936086a25..adcdbf7752a3c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::RustcDumpUserArgs; +use crate::attributes::rustc_dump::{RustcDumpUserArgs, RustcDumpDefParents}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -268,6 +268,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 42575f712d4a2..63a89c84ed4a3 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -906,6 +906,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_dump_def_parents]` + RustcDumpDefParents, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 07dd9f8e3e065..aa2a7cb6d4b49 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -97,6 +97,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcDumpDefParents => No, RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index b167f31a246c6..1ace60721eaed 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,6 +1,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::intravisit; +use rustc_hir::{find_attr, intravisit}; +use rustc_hir::attrs::AttributeKind; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; @@ -54,7 +55,7 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { pub(crate) fn def_parents(tcx: TyCtxt<'_>) { for iid in tcx.hir_free_items() { let did = iid.owner_id.def_id; - if tcx.has_attr(did, sym::rustc_dump_def_parents) { + if find_attr!(tcx.get_all_attrs(did), AttributeKind::RustcDumpDefParents) { struct AnonConstFinder<'tcx> { tcx: TyCtxt<'tcx>, anon_consts: Vec, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f088bd5b5119a..dfa407964fc4b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -310,6 +310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs + | AttributeKind::RustcDumpDefParents ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -369,7 +370,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_abi | sym::rustc_layout | sym::rustc_proc_macro_decls - | sym::rustc_dump_def_parents | sym::rustc_never_type_options | sym::rustc_autodiff | sym::rustc_capture_analysis From 2a455409e302df2d1db755edec775f5100641365 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:47:18 +0100 Subject: [PATCH 21/25] Port `#[rustc_dump_item_bounds]` --- compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_hir/src/attrs/data_structures.rs | 5 ++++- compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 4 ++-- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 86cc88fe26e6a..cc866f9297d26 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -24,3 +24,12 @@ impl NoArgsAttributeParser for RustcDumpDefParents { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; } + +pub(crate) struct RustcDumpItemBounds; + +impl NoArgsAttributeParser for RustcDumpItemBounds { + const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index adcdbf7752a3c..5b959e553482c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::{RustcDumpUserArgs, RustcDumpDefParents}; +use crate::attributes::rustc_dump::{RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -268,7 +268,8 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, + Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 63a89c84ed4a3..051bd76e6eb7d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -908,7 +908,10 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_def_parents]` RustcDumpDefParents, - + + /// Represents `#[rustc_dump_item_bounds]` + RustcDumpItemBounds, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index aa2a7cb6d4b49..f3da08bae5db6 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -98,6 +98,7 @@ impl AttributeKind { RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, RustcDumpDefParents => No, + RustcDumpItemBounds => No, RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 1ace60721eaed..f87fb3a66095a 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{find_attr, intravisit}; -use rustc_hir::attrs::AttributeKind; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; @@ -39,7 +39,7 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { } diag.emit(); } - if tcx.has_attr(id, sym::rustc_dump_item_bounds) { + if find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpItemBounds) { let bounds = tcx.item_bounds(id).instantiate_identity(); let span = tcx.def_span(id); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dfa407964fc4b..4f9f584a3a61e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -310,6 +310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs + | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpDefParents ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { @@ -386,7 +387,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_evaluate_where_clauses | sym::rustc_dump_vtable | sym::rustc_delayed_bug_from_inside_query - | sym::rustc_dump_item_bounds | sym::rustc_def_path | sym::rustc_partition_reused | sym::rustc_partition_codegened From a4c34b421cf20e187f07c5254adedcee612aaad4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:51:50 +0100 Subject: [PATCH 22/25] Port `#[rustc_dump_vtable]` --- .../src/attributes/rustc_dump.rs | 12 ++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 ++++- .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../rustc_hir_analysis/src/collect/dump.rs | 19 ++++++++++--------- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index cc866f9297d26..25e60d8994220 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -33,3 +33,15 @@ impl NoArgsAttributeParser for RustcDumpItemBounds { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } + +pub(crate) struct RustcDumpVtable; + +impl NoArgsAttributeParser for RustcDumpVtable { + const PATH: &[Symbol] = &[sym::rustc_dump_vtable]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Impl { of_trait: true }), + Allow(Target::TyAlias), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDumpVtable; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5b959e553482c..8cc09117e7108 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,9 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::{RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs}; +use crate::attributes::rustc_dump::{ + RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs, RustcDumpVtable, +}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -271,6 +273,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 051bd76e6eb7d..941c12c7d6fa7 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -915,6 +915,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, + /// Represents `#[rustc_dump_vtable]` + RustcDumpVtable(Span), + /// Represents `#[rustc_has_incoherent_inherent_impls]` RustcHasIncoherentInherentImpls, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f3da08bae5db6..df386a00dd117 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -100,6 +100,7 @@ impl AttributeKind { RustcDumpDefParents => No, RustcDumpItemBounds => No, RustcDumpUserArgs => No, + RustcDumpVtable(..) => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index f87fb3a66095a..a61ea29a1a711 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -103,7 +103,9 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { for id in tcx.hir_free_items() { let def_id = id.owner_id.def_id; - let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else { + let Some(&attr_span) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcDumpVtable(span) => span) + else { continue; }; @@ -112,14 +114,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity(); if trait_ref.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to non-generic impl", ); continue; } if !tcx.is_dyn_compatible(trait_ref.def_id) { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to dyn-compatible trait", ); continue; @@ -128,7 +130,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref) else { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` applied to impl header that cannot be normalized", ); continue; @@ -139,7 +141,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let ty = tcx.type_of(def_id).instantiate_identity(); if ty.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to non-generic type", ); continue; @@ -148,14 +150,13 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) else { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` applied to type alias that cannot be normalized", ); continue; }; let ty::Dynamic(data, _) = *ty.kind() else { - tcx.dcx() - .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type"); + tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type"); continue; }; if let Some(principal) = data.principal() { @@ -168,7 +169,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { } _ => { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` only applies to impl, or type alias of dyn type", ); continue; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4f9f584a3a61e..3d51429f20d72 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -312,6 +312,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpUserArgs | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpDefParents + | AttributeKind::RustcDumpVtable(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -385,7 +386,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_outlives | sym::rustc_symbol_name | sym::rustc_evaluate_where_clauses - | sym::rustc_dump_vtable | sym::rustc_delayed_bug_from_inside_query | sym::rustc_def_path | sym::rustc_partition_reused From abcbf72bab56c56ab395b8c7cd44a87364ac43df Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:54:54 +0100 Subject: [PATCH 23/25] Port `#[rustc_dump_predicates]` --- .../src/attributes/rustc_dump.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 25e60d8994220..53120dece916e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -34,6 +34,21 @@ impl NoArgsAttributeParser for RustcDumpItemBounds { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } +pub(crate) struct RustcDumpPredicates; + +impl NoArgsAttributeParser for RustcDumpPredicates { + const PATH: &[Symbol] = &[sym::rustc_dump_predicates]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::AssocTy), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates; +} + pub(crate) struct RustcDumpVtable; impl NoArgsAttributeParser for RustcDumpVtable { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8cc09117e7108..8305d027d13ca 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -64,7 +64,8 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_dump::{ - RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs, RustcDumpVtable, + RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, + RustcDumpVtable, }; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, @@ -272,6 +273,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 941c12c7d6fa7..3d9362d2d923c 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -912,6 +912,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_item_bounds]` RustcDumpItemBounds, + /// Represents `#[rustc_dump_predicates]` + RustcDumpPredicates, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index df386a00dd117..48f3ceba9c399 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -99,6 +99,7 @@ impl AttributeKind { RustcCoherenceIsCore(..) => No, RustcDumpDefParents => No, RustcDumpItemBounds => No, + RustcDumpPredicates => No, RustcDumpUserArgs => No, RustcDumpVtable(..) => No, RustcHasIncoherentInherentImpls => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index a61ea29a1a711..2dfd4ab6111fe 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -29,7 +29,7 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { for id in tcx.hir_crate_items(()).owners() { - if tcx.has_attr(id, sym::rustc_dump_predicates) { + if find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpPredicates) { let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; let span = tcx.def_span(id); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3d51429f20d72..f047d66a82542 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -311,6 +311,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs | AttributeKind::RustcDumpItemBounds + | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpDefParents | AttributeKind::RustcDumpVtable(..) ) => { /* do nothing */ } @@ -377,7 +378,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_capture_analysis | sym::rustc_regions | sym::rustc_strict_coherence - | sym::rustc_dump_predicates | sym::rustc_variance | sym::rustc_variance_of_opaques | sym::rustc_hidden_type_of_opaques From e027ecdbb57822527ed69e3cc81ca9ce36735678 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:24:49 -0500 Subject: [PATCH 24/25] feat: support arrays in type reflection --- .../src/const_eval/type_info.rs | 35 +++++++++++++++++-- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/mem/type_info.rs | 13 +++++++ library/coretests/tests/lib.rs | 1 + library/coretests/tests/mem.rs | 2 ++ library/coretests/tests/mem/type_info.rs | 23 ++++++++++++ tests/ui/reflection/dump.rs | 1 + tests/ui/reflection/dump.run.stdout | 6 ++++ 8 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 library/coretests/tests/mem/type_info.rs diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index f932b198b4260..814c81278a104 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -3,7 +3,7 @@ use rustc_hir::LangItem; use rustc_middle::mir::interpret::CtfeProvenance; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_middle::ty::{self, Const, ScalarInt, Ty}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -56,6 +56,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_tuple_fields(tuple_place, fields, ty)?; variant } + ty::Array(ty, len) => { + let (variant, variant_place) = downcast(sym::Array)?; + let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + self.write_array_type_info(array_place, *ty, *len)?; + + variant + } // For now just merge all primitives into one `Leaf` variant with no data ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { downcast(sym::Leaf)?.0 @@ -63,7 +71,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ty::Adt(_, _) | ty::Foreign(_) | ty::Str - | ty::Array(_, _) | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) @@ -172,4 +179,28 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } interp_ok(()) } + + pub(crate) fn write_array_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + len: Const<'tcx>, + ) -> InterpResult<'tcx> { + // Iterate over all fields of `type_info::Array`. + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + + match field.name { + // Write the `TypeId` of the array's elements to the `element_ty` field. + sym::element_ty => self.write_type_id(ty, &field_place)?, + // Write the length of the array to the `len` field. + sym::len => self.write_scalar(len.to_leaf(), &field_place)?, + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f56c3421ce0f5..34804160ed398 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -162,6 +162,7 @@ symbols! { Arc, ArcWeak, Argument, + Array, ArrayIntoIter, AsMut, AsRef, @@ -939,6 +940,7 @@ symbols! { eii_impl, eii_internals, eii_shared_macro, + element_ty, emit, emit_enum, emit_enum_variant, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7938e2b52ed02..208cbc299aae5 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -43,6 +43,8 @@ impl Type { pub enum TypeKind { /// Tuples. Tuple(Tuple), + /// Arrays. + Array(Array), /// Primitives /// FIXME(#146922): disambiguate further Leaf, @@ -69,3 +71,14 @@ pub struct Field { /// Offset in bytes from the parent type pub offset: usize, } + +/// Compile-time type information about arrays. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Array { + /// The type of each element in the array. + pub element_ty: TypeId, + /// The length of the array. + pub len: usize, +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ff4fc4c892afe..caa130be1483e 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -115,6 +115,7 @@ #![feature(try_blocks)] #![feature(try_find)] #![feature(try_trait_v2)] +#![feature(type_info)] #![feature(uint_bit_width)] #![feature(uint_gather_scatter_bits)] #![feature(unsize)] diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 5247e01fba01b..193d5416b06a7 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,3 +1,5 @@ +mod type_info; + use core::mem::*; use core::{array, ptr}; use std::cell::Cell; diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs new file mode 100644 index 0000000000000..5cd690363a010 --- /dev/null +++ b/library/coretests/tests/mem/type_info.rs @@ -0,0 +1,23 @@ +use std::any::TypeId; +use std::mem::type_info::{Type, TypeKind}; + +#[test] +fn test_arrays() { + // Normal array. + match const { Type::of::<[u16; 4]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 4); + } + _ => unreachable!(), + } + + // Zero-length array. + match const { Type::of::<[bool; 0]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 0); + } + _ => unreachable!(), + } +} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 3bf4f32b6641d..cc3bcb8b9faf7 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -22,6 +22,7 @@ struct Unsized { fn main() { println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); + println!("{:#?}", const { Type::of::<[u8; 2]>() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::<&Unsized>() }.kind); diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout index 71fd80b466580..7a0bb9592a3cd 100644 --- a/tests/ui/reflection/dump.run.stdout +++ b/tests/ui/reflection/dump.run.stdout @@ -16,6 +16,12 @@ Tuple( ], }, ) +Array( + Array { + element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + len: 2, + }, +) Other Other Other From 71f8ea99fe5cfbca752ddcfb1c0b13453941a9e6 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:19:37 -0500 Subject: [PATCH 25/25] refactor: move tuples type info ui test to coretest --- library/coretests/tests/mem/type_info.rs | 33 ++++++++++++++++++++++ tests/ui/reflection/tuples.rs | 36 ------------------------ 2 files changed, 33 insertions(+), 36 deletions(-) delete mode 100644 tests/ui/reflection/tuples.rs diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 5cd690363a010..b3b8d96d49b00 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -21,3 +21,36 @@ fn test_arrays() { _ => unreachable!(), } } + +#[test] +fn test_tuples() { + fn assert_tuple_arity() { + match const { Type::of::() }.kind { + TypeKind::Tuple(tup) => { + assert_eq!(tup.fields.len(), N); + } + _ => unreachable!(), + } + } + + assert_tuple_arity::<(), 0>(); + assert_tuple_arity::<(u8,), 1>(); + assert_tuple_arity::<(u8, u8), 2>(); + + const { + match Type::of::<(u8, u8)>().kind { + TypeKind::Tuple(tup) => { + let [a, b] = tup.fields else { unreachable!() }; + + assert!(a.offset == 0); + assert!(b.offset == 1); + + match (a.ty.info().kind, b.ty.info().kind) { + (TypeKind::Leaf, TypeKind::Leaf) => {} + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/tests/ui/reflection/tuples.rs b/tests/ui/reflection/tuples.rs deleted file mode 100644 index eab25a691efe2..0000000000000 --- a/tests/ui/reflection/tuples.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(type_info)] - -//@ run-pass - -use std::mem::type_info::{Type, TypeKind}; - -fn assert_tuple_arity() { - const { - match &Type::of::().kind { - TypeKind::Tuple(tup) => { - assert!(tup.fields.len() == N); - } - _ => unreachable!(), - } - } -} - -fn main() { - assert_tuple_arity::<(), 0>(); - assert_tuple_arity::<(u8,), 1>(); - assert_tuple_arity::<(u8, u8), 2>(); - const { - match &Type::of::<(u8, u8)>().kind { - TypeKind::Tuple(tup) => { - let [a, b] = tup.fields else { unreachable!() }; - assert!(a.offset == 0); - assert!(b.offset == 1); - match (&a.ty.info().kind, &b.ty.info().kind) { - (TypeKind::Leaf, TypeKind::Leaf) => {} - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } -}