Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions compiler/rustc_lint/src/unused/must_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,6 @@ impl IsTyMustUse {
_ => self,
}
}

fn yes(self) -> Option<MustUsePath> {
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.
Expand Down Expand Up @@ -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::<Vec<_>>();
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
Expand Down
71 changes: 52 additions & 19 deletions compiler/rustc_macros/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use syn::{
};

mod kw {
syn::custom_keyword!(non_query);
syn::custom_keyword!(query);
}

Expand Down Expand Up @@ -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<Attribute>,
name: Ident,
}

enum QueryEntry {
Query(Query),
NonQuery(NonQuery),
}

impl Parse for QueryEntry {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?;

// Try the non-query case first.
if input.parse::<kw::non_query>().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::<kw::query>()?;
if input.parse::<kw::query>().is_err() {
return Err(input.error("expected `query` or `non_query`"));
}
let name: Ident = input.parse()?;

// `(key: DefId)`
Expand All @@ -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 }))
}
}

Expand Down Expand Up @@ -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: _, .. };
};
Expand All @@ -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<Query>);
let queries = parse_macro_input!(input as List<QueryEntry>);

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! {};
Expand All @@ -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.
Expand Down Expand Up @@ -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 }
}
}
}
Expand Down
56 changes: 25 additions & 31 deletions compiler/rustc_middle/src/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,18 +270,20 @@ 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,
)*
) => {

#[macro_export]
macro_rules! make_dep_kind_array {
($mod:ident) => {[ $($mod::$variant()),* ]};
queries {
$(
$(#[$q_attr:meta])*
[$($modifiers:tt)*]
fn $q_name:ident($K:ty) -> $V:ty,
)*
}

/// This enum serves as an index into arrays built by `make_dep_kind_array`.
non_queries {
$(
$(#[$nq_attr:meta])*
$nq_name:ident,
)*
}
) => {
// 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
Expand All @@ -290,14 +292,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() {
Expand All @@ -311,7 +317,8 @@ macro_rules! define_dep_nodes {

pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
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(()),
}
}
Expand All @@ -320,27 +327,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!
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! }
14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
64 changes: 46 additions & 18 deletions compiler/rustc_query_impl/src/dep_kind_vtables.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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()))
}
Loading
Loading