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

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`
   |
   = 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;
   |     ^^^^^^
   = note: `#[deny(ambiguous_associated_items)]` on by default

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

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.

binary-asm-labels

The binary_asm_labels lint detects the use of numeric labels containing only binary digits in the inline asm! macro.

Example

#![cfg(target_arch = "x86_64")]

use std::arch::asm;

fn main() {
    unsafe {
        asm!("0: jmp 0b");
    }
}

This will produce:

error: avoid using labels containing only the digits `0` and `1` in inline assembly
 --> <source>:7:15
  |
7 |         asm!("0: jmp 0b");
  |               ^ use a different label that doesn't start with `0` or `1`
  |
  = help: start numbering with `2` instead
  = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86
  = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information
  = note: `#[deny(binary_asm_labels)]` on by default

Explanation

An LLVM bug causes this code to fail to compile because it interprets the 0b as a binary literal instead of a reference to the previous local label 0. To work around this bug, don't use labels that could be confused with a binary literal.

This behavior is platform-specific to x86 and x86-64.

See the explanation in Rust By Example for more details.

bindings-with-variant-name

The bindings_with_variant_name lint detects pattern bindings with the same name as one of the matched variants.

Example

pub enum Enum {
    Foo,
    Bar,
}

pub fn foo(x: Enum) {
    match x {
        Foo => {}
        Bar => {}
    }
}

This will produce:

error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `main::Enum`
 --> lint_example.rs:9:9
  |
9 |         Foo => {}
  |         ^^^ help: to match on the variant, qualify the path: `main::Enum::Foo`
  |
  = note: `#[deny(bindings_with_variant_name)]` on by default

Explanation

It is usually a mistake to specify an enum variant name as an identifier pattern. In the example above, the match arms are specifying a variable name to bind the value of x to. The second arm is ignored because the first one matches all values. The likely intent is that the arm was intended to match on the enum variant.

Two possible solutions are:

  • Specify the enum variant using a path pattern, such as Enum::Foo.
  • Bring the enum variants into local scope, such as adding use Enum::*; to the beginning of the foo function in the example above.

cenum-impl-drop-cast

The cenum_impl_drop_cast lint detects an as cast of a field-less enum that implements Drop.

Example

#![allow(unused)]
enum E {
    A,
}

impl Drop for E {
    fn drop(&mut self) {
        println!("Drop");
    }
}

fn main() {
    let e = E::A;
    let i = e as u32;
}

This will produce:

error: cannot cast enum `E` into integer `u32` because it implements `Drop`
  --> lint_example.rs:14:13
   |
14 |     let i = e as u32;
   |             ^^^^^^^^
   |
   = 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 #73333 <https://github.com/rust-lang/rust/issues/73333>
   = note: `#[deny(cenum_impl_drop_cast)]` on by default

Explanation

Casting a field-less enum that does not implement Copy to an integer moves the value without calling drop. This can result in surprising behavior if it was expected that drop should be called. Calling drop automatically would be inconsistent with other move operations. Since neither behavior is clear or consistent, it was decided that a cast of this nature will no longer be allowed.

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

conflicting-repr-hints

The conflicting_repr_hints lint detects repr attributes with conflicting hints.

Example

#[repr(u32, u64)]
enum Foo {
    Variant1,
}

This will produce:

error[E0566]: conflicting representation hints
 --> lint_example.rs:2:8
  |
2 | #[repr(u32, u64)]
  |        ^^^  ^^^
  |
  = 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>
  = note: `#[deny(conflicting_repr_hints)]` on by default

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.

elided-lifetimes-in-associated-constant

The elided_lifetimes_in_associated_constant lint detects elided lifetimes in associated constants when there are other lifetimes in scope. This was accidentally supported, and this lint was later relaxed to allow eliding lifetimes to 'static when there are no lifetimes in scope.

Example

#![deny(elided_lifetimes_in_associated_constant)]

struct Foo<'a>(&'a ());

impl<'a> Foo<'a> {
    const STR: &str = "hello, world";
}

This will produce:

error: `&` without an explicit lifetime name cannot be used here
 --> lint_example.rs:7:16
  |
