Skip to content

Spans for nested macro invocations are lacking #101512

Open
@jyn514

Description

@jyn514

Given the following code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=58e18e1a59570b289fca4a2b015cf638

macro_rules! rustc_cached_queries {
    ($macro:ident!) => {
        $macro!(A B C D);
    }
}

macro_rules! define_dep_nodes {
    ( $($name:ident)* ) => {
        $( #[allow(dead_code)] fn $name() {} )*
    }
}
        
rustc_cached_queries!(define_dep_nodes!);

The current output is:

warning: function `A` should have a snake case name
  --> tmp.rs:3:17
   |
1  | / macro_rules! rustc_cached_queries {
2  | |     ($macro:ident!) => {
3  | |         $macro!(A B C D);
   | |                 ^ help: convert the identifier to snake case: `a`
4  | |     }
5  | | }
   | |_- in this expansion of `rustc_cached_queries!`
...
13 |   rustc_cached_queries!(define_dep_nodes!);
   |   ---------------------------------------- in this macro invocation
   |
   = note: `#[warn(non_snake_case)]` on by default

Ideally the output should look like:

warning: function `A` should have a snake case name
  --> tmp.rs:3:17
   |
1  | / macro_rules! rustc_cached_queries {
2  | |     ($macro:ident!) => {
3  | |         $macro!(A B C D);
   | |                 ^ help: convert the identifier to snake case: `a`
4  | |     }
5  | | }
   | |_- in this expansion of `rustc_cached_queries!`
...
9       $( #[allow(dead_code)] fn $name() {} )*
                                   ^^^^ in this expansion of `define_dep_nodes`
...
13 |   rustc_cached_queries!(define_dep_nodes!);
   |   ---------------------------------------- in this macro invocation
   |
   = note: `#[warn(non_snake_case)]` on by default

In this small macro, the problem isn't too hard to figure out, but I gave up on figuring it out for the original code before the minimization:

macro_rules! define_callbacks {
(
$($(#[$attr:meta])*
[$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
// HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
// below, but using type aliases instead of associated types, to bypass
// the limitations around normalizing under HRTB - for example, this:
// `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
// doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
// This is primarily used by the `provide!` macro in `rustc_metadata`.
#[allow(nonstandard_style, unused_lifetimes)]
pub mod query_keys {
use super::*;
$(pub type $name<'tcx> = $($K)*;)*
}
#[allow(nonstandard_style, unused_lifetimes)]
pub mod query_values {
use super::*;
$(pub type $name<'tcx> = $V;)*
}
#[allow(nonstandard_style, unused_lifetimes)]
pub mod query_storage {
use super::*;
$(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
}
#[allow(nonstandard_style, unused_lifetimes)]
pub mod query_stored {
use super::*;
$(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)*
}
#[derive(Default)]
pub struct QueryCaches<'tcx> {
$($(#[$attr])* pub $name: query_storage::$name<'tcx>,)*
}
impl<'tcx> TyCtxtEnsure<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
match cached {
Ok(()) => return,
Err(()) => (),
}
self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure);
})*
}
impl<'tcx> TyCtxt<'tcx> {
$($(#[$attr])*
#[inline(always)]
#[must_use]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
{
self.at(DUMMY_SP).$name(key)
})*
}
impl<'tcx> TyCtxtAt<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
{
let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, copy);
match cached {
Ok(value) => return value,
Err(()) => (),
}
self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap()
})*
}
pub struct Providers {
$(pub $name: for<'tcx> fn(
TyCtxt<'tcx>,
query_keys::$name<'tcx>,
) -> query_values::$name<'tcx>,)*
}
pub struct ExternProviders {
$(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
}
impl Default for Providers {
fn default() -> Self {
Providers {
$($name: |_, key| bug!(
"`tcx.{}({:?})` unsupported by its crate; \
perhaps the `{}` query was never assigned a provider function",
stringify!($name),
key,
stringify!($name),
),)*
}
}
}
impl Default for ExternProviders {
fn default() -> Self {
ExternProviders {
$($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
}
}
}
impl Copy for Providers {}
impl Clone for Providers {
fn clone(&self) -> Self { *self }
}
impl Copy for ExternProviders {}
impl Clone for ExternProviders {
fn clone(&self) -> Self { *self }
}
pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool;
$($(#[$attr])*
fn $name(
&'tcx self,
tcx: TyCtxt<'tcx>,
span: Span,
key: query_keys::$name<'tcx>,
mode: QueryMode,
) -> Option<query_stored::$name<'tcx>>;)*
}
};
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions