Deny-by-default lints

These lints are all set to the 'deny' level by default.

ambiguous-associated-items

The ambiguous_associated_items lint detects ambiguity between associated items and enum variants.

Example


#![allow(unused)]
fn main() {
enum E {
    V
}

trait Tr {
    type V;
    fn foo() -> Self::V;
}

impl Tr for E {
    type V = u8;
    // `Self::V` is ambiguous because it may refer to the associated type or
    // the enum variant.
    fn foo() -> Self::V { 0 }
}
}

This will produce:

error: ambiguous associated item
  --> lint_example.rs:15:17
   |
15 |     fn foo() -> Self::V { 0 }
   |                 ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
   |
   = note: `#[deny(ambiguous_associated_items)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
note: `V` could refer to the variant defined here
  --> lint_example.rs:3:5
   |
3  |     V
   |     ^
note: `V` could also refer to the associated type defined here
  --> lint_example.rs:7:5
   |
7  |     type V;
   |     ^^^^^^^

Explanation

Previous versions of Rust did not allow accessing enum variants through type aliases. When this ability was added (see RFC 2338), this introduced some situations where it can be ambiguous what a type was referring to.

To fix this ambiguity, you should use a qualified path to explicitly state which type to use. For example, in the above example the function can be written as fn f() -> <Self as Tr>::V { 0 } to specifically refer to the associated type.

This is a future-incompatible lint to transition this to a hard error in the future. See issue #57644 for more details.

arithmetic-overflow

The arithmetic_overflow lint detects that an arithmetic operation will overflow.

Example


#![allow(unused)]
fn main() {
1_i32 << 32;
}

This will produce:

error: this arithmetic operation will overflow
 --> lint_example.rs:2:1
  |
2 | 1_i32 << 32;
  | ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default

Explanation

It is very likely a mistake to perform an arithmetic operation that overflows its value. If the compiler is able to detect these kinds of overflows at compile-time, it will trigger this lint. Consider adjusting the expression to avoid overflow, or use a data type that will not overflow.

conflicting-repr-hints

The conflicting_repr_hints lint detects repr attributes with conflicting hints.

Example


#![allow(unused)]
fn main() {
#[repr(u32, u64)]
enum Foo {
    Variant1,
}
}

This will produce:

error[E0566]: conflicting representation hints
 --> lint_example.rs:2:8
  |
2 | #[repr(u32, u64)]
  |        ^^^  ^^^
  |
  = note: `#[deny(conflicting_repr_hints)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>

Explanation

The compiler incorrectly accepted these conflicting representations in the past. This is a future-incompatible lint to transition this to a hard error in the future. See issue #68585 for more details.

To correct the issue, remove one of the conflicting hints.

const-err

The const_err lint detects an erroneous expression while doing constant evaluation.

Example


#![allow(unused)]
#![allow(unconditional_panic)]
fn main() {
const C: i32 = 1/0;
}

This will produce:

error: any use of this value will cause an error
 --> lint_example.rs:3:16
  |
3 | const C: i32 = 1/0;
  | ---------------^^^-
  |                |
  |                attempt to divide `1_i32` by zero
  |
  = note: `#[deny(const_err)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

Explanation

This lint detects constants that fail to evaluate. Allowing the lint will accept the constant declaration, but any use of this constant will still lead to a hard error. This is a future incompatibility lint; the plan is to eventually entirely forbid even declaring constants that cannot be evaluated. See issue #71800 for more details.

enum-intrinsics-non-enums

The enum_intrinsics_non_enums lint detects calls to intrinsic functions that require an enum (core::mem::discriminant, core::mem::variant_count), but are called with a non-enum type.

Example


#![allow(unused)]
#![deny(enum_intrinsics_non_enums)]
fn main() {
core::mem::discriminant::<i32>(&123);
}

This will produce:

error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
 --> lint_example.rs:3:1
  |
3 | core::mem::discriminant::<i32>(&123);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(enum_intrinsics_non_enums)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^
note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
 --> lint_example.rs:3:32
  |
3 | core::mem::discriminant::<i32>(&123);
  |                                ^^^^

Explanation

In order to accept any enum, the mem::discriminant and mem::variant_count functions are generic over a type T. This makes it technically possible for T to be a non-enum, in which case the return value is unspecified.

This lint prevents such incorrect usage of these functions.

ill-formed-attribute-input

The ill_formed_attribute_input lint detects ill-formed attribute inputs that were previously accepted and used in practice.

Example


#![allow(unused)]
fn main() {
#[inline = "this is not valid"]
fn foo() {}
}

This will produce:

error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
 --> lint_example.rs:2:1
  |
2 | #[inline = "this is not valid"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(ill_formed_attribute_input)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>

Explanation

Previously, inputs for many built-in attributes weren't validated and nonsensical attribute inputs were accepted. After validation was added, it was determined that some existing projects made use of these invalid forms. This is a future-incompatible lint to transition this to a hard error in the future. See issue #57571 for more details.

Check the attribute reference for details on the valid inputs for attributes.

incomplete-include

The incomplete_include lint detects the use of the include! macro with a file that contains more than one expression.

Example

fn main() {
    include!("foo.txt");
}

where the file foo.txt contains:

println!("hi!");

produces:

error: include macro expected single expression in source
 --> foo.txt:1:14
  |
1 | println!("1");
  |              ^
  |
  = note: `#[deny(incomplete_include)]` on by default

Explanation

The include! macro is currently only intended to be used to include a single expression or multiple items. Historically it would ignore any contents after the first expression, but that can be confusing. In the example above, the println! expression ends just before the semicolon, making the semicolon "extra" information that is ignored. Perhaps even more surprising, if the included file had multiple print statements, the subsequent ones would be ignored!

One workaround is to place the contents in braces to create a block expression. Also consider alternatives, like using functions to encapsulate the expressions, or use proc-macros.

This is a lint instead of a hard error because existing projects were found to hit this error. To be cautious, it is a lint for now. The future semantics of the include! macro are also uncertain, see issue #35560.

ineffective-unstable-trait-impl

The ineffective_unstable_trait_impl lint detects #[unstable] attributes which are not used.

Example

#![feature(staged_api)]

#[derive(Clone)]
#[stable(feature = "x", since = "1")]
struct S {}

#[unstable(feature = "y", issue = "none")]
impl Copy for S {}

{{produces}}

Explanation

staged_api does not currently support using a stability attribute on impl blocks. impls are always stable if both the type and trait are stable, and always unstable otherwise.

invalid-atomic-ordering

The invalid_atomic_ordering lint detects passing an Ordering to an atomic operation that does not support that ordering.

Example


#![allow(unused)]
fn main() {
use core::sync::atomic::{AtomicU8, Ordering};
let atom = AtomicU8::new(0);
let value = atom.load(Ordering::Release);
let _ = value;
}

This will produce:

error: atomic loads cannot have `Release` or `AcqRel` ordering
 --> lint_example.rs:4:23
  |
4 | let value = atom.load(Ordering::Release);
  |                       ^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(invalid_atomic_ordering)]` on by default
  = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`

Explanation

Some atomic operations are only supported for a subset of the atomic::Ordering variants. Passing an unsupported variant will cause an unconditional panic at runtime, which is detected by this lint.

This lint will trigger in the following cases: (where AtomicType is an atomic type from core::sync::atomic, such as AtomicBool, AtomicPtr, AtomicUsize, or any of the other integer atomics).

  • Passing Ordering::Acquire or Ordering::AcqRel to AtomicType::store.

  • Passing Ordering::Release or Ordering::AcqRel to AtomicType::load.

  • Passing Ordering::Relaxed to core::sync::atomic::fence or core::sync::atomic::compiler_fence.

  • Passing Ordering::Release or Ordering::AcqRel as the failure ordering for any of AtomicType::compare_exchange, AtomicType::compare_exchange_weak, or AtomicType::fetch_update.

  • Passing in a pair of orderings to AtomicType::compare_exchange, AtomicType::compare_exchange_weak, or AtomicType::fetch_update where the failure ordering is stronger than the success ordering.

invalid-type-param-default

The invalid_type_param_default lint detects type parameter defaults erroneously allowed in an invalid location.

Example


#![allow(unused)]
fn main() {
fn foo<T=i32>(t: T) {}
}

This will produce:

error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
 --> lint_example.rs:2:8
  |
2 | fn foo<T=i32>(t: T) {}
  |        ^
  |
  = note: `#[deny(invalid_type_param_default)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>

Explanation

Default type parameters were only intended to be allowed in certain situations, but historically the compiler allowed them everywhere. This is a future-incompatible lint to transition this to a hard error in the future. See issue #36887 for more details.

macro-expanded-macro-exports-accessed-by-absolute-paths

The macro_expanded_macro_exports_accessed_by_absolute_paths lint detects macro-expanded macro_export macros from the current crate that cannot be referred to by absolute paths.

Example

macro_rules! define_exported {
    () => {
        #[macro_export]
        macro_rules! exported {
            () => {};
        }
    };
}

define_exported!();

fn main() {
    crate::exported!();
}

This will produce:

error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
  --> lint_example.rs:13:5
   |
13 |     crate::exported!();
   |     ^^^^^^^^^^^^^^^
   |
   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
  --> lint_example.rs:4:9
   |
4  | /         macro_rules! exported {
5  | |             () => {};
6  | |         }
   | |_________^
...
10 |   define_exported!();
   |   ------------------ in this macro invocation
   = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)

Explanation

The intent is that all macros marked with the #[macro_export] attribute are made available in the root of the crate. However, when a macro_rules! definition is generated by another macro, the macro expansion is unable to uphold this rule. This is a future-incompatible lint to transition this to a hard error in the future. See issue #53495 for more details.

missing-fragment-specifier

The missing_fragment_specifier lint is issued when an unused pattern in a macro_rules! macro definition has a meta-variable (e.g. $e) that is not followed by a fragment specifier (e.g. :expr).

This warning can always be fixed by removing the unused pattern in the macro_rules! macro definition.

Example

macro_rules! foo {
   () => {};
   ($name) => { };
}

fn main() {
   foo!();
}

This will produce:

error: missing fragment specifier
 --> lint_example.rs:3:5
  |
3 |    ($name) => { };
  |     ^^^^^
  |
  = note: `#[deny(missing_fragment_specifier)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

Explanation

To fix this, remove the unused pattern from the macro_rules! macro definition:

macro_rules! foo {
    () => {};
}
fn main() {
    foo!();
}

mutable-transmutes

The mutable_transmutes lint catches transmuting from &T to &mut T because it is undefined behavior.

Example


#![allow(unused)]
fn main() {
unsafe {
    let y = std::mem::transmute::<&i32, &mut i32>(&5);
}
}

This will produce:

error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
 --> lint_example.rs:3:13
  |
3 |     let y = std::mem::transmute::<&i32, &mut i32>(&5);
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(mutable_transmutes)]` on by default

Explanation

Certain assumptions are made about aliasing of data, and this transmute violates those assumptions. Consider using UnsafeCell instead.

named-asm-labels

The named_asm_labels lint detects the use of named labels in the inline asm! macro.

Example

#![feature(asm)]
fn main() {
    unsafe {
        asm!("foo: bar");
    }
}

This will produce:

error: avoid using named labels in inline assembly
 --> lint_example.rs:4:15
  |
4 |         asm!("foo: bar");
  |               ^^^
  |
  = note: `#[deny(named_asm_labels)]` on by default
  = help: only local labels of the form `<number>:` should be used in inline asm
  = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information

Explanation

LLVM is allowed to duplicate inline assembly blocks for any reason, for example when it is in a function that gets inlined. Because of this, GNU assembler local labels must be used instead of labels with a name. Using named labels might cause assembler or linker errors.

See the unstable book for more details.

no-mangle-const-items

The no_mangle_const_items lint detects any const items with the no_mangle attribute.

Example


#![allow(unused)]
fn main() {
#[no_mangle]
const FOO: i32 = 5;
}

This will produce:

error: const items should never be `#[no_mangle]`
 --> lint_example.rs:3:1
  |
3 | const FOO: i32 = 5;
  | -----^^^^^^^^^^^^^^
  | |
  | help: try a static value: `pub static`
  |
  = note: `#[deny(no_mangle_const_items)]` on by default