7 |     const STR: &str = "hello, world";
  |                ^
  |
  = 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 #115010 <https://github.com/rust-lang/rust/issues/115010>
note: cannot automatically infer `'static` because of other lifetimes in scope
 --> lint_example.rs:6:6
  |
6 | impl<'a> Foo<'a> {
  |      ^^
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(elided_lifetimes_in_associated_constant)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use the `'static` lifetime
  |
7 |     const STR: &'static str = "hello, world";
  |                 +++++++

Explanation

Previous version of Rust

Implicit static-in-const behavior was decided against for associated constants because of ambiguity. This, however, regressed and the compiler erroneously treats elided lifetimes in associated constants as lifetime parameters on the impl.

This is a future-incompatible lint to transition this to a hard error in the future.

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

#![deny(enum_intrinsics_non_enums)]
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 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);
  |                                ^^^^
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(enum_intrinsics_non_enums)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^

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.

exceeding-bitshifts

The lint exceeding-bitshifts has been renamed to arithmetic-overflow.

explicit-builtin-cfgs-in-flags

The explicit_builtin_cfgs_in_flags lint detects builtin cfgs set via the --cfg flag.

Example

rustc --cfg unix
fn main() {}

This will produce:

error: unexpected `--cfg unix` flag
  |
  = note: config `unix` is only supposed to be controlled by `--target`
  = note: manually setting a built-in cfg can and does create incoherent behaviors
  = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default

Explanation

Setting builtin cfgs can and does produce incoherent behavior, it's better to the use the appropriate rustc flag that controls the config. For example setting the windows cfg but on Linux based target.

ill-formed-attribute-input

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

Example

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

This will produce:

error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
 --> lint_example.rs:2:1
  |
2 | #[inline = "this is not valid"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = 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>
  = note: `#[deny(ill_formed_attribute_input)]` on by default

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 {}

This will produce:

error: an `#[unstable]` annotation here has no effect
 --> lint_example.rs:8:1
  |
8 | #[unstable(feature = "y", issue = "none")]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
  = note: `#[deny(ineffective_unstable_trait_impl)]` on by default

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

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);
  |                       ^^^^^^^^^^^^^^^^^
  |
  = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
  = note: `#[deny(invalid_atomic_ordering)]` on by default

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.

invalid-doc-attributes

The invalid_doc_attributes lint detects when the #[doc(...)] is misused.

Example

#![deny(warnings)]

pub mod submodule {
    #![doc(test(no_crate_inject))]
}

This will produce:

error: this attribute can only be applied at the crate level
 --> lint_example.rs:5:12
  |
5 |     #![doc(test(no_crate_inject))]
  |            ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
  = note: `#[deny(invalid_doc_attributes)]` on by default

Explanation

Previously, incorrect usage of the #[doc(..)] attribute was not being validated. Usually these should be rejected as a hard error, but this lint was introduced to avoid breaking any existing crates which included them.

invalid-from-utf8-unchecked

The invalid_from_utf8_unchecked lint checks for calls to std::str::from_utf8_unchecked and std::str::from_utf8_unchecked_mut with a known invalid UTF-8 value.

Example

#[allow(unused)]
unsafe {
    std::str::from_utf8_unchecked(b"Ru\x82st");
}

This will produce:

error: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
 --> lint_example.rs:4:5
  |
4 |     std::str::from_utf8_unchecked(b"Ru\x82st");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^
  |                                   |
  |                                   the literal was valid UTF-8 up to the 2 bytes
  |
  = note: `#[deny(invalid_from_utf8_unchecked)]` on by default

Explanation

Creating such a str would result in undefined behavior as per documentation for std::str::from_utf8_unchecked and std::str::from_utf8_unchecked_mut.

invalid-reference-casting

The invalid_reference_casting lint checks for casts of &T to &mut T without using interior mutability.

Example

fn x(r: &i32) {
    unsafe {
        *(r as *const i32 as *mut i32) += 1;
    }
}

This will produce:

error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
 --> lint_example.rs:4:9
  |
4 |         *(r as *const i32 as *mut i32) += 1;
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
  = note: `#[deny(invalid_reference_casting)]` on by default

Explanation

