rust-lang / rust-lang/rust

`#[expect(redundant_lifetimes)]` doesn't work when `#[derive(Debug)]` is present

Open
#150,553 21 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug E-hard I-lang-nominated P-lang-drag-1 T-lang
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

View all comments

Consider the following code:

#![deny(redundant_lifetimes)]

use std::fmt::Debug;

#[derive(Debug)]
pub struct RefWrapper<'a, T>
where
    'a: 'static,
    T: Debug,
{
    pub t_ref: &'a T
}

As expected, the compiler throws an error because the 'a lifetime is redundant:

➜  rust-playground git:(master) ✗ cargo check
    Checking rust-playground v0.1.0 (/Users/luisferlcc/rust-playground)
error: unnecessary lifetime parameter `'a`
 --> src/lib.rs:6:23
  |
6 | pub struct RefWrapper<'a, T>
  |                       ^^
  |
  = note: you can use the `'static` lifetime directly, in place of `'a`
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(redundant_lifetimes)]
  |         ^^^^^^^^^^^^^^^^^^^

error: unnecessary lifetime parameter `'a`
 --> src/lib.rs:6:23
  |
6 | pub struct RefWrapper<'a, T>
  |                       ^^
  |
  = note: you can use the `'static` lifetime directly, in place of `'a`

error: could not compile `rust-playground` (lib) due to 2 previous errors

Adding #[allow(redundant_lifetimes)] to the type definition...

#![deny(redundant_lifetimes)]

use std::fmt::Debug;

#[derive(Debug)]
#[allow(redundant_lifetimes)]
pub struct RefWrapper<'a, T>
where
    'a: 'static,
    T: Debug,
{
    pub t_ref: &'a T
}

...predictably eliminates the error:

➜  rust-playground git:(master) ✗ cargo check
    Checking rust-playground v0.1.0 (/Users/luisferlcc/rust-playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s

However, changing the allow attribute to expect...

#![deny(redundant_lifetimes)]

use std::fmt::Debug;

#[derive(Debug)]
#[expect(redundant_lifetimes)]
pub struct RefWrapper<'a, T>
where
    'a: 'static,
    T: Debug,
{
    pub t_ref: &'a T
}

...inexplicably fails to make the linter stand down:

➜  rust-playground git:(master) ✗ cargo check
    Checking rust-playground v0.1.0 (/Users/luisferlcc/rust-playground)
error: unnecessary lifetime parameter `'a`
 --> src/lib.rs:7:23
  |
7 | pub struct RefWrapper<'a, T>
  |                       ^^
  |
  = note: you can use the `'static` lifetime directly, in place of `'a`
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(redundant_lifetimes)]
  |         ^^^^^^^^^^^^^^^^^^^

error: could not compile `rust-playground` (lib) due to 1 previous error

But removing #[derive(Debug)] allows the expect attribute to take effect:

#![deny(redundant_lifetimes)]

use std::fmt::Debug;

#[expect(redundant_lifetimes)]
pub struct RefWrapper<'a, T>
where
    'a: 'static,
    T: Debug,
{
    pub t_ref: &'a T
}
➜  rust-playground git:(master) ✗ cargo check
    Checking rust-playground v0.1.0 (/Users/luisferlcc/rust-playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
Meta

This issue occurs on the latest versions of all three channels:

➜  rust-playground git:(master) ✗ rustc --version --verbose
rustc 1.92.0 (ded5c06cf 2025-12-08)
binary: rustc
commit-hash: ded5c06cf21d2b93bffd5d884aa6e96934ee4234
commit-date: 2025-12-08
host: aarch64-apple-darwin
release: 1.92.0
LLVM version: 21.1.3
➜  rust-playground git:(master) ✗ rustc +beta --version --verbose
rustc 1.93.0-beta.5 (72b6488ba 2025-12-21)
binary: rustc
commit-hash: 72b6488ba485fd08cd96f194ffdd83ba8aa0b057
commit-date: 2025-12-21
host: aarch64-apple-darwin
release: 1.93.0-beta.5
LLVM version: 21.1.8
➜  rust-playground git:(master) ✗ rustc +nightly --version --verbose
rustc 1.94.0-nightly (0e8999942 2025-12-30)
binary: rustc
commit-hash: 0e8999942552691afc20495af6227eca8ab0af05
commit-date: 2025-12-30
host: aarch64-apple-darwin
release: 1.94.0-nightly
LLVM version: 21.1.8
Backtrace

➜  rust-playground git:(master) ✗ RUST_BACKTRACE=1 cargo check
    Checking rust-playground v0.1.0 (/Users/luisferlcc/rust-playground)
error: unnecessary lifetime parameter `'a`
 --> src/lib.rs:7:54
  |
7 | pub struct RefWrapper<#[expect(redundant_lifetimes)] 'a, T>
  |                                                      ^^
  |
  = note: you can use the `'static` lifetime directly, in place of `'a`
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(redundant_lifetimes)]
  |         ^^^^^^^^^^^^^^^^^^^

error: could not compile `rust-playground` (lib) due to 1 previous error

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

Reproduce the failure in src/lib.rs by running cargo check with #[derive(Debug)], #[expect(redundant_lifetimes)], and the redundant lifetime example. Trace how the compiler handles the redundant_lifetimes lint and #[expect] around the derived implementation, then add regression coverage; done means the expect suppresses the lint while the derive remains present.

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
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.