Explanation

Constants do not have their symbols exported, and therefore, this probably means you meant to use a static, not a const.

order-dependent-trait-objects

The order_dependent_trait_objects lint detects a trait coherency violation that would allow creating two trait impls for the same dynamic trait object involving marker traits.

Example


#![allow(unused)]
fn main() {
pub trait Trait {}

impl Trait for dyn Send + Sync { }
impl Trait for dyn Sync + Send { }
}

This will produce:

error: conflicting implementations of trait `main::Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
 --> lint_example.rs:5:1
  |
4 | impl Trait for dyn Send + Sync { }
  | ------------------------------ first implementation here
5 | impl Trait for dyn Sync + Send { }
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
  |
  = note: `#[deny(order_dependent_trait_objects)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>

Explanation

A previous bug caused the compiler to interpret traits with different orders (such as Send + Sync and Sync + Send) as distinct types when they were intended to be treated the same. This allowed code to define separate trait implementations when there should be a coherence error. This is a future-incompatible lint to transition this to a hard error in the future. See issue #56484 for more details.

overflowing-literals

The overflowing_literals lint detects literal out of range for its type.

Example


#![allow(unused)]
fn main() {
let x: u8 = 1000;
}

This will produce:

error: literal out of range for `u8`
 --> lint_example.rs:2:13
  |
2 | let x: u8 = 1000;
  |             ^^^^
  |
  = note: `#[deny(overflowing_literals)]` on by default
  = note: the literal `1000` does not fit into the type `u8` whose range is `0..=255`

Explanation

It is usually a mistake to use a literal that overflows the type where it is used. Either use a literal that is within range, or change the type to be within the range of the literal.

patterns-in-fns-without-body

The patterns_in_fns_without_body lint detects mut identifier patterns as a parameter in functions without a body.

Example


#![allow(unused)]
fn main() {
trait Trait {
    fn foo(mut arg: u8);
}
}

This will produce:

error: patterns aren't allowed in functions without bodies
 --> lint_example.rs:3:12
  |
3 |     fn foo(mut arg: u8);
  |            ^^^^^^^ help: remove `mut` from the parameter: `arg`
  |
  = note: `#[deny(patterns_in_fns_without_body)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>

Explanation

To fix this, remove mut from the parameter in the trait definition; it can be used in the implementation. That is, the following is OK:


#![allow(unused)]
fn main() {
trait Trait {
    fn foo(arg: u8); // Removed `mut` here
}

impl Trait for i32 {
    fn foo(mut arg: u8) { // `mut` here is OK

    }
}
}

Trait definitions can define functions without a body to specify a function that implementors must define. The parameter names in the body-less functions are only allowed to be _ or an identifier for documentation purposes (only the type is relevant). Previous versions of the compiler erroneously allowed identifier patterns with the mut keyword, but this was not intended to be allowed. This is a future-incompatible lint to transition this to a hard error in the future. See issue #35203 for more details.

pub-use-of-private-extern-crate

The pub_use_of_private_extern_crate lint detects a specific situation of re-exporting a private extern crate.

Example


#![allow(unused)]
fn main() {
extern crate core;
pub use core as reexported_core;
}

This will produce:

error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
 --> lint_example.rs:3:9
  |
3 | pub use core as reexported_core;
  |         ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(pub_use_of_private_extern_crate)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>

Explanation

A public use declaration should not be used to publicly re-export a private extern crate. pub extern crate should be used instead.

This was historically allowed, but is not the intended behavior according to the visibility rules. This is a future-incompatible lint to transition this to a hard error in the future. See issue #34537 for more details.

soft-unstable

The soft_unstable lint detects unstable features that were unintentionally allowed on stable.

Example


#![allow(unused)]
fn main() {
#[cfg(test)]
extern crate test;

#[bench]
fn name(b: &mut test::Bencher) {
    b.iter(|| 123)
}
}

This will produce:

error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
 --> lint_example.rs:5:3
  |
5 | #[bench]
  |   ^^^^^
  |
  = note: `#[deny(soft_unstable)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>

Explanation