Casting &T to &mut T without using interior mutability is undefined behavior, as it's a violation of Rust reference aliasing requirements.

UnsafeCell is the only way to obtain aliasable data that is considered mutable.

invalid-type-param-default

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

Example

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) {}
  |        ^^^^^
  |
  = 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>
  = note: `#[deny(invalid_type_param_default)]` on by default

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.

let-underscore-lock

The let_underscore_lock lint checks for statements which don't bind a mutex to anything, causing the lock to be released immediately instead of at end of scope, which is typically incorrect.

Example

use std::sync::{Arc, Mutex};
use std::thread;
let data = Arc::new(Mutex::new(0));

thread::spawn(move || {
    // The lock is immediately released instead of at the end of the
    // scope, which is probably not intended.
    let _ = data.lock().unwrap();
    println!("doing some work");
    let mut lock = data.lock().unwrap();
    *lock += 1;
});

This will produce:

error: non-binding let on a synchronization lock
 --> lint_example.rs:9:9
  |
9 |     let _ = data.lock().unwrap();
  |         ^ this lock is not assigned to a binding and is immediately dropped
  |
  = note: `#[deny(let_underscore_lock)]` on by default
help: consider binding to an unused variable to avoid immediately dropping the value
  |
9 |     let _unused = data.lock().unwrap();
  |         ~~~~~~~
help: consider immediately dropping the value
  |
9 |     drop(data.lock().unwrap());
  |     ~~~~~                    +

Explanation

Statements which assign an expression to an underscore causes the expression to immediately drop instead of extending the expression's lifetime to the end of the scope. This is usually unintended, especially for types like MutexGuard, which are typically used to lock a mutex for the duration of an entire scope.

If you want to extend the expression's lifetime to the end of the scope, assign an underscore-prefixed name (such as _foo) to the expression. If you do actually want to drop the expression immediately, then calling std::mem::drop on the expression is clearer and helps convey intent.

long-running-const-eval

The long_running_const_eval lint is emitted when const eval is running for a long time to ensure rustc terminates even if you accidentally wrote an infinite loop.

Example

const FOO: () = loop {};

This will produce:

error: constant evaluation is taking a long time
 --> lint_example.rs:2:17
  |
2 | const FOO: () = loop {};
  |                 ^^^^^^^
  |
  = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
          If your compilation actually takes a long time, you can safely allow the lint.
help: the constant being evaluated
 --> lint_example.rs:2:1
  |
2 | const FOO: () = loop {};
  | ^^^^^^^^^^^^^
  = note: `#[deny(long_running_const_eval)]` on by default

Explanation

Loops allow const evaluation to compute arbitrary code, but may also cause infinite loops or just very long running computations. Users can enable long running computations by allowing the lint on individual constants or for entire crates.

Unconditional warnings

Note that regardless of whether the lint is allowed or set to warn, the compiler will issue warnings if constant evaluation runs significantly longer than this lint's limit. These warnings are also shown to downstream users from crates.io or similar registries. If you are above the lint's limit, both you and downstream users might be exposed to these warnings. They might also appear on compiler updates, as the compiler makes minor changes about how complexity is measured: staying below the limit ensures that there is enough room, and given that the lint is disabled for people who use your dependency it means you will be the only one to get the warning and can put out an update in your own time.

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!();
   |     ^^^^^^^^^^^^^^^
   |
   = 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: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
   = 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) => { };
  |     ^^^^^
  |
  = 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>
  = note: `#[deny(missing_fragment_specifier)]` on by default

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

unsafe {
    let y = std::mem::transmute::<&i32, &mut i32>(&5);
}

This will produce:

error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, 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_experimental_arch)]
use std::arch::asm;

fn main() {
    unsafe {
        asm!("foo: bar");
    }
}

This will produce:

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

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 explanation in Rust By Example for more details.

no-mangle-const-items

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

Example

#[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

pub trait Trait {}

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

This will produce:

error: conflicting implementations of trait `Trait` for type `(dyn Send + 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 Send + Sync + 'static)`
  |
  = 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>
  = note: `#[deny(order_dependent_trait_objects)]` on by default

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

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: the literal `1000` does not fit into the type `u8` whose range is `0..=255`
  = note: `#[deny(overflowing_literals)]` on by default

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

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`
  |
  = 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>
  = note: `#[deny(patterns_in_fns_without_body)]` on by default

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:

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.

proc-macro-derive-resolution-fallback

The proc_macro_derive_resolution_fallback lint detects proc macro derives using inaccessible names from parent modules.

Example

// foo.rs
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::*;

#[proc_macro_derive(Foo)]
pub fn foo1(a: TokenStream) -> TokenStream {
    drop(a);
    "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
}
// bar.rs
#[macro_use]
extern crate foo;

struct Something;

#[derive(Foo)]
struct Another;

fn main() {}

This will produce:

warning: cannot find type `Something` in this scope
 --> src/main.rs:8:10
  |
8 | #[derive(Foo)]
  |          ^^^ names from parent modules are not accessible without an explicit import
  |
  = note: `#[warn(proc_macro_derive_resolution_fallback)]` 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 #50504 <https://github.com/rust-lang/rust/issues/50504>

Explanation

If a proc-macro generates a module, the compiler unintentionally allowed items in that module to refer to items in the crate root without importing them. This is a future-incompatible lint to transition this to a hard error in the future. See issue #50504 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

extern crate core;
pub use core as reexported_core;

This will produce:

error[E0365]: extern crate `core` is private and cannot be re-exported
 --> lint_example.rs:3:9
  |
3 | pub use core as reexported_core;
  |         ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = 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 #127909 <https://github.com/rust-lang/rust/issues/127909>
  = note: `#[deny(pub_use_of_private_extern_crate)]` on by default
help: consider making the `extern crate` item publicly accessible
  |
2 | pub extern crate core;
  | +++

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 #127909 for more details.

soft-unstable

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

Example

#[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]
  |   ^^^^^
  |
  = 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>
  = note: `#[deny(soft_unstable)]` on by default

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.

test-unstable-lint

The test_unstable_lint lint tests unstable lints and is perma-unstable.

Example

#![allow(test_unstable_lint)]

This will produce:

warning: unknown lint: `test_unstable_lint`
 --> lint_example.rs:1:1
  |
1 | #![allow(test_unstable_lint)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: the `test_unstable_lint` lint is unstable
  = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
  = note: this compiler was built on 2024-12-21; consider upgrading it if it is out of date
  = note: `#[warn(unknown_lints)]` on by default

Explanation

In order to test the behavior of unstable lints, a permanently-unstable lint is required. This lint can be used to trigger warnings and errors from the compiler related to unstable lints.

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: 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
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(text_direction_codepoint_in_comment)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = 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: 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
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(text_direction_codepoint_in_literal)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = 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)]
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.

undropped-manually-drops

The undropped_manually_drops lint check for calls to std::mem::drop with a value of std::mem::ManuallyDrop which doesn't drop.

Example

struct S;
drop(std::mem::ManuallyDrop::new(S));

This will produce:

error: calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing
 --> lint_example.rs:3:1
  |
3 | drop(std::mem::ManuallyDrop::new(S));
  | ^^^^^------------------------------^
  |      |
  |      argument has type `ManuallyDrop<S>`
  |
  = note: `#[deny(undropped_manually_drops)]` on by default
help: use `std::mem::ManuallyDrop::into_inner` to get the inner value
  |
3 | drop(std::mem::ManuallyDrop::into_inner(std::mem::ManuallyDrop::new(S)));
  |      +++++++++++++++++++++++++++++++++++                              +

Explanation

ManuallyDrop does not drop it's inner value so calling std::mem::drop will not drop the inner value of the ManuallyDrop either.

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

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.

wasm-c-abi

The wasm_c_abi lint detects crate dependencies that are incompatible with future versions of Rust that will emit spec-compliant C ABI.

Example

#![deny(wasm_c_abi)]

This will produce:

error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87
  |
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(wasm_c_abi)]
  |         ^^^^^^^^^^

Explanation

Rust has historically emitted non-spec-compliant C ABI. This has caused incompatibilities between other compilers and Wasm targets. In a future version of Rust this will be fixed and therefore dependencies relying on the non-spec-compliant C ABI will stop functioning.