From d351448404595e4564e60933e66d4a939656fc38 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 27 Feb 2026 16:46:44 +0100 Subject: [PATCH 1/8] add more tests for `unused_results` lints --- tests/ui/lint/unused/unused-result.rs | 14 +++++++++ tests/ui/lint/unused/unused-result.stderr | 36 +++++++++++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/tests/ui/lint/unused/unused-result.rs b/tests/ui/lint/unused/unused-result.rs index e283eaa88dd13..9dc18ff6243d2 100644 --- a/tests/ui/lint/unused/unused-result.rs +++ b/tests/ui/lint/unused/unused-result.rs @@ -3,12 +3,16 @@ //~^ NOTE: the lint level is defined here //~| NOTE: the lint level is defined here +use std::ops::ControlFlow; + #[must_use] enum MustUse { Test } #[must_use = "some message"] enum MustUseMsg { Test2 } +enum Nothing {} + fn foo() -> T { panic!() } fn bar() -> isize { return foo::(); } @@ -39,4 +43,14 @@ fn main() { let _ = foo::(); let _ = foo::(); let _ = foo::(); + + (); + ((), ()); //~ ERROR: unused result of type + Ok::<(), Nothing>(()); + ControlFlow::::Continue(()); + ((), Ok::<(), Nothing>(()), ((((), ())), ((),))); //~ ERROR: unused result of type + foo::(); + + ((), 1); //~ ERROR: unused result of type `((), i32)` + (1, ()); //~ ERROR: unused result of type `(i32, ())` } diff --git a/tests/ui/lint/unused/unused-result.stderr b/tests/ui/lint/unused/unused-result.stderr index f42995a65d13e..27d7d57bc6eb4 100644 --- a/tests/ui/lint/unused/unused-result.stderr +++ b/tests/ui/lint/unused/unused-result.stderr @@ -1,5 +1,5 @@ error: unused `MustUse` that must be used - --> $DIR/unused-result.rs:21:5 + --> $DIR/unused-result.rs:25:5 | LL | foo::(); | ^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let _ = foo::(); | +++++++ error: unused `MustUseMsg` that must be used - --> $DIR/unused-result.rs:22:5 + --> $DIR/unused-result.rs:26:5 | LL | foo::(); | ^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | let _ = foo::(); | +++++++ error: unused result of type `isize` - --> $DIR/unused-result.rs:34:5 + --> $DIR/unused-result.rs:38:5 | LL | foo::(); | ^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | #![deny(unused_results, unused_must_use)] | ^^^^^^^^^^^^^^ error: unused `MustUse` that must be used - --> $DIR/unused-result.rs:35:5 + --> $DIR/unused-result.rs:39:5 | LL | foo::(); | ^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | let _ = foo::(); | +++++++ error: unused `MustUseMsg` that must be used - --> $DIR/unused-result.rs:36:5 + --> $DIR/unused-result.rs:40:5 | LL | foo::(); | ^^^^^^^^^^^^^^^^^^^ @@ -61,5 +61,29 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = foo::(); | +++++++ -error: aborting due to 5 previous errors +error: unused result of type `((), ())` + --> $DIR/unused-result.rs:48:5 + | +LL | ((), ()); + | ^^^^^^^^^ + +error: unused result of type `((), Result<(), Nothing>, (((), ()), ((),)))` + --> $DIR/unused-result.rs:51:5 + | +LL | ((), Ok::<(), Nothing>(()), ((((), ())), ((),))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unused result of type `((), i32)` + --> $DIR/unused-result.rs:54:5 + | +LL | ((), 1); + | ^^^^^^^^ + +error: unused result of type `(i32, ())` + --> $DIR/unused-result.rs:55:5 + | +LL | (1, ()); + | ^^^^^^^^ + +error: aborting due to 9 previous errors From 8958cb974dd6931219888d272d9b83c4db1b7a01 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 27 Feb 2026 16:37:31 +0100 Subject: [PATCH 2/8] don't emit `unused_results` lint for tuples of trivial types --- compiler/rustc_lint/src/unused/must_use.rs | 32 +++++++++++----------- tests/ui/lint/unused/unused-result.rs | 5 ++-- tests/ui/lint/unused/unused-result.stderr | 18 ++---------- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_lint/src/unused/must_use.rs b/compiler/rustc_lint/src/unused/must_use.rs index f37cf4c8dc8c0..9eb45666442fc 100644 --- a/compiler/rustc_lint/src/unused/must_use.rs +++ b/compiler/rustc_lint/src/unused/must_use.rs @@ -108,13 +108,6 @@ impl IsTyMustUse { _ => self, } } - - fn yes(self) -> Option { - match self { - Self::Yes(must_use_path) => Some(must_use_path), - _ => None, - } - } } /// A path through a type to a `must_use` source. Contains useful info for the lint. @@ -254,16 +247,23 @@ pub fn is_ty_must_use<'tcx>( // Default to `expr`. let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr)); - let nested_must_use = tys - .iter() - .zip(elem_exprs) - .enumerate() - .filter_map(|(i, (ty, expr))| { - is_ty_must_use(cx, ty, expr, simplify_uninhabited).yes().map(|path| (i, path)) - }) - .collect::>(); + let mut all_trivial = true; + let mut nested_must_use = Vec::new(); + + tys.iter().zip(elem_exprs).enumerate().for_each(|(i, (ty, expr))| { + let must_use = is_ty_must_use(cx, ty, expr, simplify_uninhabited); + + all_trivial &= matches!(must_use, IsTyMustUse::Trivial); + if let IsTyMustUse::Yes(path) = must_use { + nested_must_use.push((i, path)); + } + }); - if !nested_must_use.is_empty() { + if all_trivial { + // If all tuple elements are trivial, mark the whole tuple as such. + // i.e. don't emit `unused_results` for types such as `((), ())` + IsTyMustUse::Trivial + } else if !nested_must_use.is_empty() { IsTyMustUse::Yes(MustUsePath::TupleElement(nested_must_use)) } else { IsTyMustUse::No diff --git a/tests/ui/lint/unused/unused-result.rs b/tests/ui/lint/unused/unused-result.rs index 9dc18ff6243d2..bfc9d61bb9c88 100644 --- a/tests/ui/lint/unused/unused-result.rs +++ b/tests/ui/lint/unused/unused-result.rs @@ -44,11 +44,12 @@ fn main() { let _ = foo::(); let _ = foo::(); + // "trivial" types (); - ((), ()); //~ ERROR: unused result of type + ((), ()); Ok::<(), Nothing>(()); ControlFlow::::Continue(()); - ((), Ok::<(), Nothing>(()), ((((), ())), ((),))); //~ ERROR: unused result of type + ((), Ok::<(), Nothing>(()), ((((), ())), ((),))); foo::(); ((), 1); //~ ERROR: unused result of type `((), i32)` diff --git a/tests/ui/lint/unused/unused-result.stderr b/tests/ui/lint/unused/unused-result.stderr index 27d7d57bc6eb4..b584733ba1cb4 100644 --- a/tests/ui/lint/unused/unused-result.stderr +++ b/tests/ui/lint/unused/unused-result.stderr @@ -61,29 +61,17 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = foo::(); | +++++++ -error: unused result of type `((), ())` - --> $DIR/unused-result.rs:48:5 - | -LL | ((), ()); - | ^^^^^^^^^ - -error: unused result of type `((), Result<(), Nothing>, (((), ()), ((),)))` - --> $DIR/unused-result.rs:51:5 - | -LL | ((), Ok::<(), Nothing>(()), ((((), ())), ((),))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: unused result of type `((), i32)` - --> $DIR/unused-result.rs:54:5 + --> $DIR/unused-result.rs:55:5 | LL | ((), 1); | ^^^^^^^^ error: unused result of type `(i32, ())` - --> $DIR/unused-result.rs:55:5 + --> $DIR/unused-result.rs:56:5 | LL | (1, ()); | ^^^^^^^^ -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors From 253c6965bc561995c1d185270e6b8f9e672abf50 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 27 Feb 2026 13:24:21 +1100 Subject: [PATCH 3/8] Make non-queries available to `rustc_with_all_queries`. `rustc_with_all_queries` currently provides information about all queries. Also, a caller can provide an ad hoc list of extra non-queries. This is used by `define_queries` for non-query dep kinds: `Null`, `Red`, etc. This is pretty hacky. This commit changes `rustc_with_all_queries` so that the non-queries information is available to all callers. (Some callers ignore the non-query information.) This is done by adding `non_query` entries to the primary list of queries in `rustc_queries!`. --- compiler/rustc_macros/src/query.rs | 71 ++++++++++++++----- .../rustc_middle/src/dep_graph/dep_node.rs | 55 +++++++------- compiler/rustc_middle/src/queries.rs | 17 +++++ compiler/rustc_middle/src/query/plumbing.rs | 14 ++-- compiler/rustc_query_impl/src/plumbing.rs | 17 +++-- 5 files changed, 118 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index cd9c53134ae20..721cc7fe4d9b3 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -10,6 +10,7 @@ use syn::{ }; mod kw { + syn::custom_keyword!(non_query); syn::custom_keyword!(query); } @@ -54,12 +55,37 @@ struct Query { modifiers: QueryModifiers, } -impl Parse for Query { +/// Declaration of a non-query dep kind. +/// ```ignore (illustrative) +/// /// Doc comment for `MyNonQuery`. +/// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doc_comments +/// non_query MyNonQuery +/// // ^^^^^^^^^^ name +/// ``` +struct NonQuery { + doc_comments: Vec, + name: Ident, +} + +enum QueryEntry { + Query(Query), + NonQuery(NonQuery), +} + +impl Parse for QueryEntry { fn parse(input: ParseStream<'_>) -> Result { let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; + // Try the non-query case first. + if input.parse::().is_ok() { + let name: Ident = input.parse()?; + return Ok(QueryEntry::NonQuery(NonQuery { doc_comments, name })); + } + // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` - input.parse::()?; + if input.parse::().is_err() { + return Err(input.error("expected `query` or `non_query`")); + } let name: Ident = input.parse()?; // `(key: DefId)` @@ -84,7 +110,7 @@ impl Parse for Query { doc_comments.push(doc_comment_from_desc(&modifiers.desc.expr_list)?); } - Ok(Query { doc_comments, modifiers, name, key_pat, key_ty, return_ty }) + Ok(QueryEntry::Query(Query { doc_comments, modifiers, name, key_pat, key_ty, return_ty })) } } @@ -375,9 +401,9 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke // macro producing a higher order macro that has all its token in the macro declaration we lose // any meaningful spans, resulting in rust-analyzer being unable to make the connection between // the query name and the corresponding providers field. The trick to fix this is to have - // `rustc_queries` emit a field access with the given name's span which allows it to successfully - // show references / go to definition to the corresponding provider assignment which is usually - // the more interesting place. + // `rustc_queries` emit a field access with the given name's span which allows it to + // successfully show references / go to definition to the corresponding provider assignment + // which is usually the more interesting place. let ra_hint = quote! { let crate::query::Providers { #name: _, .. }; }; @@ -393,9 +419,10 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke } pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { - let queries = parse_macro_input!(input as List); + let queries = parse_macro_input!(input as List); let mut query_stream = quote! {}; + let mut non_query_stream = quote! {}; let mut helpers = HelperTokenStreams::default(); let mut analyzer_stream = quote! {}; let mut errors = quote! {}; @@ -411,6 +438,18 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } for query in queries.0 { + let query = match query { + QueryEntry::Query(query) => query, + QueryEntry::NonQuery(NonQuery { doc_comments, name }) => { + // Get the exceptional non-query case out of the way first. + non_query_stream.extend(quote! { + #(#doc_comments)* + #name, + }); + continue; + } + }; + let Query { doc_comments, name, key_ty, return_ty, modifiers, .. } = &query; // Normalize an absent return type into `-> ()` to make macro-rules parsing easier. @@ -486,24 +525,18 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { let HelperTokenStreams { description_fns_stream, cache_on_disk_if_fns_stream } = helpers; TokenStream::from(quote! { - /// Higher-order macro that invokes the specified macro with a prepared - /// list of all query signatures (including modifiers). - /// - /// This allows multiple simpler macros to each have access to the list - /// of queries. + /// Higher-order macro that invokes the specified macro with (a) a list of all query + /// signatures (including modifiers), and (b) a list of non-query names. This allows + /// multiple simpler macros to each have access to these lists. #[macro_export] macro_rules! rustc_with_all_queries { ( - // The macro to invoke once, on all queries (plus extras). + // The macro to invoke once, on all queries and non-queries. $macro:ident! - - // Within [], an optional list of extra "query" signatures to - // pass to the given macro, in addition to the actual queries. - $( [$($extra_fake_queries:tt)*] )? ) => { $macro! { - $( $($extra_fake_queries)* )? - #query_stream + queries { #query_stream } + non_queries { #non_query_stream } } } } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 599c84597a8b9..f8b98b3991e73 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -270,15 +270,26 @@ impl StableOrd for WorkProductId { // Note: `$K` and `$V` are unused but present so this can be called by `rustc_with_all_queries`. macro_rules! define_dep_nodes { ( - $( - $(#[$attr:meta])* - [$($modifiers:tt)*] fn $variant:ident($K:ty) -> $V:ty, - )* + queries { + $( + $(#[$q_attr:meta])* + [$($modifiers:tt)*] + fn $q_name:ident($K:ty) -> $V:ty, + )* + } + non_queries { + $( + $(#[$nq_attr:meta])* + $nq_name:ident, + )* + } ) => { - #[macro_export] macro_rules! make_dep_kind_array { - ($mod:ident) => {[ $($mod::$variant()),* ]}; + ($mod:ident) => {[ + $( $mod::$nq_name(), )* + $( $mod::$q_name(), )* + ]}; } /// This enum serves as an index into arrays built by `make_dep_kind_array`. @@ -290,14 +301,18 @@ macro_rules! define_dep_nodes { #[allow(non_camel_case_types)] #[repr(u16)] // Must be kept in sync with the rest of `DepKind`. pub enum DepKind { - $( $( #[$attr] )* $variant),* + $( $(#[$nq_attr])* $nq_name, )* + $( $(#[$q_attr])* $q_name, )* } // This computes the number of dep kind variants. Along the way, it sanity-checks that the // discriminants of the variants have been assigned consecutively from 0 so that they can // be used as a dense index, and that all discriminants fit in a `u16`. pub(crate) const DEP_KIND_NUM_VARIANTS: u16 = { - let deps = &[$(DepKind::$variant,)*]; + let deps = &[ + $(DepKind::$nq_name,)* + $(DepKind::$q_name,)* + ]; let mut i = 0; while i < deps.len() { if i != deps[i].as_usize() { @@ -311,7 +326,8 @@ macro_rules! define_dep_nodes { pub(super) fn dep_kind_from_label_string(label: &str) -> Result { match label { - $( stringify!($variant) => Ok(self::DepKind::$variant), )* + $( stringify!($nq_name) => Ok(self::DepKind::$nq_name), )* + $( stringify!($q_name) => Ok(self::DepKind::$q_name), )* _ => Err(()), } } @@ -320,27 +336,14 @@ macro_rules! define_dep_nodes { /// DepNode groups for tests. #[expect(non_upper_case_globals)] pub mod label_strs { - $( pub const $variant: &str = stringify!($variant); )* + $( pub const $nq_name: &str = stringify!($nq_name); )* + $( pub const $q_name: &str = stringify!($q_name); )* } }; } -// Create various data structures for each query, and also for a few things -// that aren't queries. The key and return types aren't used, hence the use of `()`. -rustc_with_all_queries!(define_dep_nodes![ - /// We use this for most things when incr. comp. is turned off. - [] fn Null(()) -> (), - /// We use this to create a forever-red node. - [] fn Red(()) -> (), - /// We use this to create a side effect node. - [] fn SideEffect(()) -> (), - /// We use this to create the anon node with zero dependencies. - [] fn AnonZeroDeps(()) -> (), - [] fn TraitSelect(()) -> (), - [] fn CompileCodegenUnit(()) -> (), - [] fn CompileMonoItem(()) -> (), - [] fn Metadata(()) -> (), -]); +// Create various data structures for each query, and also for a few things that aren't queries. +rustc_with_all_queries! { define_dep_nodes! } // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 0ff38a0f36041..92c0d6fe895b7 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2771,6 +2771,23 @@ rustc_queries! { cache_on_disk_if { *cnum == LOCAL_CRATE } separate_provide_extern } + + //----------------------------------------------------------------------------- + // "Non-queries" are special dep kinds that are not queries. + //----------------------------------------------------------------------------- + + /// We use this for most things when incr. comp. is turned off. + non_query Null + /// We use this to create a forever-red node. + non_query Red + /// We use this to create a side effect node. + non_query SideEffect + /// We use this to create the anon node with zero dependencies. + non_query AnonZeroDeps + non_query TraitSelect + non_query CompileCodegenUnit + non_query CompileMonoItem + non_query Metadata } rustc_with_all_queries! { define_callbacks! } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 072e29aaa9063..6b83c58a7bec1 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -378,11 +378,15 @@ macro_rules! define_callbacks { ( // You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that // `query_helper_param_ty!` can match on specific type names. - $( - $(#[$attr:meta])* - [$($modifiers:tt)*] - fn $name:ident($($K:tt)*) -> $V:ty, - )* + queries { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] + fn $name:ident($($K:tt)*) -> $V:ty, + )* + } + // Non-queries are unused here. + non_queries { $($_:tt)* } ) => { $( #[allow(unused_lifetimes)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f005e55418294..d972bab766c3d 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -414,15 +414,20 @@ pub(crate) fn force_from_dep_node_inner<'tcx, Q: GetQueryVTable<'tcx>>( } } -// Note: `$K` and `$V` are unused but present so this can be called by `rustc_with_all_queries`. macro_rules! define_queries { ( - $( - $(#[$attr:meta])* - [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty, - )* + // Note: `$K` and `$V` are unused but present so this can be called by + // `rustc_with_all_queries`. + queries { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] + fn $name:ident($K:ty) -> $V:ty, + )* + } + // Non-queries are unused here. + non_queries { $($_:tt)* } ) => { - pub(crate) mod query_impl { $(pub(crate) mod $name { use super::super::*; use ::rustc_middle::query::erase::{self, Erased}; From 40b2274f6c32742980eb3bc4193eae2331999e3b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 27 Feb 2026 13:25:01 +1100 Subject: [PATCH 4/8] Change how query vtables are constructed. Currently `define_dep_nodes` produces a macro `make_dep_kind_array` that encodes the names of non-queries followed by queries. This macro is used by `make_dep_kind_vtables` to make the full array of vtables, by referring to vtable constructor functions that are put into `mod _dep_kind_vtable_ctors`. Pretty weird! This commit takes advantage of the previous commit's changes to `rustc_with_all_queries`, which makes both query and non-query information available. A new call to `rustc_with_all_queries` is used to construct the vtable array. (This moves some dep_kind_vtable code from `plumbing.rs` to `dep_kind_vtables.rs`, which is good.) It's straightforward now with iterator chaining, and `mod _dep_kind_vtable_ctors` is no longer needed. --- .../rustc_middle/src/dep_graph/dep_node.rs | 9 --- .../rustc_query_impl/src/dep_kind_vtables.rs | 64 +++++++++++++------ compiler/rustc_query_impl/src/plumbing.rs | 18 ------ 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index f8b98b3991e73..a40c9e25e6def 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -284,15 +284,6 @@ macro_rules! define_dep_nodes { )* } ) => { - #[macro_export] - macro_rules! make_dep_kind_array { - ($mod:ident) => {[ - $( $mod::$nq_name(), )* - $( $mod::$q_name(), )* - ]}; - } - - /// This enum serves as an index into arrays built by `make_dep_kind_array`. // This enum has more than u8::MAX variants so we need some kind of multi-byte // encoding. The derived Encodable/Decodable uses leb128 encoding which is // dense when only considering this enum. But DepKind is encoded in a larger diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index fa82a0413b1ad..19dca50bd6ecc 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -1,3 +1,4 @@ +use rustc_middle::arena::Arena; use rustc_middle::bug; use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle}; use rustc_middle::query::QueryCache; @@ -133,24 +134,51 @@ where } } -/// Helper module containing a [`DepKindVTable`] constructor for each dep kind, -/// for use with [`rustc_middle::make_dep_kind_array`]. -/// -/// That macro will check that we gave it a constructor for every known dep kind. -mod _dep_kind_vtable_ctors { - // Re-export all of the vtable constructors for non-query and query dep kinds. - - // Non-query vtable constructors are defined in normal code. - pub(crate) use super::non_query::*; - // Query vtable constructors are defined via a macro. - pub(crate) use crate::_dep_kind_vtable_ctors_for_queries::*; +macro_rules! define_dep_kind_vtables { + ( + queries { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] + fn $name:ident($K:ty) -> $V:ty, + )* + } + non_queries { + $( + $(#[$nq_attr:meta])* + $nq_name:ident, + )* + } + ) => {{ + // The small number of non-query vtables: `Null`, `Red`, etc. + let nq_vtables = [ + $( + non_query::$nq_name(), + )* + ]; + + // The large number of query vtables. + let q_vtables: [DepKindVTable<'tcx>; _] = [ + $( + $crate::dep_kind_vtables::make_dep_kind_vtable_for_query::< + $crate::query_impl::$name::VTableGetter, + >( + is_anon!([$($modifiers)*]), + if_cache_on_disk!([$($modifiers)*] true false), + is_eval_always!([$($modifiers)*]), + ) + ),* + ]; + + (nq_vtables, q_vtables) + }} } -pub fn make_dep_kind_vtables<'tcx>( - arena: &'tcx rustc_middle::arena::Arena<'tcx>, -) -> &'tcx [DepKindVTable<'tcx>] { - // Create an array of vtables, one for each dep kind (non-query and query). - let dep_kind_vtables: [DepKindVTable<'tcx>; _] = - rustc_middle::make_dep_kind_array!(_dep_kind_vtable_ctors); - arena.alloc_from_iter(dep_kind_vtables) +// Create an array of vtables, one for each dep kind (non-query and query). +pub fn make_dep_kind_vtables<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindVTable<'tcx>] { + let (nq_vtables, q_vtables) = + rustc_middle::rustc_with_all_queries! { define_dep_kind_vtables! }; + + // Non-query vtables must come before query vtables, to match the order of `DepKind`. + arena.alloc_from_iter(nq_vtables.into_iter().chain(q_vtables.into_iter())) } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index d972bab766c3d..00ee241c6ff5c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -693,23 +693,5 @@ macro_rules! define_queries { }) } } - - /// Declares a dep-kind vtable constructor for each query. - mod _dep_kind_vtable_ctors_for_queries { - use ::rustc_middle::dep_graph::DepKindVTable; - use $crate::dep_kind_vtables::make_dep_kind_vtable_for_query; - - $( - /// `DepKindVTable` constructor for this query. - pub(crate) fn $name<'tcx>() -> DepKindVTable<'tcx> { - use $crate::query_impl::$name::VTableGetter; - make_dep_kind_vtable_for_query::( - is_anon!([$($modifiers)*]), - if_cache_on_disk!([$($modifiers)*] true false), - is_eval_always!([$($modifiers)*]), - ) - } - )* - } } } From f53852672416ab9c00230ac546193cc18aaba7db Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Sun, 1 Mar 2026 21:47:52 -0800 Subject: [PATCH 5/8] vec/mod.rs: add missing period in "ie." in docs "i.e." is short for the Latin "id est" and thus both letters should be followed by periods. --- library/alloc/src/vec/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 4e3a5a7325b4f..3d4f5dd758e13 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -556,7 +556,7 @@ impl Vec { /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if + /// * The size of `T` times the `capacity` (i.e. the allocated size in bytes), if /// nonzero, needs to be the same size as the pointer was allocated with. /// (Because similar to alignment, [`dealloc`] must be called with the same /// layout `size`.) @@ -658,7 +658,7 @@ impl Vec { /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// * The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. @@ -1090,7 +1090,7 @@ impl Vec { /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// * The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. @@ -1201,7 +1201,7 @@ impl Vec { /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// * The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. From 66786fc407e79f013c6f0f256f36de7efcd96ae0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 2 Feb 2026 02:07:19 +0900 Subject: [PATCH 6/8] fix next-solver ICE on PointeeSized goals --- .../traits/fulfillment_errors.rs | 2 + .../pointee-sized-next-solver-ice.rs | 20 ++++ .../pointee-sized-next-solver-ice.stderr | 92 +++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs create mode 100644 tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4f51435290e49..ab02c6ce8b05a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2632,6 +2632,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_def_id != def_id && trait_name == self.tcx.item_name(def_id) && trait_has_same_params(def_id) + // `PointeeSized` is removed during lowering. + && !self.tcx.is_lang_item(*def_id, LangItem::PointeeSized) && self.predicate_must_hold_modulo_regions(&Obligation::new( self.tcx, obligation.cause.clone(), diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs new file mode 100644 index 0000000000000..3c8e0a797c52c --- /dev/null +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Znext-solver=globally + +// Regression test for #151957 + +trait PointeeSized { + type Undefined; +} + +struct T; + +impl PointeeSized for T +//~^ ERROR not all trait items implemented, missing: `Undefined` +//~| ERROR the trait bound `T: PointeeSized` is not satisfied +where + ::Undefined: PointeeSized, +//~^ ERROR the trait bound `T: PointeeSized` is not satisfied +//~| ERROR the trait bound `T: PointeeSized` is not satisfied +{} + +fn main() {} diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr new file mode 100644 index 0000000000000..fd18f71606b11 --- /dev/null +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr @@ -0,0 +1,92 @@ +error[E0046]: not all trait items implemented, missing: `Undefined` + --> $DIR/pointee-sized-next-solver-ice.rs:11:1 + | +LL | type Undefined; + | -------------- `Undefined` from trait +... +LL | / impl PointeeSized for T +LL | | +LL | | +LL | | where +LL | | ::Undefined: PointeeSized, + | |_________________________________________________^ missing `Undefined` in implementation + +error[E0277]: the trait bound `T: PointeeSized` is not satisfied + --> $DIR/pointee-sized-next-solver-ice.rs:15:5 + | +LL | ::Undefined: PointeeSized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `PointeeSized` is not implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:9:1 + | +LL | struct T; + | ^^^^^^^^ +help: the trait `PointeeSized` is implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:11:1 + | +LL | / impl PointeeSized for T +LL | | +LL | | +LL | | where +LL | | ::Undefined: PointeeSized, + | |_________________________________________________^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `T: PointeeSized` is not satisfied + --> $DIR/pointee-sized-next-solver-ice.rs:11:23 + | +LL | impl PointeeSized for T + | ^ unsatisfied trait bound + | +help: the trait `PointeeSized` is not implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:9:1 + | +LL | struct T; + | ^^^^^^^^ +help: the trait `PointeeSized` is implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:11:1 + | +LL | / impl PointeeSized for T +LL | | +LL | | +LL | | where +LL | | ::Undefined: PointeeSized, + | |_________________________________________________^ + +error[E0277]: the trait bound `T: PointeeSized` is not satisfied + --> $DIR/pointee-sized-next-solver-ice.rs:15:37 + | +LL | ::Undefined: PointeeSized, + | ^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `PointeeSized` is not implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:9:1 + | +LL | struct T; + | ^^^^^^^^ +help: the trait `PointeeSized` is implemented for `T` + --> $DIR/pointee-sized-next-solver-ice.rs:11:1 + | +LL | / impl PointeeSized for T +LL | | +LL | | +LL | | where +LL | | ::Undefined: PointeeSized, + | |_________________________________________________^ +note: required by a bound in `PointeeSized` + --> $DIR/pointee-sized-next-solver-ice.rs:5:1 + | +LL | / trait PointeeSized { +LL | | type Undefined; +LL | | } + | |_^ required by this bound in `PointeeSized` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0277. +For more information about an error, try `rustc --explain E0046`. From 6cda9bfafc16be357f94bfd03177c4a13622cbca Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 2 Feb 2026 03:21:51 +0900 Subject: [PATCH 7/8] replace issue number with link --- tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs index 3c8e0a797c52c..b69382ebeccda 100644 --- a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver=globally -// Regression test for #151957 +// Regression test for https://github.com/rust-lang/rust/issues/151957 trait PointeeSized { type Undefined; From ca74063cea46d15b29c602be71ef8048c8aff63d Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 2 Mar 2026 17:41:36 +0900 Subject: [PATCH 8/8] simplify test case and add revisions for both solvers remove * --- .../traits/fulfillment_errors.rs | 2 +- ...intee-sized-next-solver-ice.current.stderr | 20 ++++ .../pointee-sized-next-solver-ice.next.stderr | 20 ++++ .../pointee-sized-next-solver-ice.rs | 31 ++++--- .../pointee-sized-next-solver-ice.stderr | 92 ------------------- 5 files changed, 57 insertions(+), 108 deletions(-) create mode 100644 tests/ui/cycle-trait/pointee-sized-next-solver-ice.current.stderr create mode 100644 tests/ui/cycle-trait/pointee-sized-next-solver-ice.next.stderr delete mode 100644 tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index ab02c6ce8b05a..364152475e94d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2633,7 +2633,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && trait_name == self.tcx.item_name(def_id) && trait_has_same_params(def_id) // `PointeeSized` is removed during lowering. - && !self.tcx.is_lang_item(*def_id, LangItem::PointeeSized) + && !self.tcx.is_lang_item(def_id, LangItem::PointeeSized) && self.predicate_must_hold_modulo_regions(&Obligation::new( self.tcx, obligation.cause.clone(), diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.current.stderr b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.current.stderr new file mode 100644 index 0000000000000..39e815b9af4b5 --- /dev/null +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.current.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `i32: PointeeSized` is not satisfied + --> $DIR/pointee-sized-next-solver-ice.rs:19:21 + | +LL | require_trait::(); + | ^^^ the trait `PointeeSized` is not implemented for `i32` + | +help: this trait has no implementations, consider adding one + --> $DIR/pointee-sized-next-solver-ice.rs:14:1 + | +LL | trait PointeeSized {} + | ^^^^^^^^^^^^^^^^^^ +note: required by a bound in `require_trait` + --> $DIR/pointee-sized-next-solver-ice.rs:16:21 + | +LL | fn require_trait() {} + | ^^^^^^^^^^^^ required by this bound in `require_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.next.stderr b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.next.stderr new file mode 100644 index 0000000000000..39e815b9af4b5 --- /dev/null +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.next.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `i32: PointeeSized` is not satisfied + --> $DIR/pointee-sized-next-solver-ice.rs:19:21 + | +LL | require_trait::(); + | ^^^ the trait `PointeeSized` is not implemented for `i32` + | +help: this trait has no implementations, consider adding one + --> $DIR/pointee-sized-next-solver-ice.rs:14:1 + | +LL | trait PointeeSized {} + | ^^^^^^^^^^^^^^^^^^ +note: required by a bound in `require_trait` + --> $DIR/pointee-sized-next-solver-ice.rs:16:21 + | +LL | fn require_trait() {} + | ^^^^^^^^^^^^ required by this bound in `require_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs index b69382ebeccda..20a11bf969184 100644 --- a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs +++ b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.rs @@ -1,20 +1,21 @@ -//@ compile-flags: -Znext-solver=globally +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Regression test for https://github.com/rust-lang/rust/issues/151957 +// +// When a user-defined trait shares the name `PointeeSized` with +// `core::marker::PointeeSized`, error reporting tries to check whether +// the type implements the lang-item `PointeeSized` trait via +// `predicate_must_hold_modulo_regions`. This creates a `PointeeSized` +// solver obligation which causes an ICE. We avoid this by skipping the +// `PointeeSized` lang item during the "similarly named trait" suggestion. -trait PointeeSized { - type Undefined; -} - -struct T; +trait PointeeSized {} -impl PointeeSized for T -//~^ ERROR not all trait items implemented, missing: `Undefined` -//~| ERROR the trait bound `T: PointeeSized` is not satisfied -where - ::Undefined: PointeeSized, -//~^ ERROR the trait bound `T: PointeeSized` is not satisfied -//~| ERROR the trait bound `T: PointeeSized` is not satisfied -{} +fn require_trait() {} -fn main() {} +fn main() { + require_trait::(); + //~^ ERROR the trait bound `i32: PointeeSized` is not satisfied +} diff --git a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr b/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr deleted file mode 100644 index fd18f71606b11..0000000000000 --- a/tests/ui/cycle-trait/pointee-sized-next-solver-ice.stderr +++ /dev/null @@ -1,92 +0,0 @@ -error[E0046]: not all trait items implemented, missing: `Undefined` - --> $DIR/pointee-sized-next-solver-ice.rs:11:1 - | -LL | type Undefined; - | -------------- `Undefined` from trait -... -LL | / impl PointeeSized for T -LL | | -LL | | -LL | | where -LL | | ::Undefined: PointeeSized, - | |_________________________________________________^ missing `Undefined` in implementation - -error[E0277]: the trait bound `T: PointeeSized` is not satisfied - --> $DIR/pointee-sized-next-solver-ice.rs:15:5 - | -LL | ::Undefined: PointeeSized, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound - | -help: the trait `PointeeSized` is not implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:9:1 - | -LL | struct T; - | ^^^^^^^^ -help: the trait `PointeeSized` is implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:11:1 - | -LL | / impl PointeeSized for T -LL | | -LL | | -LL | | where -LL | | ::Undefined: PointeeSized, - | |_________________________________________________^ - = help: see issue #48214 -help: add `#![feature(trivial_bounds)]` to the crate attributes to enable - | -LL + #![feature(trivial_bounds)] - | - -error[E0277]: the trait bound `T: PointeeSized` is not satisfied - --> $DIR/pointee-sized-next-solver-ice.rs:11:23 - | -LL | impl PointeeSized for T - | ^ unsatisfied trait bound - | -help: the trait `PointeeSized` is not implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:9:1 - | -LL | struct T; - | ^^^^^^^^ -help: the trait `PointeeSized` is implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:11:1 - | -LL | / impl PointeeSized for T -LL | | -LL | | -LL | | where -LL | | ::Undefined: PointeeSized, - | |_________________________________________________^ - -error[E0277]: the trait bound `T: PointeeSized` is not satisfied - --> $DIR/pointee-sized-next-solver-ice.rs:15:37 - | -LL | ::Undefined: PointeeSized, - | ^^^^^^^^^^^^ unsatisfied trait bound - | -help: the trait `PointeeSized` is not implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:9:1 - | -LL | struct T; - | ^^^^^^^^ -help: the trait `PointeeSized` is implemented for `T` - --> $DIR/pointee-sized-next-solver-ice.rs:11:1 - | -LL | / impl PointeeSized for T -LL | | -LL | | -LL | | where -LL | | ::Undefined: PointeeSized, - | |_________________________________________________^ -note: required by a bound in `PointeeSized` - --> $DIR/pointee-sized-next-solver-ice.rs:5:1 - | -LL | / trait PointeeSized { -LL | | type Undefined; -LL | | } - | |_^ required by this bound in `PointeeSized` - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0046, E0277. -For more information about an error, try `rustc --explain E0046`.