The bench attribute was accidentally allowed to be specified on the stable release channel. Turning this to a hard error would have broken some projects. This lint allows those projects to continue to build correctly when --cap-lints is used, but otherwise signal an error that #[bench] should not be used on the stable channel. This is a future-incompatible lint to transition this to a hard error in the future. See issue #64266 for more details.

text-direction-codepoint-in-comment

The text_direction_codepoint_in_comment lint detects Unicode codepoints in comments that change the visual representation of text on screen in a way that does not correspond to their on memory representation.

Example

#![deny(text_direction_codepoint_in_comment)]
fn main() {
    println!("{:?}"); // '‮');
}

This will produce:

error: unicode codepoint changing visible direction of text present in comment
 --> lint_example.rs:3:23
  |
3 |     println!("{:?}"); // '');
  |                       ^^^^-^^
  |                       |   |
  |                       |   '\u{202e}'
  |                       this comment contains an invisible unicode text flow control codepoint
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(text_direction_codepoint_in_comment)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
  = help: if their presence wasn't intentional, you can remove them

Explanation

Unicode allows changing the visual flow of text on screen in order to support scripts that are written right-to-left, but a specially crafted comment can make code that will be compiled appear to be part of a comment, depending on the software used to read the code. To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny their use.

text-direction-codepoint-in-literal

The text_direction_codepoint_in_literal lint detects Unicode codepoints that change the visual representation of text on screen in a way that does not correspond to their on memory representation.

Explanation

The unicode characters \u{202A}, \u{202B}, \u{202D}, \u{202E}, \u{2066}, \u{2067}, \u{2068}, \u{202C} and \u{2069} make the flow of text on screen change its direction on software that supports these codepoints. This makes the text "abc" display as "cba" on screen. By leveraging software that supports these, people can write specially crafted literals that make the surrounding code seem like it's performing one action, when in reality it is performing another. Because of this, we proactively lint against their presence to avoid surprises.

Example

#![deny(text_direction_codepoint_in_literal)]
fn main() {
    println!("{:?}", '‮');
}

This will produce:

error: unicode codepoint changing visible direction of text present in literal
 --> lint_example.rs:3:22
  |
3 |     println!("{:?}", '');
  |                      ^-
  |                      ||
  |                      |'\u{202e}'
  |                      this literal contains an invisible unicode text flow control codepoint
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(text_direction_codepoint_in_literal)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
  = help: if their presence wasn't intentional, you can remove them
help: if you want to keep them but make them visible in your source code, you can escape them
  |
3 |     println!("{:?}", '\u{202e}');
  |                       ~~~~~~~~

unconditional-panic

The unconditional_panic lint detects an operation that will cause a panic at runtime.

Example


#![allow(unused)]
fn main() {
#![allow(unused)]
let x = 1 / 0;
}

This will produce:

error: this operation will panic at runtime
 --> lint_example.rs:3:9
  |
3 | let x = 1 / 0;
  |         ^^^^^ attempt to divide `1_i32` by zero
  |
  = note: `#[deny(unconditional_panic)]` on by default

Explanation

This lint detects code that is very likely incorrect because it will always panic, such as division by zero and out-of-bounds array accesses. Consider adjusting your code if this is a bug, or using the panic! or unreachable! macro instead in case the panic is intended.

unknown-crate-types

The unknown_crate_types lint detects an unknown crate type found in a crate_type attribute.

Example

#![crate_type="lol"]
fn main() {}

This will produce:

error: invalid `crate_type` value
 --> lint_example.rs:1:15
  |
1 | #![crate_type="lol"]
  |               ^^^^^
  |
  = note: `#[deny(unknown_crate_types)]` on by default

Explanation

An unknown value give to the crate_type attribute is almost certainly a mistake.

useless-deprecated

The useless_deprecated lint detects deprecation attributes with no effect.

Example


#![allow(unused)]
fn main() {
struct X;

#[deprecated = "message"]
impl Default for X {
    fn default() -> Self {
        X
    }
}
}

This will produce:

error: this `#[deprecated]` annotation has no effect
 --> lint_example.rs:4:1
  |
4 | #[deprecated = "message"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute
  |
  = note: `#[deny(useless_deprecated)]` on by default

Explanation

Deprecation attributes have no effect on trait implementations.