rust-lang / rust-lang/rust

keyword-idents is incompatible with macros

Open
#133,709 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-edition-2024 A-lints A-macros A-suggestion-diagnostics C-bug D-edition D-invalid-suggestion I-edition-triaged L-keyword_idents L-keyword_idents_2024 T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

The keyword_idents lint has incorrect suggestions in macro_rules macros (there are potentially separate concerns for the definition versus invocation). It suggests changing a new keyword to the raw identifier, but this is a semantic change (see #49520).

LHS Definition

Consider:

// edition 2021
#![warn(keyword_idents)]
#[macro_export]
macro_rules! m {
    (gen) => {};
}

This suggests changing it to a raw identifier:

@@ -1,5 +1,5 @@
 #![warn(keyword_idents)]
 #[macro_export]
 macro_rules! m {
-    (gen) => {};
+    (r#gen) => {};
 }

However, this is a semantic change because macro_rules does not treat an equivalence between raw and normal identifiers (or keywords). Thus, another crate using this macro:

// any edition
m!(gen);

will fail with the error "no rules expected gen", or "no rules expected reserved keyword gen" in 2024.

Invocation

Perhaps more difficult to resolve is the rewrites for an invocation.

Let's say we have a crate (any edition), with something like:

// crate a, any edition
#[macro_export]
macro_rules! other_macro {
    (gen) => {};
}

and then I am trying to migrate my crate to 2024:

// edition 2021
#![warn(keyword_idents)]
a::other_macro!(gen);

This will suggest to change it to a::other_macro!(r#gen), which is incorrect because that does not match any matchers.

I say this is more difficult, because there are some situations where changing the invocation is the correct thing to do. Consider:

// crate a, any edition
#[macro_export]
macro_rules! other_macro {
    ($e:stmt) => {};
}

and trying to migrate another crate to 2024:

// edition 2021
#![warn(keyword_idents)]
a::other_macro!(let gen = 1);

this gives the correct suggestion to rewrite it to a::other_macro!(let r#gen = 1);, which would fail to compile if it wasn't changed.

Possible solutions

There are different angles to tackle this problem:

  • Changing the suggestions provided by keyword_idents.
  • Changing the behavior of macros.

The latter seems like a bigger can of worms.

For the former, some rough thoughts:

  • Don't suggest changes on the LHS of a macro_rules matcher. This is clearly a semantics change.
  • Detect the situations where changing an invocation is incorrect, and avoid those suggestions. No idea how feasible that is.

Meta

rustc 1.85.0-nightly (7442931d4 2024-11-30)
binary: rustc
commit-hash: 7442931d49b199ad0a1cc0f8ca54e327b5139b66
commit-date: 2024-11-30
host: aarch64-apple-darwin
release: 1.85.0-nightly
LLVM version: 19.1.4

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the keyword_idents lint suggestions in the macro_rules definition and invocation examples from the issue, using the stated rustc nightly context. Compare matcher behavior for raw and ordinary identifiers, then determine whether the lint should suppress or alter these suggestions; done means the affected cases no longer produce semantically incorrect rewrites.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.