Repository: rust
Issue: "deny" lints are ignored in macro expansion
Labels: A-lints,A-macros,T-compiler,C-bug

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

I tried this code:

```rust
// In a lib crate
pub trait Val {
    const VAL: [u8; 8];
}

impl Val for u8 {
    const VAL: [u8; 8] = [0u8; 8];
}

impl Val for u16 {
    const VAL: [u8; 8] = [1u8; 8];
}


#[macro_export]
macro_rules! example {
    ($val: ident, $($name:ty),*) => {
        // We want this macro to fire if there are dupes
        #[deny(unreachable_patterns)]
        match $val {
            $(
                <$name as Val>::VAL => println!("$name"),
            )*
            _ => println!("Other"),
        }
    };
}
```

then:

```rust
// in a crate that depends on the above crate's code:
#![deny(unreachable_patterns)]

use macro_source::Val;

fn main() {
    let val = [2u8; 8];
    macro_source::example!(val, u8, u8, u16);
}
```

I expected to see this happen:

I would expect the deny lint to fire and halt compilation

Instead, this happened:

The crate compiles with no warnings or errors

You can see the issue in the expanded code:

```rust
#![feature(prelude_import)]
#![deny(unreachable_patterns)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use macro_source::Val;
fn main() {
    let val = [2u8; 8];
    #[deny(unreachable_patterns)]
    match val {
        <u8 as Val>::VAL => {
            ::std::io::_print(format_args!("$name\n"));
        }
        <u8 as Val>::VAL => {
//      ^^^^^^^^^^^^^^^^ duplicate arm - will never match!
            ::std::io::_print(format_args!("$name\n"));
        }
        <u16 as Val>::VAL => {
            ::std::io::_print(format_args!("$name\n"));
        }
        _ => {
            ::std::io::_print(format_args!("Other\n"));
        }
    };
}
```

### Meta

I asked about this [in Zulip](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/deny.20lint.20behavior.20in.20macro.20expansion/near/444722399), and it was mentioned that only a select number of lints still fire during macro expansion.

However:

* It seems questionable to me to ignore "deny" lints, rather than just silencing "warn" lints
* It was surprising to me that adding the deny level at the expansion point was also ignored
* Unreachable patterns seems like a somewhat important lint, but there's probably a number of other ones that could also be argued for
* It was surprising to me that the lint DOES fire in the declaring crate (where I tested it), but DOESN'T fire when included in another crate

But more importantly:

If the compiler could potentially *know* that a lint will never fire, it might be good to add a warning for that at the macro declaration site, something like:

```rust
#[macro_export]
macro_rules! example {
    ($val: ident, $($name:ty),*) => {
        #[deny(unreachable_patterns)]
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: lints in macros don't fire at their expansion point
        match $val {
            $(
                <$name as Val>::VAL => println!("$name"),
            )*
            _ => println!("Other"),
        }
    };
}
```