Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn about unused macro arms. #73576

Closed
iago-lito opened this issue Jun 21, 2020 · 13 comments · Fixed by #96150
Closed

Warn about unused macro arms. #73576

iago-lito opened this issue Jun 21, 2020 · 13 comments · Fixed by #96150
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@iago-lito
Copy link
Contributor

rustc now warns about unused macros. With the following code:

macro_rules! used {
    () => {};
}

macro_rules! unused { // <- This should be cleaned up.
    () => {};
}

fn main() {
    used!();
} 

we get the warning:

warning: unused macro definition
 --> src/main.rs:5:1
  |
5 | / macro_rules! unused {
6 | |     () => {};
7 | | }
  | |_^
  |
  = note: `#[warn(unused_macros)]` on by default

This is really helpful while cleaning up a large meta-programming mess.

However, it does not warn about unused macro arms, so the following:

macro_rules! used_macro {
    (used_arm) => {};
    (unused_arm) => {}; // <-- This should be cleaned up.
}

fn main() {
    used_macro!(used_arm);
} 

yields no warning yet.

Following #34938, I open this issue for discussing this feature. Is this something desirable to have rustc warn about unused macro arms?

@lcnr
Copy link
Contributor

lcnr commented Jun 21, 2020

I personally think that we should not warn for unused macro arms by default, as I tend to fairly often write the following:

macro_rules! used_macro {
    ($($e:expr),*) => {};
    ($($e:expr),*,) => {}; // <-- This is unused.
}

fn main() {
    used_macro!(7, 13);
} 

To not have to worry about this in case I ever change a macro invocation to

use_macro!(
    7,
    13,
);

@iago-lito
Copy link
Contributor Author

iago-lito commented Jun 21, 2020

@lcnr This is convenient indeed :) But I don't think it should be blocking, for several reasons:

  • First, ($($e:expr),*$(,)?) already works fine in this situation:
macro_rules! used_macro {
    ($($e:expr),*$(,)?) => {}; // Only one used arm.
}

fn main() {
    used_macro!(7, 13); // Without the comma.
    used_macro!(
        7,
        13, // With the comma.
        );
}
  • Or, if this alternate solution is still not acceptable for some reason:

    • Then this problem is still only a matter of style, so it could maybe be special-cased and/or handled by rustfmt?

    • In any case, like we have the option to opt-out from this warning on a local basis for unused variables (let _unused_var = ();) with a _ prefix, we might consider an option to opt-out from this warning for unused macro arms, although I'm afraid it would need new syntax, like

      _(unused_arm) => { ... } // or
      (unused_arm) _=> { ... } // (eew.) or
      (unused_arm) => _{ ... } // (ew.)
      
    • Alternately, we could consider the warning to be a way to discourage such syntax extensions with redundant syntactic forms (like a macro working both with and without the comma).

In any case, I think that this is a good point, but also that it does not hinder the need for a warning about unused macro arms.

@jonas-schievink jonas-schievink added A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jun 21, 2020
@est31
Copy link
Member

est31 commented Jun 21, 2020

One concern I have is that it's not possible to cfg-gate single macro arms, which would be needed in situations I've outlined in this comment: #34938 (comment)

@petrochenkov
Copy link
Contributor

@est31
You could put an allow on the whole macro.

#[allow(unused_macro_arms)]
macro foo {
    used_arm => {},
    conditionally_used_arm => {}
}

Not perfect, but still a pretty good approximation.
Macros with platform-dependent use of arms are not common.

@est31
Copy link
Member

est31 commented Jun 22, 2020

Good point. Concern resolved! Would love to see this implemented. Begone, unused stuff!

@iago-lito
Copy link
Contributor Author

@petrochenkov Is this finer-grained alternate allow line straightforward to feature, or would it need new syntax?

macro foo {
    used_arm => {},
    #[allow(unused_macro_arm)]
    conditionally_used_arm => {}
}

@petrochenkov
Copy link
Contributor

@iago-lito
It will need some work, right now the whole macro body is treated as a single token stream.
The individual arms will need to be kept as nodes in AST and assigned NodeIds, then you'll be able to attach lint attributes like allow to them.
Also, the attributes on macro arms are indeed a new syntax.

@est31
Copy link
Member

est31 commented Jun 22, 2020

