From ee58df4ac93b9f4ebb24344ea48d60f2d1fdd882 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 2 Feb 2026 22:47:06 +0200 Subject: [PATCH 01/37] there is a policy now --- src/doc/rustc-dev-guide/src/crates-io.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 677b1fc03134..2a7431b40310 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -3,17 +3,7 @@ The Rust compiler supports building with some dependencies from `crates.io`. Examples are `log` and `env_logger`. -In general, -you should avoid adding dependencies to the compiler for several reasons: - -- The dependency may not be of high quality or well-maintained. -- The dependency may not be using a compatible license. -- The dependency may have transitive dependencies that have one of the above - problems. - - -Note that there is no official policy for vetting new dependencies to the compiler. -Decisions are made on a case-by-case basis, during code review. +Rust Forge has [official policy for vetting new dependencies]. ## Permitted dependencies @@ -21,3 +11,4 @@ The `tidy` tool has [a list of crates that are allowed]. To add a dependency that is not already in the compiler, you will need to add it to the list. [a list of crates that are allowed]: https://github.com/rust-lang/rust/blob/9d1b2106e23b1abd32fce1f17267604a5102f57a/src/tools/tidy/src/deps.rs#L73 +[official policy for vetting new dependencies]: https://forge.rust-lang.org/compiler/third-party-out-of-tree#third-party-crates From 1c7e6161f12dfac787c16cfd254da00e6d431f58 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 2 Feb 2026 22:48:26 +0200 Subject: [PATCH 02/37] they are so many that it feels strange to list any --- src/doc/rustc-dev-guide/src/crates-io.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 2a7431b40310..7e998020513e 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -1,7 +1,6 @@ # crates.io dependencies The Rust compiler supports building with some dependencies from `crates.io`. -Examples are `log` and `env_logger`. Rust Forge has [official policy for vetting new dependencies]. From e9965b80ff5f723d55a0a5ee5dcab63534062e34 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 2 Feb 2026 22:50:10 +0200 Subject: [PATCH 03/37] sembr src/crates-io.md --- src/doc/rustc-dev-guide/src/crates-io.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 7e998020513e..4c6de98ab56e 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -6,8 +6,8 @@ Rust Forge has [official policy for vetting new dependencies]. ## Permitted dependencies -The `tidy` tool has [a list of crates that are allowed]. To add a -dependency that is not already in the compiler, you will need to add it to the list. +The `tidy` tool has [a list of crates that are allowed]. +To add a dependency that is not already in the compiler, you will need to add it to the list. [a list of crates that are allowed]: https://github.com/rust-lang/rust/blob/9d1b2106e23b1abd32fce1f17267604a5102f57a/src/tools/tidy/src/deps.rs#L73 [official policy for vetting new dependencies]: https://forge.rust-lang.org/compiler/third-party-out-of-tree#third-party-crates From 2626872c300296598fc7d13c167e45249c1430ca Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 3 Feb 2026 14:53:02 +0900 Subject: [PATCH 04/37] Add label for date reference triage --- src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index c9f349147e79..28d48ba4e996 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -163,6 +163,9 @@ fn main() { } } println!(); + + println!("@rustbot label +C-date-reference-triage +E-easy +E-help-wanted"); + println!(); } } From 49d41d74861ad156b1cab5bef0fbec534ae8f8c8 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 3 Feb 2026 14:54:37 +0900 Subject: [PATCH 05/37] Add 'C-date-reference-triage' to exclude_labels --- src/doc/rustc-dev-guide/triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index f894456d0de3..07118872809e 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -5,6 +5,7 @@ new_issue = true exclude_labels = [ "A-diagnostics", + "C-date-reference-triage", "C-tracking-issue", ] From fb2be7b1b84602692c3e26d0c6409b7a15ced231 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 16:19:13 +0900 Subject: [PATCH 06/37] Fix rustdoc links for BoundRegionKind/BoundTyKind --- src/doc/rustc-dev-guide/src/ty-module/binders.md | 4 ++-- .../rustc-dev-guide/src/ty-module/instantiating-binders.md | 2 +- .../rustc-dev-guide/src/ty-module/param-ty-const-regions.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-module/binders.md b/src/doc/rustc-dev-guide/src/ty-module/binders.md index 7fd9eeed54ac..21cf80abc6e3 100644 --- a/src/doc/rustc-dev-guide/src/ty-module/binders.md +++ b/src/doc/rustc-dev-guide/src/ty-module/binders.md @@ -48,5 +48,5 @@ This would cause all kinds of issues as the region `'^1_0` refers to a binder at [`Binder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Binder.html [`BoundVar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.BoundVar.html -[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundRegionKind.html -[`BoundTyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundTyKind.html +[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.BoundRegionKind.html +[`BoundTyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.BoundTyKind.html diff --git a/src/doc/rustc-dev-guide/src/ty-module/instantiating-binders.md b/src/doc/rustc-dev-guide/src/ty-module/instantiating-binders.md index 3c7408465c44..82c340e87a81 100644 --- a/src/doc/rustc-dev-guide/src/ty-module/instantiating-binders.md +++ b/src/doc/rustc-dev-guide/src/ty-module/instantiating-binders.md @@ -136,7 +136,7 @@ As a concrete example, accessing the signature of a function we are type checkin [`liberate_late_bound_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.liberate_late_bound_regions [representing-types]: param-ty-const-regions.md -[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundRegionKind.html +[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.BoundRegionKind.html [`enter_forall`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/struct.InferCtxt.html#method.enter_forall [ch_placeholders_universes]: ../borrow-check/region-inference/placeholders-and-universes.md [`instantiate_binder_with_fresh_vars`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/struct.InferCtxt.html#method.instantiate_binder_with_fresh_vars diff --git a/src/doc/rustc-dev-guide/src/ty-module/param-ty-const-regions.md b/src/doc/rustc-dev-guide/src/ty-module/param-ty-const-regions.md index ce4e887862c7..b0c793003041 100644 --- a/src/doc/rustc-dev-guide/src/ty-module/param-ty-const-regions.md +++ b/src/doc/rustc-dev-guide/src/ty-module/param-ty-const-regions.md @@ -88,7 +88,7 @@ fn foo<'a, 'b, T: 'a>(one: T, two: &'a &'b u32) -> &'b u32 { [ch_early_late_bound]: ../early-late-parameters.md [ch_binders]: ./binders.md [ch_instantiating_binders]: ./instantiating-binders.md -[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundRegionKind.html +[`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.BoundRegionKind.html [`RegionKind::EarlyParam`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.RegionKind.html#variant.ReEarlyParam [`RegionKind::LateParam`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.RegionKind.html#variant.ReLateParam [`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param From 39a238cdba8cd33620f879724ae69a87f2057ed8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 31 Jan 2026 06:46:57 +0900 Subject: [PATCH 07/37] Document feature gate checking --- .../rustc-dev-guide/src/feature-gate-ck.md | 132 +++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-ck.md b/src/doc/rustc-dev-guide/src/feature-gate-ck.md index c17747a11b75..c840118075e2 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-ck.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-ck.md @@ -1,3 +1,133 @@ # Feature Gate Checking -**TODO**: this chapter [#1158](https://github.com/rust-lang/rustc-dev-guide/issues/1158) +Feature gates prevent usage of unstable language and library features without a +nightly-only `#![feature(...)]` opt-in. This chapter documents the implementation +of feature gating: where gates are defined, how they are enabled, and how usage +is verified. + +## Feature Definitions + +All feature gate definitions are located in the `rustc_feature` crate: + +- **Unstable features** are declared in [`rustc_feature/src/unstable.rs`] via + the `declare_features!` macro. This associates features with issue numbers and + tracking metadata. +- **Accepted features** (stabilized) are listed in [`rustc_feature/src/accepted.rs`]. +- **Removed features** (explicitly disallowed) are listed in [`rustc_feature/src/removed.rs`]. +- **Gated built-in attributes and cfgs** are declared in [`rustc_feature/src/builtin_attrs.rs`]. + +The [`rustc_feature::Features`] type represents the **active feature set** for a +crate. Helpers like `enabled`, `incomplete`, and `internal` are used during +compilation to check status. + +## Collecting Features + +Before AST validation or expansion, `rustc` collects crate-level +`#![feature(...)]` attributes to build the active `Features` set. + +- The collection happens in [`rustc_expand/src/config.rs`] in [`features`]. +- Each `#![feature]` entry is classified against the `unstable`, `accepted`, and + `removed` tables: + - **Removed** features cause an immediate error. + - **Accepted** features are recorded but do not require nightly. On + stable/beta they trigger the "already stabilized" diagnostic. + - **Unstable** features are recorded as enabled. + - Unknown features are treated as **library features** and validated later. +- With `-Z allow-features=...`, any **unstable** or **unknown** feature + not in the allowlist is rejected. +- [`RUSTC_BOOTSTRAP`] feeds into `UnstableFeatures::from_environment`. This + variable controls whether the compiler is treated as "nightly", allowing + feature gates to be bypassed during bootstrapping or explicitly disabled (`-1`). + +## Parser Gating + +Some syntax is detected and gated during parsing. The parser records spans for +later checking to keep diagnostics consistent and deferred until after parsing. + +- [`rustc_session/src/parse.rs`] defines [`GatedSpans`] and the `gate` method. +- The parser uses it in [`rustc_parse/src/parser/*`] when it encounters + syntax that requires a gate (e.g., `async for`, `yield`, experimental patterns). + +## Checking Pass + +The central logic lives in [`rustc_ast_passes/src/feature_gate.rs`], primarily +in `check_crate` and its AST visitor. + +### `check_crate` + +`check_crate` performs high-level validation: + +- `maybe_stage_features`: Rejects `#![feature]` on stable/beta. +- `check_incompatible_features`: Ensures incompatible feature combinations + (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. +- `check_new_solver_banned_features`: Bans features incompatible with + certain compiler modes (e.g., the next trait solver). +- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. + +### AST Visitor + +A `PostExpansionVisitor` walks the expanded AST to check constructs that are +easier to validate after expansion. + +- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: + 1. Is the feature enabled? + 2. Does `span.allows_unstable` permit it (for internal compiler macros)? +- Examples include `trait_alias`, `decl_macro`, `extern types`, and various + `impl Trait` forms. + +### Checking `GatedSpans` + +`check_crate` iterates over `sess.psess.gated_spans`: + +- The `gate_all!` macro emits diagnostics for each gated span if the feature is + not enabled. +- Some gates have extra logic (e.g., `yield` can be allowed by `coroutines` or + `gen_blocks`). +- Legacy gates (e.g., `box_patterns`, `try_blocks`) may use a separate path that + emits future-incompatibility warnings instead of hard errors. + +## Attributes and `cfg` + +Beyond syntax, rustc also gates attributes and `cfg` options. + +### Built-in attributes + +- [`rustc_ast_passes::check_attribute`] inspects attributes against + `BUILTIN_ATTRIBUTE_MAP`. +- If the attribute is `AttributeGate::Gated` and the feature isn’t enabled, + `feature_err` is emitted. + +### `cfg` options + +- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines + `find_gated_cfg`/`gate_cfg` to reject gated `cfg`s. +- `gate_cfg` respects `Span::allows_unstable`, allowing internal compiler + macros to bypass `cfg` gates when marked with `#[allow_internal_unstable]`. +- The gated cfg list is defined in [`rustc_feature/src/builtin_attrs.rs`]. + +## Diagnostics + +Diagnostic helpers are located in [`rustc_session/src/parse.rs`]. + +- `feature_err` and `feature_warn` emit standardized diagnostics, attaching the + tracking issue number where possible. +- `Span::allows_unstable` in [`rustc_span/src/lib.rs`] checks if a span originates + from a macro marked with `#[allow_internal_unstable]`. This allows internal + macros to use unstable features on stable channels while enforcing gates for + user code. + +[`rustc_feature/src/unstable.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/unstable.rs +[`rustc_feature/src/removed.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/removed.rs +[`rustc_feature/src/accepted.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/accepted.rs +[`rustc_feature/src/builtin_attrs.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/builtin_attrs.rs +[`rustc_feature::Features`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/struct.Features.html +[`rustc_expand/src/config.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_expand/src/config.rs +[`features`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/config/fn.features.html +[`RUSTC_BOOTSTRAP`]: https://doc.rust-lang.org/beta/unstable-book/compiler-environment-variables/RUSTC_BOOTSTRAP.html +[`rustc_session/src/parse.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_session/src/parse.rs +[`GatedSpans`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.GatedSpans.html +[`rustc_ast_passes/src/feature_gate.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_ast_passes/src/feature_gate.rs +[`rustc_parse/src/parser/*`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html +[`rustc_ast_passes::check_attribute`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_passes/feature_gate/fn.check_attribute.html +[`rustc_attr_parsing/src/attributes/cfg.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_attr_parsing/src/attributes/cfg.rs +[`rustc_span/src/lib.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_span/src/lib.rs From f3b9e8a09fc87d7e2c71db9e3343fefebbc95dbb Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 3 Feb 2026 14:24:48 +0900 Subject: [PATCH 08/37] Clarify description of new solver banned features Co-authored-by: Tshepang Mbambo --- src/doc/rustc-dev-guide/src/feature-gate-ck.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-ck.md b/src/doc/rustc-dev-guide/src/feature-gate-ck.md index c840118075e2..8a93fbc7561f 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-ck.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-ck.md @@ -61,7 +61,7 @@ in `check_crate` and its AST visitor. - `check_incompatible_features`: Ensures incompatible feature combinations (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with - certain compiler modes (e.g., the next trait solver). + compiler mode for the next trait solver. - **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. ### AST Visitor From 33b2fcb1e78aae68474ba38f9fd5d38352abf20e Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 14:36:17 +0900 Subject: [PATCH 09/37] Rename `feature-gate-ck.md` to `feature-gate-check.md` --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- .../src/{feature-gate-ck.md => feature-gate-check.md} | 0 src/doc/rustc-dev-guide/src/syntax-intro.md | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/doc/rustc-dev-guide/src/{feature-gate-ck.md => feature-gate-check.md} (100%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 5342c54607b7..22f4da50b62c 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -124,7 +124,7 @@ - [`#[test]` implementation](./test-implementation.md) - [Panic implementation](./panic-implementation.md) - [AST validation](./ast-validation.md) - - [Feature gate checking](./feature-gate-ck.md) + - [Feature gate checking](./feature-gate-check.md) - [Lang Items](./lang-items.md) - [The HIR (High-level IR)](./hir.md) - [Lowering AST to HIR](./hir/lowering.md) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-ck.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md similarity index 100% rename from src/doc/rustc-dev-guide/src/feature-gate-ck.md rename to src/doc/rustc-dev-guide/src/feature-gate-check.md diff --git a/src/doc/rustc-dev-guide/src/syntax-intro.md b/src/doc/rustc-dev-guide/src/syntax-intro.md index 0f5a91ee50d8..a5a8bab14971 100644 --- a/src/doc/rustc-dev-guide/src/syntax-intro.md +++ b/src/doc/rustc-dev-guide/src/syntax-intro.md @@ -13,7 +13,7 @@ And parsing requires macro expansion, which in turn may require parsing the outp [AST]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [macro expansion]: ./macro-expansion.md -[feature-gate checking]: ./feature-gate-ck.md +[feature-gate checking]: ./feature-gate-check.md [lexing, parsing]: ./the-parser.md [name resolution]: ./name-resolution.md [validation]: ./ast-validation.md From 11ac5bd665e9a7cc9cd4db873e1db5b6b8ef6478 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 14:41:54 +0900 Subject: [PATCH 10/37] Clarify and reorganize feature-gate-check doc --- .../rustc-dev-guide/src/feature-gate-check.md | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 8a93fbc7561f..591231c0229f 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -5,6 +5,8 @@ nightly-only `#![feature(...)]` opt-in. This chapter documents the implementatio of feature gating: where gates are defined, how they are enabled, and how usage is verified. + + ## Feature Definitions All feature gate definitions are located in the `rustc_feature` crate: @@ -30,7 +32,10 @@ Before AST validation or expansion, `rustc` collects crate-level `removed` tables: - **Removed** features cause an immediate error. - **Accepted** features are recorded but do not require nightly. On - stable/beta they trigger the "already stabilized" diagnostic. + stable/beta, `maybe_stage_features` in + [`rustc_ast_passes/src/feature_gate.rs`] emits the non-nightly + diagnostic and lists stable features, which is where the "already + stabilized" messaging comes from. - **Unstable** features are recorded as enabled. - Unknown features are treated as **library features** and validated later. - With `-Z allow-features=...`, any **unstable** or **unknown** feature @@ -62,18 +67,8 @@ in `check_crate` and its AST visitor. (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with compiler mode for the next trait solver. -- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. - -### AST Visitor - -A `PostExpansionVisitor` walks the expanded AST to check constructs that are -easier to validate after expansion. - -- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: - 1. Is the feature enabled? - 2. Does `span.allows_unstable` permit it (for internal compiler macros)? -- Examples include `trait_alias`, `decl_macro`, `extern types`, and various - `impl Trait` forms. +- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing + (see [Checking `GatedSpans`](#checking-gatedspans)). ### Checking `GatedSpans` @@ -86,6 +81,17 @@ easier to validate after expansion. - Legacy gates (e.g., `box_patterns`, `try_blocks`) may use a separate path that emits future-incompatibility warnings instead of hard errors. +### AST Visitor + +A `PostExpansionVisitor` walks the expanded AST to check constructs that are +easier to validate after expansion. + +- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: + 1. Is the feature enabled? + 2. Does `span.allows_unstable` permit it (for internal compiler macros)? +- Examples include `trait_alias`, `decl_macro`, `extern types`, and various + `impl Trait` forms. + ## Attributes and `cfg` Beyond syntax, rustc also gates attributes and `cfg` options. @@ -99,8 +105,8 @@ Beyond syntax, rustc also gates attributes and `cfg` options. ### `cfg` options -- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines - `find_gated_cfg`/`gate_cfg` to reject gated `cfg`s. +- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines `gate_cfg` and uses + [`rustc_feature::find_gated_cfg`] to reject gated `cfg`s. - `gate_cfg` respects `Span::allows_unstable`, allowing internal compiler macros to bypass `cfg` gates when marked with `#[allow_internal_unstable]`. - The gated cfg list is defined in [`rustc_feature/src/builtin_attrs.rs`]. @@ -130,4 +136,5 @@ Diagnostic helpers are located in [`rustc_session/src/parse.rs`]. [`rustc_parse/src/parser/*`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html [`rustc_ast_passes::check_attribute`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_passes/feature_gate/fn.check_attribute.html [`rustc_attr_parsing/src/attributes/cfg.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_attr_parsing/src/attributes/cfg.rs +[`rustc_feature::find_gated_cfg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/fn.find_gated_cfg.html [`rustc_span/src/lib.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_span/src/lib.rs From 89771a79fae2da3fe8197eac10f997b4c066189f Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 17:06:53 +0900 Subject: [PATCH 11/37] Add cross-links between feature gate docs --- src/doc/rustc-dev-guide/src/feature-gate-check.md | 4 ++++ src/doc/rustc-dev-guide/src/feature-gates.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 591231c0229f..c5a499f5708c 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -1,5 +1,8 @@ # Feature Gate Checking +For the how-to steps to add, remove, rename, or stabilize feature gates, +see [Feature gates][feature-gates]. + Feature gates prevent usage of unstable language and library features without a nightly-only `#![feature(...)]` opt-in. This chapter documents the implementation of feature gating: where gates are defined, how they are enabled, and how usage @@ -138,3 +141,4 @@ Diagnostic helpers are located in [`rustc_session/src/parse.rs`]. [`rustc_attr_parsing/src/attributes/cfg.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_attr_parsing/src/attributes/cfg.rs [`rustc_feature::find_gated_cfg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/fn.find_gated_cfg.html [`rustc_span/src/lib.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_span/src/lib.rs +[feature-gates]: ./feature-gates.md diff --git a/src/doc/rustc-dev-guide/src/feature-gates.md b/src/doc/rustc-dev-guide/src/feature-gates.md index d2a517360714..76bf111fe772 100644 --- a/src/doc/rustc-dev-guide/src/feature-gates.md +++ b/src/doc/rustc-dev-guide/src/feature-gates.md @@ -3,9 +3,13 @@ This chapter is intended to provide basic help for adding, removing, and modifying feature gates. +For how rustc enforces and checks feature gates in the compiler pipeline, +see [Feature Gate Checking][feature-gate-check]. + Note that this is specific to *language* feature gates; *library* feature gates use [a different mechanism][libs-gate]. +[feature-gate-check]: ./feature-gate-check.md [libs-gate]: ./stability.md ## Adding a feature gate From 2184b446ce264d19e43cb6c38611da7cf1a14150 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova <58857108+ada4a@users.noreply.github.com> Date: Sat, 31 Jan 2026 18:29:28 +0100 Subject: [PATCH 12/37] Fix typo --- src/doc/rustc-dev-guide/src/const-generics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 4c2a0ddbabd5..344d9b1d26de 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -61,7 +61,7 @@ In some sense the desugarings from the previous examples are to: struct Foo; type Alias = [u8; 1 + 1]; -// sort-of desugars to psuedo-rust: +// sort-of desugars to pseudo-rust: struct Foo; const ANON = 1 + 1; @@ -178,7 +178,7 @@ To check this we have [`ClauseKind::ConstArgHasType(ty::Const, Ty)`][const_arg_h ```rust fn foo() {} -// desugars to in psuedo-rust +// desugars to in pseudo-rust fn foo() where From 2495d07fc7f15fa88dce5d566d1a30377f886a3e Mon Sep 17 00:00:00 2001 From: Redddy Date: Thu, 5 Feb 2026 23:46:34 +0900 Subject: [PATCH 13/37] Updated link to the Rust CI successful workflow runs page --- src/doc/rustc-dev-guide/src/tests/ci.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 723926f2241f..c04e3da8b2c2 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -447,7 +447,7 @@ If you want to determine which `bootstrap.toml` settings are used in CI for a particular job, it is probably easiest to just look at the build log. To do this: -1. Go to +1. Go to [the Rust CI successful workflow runs page][workflow runs] to find the most recently successful build, and click on it. 2. Choose the job you are interested in on the left-hand side. 3. Click on the gear icon and choose "View raw logs" @@ -462,3 +462,4 @@ To do this: [merge queue]: https://bors.rust-lang.org/queue/rust [dist-x86_64-linux]: https://github.com/rust-lang/rust/blob/HEAD/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile [the GitHub Actions workflows page]: https://github.com/rust-lang/rust/actions +[workflow runs]: https://github.com/rust-lang/rust/actions?query=branch%3Aautomation%2Fbors%2Fauto+is%3Asuccess From f85323666d032469fde09063d3bab55a09b6de43 Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 6 Feb 2026 00:20:10 +0900 Subject: [PATCH 14/37] Update CI documentation for branch names --- src/doc/rustc-dev-guide/src/tests/ci.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index c04e3da8b2c2..45cb10cfcb02 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -102,7 +102,7 @@ Most platforms only run the build steps, some run a restricted set of tests; only a subset run the full suite of tests (see Rust's [platform tiers]). Auto jobs are defined in the `auto` section of [`jobs.yml`]. -They are executed on the `auto` branch under the `rust-lang/rust` repository, +They are executed on the [`automation/bors/auto`][auto] branch under the `rust-lang/rust` repository, and the final result will be reported via a comment made by bors on the corresponding PR. The live results can be seen on [the GitHub Actions workflows page]. @@ -110,6 +110,7 @@ At any given time, at most a single `auto` build is being executed. Find out more in [Merging PRs serially with bors](#merging-prs-serially-with-bors). [platform tiers]: https://forge.rust-lang.org/release/platform-support.html#rust-platform-support +[auto]: https://github.com/rust-lang/rust/tree/automation/bors/auto ### Try builds @@ -204,7 +205,7 @@ to help make the perf comparison as fair as possible. > However, it can be less flexible because you cannot adjust the set of tests > that are exercised this way. -Try builds are executed on the `try` branch under the `rust-lang/rust` repository and +Try builds are executed on the [`automation/bors/try`][try] branch under the `rust-lang/rust` repository and their results can be seen on [the GitHub Actions workflows page], although usually you will be notified of the result by a comment made by bors on the corresponding PR. @@ -213,6 +214,7 @@ Multiple try builds can execute concurrently across different PRs, but there can a single try build running on a single PR at any given time. [rustc-perf]: https://github.com/rust-lang/rustc-perf +[try]: https://github.com/rust-lang/rust/tree/automation/bors/try ### Modifying CI jobs @@ -284,8 +286,8 @@ If all the builders are green, the PR is merged, otherwise the failure is recorded and the PR will have to be re-approved again. Bors doesn’t interact with CI services directly, but it works by pushing the -merge commit it wants to test to specific branches (like `auto` or `try`), which -are configured to execute CI checks. +merge commit it wants to test to specific branches (like `automation/bors/auto` or `automation/bors/try`), +which are configured to execute CI checks. Bors then detects the outcome of the build by listening for either Commit Statuses or Check Runs. Since the merge commit is based on the latest `main` and only one can be tested at the same time, when From 3fd4ab427a0b3c94d9c198730e4609736e479745 Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 6 Feb 2026 00:31:37 +0900 Subject: [PATCH 15/37] Simplify redundant description --- src/doc/rustc-dev-guide/src/tests/ci.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 45cb10cfcb02..6b63f68b29ee 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -450,7 +450,7 @@ particular job, it is probably easiest to just look at the build log. To do this: 1. Go to [the Rust CI successful workflow runs page][workflow runs] - to find the most recently successful build, and click on it. + and click on the most recent one. 2. Choose the job you are interested in on the left-hand side. 3. Click on the gear icon and choose "View raw logs" 4. Search for the string "Configure the build" From b8a53ca947104bda8eed5669bb08315e1f64899b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 6 Feb 2026 05:40:22 +0200 Subject: [PATCH 16/37] typo --- .../src/building/bootstrapping/what-bootstrapping-does.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 89eca0f0a1c6..453441fd1015 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -243,7 +243,7 @@ This is also where `--keep-stage 1 library/std` comes into play. Since most changes to the compiler don't actually change the ABI, once you've produced a `std` in `stage1`, you can probably just reuse it with a different compiler. If the ABI hasn't changed, you're good to go, no need to spend time recompiling -that `std`. The flag `--keep-stage` simply instructs the build script to assumes +that `std`. The flag `--keep-stage` simply instructs the build script to assume the previous compile is fine and copies those artifacts into the appropriate place, skipping the `cargo` invocation. From 0de74158757dcb2db583c27b412f14391ae9ce0c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 7 Feb 2026 19:44:34 +0900 Subject: [PATCH 17/37] borrowck: suggest `&mut *x` for pattern reborrows --- .../src/diagnostics/mutability_errors.rs | 73 +++++++++++++++++-- tests/ui/borrowck/mut-borrow-of-mut-ref.fixed | 37 ++++++++++ tests/ui/borrowck/mut-borrow-of-mut-ref.rs | 3 +- .../ui/borrowck/mut-borrow-of-mut-ref.stderr | 16 +--- .../reborrow-in-match-suggest-deref.fixed | 23 ++++++ .../reborrow-in-match-suggest-deref.rs | 23 ++++++ .../reborrow-in-match-suggest-deref.stderr | 23 ++++++ 7 files changed, 175 insertions(+), 23 deletions(-) create mode 100644 tests/ui/borrowck/mut-borrow-of-mut-ref.fixed create mode 100644 tests/ui/borrowck/reborrow-in-match-suggest-deref.fixed create mode 100644 tests/ui/borrowck/reborrow-in-match-suggest-deref.rs create mode 100644 tests/ui/borrowck/reborrow-in-match-suggest-deref.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 4fb739403ced..07d2313cc7fd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -354,14 +354,71 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span) { if snippet.starts_with("&mut ") { - // We don't have access to the HIR to get accurate spans, but we can - // give a best effort structured suggestion. - err.span_suggestion_verbose( - source_info.span.with_hi(source_info.span.lo() + BytePos(5)), - "if there is only one mutable reborrow, remove the `&mut`", - "", - Applicability::MaybeIncorrect, - ); + // In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and + // removing the extra `&mut` is the most direct suggestion. But for + // pattern-matching expressions (`match`, `if let`, `while let`), that + // can easily turn into a move, so prefer suggesting an explicit + // reborrow via `&mut *x` instead. + let mut in_pat_scrutinee = false; + let mut is_deref_coerced = false; + if let Some(expr) = self.find_expr(source_info.span) { + let tcx = self.infcx.tcx; + let span = expr.span.source_callsite(); + for (_, node) in tcx.hir_parent_iter(expr.hir_id) { + if let Node::Expr(parent_expr) = node { + match parent_expr.kind { + ExprKind::Match(scrutinee, ..) + if scrutinee + .span + .source_callsite() + .contains(span) => + { + in_pat_scrutinee = true; + break; + } + ExprKind::Let(let_expr) + if let_expr + .init + .span + .source_callsite() + .contains(span) => + { + in_pat_scrutinee = true; + break; + } + _ => {} + } + } + } + + let typeck = tcx.typeck(expr.hir_id.owner.def_id); + is_deref_coerced = + typeck.expr_adjustments(expr).iter().any(|adj| { + matches!(adj.kind, ty::adjustment::Adjust::Deref(_)) + }); + } + + if in_pat_scrutinee { + // Best-effort structured suggestion: insert `*` after `&mut `. + err.span_suggestion_verbose( + source_info + .span + .with_lo(source_info.span.lo() + BytePos(5)) + .shrink_to_lo(), + "to reborrow the mutable reference, add `*`", + "*", + Applicability::MaybeIncorrect, + ); + } else if is_deref_coerced { + // We don't have access to the HIR to get accurate spans, but we + // can give a best effort structured suggestion. + err.span_suggestion_verbose( + source_info.span.with_hi(source_info.span.lo() + BytePos(5)), + "if there is only one mutable reborrow, remove the `&mut`", + "", + Applicability::MaybeIncorrect, + ); + } } else { // This can occur with things like `(&mut self).foo()`. err.span_help(source_info.span, "try removing `&mut` here"); diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.fixed b/tests/ui/borrowck/mut-borrow-of-mut-ref.fixed new file mode 100644 index 000000000000..f70983c65223 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.fixed @@ -0,0 +1,37 @@ +// Suggest not mutably borrowing a mutable reference +//@ run-rustfix +#![crate_type = "rlib"] + +pub fn f(mut b: &mut i32) { + //~^ ERROR: cannot borrow + //~| NOTE: not mutable + //~| NOTE: the binding is already a mutable borrow + //~| HELP: consider making the binding mutable if you need to reborrow multiple times + h(b); + //~^ NOTE: cannot borrow as mutable + //~| HELP: if there is only one mutable reborrow, remove the `&mut` + g(&mut &mut b); + //~^ NOTE: cannot borrow as mutable +} + +pub fn g(mut b: &mut i32) { //~ NOTE: the binding is already a mutable borrow + //~^ HELP: consider making the binding mutable if you need to reborrow multiple times + h(&mut &mut b); + //~^ ERROR: cannot borrow + //~| NOTE: cannot borrow as mutable +} + +pub fn h(_: &mut i32) {} + +trait Foo { + fn bar(&mut self); +} + +impl Foo for &mut String { + fn bar(&mut self) {} +} + +pub fn baz(mut f: &mut String) { //~ HELP consider making the binding mutable + f.bar(); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable + //~^ NOTE cannot borrow as mutable +} diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.rs b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs index 33954592bf65..d150b249bf2d 100644 --- a/tests/ui/borrowck/mut-borrow-of-mut-ref.rs +++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs @@ -1,4 +1,5 @@ // Suggest not mutably borrowing a mutable reference +//@ run-rustfix #![crate_type = "rlib"] pub fn f(b: &mut i32) { @@ -11,7 +12,6 @@ pub fn f(b: &mut i32) { //~| HELP: if there is only one mutable reborrow, remove the `&mut` g(&mut &mut b); //~^ NOTE: cannot borrow as mutable - //~| HELP: if there is only one mutable reborrow, remove the `&mut` } pub fn g(b: &mut i32) { //~ NOTE: the binding is already a mutable borrow @@ -19,7 +19,6 @@ pub fn g(b: &mut i32) { //~ NOTE: the binding is already a mutable borrow h(&mut &mut b); //~^ ERROR: cannot borrow //~| NOTE: cannot borrow as mutable - //~| HELP: if there is only one mutable reborrow, remove the `&mut` } pub fn h(_: &mut i32) {} diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr index 4c4a5e718393..01ceba90c943 100644 --- a/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr +++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable - --> $DIR/mut-borrow-of-mut-ref.rs:4:10 + --> $DIR/mut-borrow-of-mut-ref.rs:5:10 | LL | pub fn f(b: &mut i32) { | ^ not mutable @@ -11,7 +11,7 @@ LL | g(&mut &mut b); | ------ cannot borrow as mutable | note: the binding is already a mutable borrow - --> $DIR/mut-borrow-of-mut-ref.rs:4:13 + --> $DIR/mut-borrow-of-mut-ref.rs:5:13 | LL | pub fn f(b: &mut i32) { | ^^^^^^^^ @@ -24,11 +24,6 @@ help: if there is only one mutable reborrow, remove the `&mut` LL - h(&mut b); LL + h(b); | -help: if there is only one mutable reborrow, remove the `&mut` - | -LL - g(&mut &mut b); -LL + g(&mut b); - | error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable --> $DIR/mut-borrow-of-mut-ref.rs:19:12 @@ -45,14 +40,9 @@ help: consider making the binding mutable if you need to reborrow multiple times | LL | pub fn g(mut b: &mut i32) { | +++ -help: if there is only one mutable reborrow, remove the `&mut` - | -LL - h(&mut &mut b); -LL + h(&mut b); - | error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable - --> $DIR/mut-borrow-of-mut-ref.rs:36:5 + --> $DIR/mut-borrow-of-mut-ref.rs:35:5 | LL | f.bar(); | ^ cannot borrow as mutable diff --git a/tests/ui/borrowck/reborrow-in-match-suggest-deref.fixed b/tests/ui/borrowck/reborrow-in-match-suggest-deref.fixed new file mode 100644 index 000000000000..3f52e57a804c --- /dev/null +++ b/tests/ui/borrowck/reborrow-in-match-suggest-deref.fixed @@ -0,0 +1,23 @@ +// Regression test for #81059. +// edition:2024 +//@ run-rustfix + +#![allow(unused)] + +fn test(mut outer: &mut Option) { + //~^ NOTE: the binding is already a mutable borrow + //~| HELP: consider making the binding mutable if you need to reborrow multiple times + match (&mut *outer, 23) { + //~^ ERROR: cannot borrow `outer` as mutable, as it is not declared as mutable + //~| NOTE: cannot borrow as mutable + //~| HELP: to reborrow the mutable reference, add `*` + (Some(inner), _) => { + *inner = 17; + } + _ => { + *outer = Some(2); + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/reborrow-in-match-suggest-deref.rs b/tests/ui/borrowck/reborrow-in-match-suggest-deref.rs new file mode 100644 index 000000000000..34c299f4f7b1 --- /dev/null +++ b/tests/ui/borrowck/reborrow-in-match-suggest-deref.rs @@ -0,0 +1,23 @@ +// Regression test for #81059. +// edition:2024 +//@ run-rustfix + +#![allow(unused)] + +fn test(outer: &mut Option) { + //~^ NOTE: the binding is already a mutable borrow + //~| HELP: consider making the binding mutable if you need to reborrow multiple times + match (&mut outer, 23) { + //~^ ERROR: cannot borrow `outer` as mutable, as it is not declared as mutable + //~| NOTE: cannot borrow as mutable + //~| HELP: to reborrow the mutable reference, add `*` + (Some(inner), _) => { + *inner = 17; + } + _ => { + *outer = Some(2); + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/reborrow-in-match-suggest-deref.stderr b/tests/ui/borrowck/reborrow-in-match-suggest-deref.stderr new file mode 100644 index 000000000000..db3129461518 --- /dev/null +++ b/tests/ui/borrowck/reborrow-in-match-suggest-deref.stderr @@ -0,0 +1,23 @@ +error[E0596]: cannot borrow `outer` as mutable, as it is not declared as mutable + --> $DIR/reborrow-in-match-suggest-deref.rs:10:12 + | +LL | match (&mut outer, 23) { + | ^^^^^^^^^^ cannot borrow as mutable + | +note: the binding is already a mutable borrow + --> $DIR/reborrow-in-match-suggest-deref.rs:7:16 + | +LL | fn test(outer: &mut Option) { + | ^^^^^^^^^^^^^^^^ +help: consider making the binding mutable if you need to reborrow multiple times + | +LL | fn test(mut outer: &mut Option) { + | +++ +help: to reborrow the mutable reference, add `*` + | +LL | match (&mut *outer, 23) { + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. From f693a1df2b5fd345f73f78ac674c6b8c67314d61 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Feb 2026 14:12:42 +0100 Subject: [PATCH 18/37] Update diagnostics documentation --- .../src/diagnostics/diagnostic-structs.md | 173 ++++++------------ 1 file changed, 53 insertions(+), 120 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index 4e5c3413cb8a..2260b1ec4df1 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -12,7 +12,7 @@ customizing the rendering logic, or selecting messages at runtime, you will need the corresponding trait (`Diagnostic`, `LintDiagnostic`, or `Subdiagnostic`). This approach provides greater flexibility and is recommended for diagnostics that go beyond simple, static structures. -Diagnostic can be translated into different languages and each has a slug that uniquely identifies the diagnostic. +Diagnostic can be translated into different languages. ## `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` @@ -21,13 +21,13 @@ shown below: ```rust,ignore #[derive(Diagnostic)] -#[diag(hir_analysis_field_already_declared, code = E0124)] +#[diag("field `{$field_name}` is already declared", code = E0124)] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] - #[label] + #[label("field already declared")] pub span: Span, - #[label(previous_decl_label)] + #[label("`{$field_name}` first declared here")] pub prev_span: Span, } ``` @@ -42,25 +42,10 @@ the `code` sub-attribute. Specifying a `code` isn't mandatory, but if you are porting a diagnostic that uses `Diag` to use `Diagnostic` then you should keep the code if there was one. -`#[diag(..)]` must provide a slug as the first positional argument (a path to an -item in `rustc_errors::fluent::*`). A slug uniquely identifies the diagnostic -and is also how the compiler knows what error message to emit (in the default -locale of the compiler, or in the locale requested by the user). See +`#[diag(..)]` must provide a message as the first positional argument. +The message is written in English, but might be translated to the locale requested by the user. See [translation documentation](./translation.md) to learn more about how -translatable error messages are written and how slug items are generated. - -In our example, the Fluent message for the "field already declared" diagnostic -looks like this: - -```fluent -hir_analysis_field_already_declared = - field `{$field_name}` is already declared - .label = field already declared - .previous_decl_label = `{$field_name}` first declared here -``` - -`hir_analysis_field_already_declared` is the slug from our example and is followed -by the diagnostic message. +translatable error messages are written and how they are generated. Every field of the `Diagnostic` which does not have an annotation is available in Fluent messages as a variable, like `field_name` in the example @@ -76,13 +61,7 @@ specified on a `Diagnostic`. `#[label]`, `#[help]`, `#[warning]` and `#[note]` can all be applied to fields which have the type `Span`. Applying any of these attributes will create the corresponding -subdiagnostic with that `Span`. These attributes will look for their -diagnostic message in a Fluent attribute attached to the primary Fluent -message. In our example, `#[label]` will look for -`hir_analysis_field_already_declared.label` (which has the message "field already -declared"). If there is more than one subdiagnostic of the same type, then -these attributes can also take a value that is the attribute name to look for -(e.g. `previous_decl_label` in our example). +subdiagnostic with that `Span`. These attributes take a diagnostic message as an argument. Other types have special behavior when used in a `Diagnostic` derive: @@ -99,17 +78,17 @@ represent optional `#[note]`/`#[help]`/`#[warning]` subdiagnostics. Suggestions can be emitted using one of four field attributes: -- `#[suggestion(slug, code = "...", applicability = "...")]` -- `#[suggestion_hidden(slug, code = "...", applicability = "...")]` -- `#[suggestion_short(slug, code = "...", applicability = "...")]` -- `#[suggestion_verbose(slug, code = "...", applicability = "...")]` +- `#[suggestion("message", code = "...", applicability = "...")]` +- `#[suggestion_hidden("message", code = "...", applicability = "...")]` +- `#[suggestion_short("message", code = "...", applicability = "...")]` +- `#[suggestion_verbose("message", code = "...", applicability = "...")]` Suggestions must be applied on either a `Span` field or a `(Span, -MachineApplicability)` field. Similarly to other field attributes, the slug -specifies the Fluent attribute with the message and defaults to the equivalent -of `.suggestion`. `code` specifies the code that should be suggested as a +MachineApplicability)` field. Similarly to other field attributes, a message +needs to be provided which will be shown to the user. +`code` specifies the code that should be suggested as a replacement and is a format string (e.g. `{field_name}` would be replaced by -the value of the `field_name` field of the struct), not a Fluent identifier. +the value of the `field_name` field of the struct). `applicability` can be used to specify the applicability in the attribute, it cannot be used when the field's type contains an `Applicability`. @@ -119,15 +98,15 @@ In the end, the `Diagnostic` derive will generate an implementation of ```rust,ignore impl<'a, G: EmissionGuarantee> Diagnostic<'a> for FieldAlreadyDeclared { fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new(dcx, level, fluent::hir_analysis_field_already_declared); + let mut diag = Diag::new(dcx, level, "field `{$field_name}` is already declared"); diag.set_span(self.span); diag.span_label( self.span, - fluent::hir_analysis_label + "field already declared" ); diag.span_label( self.prev_span, - fluent::hir_analysis_previous_decl_label + "`{$field_name}` first declared here" ); diag } @@ -150,60 +129,40 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` support the following attributes: -- `#[diag(slug, code = "...")]` +- `#[diag("message", code = "...")]` - _Applied to struct or enum variant._ - _Mandatory_ - Defines the text and error code to be associated with the diagnostic. - - Slug (_Mandatory_) - - Uniquely identifies the diagnostic and corresponds to its Fluent message, - mandatory. - - A path to an item in `rustc_errors::fluent`, e.g. - `rustc_errors::fluent::hir_analysis_field_already_declared` - (`rustc_errors::fluent` is implicit in the attribute, so just - `hir_analysis_field_already_declared`). + - Message (_Mandatory_) + - The diagnostic message which will be shown to the user. - See [translation documentation](./translation.md). - `code = "..."` (_Optional_) - Specifies the error code. -- `#[note]` or `#[note(slug)]` (_Optional_) +- `#[note("message")]` (_Optional_) - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ - Adds a note subdiagnostic. - - Value is a path to an item in `rustc_errors::fluent` for the note's - message. - - Defaults to equivalent of `.note`. + - Value is the note's message. - If applied to a `Span` field, creates a spanned note. -- `#[help]` or `#[help(slug)]` (_Optional_) +- `#[help("message")]` (_Optional_) - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ - Adds a help subdiagnostic. - - Value is a path to an item in `rustc_errors::fluent` for the note's - message. - - Defaults to equivalent of `.help`. + - Value is the help message. - If applied to a `Span` field, creates a spanned help. -- `#[label]` or `#[label(slug)]` (_Optional_) +- `#[label("message")]` (_Optional_) - _Applied to `Span` fields._ - Adds a label subdiagnostic. - - Value is a path to an item in `rustc_errors::fluent` for the note's - message. - - Defaults to equivalent of `.label`. -- `#[warning]` or `#[warning(slug)]` (_Optional_) + - Value is the label's message. +- `#[warning("message")]` (_Optional_) - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ - Adds a warning subdiagnostic. - - Value is a path to an item in `rustc_errors::fluent` for the note's - message. - - Defaults to equivalent of `.warn`. -- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` + - Value is the warning's message. +- `#[suggestion{,_hidden,_short,_verbose}("message", code = "...", applicability = "...")]` (_Optional_) - _Applied to `(Span, MachineApplicability)` or `Span` fields._ - Adds a suggestion subdiagnostic. - - Slug (_Mandatory_) - - A path to an item in `rustc_errors::fluent`, e.g. - `rustc_errors::fluent::hir_analysis_field_already_declared` - (`rustc_errors::fluent` is implicit in the attribute, so just - `hir_analysis_field_already_declared`). Fluent attributes for all messages - exist as top-level items in that module (so `hir_analysis_message.attr` is just - `attr`). + - Message (_Mandatory_) + - Value is the suggestion message that will be shown to the user. - See [translation documentation](./translation.md). - - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or - - `.suggestion` in Fluent). - `code = "..."`/`code("...", ...)` (_Mandatory_) - One or multiple format strings indicating the code to be suggested as a replacement. Multiple values signify multiple possible replacements. @@ -235,12 +194,12 @@ shown below: ```rust #[derive(Subdiagnostic)] pub enum ExpectedReturnTypeLabel<'tcx> { - #[label(hir_analysis_expected_default_return_type)] + #[label("expected `()` because of default return type")] Unit { #[primary_span] span: Span, }, - #[label(hir_analysis_expected_return_type)] + #[label("expected `{$expected}` because of return type")] Other { #[primary_span] span: Span, @@ -260,21 +219,9 @@ attribute applied to the struct or each variant, one of: - `#[warning(..)]` for defining a warning - `#[suggestion{,_hidden,_short,_verbose}(..)]` for defining a suggestion -All of the above must provide a slug as the first positional argument (a path -to an item in `rustc_errors::fluent::*`). A slug uniquely identifies the -diagnostic and is also how the compiler knows what error message to emit (in -the default locale of the compiler, or in the locale requested by the user). +All of the above must provide a diagnostic message as the first positional argument. See [translation documentation](./translation.md) to learn more about how -translatable error messages are written and how slug items are generated. - -In our example, the Fluent message for the "expected return type" label -looks like this: - -```fluent -hir_analysis_expected_default_return_type = expected `()` because of default return type - -hir_analysis_expected_return_type = expected `{$expected}` because of return type -``` +translatable error messages are generated. Using the `#[primary_span]` attribute on a field (with type `Span`) will denote the primary span of the subdiagnostic. A primary span is only necessary for a @@ -289,17 +236,15 @@ Like `Diagnostic`, `Subdiagnostic` supports `Option` and Suggestions can be emitted using one of four attributes on the type/variant: -- `#[suggestion(..., code = "...", applicability = "...")]` -- `#[suggestion_hidden(..., code = "...", applicability = "...")]` -- `#[suggestion_short(..., code = "...", applicability = "...")]` -- `#[suggestion_verbose(..., code = "...", applicability = "...")]` +- `#[suggestion("...", code = "...", applicability = "...")]` +- `#[suggestion_hidden("...", code = "...", applicability = "...")]` +- `#[suggestion_short("...", code = "...", applicability = "...")]` +- `#[suggestion_verbose("...", code = "...", applicability = "...")]` Suggestions require `#[primary_span]` be set on a field and can have the following sub-attributes: -- The first positional argument specifies the path to a item in - `rustc_errors::fluent` corresponding to the Fluent attribute with the message - and defaults to the equivalent of `.suggestion`. +- The first positional argument specifies the message which will be shown to the user. - `code` specifies the code that should be suggested as a replacement and is a format string (e.g. `{field_name}` would be replaced by the value of the `field_name` field of the struct), not a Fluent identifier. @@ -318,11 +263,11 @@ impl<'tcx> Subdiagnostic for ExpectedReturnTypeLabel<'tcx> { use rustc_errors::{Applicability, IntoDiagArg}; match self { ExpectedReturnTypeLabel::Unit { span } => { - diag.span_label(span, rustc_errors::fluent::hir_analysis_expected_default_return_type) + diag.span_label(span, "expected `()` because of default return type") } ExpectedReturnTypeLabel::Other { span, expected } => { diag.set_arg("expected", expected); - diag.span_label(span, rustc_errors::fluent::hir_analysis_expected_return_type) + diag.span_label(span, "expected `{$expected}` because of return type") } } } @@ -354,7 +299,7 @@ If a subdiagnostic sets a argument with the same name as a arguments already in it will report an error at runtime unless both have exactly the same value. It has two benefits: - preserves the flexibility that arguments in the main diagnostic are allowed to appear in the attributes of the subdiagnostic. -For example, There is an attribute `#[suggestion(code = "{new_vis}")]` in the subdiagnostic, but `new_vis` is the field in the main diagnostic struct. +For example, There is an attribute `#[suggestion("...", code = "{new_vis}")]` in the subdiagnostic, but `new_vis` is the field in the main diagnostic struct. - prevents accidental overwriting or deletion of arguments required by the main diagnostic or other subdiagnostics. These rules guarantee that arguments injected by subdiagnostics are strictly scoped to their own rendering. @@ -364,32 +309,20 @@ Additionally, subdiagnostics can access arguments from the main diagnostic with ### Reference for `#[derive(Subdiagnostic)]` `#[derive(Subdiagnostic)]` supports the following attributes: -- `#[label(slug)]`, `#[help(slug)]`, `#[warning(slug)]` or `#[note(slug)]` +- `#[label("message")]`, `#[help("message")]`, `#[warning("message")]` or `#[note("message")]` - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._ - _Mandatory_ - Defines the type to be representing a label, help or note. - - Slug (_Mandatory_) - - Uniquely identifies the diagnostic and corresponds to its Fluent message, - mandatory. - - A path to an item in `rustc_errors::fluent`, e.g. - `rustc_errors::fluent::hir_analysis_field_already_declared` - (`rustc_errors::fluent` is implicit in the attribute, so just - `hir_analysis_field_already_declared`). + - Message (_Mandatory_) + - The diagnostic message that will be shown to the user. - See [translation documentation](./translation.md). -- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` +- `#[suggestion{,_hidden,_short,_verbose}("message", code = "...", applicability = "...")]` - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._ - _Mandatory_ - Defines the type to be representing a suggestion. - - Slug (_Mandatory_) - - A path to an item in `rustc_errors::fluent`, e.g. - `rustc_errors::fluent::hir_analysis_field_already_declared` - (`rustc_errors::fluent` is implicit in the attribute, so just - `hir_analysis::field_already_declared`). Fluent attributes for all messages - exist as top-level items in that module (so `hir_analysis_message.attr` is just - `hir_analysis::attr`). + - Message (_Mandatory_) + - The diagnostic message that will be shown to the user. - See [translation documentation](./translation.md). - - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or - - `.suggestion` in Fluent). - `code = "..."`/`code("...", ...)` (_Mandatory_) - One or multiple format strings indicating the code to be suggested as a replacement. Multiple values signify multiple possible replacements. @@ -401,11 +334,11 @@ Additionally, subdiagnostics can access arguments from the main diagnostic with - `maybe-incorrect` - `has-placeholders` - `unspecified` -- `#[multipart_suggestion{,_hidden,_short,_verbose}(slug, applicability = "...")]` +- `#[multipart_suggestion{,_hidden,_short,_verbose}("message", applicability = "...")]` - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._ - _Mandatory_ - Defines the type to be representing a multipart suggestion. - - Slug (_Mandatory_): see `#[suggestion]` + - Message (_Mandatory_): see `#[suggestion]` - `applicability = "..."` (_Optional_): see `#[suggestion]` - `#[primary_span]` (_Mandatory_ for labels and suggestions; _optional_ otherwise; not applicable to multipart suggestions) From 37a314b719af622c982c29fad4aeb992f5068035 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Feb 2026 14:12:46 +0100 Subject: [PATCH 19/37] Update translation documentation --- .../src/diagnostics/translation.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index 58d75f54a005..fcb26fab667c 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -13,10 +13,7 @@ active redesign proposals (as of Please see the tracking issue for status updates. -We have downgraded the internal lints `untranslatable_diagnostic` and -`diagnostic_outside_of_impl`. Those internal lints previously required new code -to use the current translation infrastructure. However, because the translation -infra is waiting for a yet-to-be-proposed redesign and thus rework, we are not +The translation infra is waiting for a yet-to-be-proposed redesign and thus rework, we are not mandating usage of current translation infra. Use the infra if you *want to* or otherwise makes the code cleaner, but otherwise sidestep the translation infra if you need more flexibility. @@ -40,11 +37,6 @@ There are two ways of writing translatable diagnostics: When adding or changing a translatable diagnostic, you don't need to worry about the translations. Only updating the original English message is required. -Currently, -each crate which defines translatable diagnostics has its own Fluent resource, -which is a file named `messages.ftl`, -located in the root of the crate -(such as`compiler/rustc_expand/messages.ftl`). ## Fluent @@ -118,11 +110,8 @@ information that needs to be provided by the code to do so. ### Compile-time validation and typed identifiers -rustc's `fluent_messages` macro performs compile-time validation of Fluent -resources and generates code to make it easier to refer to Fluent messages in -diagnostics. - -Compile-time validation of Fluent resources will emit any parsing errors +rustc's `#[derive(Diagnostic)]` macro performs compile-time validation of Fluent +messages. Compile-time validation of Fluent resources will emit any parsing errors from Fluent resources while building the compiler, preventing invalid Fluent resources from causing panics in the compiler. Compile-time validation also emits an error if multiple Fluent messages have the same identifier. From 875c5908c747f5e97227aab367d4bcc7c161c892 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Feb 2026 20:39:02 +0100 Subject: [PATCH 20/37] Update examples for diagnostics changes Co-authored-by: bjorn3 --- .../examples/rustc-interface-example.rs | 15 +++++---------- .../rustc-interface-getting-diagnostics.rs | 8 +++----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs index 360f70c8e865..b4439504650a 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs @@ -4,14 +4,12 @@ extern crate rustc_driver; extern crate rustc_error_codes; -extern crate rustc_errors; extern crate rustc_hash; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; -use rustc_errors::registry; use rustc_hash::FxHashMap; use rustc_session::config; @@ -30,12 +28,11 @@ fn main() { println!("{HELLO}"); } "# - .into(), + .into(), }, - output_dir: None, // Option - output_file: None, // Option - file_loader: None, // Option> - locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(), + output_dir: None, // Option + output_file: None, // Option + file_loader: None, // Option> lint_caps: FxHashMap::default(), // FxHashMap // This is a callback from the driver that is called when [`ParseSess`] is created. psess_created: None, //Option> @@ -50,8 +47,6 @@ fn main() { // // The second parameter is local providers and the third parameter is external providers. override_queries: None, // Option, &mut ty::query::Providers<'_>)> - // Registry of diagnostics codes. - registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS), make_codegen_backend: None, expanded_args: Vec::new(), ice_file: None, @@ -77,4 +72,4 @@ fn main() { } }); }); -} +} \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs index 2512ba3c3f92..342316ba670a 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs @@ -15,7 +15,7 @@ extern crate rustc_span; use std::sync::{Arc, Mutex}; use rustc_errors::emitter::Emitter; -use rustc_errors::registry::{self, Registry}; +use rustc_errors::registry::Registry; use rustc_errors::translation::Translate; use rustc_errors::{DiagInner, FluentBundle}; use rustc_session::config; @@ -59,14 +59,13 @@ fn main() { let x: &str = 1; } " - .into(), + .into(), }, crate_cfg: Vec::new(), crate_check_cfg: Vec::new(), output_dir: None, output_file: None, file_loader: None, - locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(), lint_caps: rustc_hash::FxHashMap::default(), psess_created: Some(Box::new(|parse_sess| { parse_sess.dcx().set_emitter(Box::new(DebugEmitter { @@ -76,7 +75,6 @@ fn main() { })), register_lints: None, override_queries: None, - registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS), make_codegen_backend: None, expanded_args: Vec::new(), ice_file: None, @@ -99,4 +97,4 @@ fn main() { buffer.lock().unwrap().iter().for_each(|diagnostic| { println!("{diagnostic:#?}"); }); -} +} \ No newline at end of file From 0cf7b94bf52f45996776d8b27708516928b12e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 13 Nov 2025 15:44:20 +0100 Subject: [PATCH 21/37] fix Nix setup description --- src/doc/rustc-dev-guide/src/building/suggested.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 3ed4f129d144..ac8f15db7751 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -426,7 +426,7 @@ You can then use that rust2 folder as a separate workspace for modifying and bui Several nix configurations are defined in `src/tools/nix-dev-shell`. -If you're using direnv, you can create a symbol link to `src/tools/nix-dev-shell/envrc-flake` or `src/tools/nix-dev-shell/envrc-shell` +If you're using direnv, you can create a symbolic link to `src/tools/nix-dev-shell/envrc-flake` or `src/tools/nix-dev-shell/envrc-shell` ```bash ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc # Use flake @@ -436,6 +436,12 @@ or ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc # Use nix-shell ``` +If you're using the flake, make sure to also update it with the following command: + +``` +nix flake update --flake ./src/tools/nix-dev-shell +``` + ### Note Note that when using nix on a not-NixOS distribution, it may be necessary to set From 34ed98677513c81efa3fa7cf5948a810ac4c9e48 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 9 Feb 2026 16:31:39 -0500 Subject: [PATCH 22/37] improve build docs --- src/doc/rustc-dev-guide/src/offload/internals.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/offload/internals.md b/src/doc/rustc-dev-guide/src/offload/internals.md index 520c48d95896..836fd7ad2670 100644 --- a/src/doc/rustc-dev-guide/src/offload/internals.md +++ b/src/doc/rustc-dev-guide/src/offload/internals.md @@ -8,9 +8,15 @@ also offer more advanced, possibly unsafe, interfaces which allow a higher degre The implementation is based on LLVM's "offload" project, which is already used by OpenMP to run Fortran or C++ code on GPUs. While the project is under development, users will need to call other compilers like clang to finish the compilation process. -## High-level design: +## High-level compilation design: We use a single-source, two-pass compilation approach. First we compile all functions that should be offloaded for the device (e.g nvptx64, amdgcn-amd-amdhsa, intel in the future). Currently we require cumbersome `#cfg(target_os="")` annotations, but we intend to recognize those in the future based on our offload intrinsic. +This first compilation currently does not leverage rustc's internal Query system, so it will always recompile your kernels at the moment. This should be easy to fix, but we prioritize features and runtime performance improvements at the moment. Please reach out if you want to implement it, though! We then compile the code for the host (e.g. x86-64), where most of the offloading logic happens. On the host side, we generate calls to the openmp offload runtime, to inform it about the layout of the types (a simplified version of the autodiff TypeTrees). We also use the type system to figure out whether kernel arguments have to be moved only to the device (e.g. `&[f32;1024]`), from the device, or both (e.g. `&mut [f64]`). We then launch the kernel, after which we inform the runtime to end this environment and move data back (as far as needed). + +The second pass for the host will load the kernel artifacts from the previous compilation. rustc in general may not "guess" or hardcode the build directory layout, and as such it must be told the path to the kernel artifacts in the second invocation. The logic for this could be integrated into cargo, but it also only requires a trivial cargo wrapper, which we could trivially provide via crates.io till we see larger adoption. + +It might seem tempting to think about a single-source, single pass compilation approach. However, a lot of the rustc frontend (e.g. AST) will drop any dead code (e.g. code behind an inactive `cfg`). Getting the frontend to expand and lower code for two targets naively will result in multiple definitions of the same symbol (and other issues). Trying to teach the whole rustc middle and backend to be aware that any symbol now might contain two implementations is a large undertaking, and it is questionable why we should make the whole compiler more complex, if the alternative is a ~5 line cargo wrapper. We still control the full compilation pipeline and have both host and device code available, therefore there shouldn't be a runtime performance difference between the two approaches. + From b23d30885308fadf851af7fc3134d129731b6417 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 14 Jan 2026 22:19:12 +0100 Subject: [PATCH 23/37] Support structs in type info reflection --- .../src/const_eval/type_info.rs | 177 ++++++++++++++---- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/mem/type_info.rs | 15 ++ library/coretests/tests/mem/type_info.rs | 51 +++++ .../missing-trait-bounds/issue-69725.stderr | 8 +- tests/ui/reflection/dump.bit32.run.stdout | 55 +++++- tests/ui/reflection/dump.bit64.run.stdout | 55 +++++- tests/ui/reflection/dump.rs | 9 +- 8 files changed, 333 insertions(+), 39 deletions(-) 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 f8881f0968bb..5b96856b253f 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -1,18 +1,36 @@ -use rustc_abi::FieldIdx; +use std::borrow::Cow; + +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Const, ScalarInt, Ty}; +use rustc_middle::ty::{self, AdtDef, AdtKind, Const, GenericArgs, ScalarInt, Ty, VariantDef}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; use crate::interpret::{ - CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable, - interp_ok, + CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar, + Writeable, interp_ok, }; impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { + /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. + fn downcast<'a>( + &self, + place: &(impl Writeable<'tcx, CtfeProvenance> + 'a), + name: Symbol, + ) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> { + let variants = place.layout().ty.ty_adt_def().unwrap().variants(); + let variant_idx = variants + .iter_enumerated() + .find(|(_idx, var)| var.name == name) + .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) + .0; + + interp_ok((variant_idx, self.project_downcast(place, variant_idx)?)) + } + /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place. pub(crate) fn write_type_info( &mut self, @@ -26,22 +44,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { // Fill all fields of the `TypeInfo` struct. for (idx, field) in ty_struct.fields.iter_enumerated() { let field_dest = self.project_field(dest, idx)?; - let downcast = |name: Symbol| { - let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants(); - let variant_id = variants - .iter_enumerated() - .find(|(_idx, var)| var.name == name) - .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) - .0; - - interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?)) - }; let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits(); match field.name { sym::kind => { let variant_index = match ty.kind() { ty::Tuple(fields) => { - let (variant, variant_place) = downcast(sym::Tuple)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Tuple)?; // project to the single tuple variant field of `type_info::Tuple` struct type let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; assert_eq!( @@ -59,7 +68,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Array(ty, len) => { - let (variant, variant_place) = downcast(sym::Array)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Array)?; let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_array_type_info(array_place, *ty, *len)?; @@ -67,23 +77,38 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Slice(ty) => { - let (variant, variant_place) = downcast(sym::Slice)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Slice)?; let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_slice_type_info(slice_place, *ty)?; variant } + ty::Adt(adt_def, generics) => { + // TODO(type_info): Handle enum and union + if !adt_def.is_struct() { + self.downcast(&field_dest, sym::Other)?.0 + } else { + let (variant, variant_place) = + self.downcast(&field_dest, sym::Struct)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_adt_type_info(place, (ty, *adt_def), generics)?; + variant + } + } ty::Bool => { - let (variant, _variant_place) = downcast(sym::Bool)?; + let (variant, _variant_place) = + self.downcast(&field_dest, sym::Bool)?; variant } ty::Char => { - let (variant, _variant_place) = downcast(sym::Char)?; + let (variant, _variant_place) = + self.downcast(&field_dest, sym::Char)?; variant } ty::Int(int_ty) => { - let (variant, variant_place) = downcast(sym::Int)?; + let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -93,7 +118,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Uint(uint_ty) => { - let (variant, variant_place) = downcast(sym::Int)?; + let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -103,17 +128,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Float(float_ty) => { - let (variant, variant_place) = downcast(sym::Float)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Float)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_float_type_info(place, float_ty.bit_width())?; variant } ty::Str => { - let (variant, _variant_place) = downcast(sym::Str)?; + let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?; variant } ty::Ref(_, ty, mutability) => { - let (variant, variant_place) = downcast(sym::Reference)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Reference)?; let reference_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_reference_type_info(reference_place, *ty, *mutability)?; @@ -121,7 +148,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::RawPtr(ty, mutability) => { - let (variant, variant_place) = downcast(sym::Pointer)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::Pointer)?; let pointer_place = self.project_field(&variant_place, FieldIdx::ZERO)?; @@ -130,13 +158,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Dynamic(predicates, region) => { - let (variant, variant_place) = downcast(sym::DynTrait)?; + let (variant, variant_place) = + self.downcast(&field_dest, sym::DynTrait)?; let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?; variant } - ty::Adt(_, _) - | ty::Foreign(_) + ty::Foreign(_) | ty::Pat(_, _) | ty::FnDef(..) | ty::FnPtr(..) @@ -151,14 +179,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(..) - | ty::Error(_) => downcast(sym::Other)?.0, + | ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0, }; self.write_discriminant(variant_index, &field_dest)? } sym::size => { let layout = self.layout_of(ty)?; let variant_index = if layout.is_sized() { - let (variant, variant_place) = downcast(sym::Some)?; + let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?; let size_field_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_scalar( @@ -168,7 +196,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { )?; variant } else { - downcast(sym::None)?.0 + self.downcast(&field_dest, sym::None)?.0 }; self.write_discriminant(variant_index, &field_dest)?; } @@ -204,7 +232,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { while let Some((i, place)) = fields_places.next(self)? { let field_ty = fields[i as usize]; - self.write_field(field_ty, place, tuple_layout, i)?; + self.write_field(field_ty, place, tuple_layout, None, i)?; } let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); @@ -219,6 +247,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { field_ty: Ty<'tcx>, place: MPlaceTy<'tcx>, layout: TyAndLayout<'tcx>, + name: Option, idx: u64, ) -> InterpResult<'tcx> { for (field_idx, field_ty_field) in @@ -226,6 +255,15 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { { let field_place = self.project_field(&place, field_idx)?; match field_ty_field.name { + sym::name => { + let name = match name.as_ref() { + Some(name) => Cow::Borrowed(name.as_str()), + None => Cow::Owned(idx.to_string()), // For tuples + }; + let name_place = self.allocate_str_dedup(&name)?; + let ptr = self.mplace_to_ref(&name_place)?; + self.write_immediate(*ptr, &field_place)? + } sym::ty => self.write_type_id(field_ty, &field_place)?, sym::offset => { let offset = layout.fields.offset(idx as usize); @@ -287,6 +325,81 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + // FIXME(type_info): No semver considerations for now + pub(crate) fn write_adt_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + adt: (Ty<'tcx>, AdtDef<'tcx>), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (adt_ty, adt_def) = adt; + match adt_def.adt_kind() { + AdtKind::Struct => self.write_struct_type_info( + place, + (adt_ty, adt_def.variant(VariantIdx::ZERO)), + generics, + ), + AdtKind::Union => todo!(), + AdtKind::Enum => todo!(), + } + } + + pub(crate) fn write_struct_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + struct_: (Ty<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (struct_ty, struct_def) = struct_; + let struct_layout = self.layout_of(struct_ty)?; + + 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 { + sym::fields => { + let fields_slice_place = field_place; + let field_type = fields_slice_place + .layout() + .ty + .builtin_deref(false) + .unwrap() + .sequence_element_type(self.tcx.tcx); + let fields_layout = self.layout_of(Ty::new_array( + self.tcx.tcx, + field_type, + struct_def.fields.len() as u64, + ))?; + let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; + let mut fields_places = self.project_array_fields(&fields_place)?; + + for field_def in &struct_def.fields { + let (i, place) = fields_places.next(self)?.unwrap(); + let field_ty = field_def.ty(*self.tcx, generics); + self.write_field(field_ty, place, struct_layout, Some(field_def.name), i)?; + } + + let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); + let ptr = Immediate::new_slice( + fields_place.ptr(), + struct_def.fields.len() as u64, + self, + ); + self.write_immediate(ptr, &fields_slice_place)? + } + sym::non_exhaustive => { + let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + fn write_int_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6aa2eae556e2..271124a4c372 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -372,6 +372,7 @@ symbols! { Stdin, Str, String, + Struct, StructuralPartialEq, SubdiagMessage, Subdiagnostic, @@ -1086,6 +1087,7 @@ symbols! { ffi_returns_twice, field, field_init_shorthand, + fields, file, file_options, flags, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 8b30803c97c9..0e87b9d9cbb7 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -49,6 +49,8 @@ pub enum TypeKind { Slice(Slice), /// Dynamic Traits. DynTrait(DynTrait), + /// Structs. + Struct(Struct), /// Primitive boolean type. Bool(Bool), /// Primitive character type. @@ -81,6 +83,8 @@ pub struct Tuple { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Field { + /// The name of the field. + pub name: &'static str, /// The field's type. pub ty: TypeId, /// Offset in bytes from the parent type @@ -137,6 +141,17 @@ pub struct Trait { pub is_auto: bool, } +/// Compile-time type information about arrays. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Struct { + /// All fields of the struct. + pub fields: &'static [Field], + /// Whether the struct field list is non-exhaustive. + pub non_exhaustive: bool, +} + /// Compile-time type information about `bool`. #[derive(Debug)] #[non_exhaustive] diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 87f2d5dd8289..03ff5f55c4f7 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -1,4 +1,7 @@ +#![allow(dead_code)] + use std::any::{Any, TypeId}; +use std::mem::offset_of; use std::mem::type_info::{Type, TypeKind}; #[test] @@ -66,6 +69,54 @@ fn test_tuples() { } } +#[test] +fn test_structs() { + use TypeKind::*; + + const { + struct TestStruct { + first: u8, + second: u16, + reference: &'static u16, + } + + let Type { kind: Struct(ty), size, .. } = Type::of::() else { panic!() }; + assert!(size == Some(size_of::())); + assert!(!ty.non_exhaustive); + assert!(ty.fields.len() == 3); + assert!(ty.fields[0].name == "first"); + assert!(ty.fields[0].ty == TypeId::of::()); + assert!(ty.fields[0].offset == offset_of!(TestStruct, first)); + assert!(ty.fields[1].name == "second"); + assert!(ty.fields[1].ty == TypeId::of::()); + assert!(ty.fields[1].offset == offset_of!(TestStruct, second)); + assert!(ty.fields[2].name == "reference"); + assert!(ty.fields[2].ty != TypeId::of::<&'static u16>()); // FIXME(type_info): should be == + assert!(ty.fields[2].offset == offset_of!(TestStruct, reference)); + } + + const { + #[non_exhaustive] + struct NonExhaustive { + a: u8, + } + + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; + assert!(ty.non_exhaustive); + } + + const { + struct TupleStruct(u8, u16); + + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; + assert!(ty.fields.len() == 2); + assert!(ty.fields[0].name == "0"); + assert!(ty.fields[0].ty == TypeId::of::()); + assert!(ty.fields[1].name == "1"); + assert!(ty.fields[1].ty == TypeId::of::()); + } +} + #[test] fn test_primitives() { use TypeKind::*; diff --git a/tests/ui/missing-trait-bounds/issue-69725.stderr b/tests/ui/missing-trait-bounds/issue-69725.stderr index f483ea849b0e..20d2213f4f5f 100644 --- a/tests/ui/missing-trait-bounds/issue-69725.stderr +++ b/tests/ui/missing-trait-bounds/issue-69725.stderr @@ -1,17 +1,17 @@ -error[E0599]: the method `clone` exists for struct `Struct`, but its trait bounds were not satisfied +error[E0599]: the method `clone` exists for struct `issue_69725::Struct`, but its trait bounds were not satisfied --> $DIR/issue-69725.rs:9:32 | LL | let _ = Struct::::new().clone(); - | ^^^^^ method cannot be called on `Struct` due to unsatisfied trait bounds + | ^^^^^ method cannot be called on `issue_69725::Struct` due to unsatisfied trait bounds | ::: $DIR/auxiliary/issue-69725.rs:2:1 | LL | pub struct Struct(A); - | -------------------- doesn't satisfy `Struct: Clone` + | -------------------- doesn't satisfy `issue_69725::Struct: Clone` | = note: the following trait bounds were not satisfied: `A: Clone` - which is required by `Struct: Clone` + which is required by `issue_69725::Struct: Clone` help: consider restricting the type parameter to satisfy the trait bound | LL | fn crash() where A: Clone { diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index d15b46509ff2..feda3401e462 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -3,14 +3,17 @@ Type { Tuple { fields: [ Field { + name: "0", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 0, }, Field { + name: "1", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 1, }, Field { + name: "2", ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), offset: 2, }, @@ -143,7 +146,18 @@ Type { ), } Type { - kind: Other, + kind: Struct( + Struct { + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 4, ), @@ -154,6 +168,45 @@ Type { 12, ), } +Type { + kind: Struct( + Struct { + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: true, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Struct( + Struct { + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "1", + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 12, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index efae22653951..d9fef71f619c 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -3,14 +3,17 @@ Type { Tuple { fields: [ Field { + name: "0", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 0, }, Field { + name: "1", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 1, }, Field { + name: "2", ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), offset: 2, }, @@ -143,7 +146,18 @@ Type { ), } Type { - kind: Other, + kind: Struct( + Struct { + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 4, ), @@ -154,6 +168,45 @@ Type { 24, ), } +Type { + kind: Struct( + Struct { + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: true, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Struct( + Struct { + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "1", + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 16, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index d42216a62fdc..fefaad325aea 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -14,6 +14,13 @@ struct Foo { a: u32, } +#[non_exhaustive] +struct NonExhaustiveStruct { + a: u32, +} + +struct TupleStruct(u32, u64); + enum Bar { Some(u32), None, @@ -37,7 +44,7 @@ fn main() { [u8; 2], i8, i32, i64, i128, isize, u8, u32, u64, u128, usize, - Foo, Bar, + Foo, Bar, NonExhaustiveStruct, TupleStruct, &Unsized, &str, &[u8], str, [u8], &u8, &mut u8, From 870fd9070b5d98422107b8c748f7c7d084d4d037 Mon Sep 17 00:00:00 2001 From: Asuna Date: Mon, 19 Jan 2026 01:07:51 +0100 Subject: [PATCH 24/37] Add generics info for structs in type info --- .../src/const_eval/type_info.rs | 153 ++++++++++++++---- compiler/rustc_span/src/symbol.rs | 4 + library/core/src/mem/type_info.rs | 41 +++++ library/coretests/tests/mem/type_info.rs | 20 ++- tests/ui/generics/wrong-number-of-args.rs | 2 +- tests/ui/generics/wrong-number-of-args.stderr | 2 +- tests/ui/reflection/dump.bit32.run.stdout | 50 ++++++ tests/ui/reflection/dump.bit64.run.stdout | 50 ++++++ tests/ui/reflection/dump.rs | 8 +- .../resolve/resolve-assoc-suggestions.stderr | 10 ++ 10 files changed, 304 insertions(+), 36 deletions(-) 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 5b96856b253f..9fb01b1f5c5c 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -3,9 +3,12 @@ use std::borrow::Cow; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; -use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, AdtDef, AdtKind, Const, GenericArgs, ScalarInt, Ty, VariantDef}; +use rustc_middle::ty::{ + self, AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, ScalarInt, Ty, + VariantDef, +}; +use rustc_middle::{bug, span_bug}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -31,6 +34,37 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok((variant_idx, self.project_downcast(place, variant_idx)?)) } + // A general method to write an array to a static slice place. + fn allocate_fill_and_write_slice_ptr( + &mut self, + slice_place: impl Writeable<'tcx, CtfeProvenance>, + len: u64, + writer: impl Fn(&mut Self, /* index */ u64, MPlaceTy<'tcx>) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { + // Array element type + let field_ty = slice_place + .layout() + .ty + .builtin_deref(false) + .unwrap() + .sequence_element_type(self.tcx.tcx); + + // Allocate an array + let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, field_ty, len))?; + let array_place = self.allocate(array_layout, MemoryKind::Stack)?; + + // Fill the array fields + let mut field_places = self.project_array_fields(&array_place)?; + while let Some((i, place)) = field_places.next(self)? { + writer(self, i, place)?; + } + + // Write the slice pointing to the array + let array_place = array_place.map_provenance(CtfeProvenance::as_immutable); + let ptr = Immediate::new_slice(array_place.ptr(), len, self); + self.write_immediate(ptr, &slice_place) + } + /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place. pub(crate) fn write_type_info( &mut self, @@ -207,6 +241,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + // TODO(type_info): Remove this method, use `allocate_fill_and_write_slice_ptr` as it's more general. pub(crate) fn write_tuple_fields( &mut self, tuple_place: impl Writeable<'tcx, CtfeProvenance>, @@ -359,36 +394,16 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let field_place = self.project_field(&place, field_idx)?; match field.name { - sym::fields => { - let fields_slice_place = field_place; - let field_type = fields_slice_place - .layout() - .ty - .builtin_deref(false) - .unwrap() - .sequence_element_type(self.tcx.tcx); - let fields_layout = self.layout_of(Ty::new_array( - self.tcx.tcx, - field_type, - struct_def.fields.len() as u64, - ))?; - let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; - let mut fields_places = self.project_array_fields(&fields_place)?; - - for field_def in &struct_def.fields { - let (i, place) = fields_places.next(self)?.unwrap(); - let field_ty = field_def.ty(*self.tcx, generics); - self.write_field(field_ty, place, struct_layout, Some(field_def.name), i)?; - } - - let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); - let ptr = Immediate::new_slice( - fields_place.ptr(), - struct_def.fields.len() as u64, - self, - ); - self.write_immediate(ptr, &fields_slice_place)? - } + sym::generics => self.write_generics(field_place, generics)?, + sym::fields => self.allocate_fill_and_write_slice_ptr( + field_place, + struct_def.fields.len() as u64, + |this, i, place| { + let field_def = &struct_def.fields[FieldIdx::from_usize(i as usize)]; + let field_ty = field_def.ty(*this.tcx, generics); + this.write_field(field_ty, place, struct_layout, Some(field_def.name), i) + }, + )?, sym::non_exhaustive => { let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? @@ -400,6 +415,80 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + fn write_generics( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| { + match generics[i as usize].kind() { + GenericArgKind::Lifetime(region) => this.write_generic_lifetime(region, place), + GenericArgKind::Type(ty) => this.write_generic_type(ty, place), + GenericArgKind::Const(c) => this.write_generic_const(c, place), + } + }) + } + + fn write_generic_lifetime( + &mut self, + _region: Region<'tcx>, + place: MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?; + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } + + fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?; + let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + for (field_idx, field_def) in generic_type_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .iter_enumerated() + { + let field_place = self.project_field(&generic_type_place, field_idx)?; + match field_def.name { + sym::ty => self.write_type_id(ty, &field_place)?, + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } + + fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") }; + + let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?; + let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + for (field_idx, field_def) in const_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .iter_enumerated() + { + let field_place = self.project_field(&const_place, field_idx)?; + match field_def.name { + sym::ty => self.write_type_id(c.ty, &field_place)?, + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } + fn write_int_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 271124a4c372..70f5c1d0c472 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -211,6 +211,7 @@ symbols! { CoercePointeeValidated, CoerceUnsized, Command, + Const, ConstParamTy, ConstParamTy_, Context, @@ -292,6 +293,7 @@ symbols! { IteratorMap, Layout, Left, + Lifetime, LinkedList, LintDiagnostic, LintPass, @@ -396,6 +398,7 @@ symbols! { Ty, TyCtxt, TyKind, + Type, Unknown, Unsize, UnsizedConstParamTy, @@ -1176,6 +1179,7 @@ symbols! { generic_const_parameter_types, generic_param_attrs, generic_pattern_types, + generics, get_context, global_alloc_ty, global_allocator, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 0e87b9d9cbb7..8b11e5bd7035 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -146,12 +146,53 @@ pub struct Trait { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Struct { + /// Instantiated generics of the struct. + pub generics: &'static [Generic], /// All fields of the struct. pub fields: &'static [Field], /// Whether the struct field list is non-exhaustive. pub non_exhaustive: bool, } +/// Compile-time type information about instantiated generics of structs, enum and union variants. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub enum Generic { + /// Lifetimes. + Lifetime(Lifetime), + /// Types. + Type(GenericType), + /// Const parameters. + Const(Const), +} + +/// Compile-time type information about generic lifetimes. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Lifetime { + // No additional information to provide for now. +} + +/// Compile-time type information about instantiated generic types. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct GenericType { + /// The type itself. + pub ty: TypeId, +} + +/// Compile-time type information about generic const parameters. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Const { + /// The const's type. + pub ty: TypeId, +} + /// Compile-time type information about `bool`. #[derive(Debug)] #[non_exhaustive] diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 03ff5f55c4f7..9daf31029af6 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -2,7 +2,7 @@ use std::any::{Any, TypeId}; use std::mem::offset_of; -use std::mem::type_info::{Type, TypeKind}; +use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind}; #[test] fn test_arrays() { @@ -115,6 +115,24 @@ fn test_structs() { assert!(ty.fields[1].name == "1"); assert!(ty.fields[1].ty == TypeId::of::()); } + + const { + struct Generics<'a, T, const C: u64> { + a: &'a T, + } + + let Type { kind: Struct(ty), .. } = Type::of::>() else { + panic!() + }; + assert!(ty.fields.len() == 1); + assert!(ty.generics.len() == 3); + + let Generic::Lifetime(_) = ty.generics[0] else { panic!() }; + let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() }; + assert!(generic_ty == TypeId::of::()); + let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() }; + assert!(const_ty == TypeId::of::()); + } } #[test] diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index 8bc384a3d817..9af16567cd75 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -127,7 +127,7 @@ mod r#trait { //~| HELP remove type D = Box; - //~^ ERROR missing generics for trait `GenericType` + //~^ ERROR missing generics for trait `r#trait::GenericType` //~| HELP add missing type E = Box>; diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index bedeeb812fc9..554d017d67e3 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -469,7 +469,7 @@ note: trait defined here, with 1 lifetime parameter: `'a` LL | trait GenericLifetime<'a> { | ^^^^^^^^^^^^^^^ -- -error[E0107]: missing generics for trait `GenericType` +error[E0107]: missing generics for trait `r#trait::GenericType` --> $DIR/wrong-number-of-args.rs:129:22 | LL | type D = Box; diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index feda3401e462..e80cea8ece2f 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -148,6 +148,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "a", @@ -171,6 +172,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "a", @@ -188,6 +190,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "0", @@ -207,6 +210,53 @@ Type { 12, ), } +Type { + kind: Struct( + Struct { + generics: [ + Lifetime( + Lifetime, + ), + Type( + GenericType { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + }, + ), + Type( + GenericType { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + }, + ), + Const( + Const { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + }, + ), + ], + fields: [ + Field { + name: "a", + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "l", + ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 12, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index d9fef71f619c..812a918e519d 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -148,6 +148,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "a", @@ -171,6 +172,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "a", @@ -188,6 +190,7 @@ Type { Type { kind: Struct( Struct { + generics: [], fields: [ Field { name: "0", @@ -207,6 +210,53 @@ Type { 16, ), } +Type { + kind: Struct( + Struct { + generics: [ + Lifetime( + Lifetime, + ), + Type( + GenericType { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + }, + ), + Type( + GenericType { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + }, + ), + Const( + Const { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + }, + ), + ], + fields: [ + Field { + name: "a", + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + offset: 8, + }, + Field { + name: "b", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 12, + }, + Field { + name: "l", + ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 16, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index fefaad325aea..d0da0582fb51 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -27,6 +27,12 @@ enum Bar { Foomp { a: (), b: &'static str }, } +struct Generics<'a, A, B, const C: u64> { + a: A, + b: B, + l: &'a (), +} + struct Unsized { x: u16, s: str, @@ -44,7 +50,7 @@ fn main() { [u8; 2], i8, i32, i64, i128, isize, u8, u32, u64, u128, usize, - Foo, Bar, NonExhaustiveStruct, TupleStruct, + Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics, &Unsized, &str, &[u8], str, [u8], &u8, &mut u8, diff --git a/tests/ui/resolve/resolve-assoc-suggestions.stderr b/tests/ui/resolve/resolve-assoc-suggestions.stderr index 7d94fb5ca35f..e6311962884f 100644 --- a/tests/ui/resolve/resolve-assoc-suggestions.stderr +++ b/tests/ui/resolve/resolve-assoc-suggestions.stderr @@ -41,12 +41,22 @@ error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope | LL | let Type(..); | ^^^^ not found in this scope + | +help: consider importing this tuple variant + | +LL + use std::mem::type_info::Generic::Type; + | error[E0425]: cannot find value `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:27:9 | LL | Type; | ^^^^ not found in this scope + | +help: consider importing this tuple variant + | +LL + use std::mem::type_info::Generic::Type; + | error[E0425]: cannot find type `method` in this scope --> $DIR/resolve-assoc-suggestions.rs:30:16 From e9037882c17d7ebd017c7403c934a5a5ef2d8488 Mon Sep 17 00:00:00 2001 From: Asuna Date: Tue, 20 Jan 2026 08:46:33 +0100 Subject: [PATCH 25/37] Support enums in type info reflection --- .../src/const_eval/type_info.rs | 142 ++++++++++++++---- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/mem/type_info.rs | 28 ++++ library/coretests/tests/mem/type_info.rs | 42 ++++++ tests/ui/privacy/issue-79593.rs | 6 +- tests/ui/privacy/issue-79593.stderr | 6 +- tests/ui/reflection/dump.bit32.run.stdout | 41 ++++- tests/ui/reflection/dump.bit64.run.stdout | 41 ++++- tests/ui/reflection/dump.rs | 6 +- 9 files changed, 279 insertions(+), 35 deletions(-) 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 9fb01b1f5c5c..701adc7f732b 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -120,15 +120,11 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Adt(adt_def, generics) => { - // TODO(type_info): Handle enum and union - if !adt_def.is_struct() { + // TODO(type_info): Handle union + if !adt_def.is_struct() && !adt_def.is_enum() { self.downcast(&field_dest, sym::Other)?.0 } else { - let (variant, variant_place) = - self.downcast(&field_dest, sym::Struct)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_adt_type_info(place, (ty, *adt_def), generics)?; - variant + self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)? } } ty::Bool => { @@ -277,6 +273,25 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_immediate(ptr, &fields_slice_place) } + // Write fields for struct, enum variants + fn write_variant_fields( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + variant_def: &'tcx VariantDef, + variant_layout: TyAndLayout<'tcx>, + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + self.allocate_fill_and_write_slice_ptr( + place, + variant_def.fields.len() as u64, + |this, i, place| { + let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)]; + let field_ty = field_def.ty(*this.tcx, generics); + this.write_field(field_ty, place, variant_layout, Some(field_def.name), i) + }, + ) + } + fn write_field( &mut self, field_ty: Ty<'tcx>, @@ -363,20 +378,31 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { // FIXME(type_info): No semver considerations for now pub(crate) fn write_adt_type_info( &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, + place: &impl Writeable<'tcx, CtfeProvenance>, adt: (Ty<'tcx>, AdtDef<'tcx>), generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, VariantIdx> { let (adt_ty, adt_def) = adt; - match adt_def.adt_kind() { - AdtKind::Struct => self.write_struct_type_info( - place, - (adt_ty, adt_def.variant(VariantIdx::ZERO)), - generics, - ), + let variant_idx = match adt_def.adt_kind() { + AdtKind::Struct => { + let (variant, variant_place) = self.downcast(place, sym::Struct)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_struct_type_info( + place, + (adt_ty, adt_def.variant(VariantIdx::ZERO)), + generics, + )?; + variant + } + AdtKind::Enum => { + let (variant, variant_place) = self.downcast(place, sym::Enum)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_enum_type_info(place, adt, generics)?; + variant + } AdtKind::Union => todo!(), - AdtKind::Enum => todo!(), - } + }; + interp_ok(variant_idx) } pub(crate) fn write_struct_type_info( @@ -395,15 +421,9 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { match field.name { sym::generics => self.write_generics(field_place, generics)?, - sym::fields => self.allocate_fill_and_write_slice_ptr( - field_place, - struct_def.fields.len() as u64, - |this, i, place| { - let field_def = &struct_def.fields[FieldIdx::from_usize(i as usize)]; - let field_ty = field_def.ty(*this.tcx, generics); - this.write_field(field_ty, place, struct_layout, Some(field_def.name), i) - }, - )?, + sym::fields => { + self.write_variant_fields(field_place, struct_def, struct_layout, generics)? + } sym::non_exhaustive => { let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? @@ -415,6 +435,76 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + pub(crate) fn write_enum_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + enum_: (Ty<'tcx>, AdtDef<'tcx>), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (enum_ty, enum_def) = enum_; + let enum_layout = self.layout_of(enum_ty)?; + + 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 { + sym::generics => self.write_generics(field_place, generics)?, + sym::variants => { + self.allocate_fill_and_write_slice_ptr( + field_place, + enum_def.variants().len() as u64, + |this, i, place| { + let variant_idx = VariantIdx::from_usize(i as usize); + let variant_def = &enum_def.variants()[variant_idx]; + let variant_layout = enum_layout.for_variant(this, variant_idx); + this.write_enum_variant(place, (variant_layout, &variant_def), generics) + }, + )?; + } + sym::non_exhaustive => { + let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + + fn write_enum_variant( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + variant: (TyAndLayout<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (variant_layout, variant_def) = variant; + + for (field_idx, field_def) 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_def.name { + sym::name => { + let name_place = self.allocate_str_dedup(variant_def.name.as_str())?; + let ptr = self.mplace_to_ref(&name_place)?; + self.write_immediate(*ptr, &field_place)? + } + sym::fields => { + self.write_variant_fields(field_place, &variant_def, variant_layout, generics)? + } + sym::non_exhaustive => { + let is_non_exhaustive = variant_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + interp_ok(()) + } + fn write_generics( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 70f5c1d0c472..a3576b9a4437 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -235,6 +235,7 @@ symbols! { DynTrait, Encodable, Encoder, + Enum, Enumerate, Eq, Equal, @@ -2480,6 +2481,7 @@ symbols! { values, var, variant_count, + variants, vec, vec_as_mut_slice, vec_as_slice, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 8b11e5bd7035..b66a836c4bd4 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -51,6 +51,8 @@ pub enum TypeKind { DynTrait(DynTrait), /// Structs. Struct(Struct), + /// Enums. + Enum(Enum), /// Primitive boolean type. Bool(Bool), /// Primitive character type. @@ -154,6 +156,32 @@ pub struct Struct { pub non_exhaustive: bool, } +/// Compile-time type information about enums. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Enum { + /// Instantiated generics of the enum. + pub generics: &'static [Generic], + /// All variants of the enum. + pub variants: &'static [Variant], + /// Whether the enum variant list is non-exhaustive. + pub non_exhaustive: bool, +} + +/// Compile-time type information about variants of enums. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Variant { + /// The name of the variant. + pub name: &'static str, + /// All fields of the variant. + pub fields: &'static [Field], + /// Whether the enum variant fields is non-exhaustive. + pub non_exhaustive: bool, +} + /// Compile-time type information about instantiated generics of structs, enum and union variants. #[derive(Debug)] #[non_exhaustive] diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 9daf31029af6..09e3a50d374c 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -135,6 +135,48 @@ fn test_structs() { } } +#[test] +fn test_enums() { + use TypeKind::*; + + const { + enum E { + Some(u32), + None, + #[non_exhaustive] + Foomp { + a: (), + b: &'static str, + }, + } + + let Type { kind: Enum(ty), size, .. } = Type::of::() else { panic!() }; + assert!(size == Some(size_of::())); + assert!(ty.variants.len() == 3); + + assert!(ty.variants[0].name == "Some"); + assert!(!ty.variants[0].non_exhaustive); + assert!(ty.variants[0].fields.len() == 1); + + assert!(ty.variants[1].name == "None"); + assert!(!ty.variants[1].non_exhaustive); + assert!(ty.variants[1].fields.len() == 0); + + assert!(ty.variants[2].name == "Foomp"); + assert!(ty.variants[2].non_exhaustive); + assert!(ty.variants[2].fields.len() == 2); + } + + const { + let Type { kind: Enum(ty), size, .. } = Type::of::>() else { panic!() }; + assert!(size == Some(size_of::>())); + assert!(ty.variants.len() == 2); + assert!(ty.generics.len() == 1); + let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[0] else { panic!() }; + assert!(generic_ty == TypeId::of::()); + } +} + #[test] fn test_primitives() { use TypeKind::*; diff --git a/tests/ui/privacy/issue-79593.rs b/tests/ui/privacy/issue-79593.rs index 39c222f7c341..663dd67fcdb1 100644 --- a/tests/ui/privacy/issue-79593.rs +++ b/tests/ui/privacy/issue-79593.rs @@ -10,7 +10,7 @@ mod foo { Pub {}; //~^ ERROR missing field `private` in initializer of `Pub` Enum::Variant { x: () }; - //~^ ERROR missing field `y` in initializer of `Enum` + //~^ ERROR missing field `y` in initializer of `foo::Enum` } } @@ -21,9 +21,9 @@ fn correct() { fn wrong() { foo::Enum::Variant { x: () }; - //~^ ERROR missing field `y` in initializer of `Enum` + //~^ ERROR missing field `y` in initializer of `foo::Enum` foo::Enum::Variant { }; - //~^ ERROR missing fields `x` and `y` in initializer of `Enum` + //~^ ERROR missing fields `x` and `y` in initializer of `foo::Enum` } fn main() {} diff --git a/tests/ui/privacy/issue-79593.stderr b/tests/ui/privacy/issue-79593.stderr index 5bb69836f609..74fea1a3ab76 100644 --- a/tests/ui/privacy/issue-79593.stderr +++ b/tests/ui/privacy/issue-79593.stderr @@ -4,7 +4,7 @@ error[E0063]: missing field `private` in initializer of `Pub` LL | Pub {}; | ^^^ missing `private` -error[E0063]: missing field `y` in initializer of `Enum` +error[E0063]: missing field `y` in initializer of `foo::Enum` --> $DIR/issue-79593.rs:12:9 | LL | Enum::Variant { x: () }; @@ -18,13 +18,13 @@ LL | foo::Pub {}; | = note: private field `private` that was not provided -error[E0063]: missing field `y` in initializer of `Enum` +error[E0063]: missing field `y` in initializer of `foo::Enum` --> $DIR/issue-79593.rs:23:5 | LL | foo::Enum::Variant { x: () }; | ^^^^^^^^^^^^^^^^^^ missing `y` -error[E0063]: missing fields `x` and `y` in initializer of `Enum` +error[E0063]: missing fields `x` and `y` in initializer of `foo::Enum` --> $DIR/issue-79593.rs:25:5 | LL | foo::Enum::Variant { }; diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index e80cea8ece2f..a6ad84f5fef1 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -164,7 +164,46 @@ Type { ), } Type { - kind: Other, + kind: Enum( + Enum { + generics: [], + variants: [ + Variant { + name: "Some", + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 4, + }, + ], + non_exhaustive: false, + }, + Variant { + name: "None", + fields: [], + non_exhaustive: false, + }, + Variant { + name: "Foomp", + fields: [ + Field { + name: "a", + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), + offset: 4, + }, + ], + non_exhaustive: true, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 12, ), diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 812a918e519d..45f0a2e2f063 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -164,7 +164,46 @@ Type { ), } Type { - kind: Other, + kind: Enum( + Enum { + generics: [], + variants: [ + Variant { + name: "Some", + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 4, + }, + ], + non_exhaustive: false, + }, + Variant { + name: "None", + fields: [], + non_exhaustive: false, + }, + Variant { + name: "Foomp", + fields: [ + Field { + name: "a", + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), + offset: 8, + }, + ], + non_exhaustive: true, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 24, ), diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index d0da0582fb51..755f0c900e33 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -24,7 +24,11 @@ struct TupleStruct(u32, u64); enum Bar { Some(u32), None, - Foomp { a: (), b: &'static str }, + #[non_exhaustive] + Foomp { + a: (), + b: &'static str, + }, } struct Generics<'a, A, B, const C: u64> { From 98e0c34f7f5ba6d68a6e3506d1569939fbf14627 Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 5 Feb 2026 19:28:55 +0100 Subject: [PATCH 26/37] Support unions in type info reflection --- .../src/const_eval/type_info.rs | 48 ++++++++++++++++--- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/mem/type_info.rs | 13 +++++ library/coretests/tests/mem/type_info.rs | 41 ++++++++++++++++ tests/ui/reflection/dump.bit32.run.stdout | 22 +++++++++ tests/ui/reflection/dump.bit64.run.stdout | 22 +++++++++ tests/ui/reflection/dump.rs | 7 ++- 7 files changed, 146 insertions(+), 8 deletions(-) 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 701adc7f732b..0529d452626b 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -120,12 +120,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Adt(adt_def, generics) => { - // TODO(type_info): Handle union - if !adt_def.is_struct() && !adt_def.is_enum() { - self.downcast(&field_dest, sym::Other)?.0 - } else { - self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)? - } + self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)? } ty::Bool => { let (variant, _variant_place) = @@ -394,13 +389,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { )?; variant } + AdtKind::Union => { + let (variant, variant_place) = self.downcast(place, sym::Union)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_union_type_info( + place, + (adt_ty, adt_def.variant(VariantIdx::ZERO)), + generics, + )?; + variant + } AdtKind::Enum => { let (variant, variant_place) = self.downcast(place, sym::Enum)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_enum_type_info(place, adt, generics)?; variant } - AdtKind::Union => todo!(), }; interp_ok(variant_idx) } @@ -435,6 +439,36 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + pub(crate) fn write_union_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + union_: (Ty<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (union_ty, union_def) = union_; + let union_layout = self.layout_of(union_ty)?; + + 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 { + sym::generics => self.write_generics(field_place, generics)?, + sym::fields => { + self.write_variant_fields(field_place, union_def, union_layout, generics)? + } + sym::non_exhaustive => { + let is_non_exhaustive = union_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + pub(crate) fn write_enum_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a3576b9a4437..1a099f0cd70f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -400,6 +400,7 @@ symbols! { TyCtxt, TyKind, Type, + Union, Unknown, Unsize, UnsizedConstParamTy, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index b66a836c4bd4..c2b2cf2f270d 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -53,6 +53,8 @@ pub enum TypeKind { Struct(Struct), /// Enums. Enum(Enum), + /// Unions. + Union(Union), /// Primitive boolean type. Bool(Bool), /// Primitive character type. @@ -156,6 +158,17 @@ pub struct Struct { pub non_exhaustive: bool, } +/// Compile-time type information about unions. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Union { + /// Instantiated generics of the union. + pub generics: &'static [Generic], + /// All fields of the union. + pub fields: &'static [Field], +} + /// Compile-time type information about enums. #[derive(Debug)] #[non_exhaustive] diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 09e3a50d374c..808ef68783af 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -135,6 +135,47 @@ fn test_structs() { } } +#[test] +fn test_unions() { + use TypeKind::*; + + const { + union TestUnion { + first: i16, + second: u16, + } + + let Type { kind: Union(ty), size, .. } = Type::of::() else { panic!() }; + assert!(size == Some(size_of::())); + assert!(ty.fields.len() == 2); + assert!(ty.fields[0].name == "first"); + assert!(ty.fields[0].offset == offset_of!(TestUnion, first)); + assert!(ty.fields[1].name == "second"); + assert!(ty.fields[1].offset == offset_of!(TestUnion, second)); + } + + const { + union Generics<'a, T: Copy, const C: u64> { + a: T, + z: &'a (), + } + + let Type { kind: Union(ty), .. } = Type::of::>() else { + panic!() + }; + assert!(ty.fields.len() == 2); + assert!(ty.fields[0].offset == offset_of!(Generics<'static, i32, 1_u64>, a)); + assert!(ty.fields[1].offset == offset_of!(Generics<'static, i32, 1_u64>, z)); + + assert!(ty.generics.len() == 3); + let Generic::Lifetime(_) = ty.generics[0] else { panic!() }; + let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() }; + assert!(generic_ty == TypeId::of::()); + let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() }; + assert!(const_ty == TypeId::of::()); + } +} + #[test] fn test_enums() { use TypeKind::*; diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index a6ad84f5fef1..24a467775725 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -296,6 +296,28 @@ Type { 12, ), } +Type { + kind: Union( + Union { + generics: [], + fields: [ + Field { + name: "first", + ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae), + offset: 0, + }, + Field { + name: "second", + ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7), + offset: 0, + }, + ], + }, + ), + size: Some( + 2, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 45f0a2e2f063..15f40d944173 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -296,6 +296,28 @@ Type { 16, ), } +Type { + kind: Union( + Union { + generics: [], + fields: [ + Field { + name: "first", + ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae), + offset: 0, + }, + Field { + name: "second", + ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7), + offset: 0, + }, + ], + }, + ), + size: Some( + 2, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 755f0c900e33..57669ca85f30 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -42,6 +42,11 @@ struct Unsized { s: str, } +union Union { + first: i16, + second: u16, +} + macro_rules! dump_types { ($($ty:ty),+ $(,)?) => { $(println!("{:#?}", const { Type::of::<$ty>() });)+ @@ -54,7 +59,7 @@ fn main() { [u8; 2], i8, i32, i64, i128, isize, u8, u32, u64, u128, usize, - Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics, + Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics, Union, &Unsized, &str, &[u8], str, [u8], &u8, &mut u8, From b410cb01fe86d992a97f6316a7265716d0e3f851 Mon Sep 17 00:00:00 2001 From: Asuna Date: Sat, 7 Feb 2026 19:03:34 +0100 Subject: [PATCH 27/37] Simplify the writing of tuple type info --- .../src/const_eval/type_info.rs | 56 +++++++------------ 1 file changed, 19 insertions(+), 37 deletions(-) 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 0529d452626b..97206e138697 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -98,7 +98,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { .fields .len() ); - self.write_tuple_fields(tuple_place, fields, ty)?; + self.write_tuple_type_info(tuple_place, fields, ty)?; variant } ty::Array(ty, len) => { @@ -232,42 +232,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - // TODO(type_info): Remove this method, use `allocate_fill_and_write_slice_ptr` as it's more general. - pub(crate) fn write_tuple_fields( - &mut self, - tuple_place: impl Writeable<'tcx, CtfeProvenance>, - fields: &[Ty<'tcx>], - tuple_ty: Ty<'tcx>, - ) -> InterpResult<'tcx> { - // project into the `type_info::Tuple::fields` field - let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?; - // get the `type_info::Field` type from `fields: &[Field]` - let field_type = fields_slice_place - .layout() - .ty - .builtin_deref(false) - .unwrap() - .sequence_element_type(self.tcx.tcx); - // Create an array with as many elements as the number of fields in the inspected tuple - let fields_layout = - self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?; - let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; - let mut fields_places = self.project_array_fields(&fields_place)?; - - let tuple_layout = self.layout_of(tuple_ty)?; - - while let Some((i, place)) = fields_places.next(self)? { - let field_ty = fields[i as usize]; - self.write_field(field_ty, place, tuple_layout, None, i)?; - } - - let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); - - let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self); - - self.write_immediate(ptr, &fields_slice_place) - } - // Write fields for struct, enum variants fn write_variant_fields( &mut self, @@ -325,6 +289,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + pub(crate) fn write_tuple_type_info( + &mut self, + tuple_place: impl Writeable<'tcx, CtfeProvenance>, + fields: &[Ty<'tcx>], + tuple_ty: Ty<'tcx>, + ) -> InterpResult<'tcx> { + let tuple_layout = self.layout_of(tuple_ty)?; + let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?; + self.allocate_fill_and_write_slice_ptr( + fields_slice_place, + fields.len() as u64, + |this, i, place| { + let field_ty = fields[i as usize]; + this.write_field(field_ty, place, tuple_layout, None, i) + }, + ) + } + pub(crate) fn write_array_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, From a575fe168f2293a9c8c2945f5c5795eaec2f4d34 Mon Sep 17 00:00:00 2001 From: Asuna Date: Tue, 10 Feb 2026 01:28:35 +0100 Subject: [PATCH 28/37] Erase type lifetime before writing type ID --- compiler/rustc_const_eval/src/const_eval/type_info.rs | 5 ++++- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 7 ++++++- library/coretests/tests/mem/type_info.rs | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) 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 97206e138697..7741027981d0 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -273,7 +273,10 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let ptr = self.mplace_to_ref(&name_place)?; self.write_immediate(*ptr, &field_place)? } - sym::ty => self.write_type_id(field_ty, &field_place)?, + sym::ty => { + let field_ty = self.tcx.erase_and_anonymize_regions(field_ty); + self.write_type_id(field_ty, &field_place)? + } sym::offset => { let offset = layout.fields.offset(idx as usize); self.write_scalar( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 2ea5e4a25c11..49038315b546 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::{Symbol, sym}; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; @@ -73,6 +73,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty: Ty<'tcx>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> { + debug_assert!( + !ty.has_erasable_regions(), + "type {ty:?} has regions that need erasing before writing a TypeId", + ); + let tcx = self.tcx; let type_id_hash = tcx.type_id_hash(ty).as_u128(); let op = self.const_val_to_op( diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 808ef68783af..2483b4c2aacd 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -91,7 +91,7 @@ fn test_structs() { assert!(ty.fields[1].ty == TypeId::of::()); assert!(ty.fields[1].offset == offset_of!(TestStruct, second)); assert!(ty.fields[2].name == "reference"); - assert!(ty.fields[2].ty != TypeId::of::<&'static u16>()); // FIXME(type_info): should be == + assert!(ty.fields[2].ty == TypeId::of::<&'static u16>()); assert!(ty.fields[2].offset == offset_of!(TestStruct, reference)); } From 6ab6734d4badb8fb8956873df1c3e2e2389a42f4 Mon Sep 17 00:00:00 2001 From: Asuna Date: Tue, 10 Feb 2026 02:09:07 +0100 Subject: [PATCH 29/37] Move ADT related code to a sub module for type info --- .../src/const_eval/type_info.rs | 271 +---------------- .../src/const_eval/type_info/adt.rs | 276 ++++++++++++++++++ 2 files changed, 280 insertions(+), 267 deletions(-) create mode 100644 compiler/rustc_const_eval/src/const_eval/type_info/adt.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 7741027981d0..0fd70d784d4f 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -1,14 +1,13 @@ +mod adt; + use std::borrow::Cow; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; +use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{ - self, AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, ScalarInt, Ty, - VariantDef, -}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::ty::{self, Const, ScalarInt, Ty}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -232,25 +231,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - // Write fields for struct, enum variants - fn write_variant_fields( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - variant_def: &'tcx VariantDef, - variant_layout: TyAndLayout<'tcx>, - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - self.allocate_fill_and_write_slice_ptr( - place, - variant_def.fields.len() as u64, - |this, i, place| { - let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)]; - let field_ty = field_def.ty(*this.tcx, generics); - this.write_field(field_ty, place, variant_layout, Some(field_def.name), i) - }, - ) - } - fn write_field( &mut self, field_ty: Ty<'tcx>, @@ -355,249 +335,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - // FIXME(type_info): No semver considerations for now - pub(crate) fn write_adt_type_info( - &mut self, - place: &impl Writeable<'tcx, CtfeProvenance>, - adt: (Ty<'tcx>, AdtDef<'tcx>), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx, VariantIdx> { - let (adt_ty, adt_def) = adt; - let variant_idx = match adt_def.adt_kind() { - AdtKind::Struct => { - let (variant, variant_place) = self.downcast(place, sym::Struct)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_struct_type_info( - place, - (adt_ty, adt_def.variant(VariantIdx::ZERO)), - generics, - )?; - variant - } - AdtKind::Union => { - let (variant, variant_place) = self.downcast(place, sym::Union)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_union_type_info( - place, - (adt_ty, adt_def.variant(VariantIdx::ZERO)), - generics, - )?; - variant - } - AdtKind::Enum => { - let (variant, variant_place) = self.downcast(place, sym::Enum)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_enum_type_info(place, adt, generics)?; - variant - } - }; - interp_ok(variant_idx) - } - - pub(crate) fn write_struct_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - struct_: (Ty<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (struct_ty, struct_def) = struct_; - let struct_layout = self.layout_of(struct_ty)?; - - 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 { - sym::generics => self.write_generics(field_place, generics)?, - sym::fields => { - self.write_variant_fields(field_place, struct_def, struct_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - pub(crate) fn write_union_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - union_: (Ty<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (union_ty, union_def) = union_; - let union_layout = self.layout_of(union_ty)?; - - 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 { - sym::generics => self.write_generics(field_place, generics)?, - sym::fields => { - self.write_variant_fields(field_place, union_def, union_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = union_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - pub(crate) fn write_enum_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - enum_: (Ty<'tcx>, AdtDef<'tcx>), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (enum_ty, enum_def) = enum_; - let enum_layout = self.layout_of(enum_ty)?; - - 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 { - sym::generics => self.write_generics(field_place, generics)?, - sym::variants => { - self.allocate_fill_and_write_slice_ptr( - field_place, - enum_def.variants().len() as u64, - |this, i, place| { - let variant_idx = VariantIdx::from_usize(i as usize); - let variant_def = &enum_def.variants()[variant_idx]; - let variant_layout = enum_layout.for_variant(this, variant_idx); - this.write_enum_variant(place, (variant_layout, &variant_def), generics) - }, - )?; - } - sym::non_exhaustive => { - let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - fn write_enum_variant( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - variant: (TyAndLayout<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (variant_layout, variant_def) = variant; - - for (field_idx, field_def) 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_def.name { - sym::name => { - let name_place = self.allocate_str_dedup(variant_def.name.as_str())?; - let ptr = self.mplace_to_ref(&name_place)?; - self.write_immediate(*ptr, &field_place)? - } - sym::fields => { - self.write_variant_fields(field_place, &variant_def, variant_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = variant_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), - } - } - interp_ok(()) - } - - fn write_generics( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| { - match generics[i as usize].kind() { - GenericArgKind::Lifetime(region) => this.write_generic_lifetime(region, place), - GenericArgKind::Type(ty) => this.write_generic_type(ty, place), - GenericArgKind::Const(c) => this.write_generic_const(c, place), - } - }) - } - - fn write_generic_lifetime( - &mut self, - _region: Region<'tcx>, - place: MPlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?; - self.write_discriminant(variant_idx, &place)?; - interp_ok(()) - } - - fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { - let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?; - let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?; - - for (field_idx, field_def) in generic_type_place - .layout() - .ty - .ty_adt_def() - .unwrap() - .non_enum_variant() - .fields - .iter_enumerated() - { - let field_place = self.project_field(&generic_type_place, field_idx)?; - match field_def.name { - sym::ty => self.write_type_id(ty, &field_place)?, - other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), - } - } - - self.write_discriminant(variant_idx, &place)?; - interp_ok(()) - } - - fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { - let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") }; - - let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?; - let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?; - - for (field_idx, field_def) in const_place - .layout() - .ty - .ty_adt_def() - .unwrap() - .non_enum_variant() - .fields - .iter_enumerated() - { - let field_place = self.project_field(&const_place, field_idx)?; - match field_def.name { - sym::ty => self.write_type_id(c.ty, &field_place)?, - other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), - } - } - - self.write_discriminant(variant_idx, &place)?; - interp_ok(()) - } - fn write_int_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs new file mode 100644 index 000000000000..60f7b95e799a --- /dev/null +++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs @@ -0,0 +1,276 @@ +use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{ + AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, VariantDef, +}; +use rustc_middle::{bug, span_bug}; +use rustc_span::sym; + +use crate::const_eval::CompileTimeMachine; +use crate::interpret::{ + CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Scalar, Writeable, interp_ok, +}; + +impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { + // FIXME(type_info): No semver considerations for now + pub(crate) fn write_adt_type_info( + &mut self, + place: &impl Writeable<'tcx, CtfeProvenance>, + adt: (Ty<'tcx>, AdtDef<'tcx>), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx, VariantIdx> { + let (adt_ty, adt_def) = adt; + let variant_idx = match adt_def.adt_kind() { + AdtKind::Struct => { + let (variant, variant_place) = self.downcast(place, sym::Struct)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_struct_type_info( + place, + (adt_ty, adt_def.variant(VariantIdx::ZERO)), + generics, + )?; + variant + } + AdtKind::Union => { + let (variant, variant_place) = self.downcast(place, sym::Union)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_union_type_info( + place, + (adt_ty, adt_def.variant(VariantIdx::ZERO)), + generics, + )?; + variant + } + AdtKind::Enum => { + let (variant, variant_place) = self.downcast(place, sym::Enum)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_enum_type_info(place, adt, generics)?; + variant + } + }; + interp_ok(variant_idx) + } + + pub(crate) fn write_struct_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + struct_: (Ty<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (struct_ty, struct_def) = struct_; + let struct_layout = self.layout_of(struct_ty)?; + + 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 { + sym::generics => self.write_generics(field_place, generics)?, + sym::fields => { + self.write_variant_fields(field_place, struct_def, struct_layout, generics)? + } + sym::non_exhaustive => { + let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + + pub(crate) fn write_union_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + union_: (Ty<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (union_ty, union_def) = union_; + let union_layout = self.layout_of(union_ty)?; + + 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 { + sym::generics => self.write_generics(field_place, generics)?, + sym::fields => { + self.write_variant_fields(field_place, union_def, union_layout, generics)? + } + sym::non_exhaustive => { + let is_non_exhaustive = union_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + + pub(crate) fn write_enum_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + enum_: (Ty<'tcx>, AdtDef<'tcx>), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (enum_ty, enum_def) = enum_; + let enum_layout = self.layout_of(enum_ty)?; + + 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 { + sym::generics => self.write_generics(field_place, generics)?, + sym::variants => { + self.allocate_fill_and_write_slice_ptr( + field_place, + enum_def.variants().len() as u64, + |this, i, place| { + let variant_idx = VariantIdx::from_usize(i as usize); + let variant_def = &enum_def.variants()[variant_idx]; + let variant_layout = enum_layout.for_variant(this, variant_idx); + this.write_enum_variant(place, (variant_layout, &variant_def), generics) + }, + )?; + } + sym::non_exhaustive => { + let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } + + fn write_enum_variant( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + variant: (TyAndLayout<'tcx>, &'tcx VariantDef), + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + let (variant_layout, variant_def) = variant; + + for (field_idx, field_def) 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_def.name { + sym::name => { + let name_place = self.allocate_str_dedup(variant_def.name.as_str())?; + let ptr = self.mplace_to_ref(&name_place)?; + self.write_immediate(*ptr, &field_place)? + } + sym::fields => { + self.write_variant_fields(field_place, &variant_def, variant_layout, generics)? + } + sym::non_exhaustive => { + let is_non_exhaustive = variant_def.is_field_list_non_exhaustive(); + self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? + } + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + interp_ok(()) + } + + // Write fields for struct, enum variants + fn write_variant_fields( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + variant_def: &'tcx VariantDef, + variant_layout: TyAndLayout<'tcx>, + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + self.allocate_fill_and_write_slice_ptr( + place, + variant_def.fields.len() as u64, + |this, i, place| { + let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)]; + let field_ty = field_def.ty(*this.tcx, generics); + this.write_field(field_ty, place, variant_layout, Some(field_def.name), i) + }, + ) + } + + fn write_generics( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| { + match generics[i as usize].kind() { + GenericArgKind::Lifetime(region) => this.write_generic_lifetime(region, place), + GenericArgKind::Type(ty) => this.write_generic_type(ty, place), + GenericArgKind::Const(c) => this.write_generic_const(c, place), + } + }) + } + + fn write_generic_lifetime( + &mut self, + _region: Region<'tcx>, + place: MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?; + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } + + fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?; + let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + for (field_idx, field_def) in generic_type_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .iter_enumerated() + { + let field_place = self.project_field(&generic_type_place, field_idx)?; + match field_def.name { + sym::ty => self.write_type_id(ty, &field_place)?, + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } + + fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") }; + + let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?; + let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + for (field_idx, field_def) in const_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .iter_enumerated() + { + let field_place = self.project_field(&const_place, field_idx)?; + match field_def.name { + sym::ty => self.write_type_id(c.ty, &field_place)?, + other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), + } + } + + self.write_discriminant(variant_idx, &place)?; + interp_ok(()) + } +} From e20a44db783650a5d0d43a430810f9d12c2c890e Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 10 Feb 2026 11:35:43 -0500 Subject: [PATCH 30/37] Fix typos and capitalization across documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix "Github" → "GitHub" capitalization throughout (about.md, git.md, about-this-guide.md, debugging-support-in-rustc.md, and all notification-groups files) - Fix "its self" → "itself" (macro-expansion.md, what-bootstrapping-does.md) - Fix "MIRI" → "Miri" (overview.md, what-bootstrapping-does.md) - Fix grammar: "to given" → "to give", "an user-specified" → "a user-specified", "an separate" → "a separate" (diagnostics.md, git.md) - Fix incorrect attribute syntax: `!#[warn` → `#![warn` (diagnostics.md) - Fix "overrides" → "override" (suggested.md) - Fix "issue commit" → "commit message" (contributing.md) - Fix double spaces (ty.md) --- src/doc/rustc-dev-guide/src/about-this-guide.md | 2 +- .../building/bootstrapping/what-bootstrapping-does.md | 2 +- src/doc/rustc-dev-guide/src/building/suggested.md | 2 +- src/doc/rustc-dev-guide/src/contributing.md | 2 +- .../rustc-dev-guide/src/debugging-support-in-rustc.md | 2 +- src/doc/rustc-dev-guide/src/diagnostics.md | 6 +++--- src/doc/rustc-dev-guide/src/git.md | 10 +++++----- src/doc/rustc-dev-guide/src/macro-expansion.md | 2 +- .../rustc-dev-guide/src/notification-groups/about.md | 4 ++-- .../rustc-dev-guide/src/notification-groups/apple.md | 2 +- src/doc/rustc-dev-guide/src/notification-groups/arm.md | 2 +- .../src/notification-groups/emscripten.md | 2 +- .../rustc-dev-guide/src/notification-groups/fuchsia.md | 2 +- .../src/notification-groups/loongarch.md | 2 +- .../rustc-dev-guide/src/notification-groups/risc-v.md | 2 +- .../src/notification-groups/rust-for-linux.md | 2 +- .../rustc-dev-guide/src/notification-groups/wasi.md | 2 +- .../rustc-dev-guide/src/notification-groups/wasm.md | 2 +- .../rustc-dev-guide/src/notification-groups/windows.md | 2 +- src/doc/rustc-dev-guide/src/overview.md | 4 ++-- src/doc/rustc-dev-guide/src/ty.md | 4 ++-- 21 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 9d493e0cb065..4dc453a2042d 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -10,7 +10,7 @@ There are several parts to this guide: about building, debugging, profiling, etc. 1. [Contributing to Rust][p2]: Contains information that should be useful no matter how you are contributing, - about procedures for contribution, using git and Github, stabilizing features, etc. + about procedures for contribution, using git and GitHub, stabilizing features, etc. 1. [Bootstrapping][p3]: Describes how the Rust compiler builds itself using previous versions, including an introduction to the bootstrap process and debugging methods. diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 453441fd1015..a5dfd9a0e832 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -342,7 +342,7 @@ This flag has the following effects: Code which does not use `-Z force-unstable-if-unmarked` should include the `#![feature(rustc_private)]` crate attribute to access these forced-unstable -crates. This is needed for things which link `rustc` its self, such as `MIRI` or +crates. This is needed for things which link `rustc` itself, such as `Miri` or `clippy`. You can find more discussion about sysroots in: diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index ac8f15db7751..0014ba0e9a94 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -56,7 +56,7 @@ You can also include extensions within extensions recursively. **Note:** In the `include` field, the overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`, extension `b.toml` overrides `a.toml`. -Also, parent extensions always overrides the inner ones. +Also, parent extensions always override the inner ones. ## Configuring `rust-analyzer` for `rustc` diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 83f4253a6a10..7f4779515b13 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -324,7 +324,7 @@ When you resolve them, you should use `@rustbot` to mark it as `S-waiting-on-rev GitHub allows [closing issues using keywords][closing-keywords]. This feature should be used to keep the issue tracker tidy. However, it is generally preferred -to put the "closes #123" text in the PR description rather than the issue commit; +to put the "closes #123" text in the PR description rather than the commit message; particularly during rebasing, citing the issue number in the commit can "spam" the issue in question. diff --git a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md index bd4f795ce03b..f2193e8abf98 100644 --- a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md +++ b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md @@ -216,7 +216,7 @@ trait for a type would be one of these interfaces (`DW_tag_interface` type). Als which it is implemented would describe all the interfaces this type implements. This requires a DWARF extension. -Issue on Github: [https://github.com/rust-lang/rust/issues/33014] +Issue on GitHub: [https://github.com/rust-lang/rust/issues/33014] ## Typical process for a Debug Info change (LLVM) diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 89c18b8e40f1..1ed19663118f 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -228,7 +228,7 @@ Guidelines for different diagnostic levels: The error or warning portion should *not* suggest how to fix the problem, only the "help" sub-diagnostic should. -- `note`: emitted to given more context and identify additional circumstances +- `note`: emitted to give more context and identify additional circumstances and parts of the code that caused the warning or error. For example, the borrow checker will note any previous conflicting borrows. @@ -788,7 +788,7 @@ add_lint_group!(sess, ``` This defines the `nonstandard_style` group which turns on the listed lints. A -user can turn on these lints with a `!#[warn(nonstandard_style)]` attribute in +user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in the source code, or by passing `-W nonstandard-style` on the command line. Some lint groups are created automatically in `LintStore::register_lints`. For instance, @@ -944,7 +944,7 @@ You can filter on the following boolean flags: - `crate_local`: whether the code causing the trait bound to not be fulfilled is part of the user's crate. This is used to avoid suggesting code changes that would require modifying a dependency. - - `direct`: whether this is an user-specified rather than derived obligation. + - `direct`: whether this is a user-specified rather than derived obligation. - `from_desugaring`: whether we are in some kind of desugaring, like `?` or a `try` block for example. This flag can also be matched on, see below. diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index c0b449e8fb28..e85e6bd70850 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -372,7 +372,7 @@ to ensure that Git doesn't create merge commits when `git pull`ing, without needing to pass `--ff-only` or `--rebase` every time. You can also `git push --force-with-lease` from main to double-check that your -feature branches are in sync with their state on the Github side. +feature branches are in sync with their state on the GitHub side. ## Advanced Rebasing @@ -494,7 +494,7 @@ to follow and understand. ### Hiding whitespace -Github has a button for disabling whitespace changes that may be useful. +GitHub has a button for disabling whitespace changes that may be useful. You can also use `git diff -w origin/main` to view changes locally. ![hide whitespace](./img/github-whitespace-changes.png) @@ -505,7 +505,7 @@ To checkout PRs locally, you can use `git fetch upstream pull/NNNNN/head && git FETCH_HEAD`. You can also use github's cli tool. -Github shows a button on PRs where you can copy-paste the command to check it out locally. +GitHub shows a button on PRs where you can copy-paste the command to check it out locally. See for more info. ![`gh` suggestion](./img/github-cli.png) @@ -521,7 +521,7 @@ for more details. ### Moving large sections of code -Git and Github's default diff view for large moves *within* a file is quite poor; it will show each +Git and GitHub's default diff view for large moves *within* a file is quite poor; it will show each line as deleted and each line as added, forcing you to compare each line yourself. Git has an option to show moved lines in a different color: @@ -562,7 +562,7 @@ Rust projects from within the `rust` repo. Examples include Rust's fork of `llvm-project`, `cargo`, and libraries like `stdarch` and `backtrace`. -Those projects are developed and maintained in an separate Git (and GitHub) +Those projects are developed and maintained in a separate Git (and GitHub) repository, and they have their own Git history/commits, issue tracker and PRs. Submodules allow us to create some sort of embedded sub-repository inside the `rust` repository and use them like they were directories in the `rust` repository. diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index f9ab946245b0..3199e9950d7e 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -468,7 +468,7 @@ Here `$mvar` is called a _metavariable_. Unlike normal variables, rather than binding to a value _at runtime_, a metavariable binds _at compile time_ to a tree of _tokens_. A _token_ is a single "unit" of the grammar, such as an identifier (e.g. `foo`) or punctuation (e.g. `=>`). There are also other -special tokens, such as `EOF`, which its self indicates that there are no more +special tokens, such as `EOF`, which itself indicates that there are no more tokens. There are token trees resulting from the paired parentheses-like characters (`(`...`)`, `[`...`]`, and `{`...`}`) – they include the open and close and all the tokens in between (Rust requires that parentheses-like diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md index 917a0f8a1020..2c2c98860a9b 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/about.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md @@ -11,7 +11,7 @@ that fits the notification group's criteria. If you are interested, you can then [claim the issue] and start working on it. Of course, you don't have to wait for new issues to be tagged! If you -prefer, you can use the Github label for a notification group to +prefer, you can use the GitHub label for a notification group to search for existing issues that haven't been claimed yet. [claim the issue]: https://forge.rust-lang.org/triagebot/issue-assignment.html @@ -47,7 +47,7 @@ particularly those of **middle priority**: ## Joining a notification group To join a notification group, you just have to open a PR adding your -Github username to the appropriate file in the Rust team repository. +GitHub username to the appropriate file in the Rust team repository. See the "example PRs" below to get a precise idea and to identify the file to edit. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/apple.md b/src/doc/rustc-dev-guide/src/notification-groups/apple.md index f1e62945a7ee..c176107deb76 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/apple.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/apple.md @@ -1,6 +1,6 @@ # Apple notification group -**Github Labels:** [O-macos], [O-ios], [O-tvos], [O-watchos] and [O-visionos]
+**GitHub Labels:** [O-macos], [O-ios], [O-tvos], [O-watchos] and [O-visionos]
**Ping command:** `@rustbot ping apple` This list will be used to ask for help both in diagnosing and testing diff --git a/src/doc/rustc-dev-guide/src/notification-groups/arm.md b/src/doc/rustc-dev-guide/src/notification-groups/arm.md index 5b79030d20de..bffcc6c04571 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/arm.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/arm.md @@ -1,6 +1,6 @@ # ARM notification group -**Github Label:** [O-ARM]
+**GitHub Label:** [O-ARM]
**Ping command:** `@rustbot ping arm` [O-ARM]: https://github.com/rust-lang/rust/labels/O-ARM diff --git a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md index 9e4086c884e0..4996ed62e46a 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md @@ -1,6 +1,6 @@ # Emscripten notification group -**Github Label:** [O-emscripten]
+**GitHub Label:** [O-emscripten]
**Ping command:** `@rustbot ping emscripten` [O-emscripten]: https://github.com/rust-lang/rust/labels/O-emscripten diff --git a/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md b/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md index e3c1a7148d3c..fd9c5d236f5c 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md @@ -1,6 +1,6 @@ # Fuchsia notification group -**Github Label:** [O-fuchsia]
+**GitHub Label:** [O-fuchsia]
**Ping command:** `@rustbot ping fuchsia` [O-fuchsia]: https://github.com/rust-lang/rust/labels/O-fuchsia diff --git a/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md index 0a3707a9ad99..09620a6a5ce8 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md @@ -1,6 +1,6 @@ # LoongArch notification group -**Github Label:** [O-loongarch]
+**GitHub Label:** [O-loongarch]
**Ping command:** `@rustbot ping loongarch` [O-loongarch]: https://github.com/rust-lang/rust/labels/O-loongarch diff --git a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md index 7c8a3cdf8a64..250a512fbaac 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md @@ -1,6 +1,6 @@ # RISC-V notification group -**Github Label:** [O-riscv]
+**GitHub Label:** [O-riscv]
**Ping command:** `@rustbot ping risc-v` [O-riscv]: https://github.com/rust-lang/rust/labels/O-riscv diff --git a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md index ed1de9196de6..c08cf9deecec 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md @@ -1,6 +1,6 @@ # Rust for Linux notification group -**Github Label:** [A-rust-for-linux]
+**GitHub Label:** [A-rust-for-linux]
**Ping command:** `@rustbot ping rfl` [A-rust-for-linux]: https://github.com/rust-lang/rust/labels/A-rust-for-linux diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md index 88b9465be018..3d7fd01af28d 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md @@ -1,6 +1,6 @@ # WASI notification group -**Github Label:** [O-wasi]
+**GitHub Label:** [O-wasi]
**Ping command:** `@rustbot ping wasi` [O-wasi]: https://github.com/rust-lang/rust/labels/O-wasi diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md index 6f52b04251f0..12e457546ba9 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md @@ -1,6 +1,6 @@ # WebAssembly (WASM) notification group -**Github Label:** [O-wasm]
+**GitHub Label:** [O-wasm]
**Ping command:** `@rustbot ping wasm` [O-wasm]: https://github.com/rust-lang/rust/labels/O-wasm diff --git a/src/doc/rustc-dev-guide/src/notification-groups/windows.md b/src/doc/rustc-dev-guide/src/notification-groups/windows.md index d245208e2abc..4b3970a9d63f 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/windows.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/windows.md @@ -1,6 +1,6 @@ # Windows notification group -**Github Label:** [O-Windows]
+**GitHub Label:** [O-Windows]
**Ping command:** `@rustbot ping windows` [O-Windows]: https://github.com/rust-lang/rust/labels/O-Windows diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index 7858c09fe724..d4ffc7b6c2db 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -198,7 +198,7 @@ satisfy/optimize for. For example, the input programs says they do, and should continue to do so despite the tremendous amount of change constantly going on. - Integration: a number of other tools need to use the compiler in - various ways (e.g. `cargo`, `clippy`, `MIRI`) that must be supported. + various ways (e.g. `cargo`, `clippy`, `Miri`) that must be supported. - Compiler stability: the compiler should not crash or fail ungracefully on the stable channel. - Rust stability: the compiler must respect Rust's stability guarantees by not @@ -245,7 +245,7 @@ for different purposes: values). `MIR` is used for borrow checking and other important dataflow-based checks, such as checking for uninitialized values. It is also used for a series of optimizations and for constant evaluation (via - `MIRI`). Because `MIR` is still generic, we can do a lot of analyses here more + `Miri`). Because `MIR` is still generic, we can do a lot of analyses here more efficiently than after monomorphization. - `LLVM-IR`: This is the standard form of all input to the LLVM compiler. `LLVM-IR` is a sort of typed assembly language with lots of annotations. It's diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index 4055f475e992..c84e82adf5c5 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -5,7 +5,7 @@ The `ty` module defines how the Rust compiler represents types internally. It al ## `ty::Ty` -When we talk about how rustc represents types, we usually refer to a type called `Ty` . There are +When we talk about how rustc represents types, we usually refer to a type called `Ty`. There are quite a few modules and types for `Ty` in the compiler ([Ty documentation][ty]). [ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/index.html @@ -46,7 +46,7 @@ That is, they have two different [`Span`s][span] (locations). In addition, HIR might have information left out. This type `&u32` is incomplete, since in the full Rust type there is actually a lifetime, but we didn’t need to write those lifetimes. There are also some elision rules that insert information. The result may -look like `fn foo<'a>(x: &'a u32) -> &'a u32`. +look like `fn foo<'a>(x: &'a u32) -> &'a u32`. In the HIR level, these things are not spelled out and you can say the picture is rather incomplete. However, at the `ty::Ty` level, these details are added and it is complete. Moreover, we will have From bdd8b21e41ce20c7d5090fb1dcea769adfa34600 Mon Sep 17 00:00:00 2001 From: Redddy Date: Wed, 11 Feb 2026 15:09:46 +0900 Subject: [PATCH 31/37] Add reddevilmidzy to review group --- src/doc/rustc-dev-guide/triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index 07118872809e..13b43d94ab8b 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -85,6 +85,7 @@ does not need reviews. You can request a review using `r? rustc-dev-guide` or \ rustc-dev-guide = [ "@BoxyUwU", "@jyn514", + "@reddevilmidzy", "@tshepang", ] From 8b5a212031be6d7381f2129c9921a9a2a387f9c8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 11 Feb 2026 06:39:34 +0000 Subject: [PATCH 32/37] Fix doc links to rustc_lexer and rustc_middle --- src/doc/rustc-dev-guide/src/overview.md | 2 +- src/doc/rustc-dev-guide/src/query.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index 7858c09fe724..3720b6cd637e 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -395,7 +395,7 @@ For more details on bootstrapping, see - Lexical Analysis: Lex the user program to a stream of tokens - Guide: [Lexing and Parsing](the-parser.md) - Lexer definition: [`rustc_lexer`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lexer/index.html) - - Main entry point: [`rustc_lexer::cursor::Cursor::advance_token`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lexer/cursor/struct.Cursor.html#method.advance_token) + - Main entry point: [`rustc_lexer::Cursor::advance_token`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lexer/struct.Cursor.html#method.advance_token) - Parsing: Parse the stream of tokens to an Abstract Syntax Tree (AST) - Guide: [Lexing and Parsing](the-parser.md) - Guide: [Macro Expansion](macro-expansion.md) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 1961d68509f9..5ab2ab428e81 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -254,8 +254,8 @@ You will typically need to: An example of introducing such a cross-crate query can be found in commit [`996a185`](https://github.com/rust-lang/rust/commit/996a185) in the `rust-lang/rust` repository. [rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html -[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html -[extern_providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.ExternProviders.html +[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/queries/struct.Providers.html +[extern_providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/queries/struct.ExternProviders.html --- From 4810270252324b39a8019c09dd0fa5eac6c35768 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 11 Feb 2026 12:18:20 +0100 Subject: [PATCH 33/37] Drop dump test for type info reflection --- tests/ui/reflection/dump.bit32.run.stdout | 389 ---------------------- tests/ui/reflection/dump.bit64.run.stdout | 389 ---------------------- tests/ui/reflection/dump.rs | 67 ---- 3 files changed, 845 deletions(-) delete mode 100644 tests/ui/reflection/dump.bit32.run.stdout delete mode 100644 tests/ui/reflection/dump.bit64.run.stdout delete mode 100644 tests/ui/reflection/dump.rs diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout deleted file mode 100644 index 24a467775725..000000000000 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ /dev/null @@ -1,389 +0,0 @@ -Type { - kind: Tuple( - Tuple { - fields: [ - Field { - name: "0", - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 0, - }, - Field { - name: "1", - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 1, - }, - Field { - name: "2", - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), - offset: 2, - }, - ], - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Array( - Array { - element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - len: 2, - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Int( - Int { - bits: 8, - signed: true, - }, - ), - size: Some( - 1, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: true, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: true, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Int( - Int { - bits: 128, - signed: true, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: true, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Int( - Int { - bits: 8, - signed: false, - }, - ), - size: Some( - 1, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Int( - Int { - bits: 128, - signed: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "a", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Enum( - Enum { - generics: [], - variants: [ - Variant { - name: "Some", - fields: [ - Field { - name: "0", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 4, - }, - ], - non_exhaustive: false, - }, - Variant { - name: "None", - fields: [], - non_exhaustive: false, - }, - Variant { - name: "Foomp", - fields: [ - Field { - name: "a", - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), - offset: 4, - }, - Field { - name: "b", - ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), - offset: 4, - }, - ], - non_exhaustive: true, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 12, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "a", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 0, - }, - ], - non_exhaustive: true, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "0", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 8, - }, - Field { - name: "1", - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 12, - ), -} -Type { - kind: Struct( - Struct { - generics: [ - Lifetime( - Lifetime, - ), - Type( - GenericType { - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), - }, - ), - Type( - GenericType { - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - }, - ), - Const( - Const { - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), - }, - ), - ], - fields: [ - Field { - name: "a", - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), - offset: 4, - }, - Field { - name: "b", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 8, - }, - Field { - name: "l", - ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 12, - ), -} -Type { - kind: Union( - Union { - generics: [], - fields: [ - Field { - name: "first", - ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae), - offset: 0, - }, - Field { - name: "second", - ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7), - offset: 0, - }, - ], - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79), - mutable: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), - mutable: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196), - mutable: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Str( - Str, - ), - size: None, -} -Type { - kind: Slice( - Slice { - element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - }, - ), - size: None, -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - mutable: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - mutable: true, - }, - ), - size: Some( - 4, - ), -} diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout deleted file mode 100644 index 15f40d944173..000000000000 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ /dev/null @@ -1,389 +0,0 @@ -Type { - kind: Tuple( - Tuple { - fields: [ - Field { - name: "0", - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 0, - }, - Field { - name: "1", - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 1, - }, - Field { - name: "2", - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), - offset: 2, - }, - ], - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Array( - Array { - element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - len: 2, - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Int( - Int { - bits: 8, - signed: true, - }, - ), - size: Some( - 1, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: true, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: true, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Int( - Int { - bits: 128, - signed: true, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: true, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Int( - Int { - bits: 8, - signed: false, - }, - ), - size: Some( - 1, - ), -} -Type { - kind: Int( - Int { - bits: 32, - signed: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Int( - Int { - bits: 128, - signed: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Int( - Int { - bits: 64, - signed: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "a", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Enum( - Enum { - generics: [], - variants: [ - Variant { - name: "Some", - fields: [ - Field { - name: "0", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 4, - }, - ], - non_exhaustive: false, - }, - Variant { - name: "None", - fields: [], - non_exhaustive: false, - }, - Variant { - name: "Foomp", - fields: [ - Field { - name: "a", - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), - offset: 4, - }, - Field { - name: "b", - ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), - offset: 8, - }, - ], - non_exhaustive: true, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 24, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "a", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 0, - }, - ], - non_exhaustive: true, - }, - ), - size: Some( - 4, - ), -} -Type { - kind: Struct( - Struct { - generics: [], - fields: [ - Field { - name: "0", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 8, - }, - Field { - name: "1", - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Struct( - Struct { - generics: [ - Lifetime( - Lifetime, - ), - Type( - GenericType { - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), - }, - ), - Type( - GenericType { - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - }, - ), - Const( - Const { - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), - }, - ), - ], - fields: [ - Field { - name: "a", - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), - offset: 8, - }, - Field { - name: "b", - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), - offset: 12, - }, - Field { - name: "l", - ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), - offset: 0, - }, - ], - non_exhaustive: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Union( - Union { - generics: [], - fields: [ - Field { - name: "first", - ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae), - offset: 0, - }, - Field { - name: "second", - ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7), - offset: 0, - }, - ], - }, - ), - size: Some( - 2, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79), - mutable: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), - mutable: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196), - mutable: false, - }, - ), - size: Some( - 16, - ), -} -Type { - kind: Str( - Str, - ), - size: None, -} -Type { - kind: Slice( - Slice { - element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - }, - ), - size: None, -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - mutable: false, - }, - ), - size: Some( - 8, - ), -} -Type { - kind: Reference( - Reference { - pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - mutable: true, - }, - ), - size: Some( - 8, - ), -} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs deleted file mode 100644 index 57669ca85f30..000000000000 --- a/tests/ui/reflection/dump.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Some types whose length depends on the target pointer length will be dumped. -//@ revisions: bit32 bit64 -//@[bit32] only-32bit -//@[bit64] only-64bit -//@ run-pass -//@ check-run-results - -#![feature(type_info)] -#![allow(dead_code)] - -use std::mem::type_info::Type; - -struct Foo { - a: u32, -} - -#[non_exhaustive] -struct NonExhaustiveStruct { - a: u32, -} - -struct TupleStruct(u32, u64); - -enum Bar { - Some(u32), - None, - #[non_exhaustive] - Foomp { - a: (), - b: &'static str, - }, -} - -struct Generics<'a, A, B, const C: u64> { - a: A, - b: B, - l: &'a (), -} - -struct Unsized { - x: u16, - s: str, -} - -union Union { - first: i16, - second: u16, -} - -macro_rules! dump_types { - ($($ty:ty),+ $(,)?) => { - $(println!("{:#?}", const { Type::of::<$ty>() });)+ - }; -} - -fn main() { - dump_types! { - (u8, u8, ()), - [u8; 2], - i8, i32, i64, i128, isize, - u8, u32, u64, u128, usize, - Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics, Union, - &Unsized, &str, &[u8], - str, [u8], - &u8, &mut u8, - } -} From 2f3b95234982c74f8fb412384cdc770437572c7e Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Fri, 23 Jan 2026 15:48:09 +0100 Subject: [PATCH 34/37] Stabilize assert_matches --- compiler/rustc_abi/src/lib.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_const_eval/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_mir_build/src/lib.rs | 2 +- compiler/rustc_mir_dataflow/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_parse/src/lib.rs | 2 +- compiler/rustc_query_system/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty_utils/src/lib.rs | 2 +- library/alloc/src/lib.rs | 1 - library/alloctests/lib.rs | 1 - library/alloctests/tests/lib.rs | 1 - library/core/src/lib.rs | 2 +- library/core/src/macros/mod.rs | 8 ++------ library/std/src/lib.rs | 3 +-- src/librustdoc/lib.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- tests/ui-fulldeps/rustc_public/check_abi.rs | 1 - tests/ui-fulldeps/rustc_public/check_allocation.rs | 1 - tests/ui-fulldeps/rustc_public/check_assoc_items.rs | 1 - tests/ui-fulldeps/rustc_public/check_coroutine_body.rs | 1 - tests/ui-fulldeps/rustc_public/check_crate_defs.rs | 1 - tests/ui-fulldeps/rustc_public/check_def_ty.rs | 1 - tests/ui-fulldeps/rustc_public/check_defs.rs | 1 - tests/ui-fulldeps/rustc_public/check_foreign.rs | 1 - tests/ui-fulldeps/rustc_public/check_instance.rs | 1 - tests/ui-fulldeps/rustc_public/check_intrinsics.rs | 1 - tests/ui-fulldeps/rustc_public/check_item_kind.rs | 1 - tests/ui-fulldeps/rustc_public/check_trait_queries.rs | 1 - tests/ui-fulldeps/rustc_public/check_transform.rs | 1 - tests/ui-fulldeps/rustc_public/check_ty_fold.rs | 1 - tests/ui-fulldeps/rustc_public/check_variant.rs | 1 - tests/ui-fulldeps/rustc_public/closure-generic-body.rs | 1 - tests/ui-fulldeps/rustc_public/closure_body.rs | 1 - tests/ui-fulldeps/rustc_public/compilation-result.rs | 1 - tests/ui-fulldeps/rustc_public/crate-info.rs | 1 - tests/ui-fulldeps/rustc_public/projections.rs | 1 - tests/ui-fulldeps/rustc_public/smir_internal.rs | 1 - tests/ui-fulldeps/rustc_public/smir_serde.rs | 1 - tests/ui-fulldeps/rustc_public/smir_visitor.rs | 1 - tests/ui/coroutine/uninhabited-field.rs | 1 - tests/ui/macros/assert-matches-macro-msg.rs | 2 -- tests/ui/stdlib-unit-tests/matches2021.rs | 2 -- 56 files changed, 28 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 061ad8617893..85f31b75e240 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,6 +1,6 @@ // tidy-alphabetical-start +#![cfg_attr(all(feature = "nightly", bootstrap), feature(assert_matches))] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![cfg_attr(feature = "nightly", feature(assert_matches))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(step_trait))] // tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 38b73a07a689..1f0fde11b8d8 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(default_field_values)] #![feature(file_buffered)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 8ac15ceb4bbe..08da5935bbea 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -3,7 +3,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index bf3ec1f39330..347d7e1e6f48 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -5,7 +5,7 @@ //! This API is completely unstable and subject to change. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(extern_types)] #![feature(file_buffered)] #![feature(if_let_guard)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index e3934065b0f7..cbfa12e21eba 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index cccebded4b0b..ead1ee9bf85e 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,6 +1,6 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(array_try_map)] -#![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index bef19d77d1e7..a56b5f5fdc7d 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,12 +10,12 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![cfg_attr(bootstrap, feature(cold_path))] #![deny(unsafe_op_in_unsafe_fn)] #![feature(allocator_api)] #![feature(ascii_char)] #![feature(ascii_char_variants)] -#![feature(assert_matches)] #![feature(auto_traits)] #![feature(cfg_select)] #![feature(const_default)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c0398b3e8da0..cfd4ae3795e1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -5,7 +5,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::direct_use_of_rustc_type_ir)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(default_field_values)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 6214106d422b..70209993a510 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -56,7 +56,7 @@ This API is completely unstable and subject to change. */ // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(default_field_values)] #![feature(gen_blocks)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index ac3db41a4d66..8692720529d5 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 2a1733ef63cb..008b5c94a5ea 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -14,7 +14,7 @@ // tidy-alphabetical-start #![allow(rustc::direct_use_of_rustc_type_ir)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(extend_one)] #![recursion_limit = "512"] // For rustdoc // tidy-alphabetical-end diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 93b6f1491041..94dc566d75f1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,7 +21,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_order_by)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5b32d4551a16..2095327ea1b5 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -27,8 +27,8 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::direct_use_of_rustc_type_ir)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(allocator_api)] -#![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_as_ptr)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index cc8035e2b0ac..21817dea6cb4 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,7 +1,7 @@ //! Construction of MIR from HIR. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(try_blocks)] diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 5f1cf1250152..692591a41a15 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 402e22621426..bc2c6bd81aca 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(const_type_name)] #![feature(cow_is_borrowed)] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 40cdcfc35c2f..014ccdc45ef8 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,7 +1,7 @@ //! The main parser interface. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(default_field_values)] diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index fc63df3595c4..e8d857cf3178 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,6 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(min_specialization)] #![feature(trait_alias)] // tidy-alphabetical-end diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0912b46f473f..1399f9933ad4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,9 +8,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![cfg_attr(bootstrap, feature(ptr_as_ref_unchecked))] #![feature(arbitrary_self_types)] -#![feature(assert_matches)] #![feature(box_patterns)] #![feature(const_default)] #![feature(const_trait_impl)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 7e126cb6a6e9..35a3d0dac8af 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -88,7 +88,7 @@ //! DefPaths which are much more robust in the face of changes to the code base. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] // tidy-alphabetical-end use rustc_hir::def::DefKind; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 645fd17ac709..708e0b9e8497 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -11,7 +11,7 @@ //! This API is completely unstable and subject to change. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(default_field_values)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 9f8f3b240890..b7f73fd5570e 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -5,7 +5,7 @@ //! This API is completely unstable and subject to change. // tidy-alphabetical-start -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f7167650635d..0e0c2fcd8b99 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,7 +89,6 @@ #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(ascii_char)] -#![feature(assert_matches)] #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_vec_non_null)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index fe14480102e3..296f76d7c073 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -16,7 +16,6 @@ // tidy-alphabetical-start #![feature(allocator_api)] #![feature(array_into_iter_constructors)] -#![feature(assert_matches)] #![feature(box_vec_non_null)] #![feature(char_internals)] #![feature(const_alloc_error)] diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index e15c86496cf1..b7b8336ee429 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -3,7 +3,6 @@ #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] -#![feature(assert_matches)] #![feature(wtf8_internals)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 17cf6b3714f5..aaa919ece6a5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -225,7 +225,7 @@ use prelude::rust_2024::*; #[macro_use] mod macros; -#[unstable(feature = "assert_matches", issue = "82775")] +#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")] pub use crate::macros::{assert_matches, debug_assert_matches}; #[unstable(feature = "derive_from", issue = "144889")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3176f3c06709..79eab552303e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -147,8 +147,6 @@ macro_rules! assert_ne { /// # Examples /// /// ``` -/// #![feature(assert_matches)] -/// /// use std::assert_matches; /// /// let a = Some(345); @@ -166,7 +164,7 @@ macro_rules! assert_ne { /// assert_matches!(a, Some(x) if x > 100); /// // assert_matches!(a, Some(x) if x < 100); // panics /// ``` -#[unstable(feature = "assert_matches", issue = "82775")] +#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(panic_internals)] #[rustc_macro_transparency = "semiopaque"] pub macro assert_matches { @@ -380,8 +378,6 @@ macro_rules! debug_assert_ne { /// # Examples /// /// ``` -/// #![feature(assert_matches)] -/// /// use std::debug_assert_matches; /// /// let a = Some(345); @@ -399,7 +395,7 @@ macro_rules! debug_assert_ne { /// debug_assert_matches!(a, Some(x) if x > 100); /// // debug_assert_matches!(a, Some(x) if x < 100); // panics /// ``` -#[unstable(feature = "assert_matches", issue = "82775")] +#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(assert_matches)] #[rustc_macro_transparency = "semiopaque"] pub macro debug_assert_matches($($arg:tt)*) { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index dcde208fac77..39c2dd4c0cb7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -394,7 +394,6 @@ // // Only for re-exporting: // tidy-alphabetical-start -#![feature(assert_matches)] #![feature(async_iterator)] #![feature(c_variadic)] #![feature(cfg_accessible)] @@ -726,7 +725,7 @@ pub use core::{ assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, r#try, unimplemented, unreachable, write, writeln, }; -#[unstable(feature = "assert_matches", issue = "82775")] +#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")] pub use core::{assert_matches, debug_assert_matches}; // Re-export unstable derive macro defined through core. diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 21ac851e5486..7d878e7df529 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(assert_matches))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/" )] #![feature(ascii_char)] #![feature(ascii_char_variants)] -#![feature(assert_matches)] #![feature(box_into_inner)] #![feature(box_patterns)] #![feature(file_buffered)] diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 16bedf199e20..269a7f333dc5 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -3,7 +3,7 @@ #![feature(macro_metavar_expr)] #![feature(never_type)] #![feature(rustc_private)] -#![feature(assert_matches)] +#![cfg_attr(bootstrap, feature(assert_matches))] #![feature(unwrap_infallible)] #![recursion_limit = "512"] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)] diff --git a/tests/ui-fulldeps/rustc_public/check_abi.rs b/tests/ui-fulldeps/rustc_public/check_abi.rs index 256e267b7d30..8e97b773db56 100644 --- a/tests/ui-fulldeps/rustc_public/check_abi.rs +++ b/tests/ui-fulldeps/rustc_public/check_abi.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(assert_matches)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_driver; diff --git a/tests/ui-fulldeps/rustc_public/check_allocation.rs b/tests/ui-fulldeps/rustc_public/check_allocation.rs index 783f562d5790..8f3b9693382b 100644 --- a/tests/ui-fulldeps/rustc_public/check_allocation.rs +++ b/tests/ui-fulldeps/rustc_public/check_allocation.rs @@ -8,7 +8,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/rustc_public/check_assoc_items.rs b/tests/ui-fulldeps/rustc_public/check_assoc_items.rs index 194d6be88a76..ee0efd083588 100644 --- a/tests/ui-fulldeps/rustc_public/check_assoc_items.rs +++ b/tests/ui-fulldeps/rustc_public/check_assoc_items.rs @@ -8,7 +8,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs b/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs index 75f4f1f5bf4c..f988452fd52b 100644 --- a/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs +++ b/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs @@ -7,7 +7,6 @@ //@ edition: 2024 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_crate_defs.rs b/tests/ui-fulldeps/rustc_public/check_crate_defs.rs index 7d949eae3910..2b6a2ff8199c 100644 --- a/tests/ui-fulldeps/rustc_public/check_crate_defs.rs +++ b/tests/ui-fulldeps/rustc_public/check_crate_defs.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_hir; extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_def_ty.rs b/tests/ui-fulldeps/rustc_public/check_def_ty.rs index 5984d6f8821a..19ea731834b7 100644 --- a/tests/ui-fulldeps/rustc_public/check_def_ty.rs +++ b/tests/ui-fulldeps/rustc_public/check_def_ty.rs @@ -8,7 +8,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_defs.rs b/tests/ui-fulldeps/rustc_public/check_defs.rs index 0d472e156b40..f3e27cdeb604 100644 --- a/tests/ui-fulldeps/rustc_public/check_defs.rs +++ b/tests/ui-fulldeps/rustc_public/check_defs.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_foreign.rs b/tests/ui-fulldeps/rustc_public/check_foreign.rs index ea6d6585e51e..4670fd409b8f 100644 --- a/tests/ui-fulldeps/rustc_public/check_foreign.rs +++ b/tests/ui-fulldeps/rustc_public/check_foreign.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_instance.rs b/tests/ui-fulldeps/rustc_public/check_instance.rs index fd7523963fa9..defea9d2f54b 100644 --- a/tests/ui-fulldeps/rustc_public/check_instance.rs +++ b/tests/ui-fulldeps/rustc_public/check_instance.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_intrinsics.rs b/tests/ui-fulldeps/rustc_public/check_intrinsics.rs index e3538a39f337..0cbb9659182a 100644 --- a/tests/ui-fulldeps/rustc_public/check_intrinsics.rs +++ b/tests/ui-fulldeps/rustc_public/check_intrinsics.rs @@ -10,7 +10,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; extern crate rustc_hir; diff --git a/tests/ui-fulldeps/rustc_public/check_item_kind.rs b/tests/ui-fulldeps/rustc_public/check_item_kind.rs index c687b3af1c63..b75ac70d86e3 100644 --- a/tests/ui-fulldeps/rustc_public/check_item_kind.rs +++ b/tests/ui-fulldeps/rustc_public/check_item_kind.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_trait_queries.rs b/tests/ui-fulldeps/rustc_public/check_trait_queries.rs index 5603add82f59..44b7275a3df6 100644 --- a/tests/ui-fulldeps/rustc_public/check_trait_queries.rs +++ b/tests/ui-fulldeps/rustc_public/check_trait_queries.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_transform.rs b/tests/ui-fulldeps/rustc_public/check_transform.rs index 815dec57b8be..f8aa40e47446 100644 --- a/tests/ui-fulldeps/rustc_public/check_transform.rs +++ b/tests/ui-fulldeps/rustc_public/check_transform.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(assert_matches)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/rustc_public/check_ty_fold.rs b/tests/ui-fulldeps/rustc_public/check_ty_fold.rs index 93cd30493440..9ac7f14570e5 100644 --- a/tests/ui-fulldeps/rustc_public/check_ty_fold.rs +++ b/tests/ui-fulldeps/rustc_public/check_ty_fold.rs @@ -8,7 +8,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/check_variant.rs b/tests/ui-fulldeps/rustc_public/check_variant.rs index 9bdd0c9d80ba..54ae8b8f83b9 100644 --- a/tests/ui-fulldeps/rustc_public/check_variant.rs +++ b/tests/ui-fulldeps/rustc_public/check_variant.rs @@ -8,7 +8,6 @@ //@ edition: 2024 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/closure-generic-body.rs b/tests/ui-fulldeps/rustc_public/closure-generic-body.rs index 46aeca76ba65..a328bc396c54 100644 --- a/tests/ui-fulldeps/rustc_public/closure-generic-body.rs +++ b/tests/ui-fulldeps/rustc_public/closure-generic-body.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/closure_body.rs b/tests/ui-fulldeps/rustc_public/closure_body.rs index 43cbca8baab8..880d7dde34b6 100644 --- a/tests/ui-fulldeps/rustc_public/closure_body.rs +++ b/tests/ui-fulldeps/rustc_public/closure_body.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/compilation-result.rs b/tests/ui-fulldeps/rustc_public/compilation-result.rs index d33e602e8191..351ca2c8295f 100644 --- a/tests/ui-fulldeps/rustc_public/compilation-result.rs +++ b/tests/ui-fulldeps/rustc_public/compilation-result.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/crate-info.rs b/tests/ui-fulldeps/rustc_public/crate-info.rs index 9bf865c54eee..3729aa7609b5 100644 --- a/tests/ui-fulldeps/rustc_public/crate-info.rs +++ b/tests/ui-fulldeps/rustc_public/crate-info.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_hir; extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/projections.rs b/tests/ui-fulldeps/rustc_public/projections.rs index 53baace827a0..e864bb9648db 100644 --- a/tests/ui-fulldeps/rustc_public/projections.rs +++ b/tests/ui-fulldeps/rustc_public/projections.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_hir; extern crate rustc_middle; diff --git a/tests/ui-fulldeps/rustc_public/smir_internal.rs b/tests/ui-fulldeps/rustc_public/smir_internal.rs index b74bdfe4eb19..98335da19dbd 100644 --- a/tests/ui-fulldeps/rustc_public/smir_internal.rs +++ b/tests/ui-fulldeps/rustc_public/smir_internal.rs @@ -8,7 +8,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_driver; extern crate rustc_interface; diff --git a/tests/ui-fulldeps/rustc_public/smir_serde.rs b/tests/ui-fulldeps/rustc_public/smir_serde.rs index 972bc5efe206..6a345023de17 100644 --- a/tests/ui-fulldeps/rustc_public/smir_serde.rs +++ b/tests/ui-fulldeps/rustc_public/smir_serde.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_driver; diff --git a/tests/ui-fulldeps/rustc_public/smir_visitor.rs b/tests/ui-fulldeps/rustc_public/smir_visitor.rs index 9438f46a59b5..1ea2ab6f560f 100644 --- a/tests/ui-fulldeps/rustc_public/smir_visitor.rs +++ b/tests/ui-fulldeps/rustc_public/smir_visitor.rs @@ -7,7 +7,6 @@ //@ edition: 2021 #![feature(rustc_private)] -#![feature(assert_matches)] extern crate rustc_middle; diff --git a/tests/ui/coroutine/uninhabited-field.rs b/tests/ui/coroutine/uninhabited-field.rs index bc1f8d773371..6debd89ef4a9 100644 --- a/tests/ui/coroutine/uninhabited-field.rs +++ b/tests/ui/coroutine/uninhabited-field.rs @@ -1,7 +1,6 @@ // Test that uninhabited saved local doesn't make the entire variant uninhabited. //@ run-pass #![allow(unused)] -#![feature(assert_matches)] #![feature(coroutine_trait)] #![feature(coroutines, stmt_expr_attributes)] #![feature(never_type)] diff --git a/tests/ui/macros/assert-matches-macro-msg.rs b/tests/ui/macros/assert-matches-macro-msg.rs index 8f4cd254f56b..17900936a299 100644 --- a/tests/ui/macros/assert-matches-macro-msg.rs +++ b/tests/ui/macros/assert-matches-macro-msg.rs @@ -4,8 +4,6 @@ //@ error-pattern: right: 3 //@ needs-subprocess -#![feature(assert_matches)] - use std::assert_matches; fn main() { diff --git a/tests/ui/stdlib-unit-tests/matches2021.rs b/tests/ui/stdlib-unit-tests/matches2021.rs index c3276cd88347..0958e82f43e4 100644 --- a/tests/ui/stdlib-unit-tests/matches2021.rs +++ b/tests/ui/stdlib-unit-tests/matches2021.rs @@ -3,8 +3,6 @@ // regression test for https://github.com/rust-lang/rust/pull/85678 -#![feature(assert_matches)] - use std::assert_matches; fn main() { From 41de246f61cd354ba0d9a685600d7d54654b47c4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 11 Feb 2026 16:14:30 +0100 Subject: [PATCH 35/37] Remove unused `fluent-syntax` dependency from tidy --- Cargo.lock | 1 - src/tools/tidy/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a930b64f458..40349ea4dee3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5561,7 +5561,6 @@ dependencies = [ "build_helper", "cargo_metadata 0.21.0", "clap", - "fluent-syntax", "globset", "ignore", "miropt-test-tools", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index d5433080efc0..4b38f9479fbc 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -16,7 +16,6 @@ semver = "1.0" serde = { version = "1.0.125", features = ["derive"], optional = true } termcolor = "1.1.3" rustc-hash = "2.0.0" -fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" tempfile = "3.15.0" From 52919c7f81dc868b7b6bfdc47ec7417d2fda2795 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 11 Feb 2026 21:39:22 +0000 Subject: [PATCH 36/37] allow `deprecated(since = "CURRENT_RUSTC_VERSION")` --- compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index e01377d247bb..c055c2936e95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,4 +1,5 @@ use rustc_hir::attrs::{DeprecatedSince, Deprecation}; +use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER}; use super::prelude::*; use super::util::parse_version; @@ -143,6 +144,8 @@ impl SingleAttributeParser for DeprecationParser { DeprecatedSince::Future } else if !is_rustc { DeprecatedSince::NonStandard(since) + } else if since.as_str() == VERSION_PLACEHOLDER { + DeprecatedSince::RustcVersion(RustcVersion::CURRENT) } else if let Some(version) = parse_version(since) { DeprecatedSince::RustcVersion(version) } else { From 1cb71f9d2287c9b16737087accada69e5fbbd22f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 11 Feb 2026 14:22:56 -0800 Subject: [PATCH 37/37] Sync relnotes for stable 1.93.1 --- RELEASES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 424e12ceec05..615146eddc92 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,12 @@ +Version 1.93.1 (2026-02-12) +=========================== + +
+ +- [Don't try to recover keyword as non-keyword identifier](https://github.com/rust-lang/rust/pull/150590), fixing an ICE that especially [affected rustfmt](https://github.com/rust-lang/rustfmt/issues/6739). +- [Fix `clippy::panicking_unwrap` false-positive on field access with implicit deref](https://github.com/rust-lang/rust-clippy/pull/16196). +- [Revert "Update wasm-related dependencies in CI"](https://github.com/rust-lang/rust/pull/152259), fixing file descriptor leaks on the `wasm32-wasip2` target. + Version 1.93.0 (2026-01-22) ==========================