You'd likely require ids to implement the lint in the first place, so at least that cost has to be paid already. At least that's how I did it in #41907 (with a set of ids of unused macros), idk how much it has changed since then.

@petrochenkov
Copy link
Contributor

For uniquely identifying the arm having only the macro's NodeId + the arm's index should be enough, then this pair can be used to track which arms are used and which are not.

For applying allows to macro arms you need real NodeIds for them because that's what the lint level infra works with.

@est31
Copy link
Member

est31 commented Apr 16, 2022

The lint might also be useful from a performance point of view, as each unused arm causes additional compile time. According to this blog post, there is sometimes a lot of compile time spent in expansion, it also reports about PRs that have reordered match arms and removed unused ones to increase whole-crate compile times by double digit percentages.

@est31
Copy link
Member

est31 commented Apr 16, 2022

I'm wondering about the name for the lint. I couldn't find the term "arm" used anywhere in official documentation to refer to macro matchers, like the reference. Instead I found the term "rule", while arm was only used for match expressions, which follow a similar, but not the same, model as declarative macros.

Per that, the name of the lint should be unused_macro_rules, not unused_macro_arms. Which is a bit of a problem, because it can be read as (unused) (macro_rules), making people think it is meant for entire macros, not just their rules. One solution would be to abandon the plural i.e. unused_macro_rule. But that would be inconsistent with other lints. The lints that use singular forms for their name like unused_unsafe, unused_mut usually don't have corresponding plurals (singularia tantum).

I'm thinking about unused_macro_matchers or unused_macro_transcribers but I don't know, those only describe parts of the rules... What do you think?

@est31
Copy link
Member

est31 commented Apr 17, 2022

I've filed a PR here: #96150 . It uses the unused_macro_rules right now. If you have alternative suggestions for the name, please tell me!

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Apr 26, 2022
Implement a lint to warn about unused macro rules

This implements a new lint to warn about unused macro rules (arms/matchers), similar to the `unused_macros` lint added by rust-lang#41907 that warns about entire macros.

```rust
macro_rules! unused_empty {
    (hello) => { println!("Hello, world!") };
    () => { println!("empty") }; //~ ERROR: 1st rule of macro `unused_empty` is never used
}

fn main() {
    unused_empty!(hello);
}
```

Builds upon ~~(and currently integrates)~~ rust-lang#96149 and rust-lang#96156.

Fixes rust-lang#73576
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue May 6, 2022
…enkov

Implement a lint to warn about unused macro rules

This implements a new lint to warn about unused macro rules (arms/matchers), similar to the `unused_macros` lint added by rust-lang#41907 that warns about entire macros.

```rust
macro_rules! unused_empty {
    (hello) => { println!("Hello, world!") };
    () => { println!("empty") }; //~ ERROR: 1st rule of macro `unused_empty` is never used
}

fn main() {
    unused_empty!(hello);
}
```

Builds upon rust-lang#96149 and rust-lang#96156.

Fixes rust-lang#73576
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue May 6, 2022
…enkov

Implement a lint to warn about unused macro rules

This implements a new lint to warn about unused macro rules (arms/matchers), similar to the `unused_macros` lint added by rust-lang#41907 that warns about entire macros.

```rust
macro_rules! unused_empty {
    (hello) => { println!("Hello, world!") };
    () => { println!("empty") }; //~ ERROR: 1st rule of macro `unused_empty` is never used
}

fn main() {
    unused_empty!(hello);
}
```

Builds upon rust-lang#96149 and rust-lang#96156.

Fixes rust-lang#73576
@bors bors closed this as completed in 0cd939e May 12, 2022
bors bot added a commit to crossbeam-rs/crossbeam that referenced this issue May 16, 2022
827: Remove unused macro rules r=taiki-e a=alygin

The [new `unused_macro_rules` lint](rust-lang/rust#73576) that recently landed in nightly [breaks](https://github.com/crossbeam-rs/crossbeam/actions/runs/2316949414) CI builds.

This fix removes unused macro arms in tests.

Co-authored-by: Andrew Lygin <[email protected]>
@A1-Triard
Copy link

* First, `($($e:expr),*$(,)?)` already works fine in this situation:

It accepts single comma as an input. There is better way: $($($e:expr),+ $(,)?)?.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants