## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Deny-by-default Lints

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

- `ambiguous_associated_items`
- `ambiguous_glob_imports`
- `arithmetic_overflow`
- `binary_asm_labels`
- `bindings_with_variant_name`
- `conflicting_repr_hints`
- `dangerous_implicit_autorefs`
- `default_overrides_default_fields`
- `elided_lifetimes_in_associated_constant`
- `enum_intrinsics_non_enums`
- `exceeding-bitshifts`
- `explicit_builtin_cfgs_in_flags`
- `ill_formed_attribute_input`
- `incomplete_include`
- `ineffective_unstable_trait_impl`
- `invalid_atomic_ordering`
- `invalid_doc_attributes`
- `invalid_from_utf8_unchecked`
- `invalid_null_arguments`
- `invalid_reference_casting`
- `invalid_type_param_default`
- `legacy_derive_helpers`
- `let_underscore_lock`
- `long_running_const_eval`
- `macro_expanded_macro_exports_accessed_by_absolute_paths`
- `mutable_transmutes`
- `named_asm_labels`
- `no_mangle_const_items`
- `out_of_scope_macro_calls`
- `overflowing_literals`
- `patterns_in_fns_without_body`
- `private_macro_use`
- `proc_macro_derive_resolution_fallback`
- `pub_use_of_private_extern_crate`
- `semicolon_in_expressions_from_macros`
- `soft_unstable`
- `test_unstable_lint`
- `text_direction_codepoint_in_comment`
- `text_direction_codepoint_in_literal`
- `unconditional_panic`
- `undropped_manually_drops`
- `unknown_crate_types`
- `useless_deprecated`

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

## ambiguous-glob-imports

The `ambiguous_glob_imports` lint detects glob imports that should report ambiguity errors, but previously didn't do that due to rustc bugs.

### Example

    #![deny(ambiguous_glob_imports)]
    pub fn foo() -> u32 {
        use sub::*;
        C
    }

    mod sub {
        mod mod1 { pub const C: u32 = 1; }
        mod mod2 { pub const C: u32 = 2; }

        pub use mod1::*;
        pub use mod2::*;
    }

This will produce:

    error: `C` is ambiguous
      --> lint_example.rs:5:5
       |
     5 |     C
       |     ^ ambiguous 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 #114095 <https://github.com/rust-lang/rust/issues/114095>
       = note: ambiguous because of multiple glob imports of a name in the same module
    note: `C` could refer to the constant imported here
      --> lint_example.rs:12:13
       |
    12 |     pub use mod1::*;
       |             ^^^^^^^
       = help: consider adding an explicit import of `C` to disambiguate
    note: `C` could also refer to the constant imported here
      --> lint_example.rs:13:13
       |
    13 |     pub use mod2::*;
       |             ^^^^^^^
       = help: consider adding an explicit import of `C` to disambiguate
    note: the lint level is defined here
      --> lint_example.rs:1:9
       |
     1 | #![deny(ambiguous_glob_imports)]
       |         ^^^^^^^^^^^^^^^^^^^^^^

### Explanation

Previous versions of Rust compile it successfully because it had lost the ambiguity error when resolve `use sub::mod2::*`.

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

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

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

## dangerous-implicit-autorefs

The `dangerous_implicit_autorefs` lint checks for implicitly taken references to dereferences of raw pointers.

### Example

    unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
        unsafe { &raw mut (*ptr)[..16] }
        //                      ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
        //                             implicitly creating a reference
    }

This will produce:

    error: implicit autoref creates a reference to the dereference of a raw pointer
     --> lint_example.rs:3:23
      |
    3 |     unsafe { &raw mut (*ptr)[..16] }
      |                       ^^---^^^^^^^
      |                         |
      |                         this raw pointer has type `*mut [u8]`
      |
      = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
    note: autoref is being applied to this expression, resulting in: `&mut [u8]`
     --> lint_example.rs:3:23
      |
    3 |     unsafe { &raw mut (*ptr)[..16] }
      |                       ^^^^^^
      = note: `#[deny(dangerous_implicit_autorefs)]` on by default
    help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
      |
    3 |     unsafe { &raw mut (&mut (*ptr))[..16] }
      |                       +++++       +

### Explanation

When working with raw pointers it's usually undesirable to create references, since they inflict additional safety requirements. Unfortunately, it's possible to take a reference to the dereference of a raw pointer implicitly, which inflicts the usual reference requirements.

If you are sure that you can soundly take a reference, then you can take it explicitly:

    unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
        unsafe { &raw mut (&mut *ptr)[..16] }
    }

Otherwise try to find an alternative way to achieve your goals using only raw pointers:

    use std::ptr;

    fn fun(ptr: *mut [u8]) -> *mut [u8] {
        ptr::slice_from_raw_parts_mut(ptr.cast(), 16)
    }

## default-overrides-default-fields

The `default_overrides_default_fields` lint checks for manual `impl` blocks of the `Default` trait of types with default field values.

### Example

    #![feature(default_field_values)]
    struct Foo {
        x: i32 = 101,
        y: NonDefault,
    }

    struct NonDefault;

    #[deny(default_overrides_default_fields)]
    impl Default for Foo {
        fn default() -> Foo {
            Foo { x: 100, y: NonDefault }
        }
    }

This will produce:

    error: `Default` impl doesn't use the declared default field values
      --> lint_example.rs:11:1
       |
    11 | / impl Default for Foo {
    12 | |     fn default() -> Foo {
    13 | |         Foo { x: 100, y: NonDefault }
       | |                  --- this field has a default value
    14 | |     }
    15 | | }
       | |_^
       |
       = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time
    note: the lint level is defined here
      --> lint_example.rs:10:8
       |
    10 | #[deny(default_overrides_default_fields)]
       |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

### Explanation

Manually writing a `Default` implementation for a type that has default field values runs the risk of diverging behavior between `Type { .. }` and `<Type as Default>::default()`, which would be a foot-gun for users of that type that would expect these to be equivalent. If `Default` can't be derived due to some fields not having a `Default` implementation, we encourage the use of `..` for the fields that do have a default field value.

## 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(always)]`, `#[inline(never)]`, and `#[inline]`
     --> 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. `impl`s 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 an 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-null-arguments

The `invalid_null_arguments` lint checks for invalid usage of null pointers in arguments.

### Example

    use std::{slice, ptr};
    // Undefined behavior
    let _slice: &[u8] =
    unsafe { slice::from_raw_parts(ptr::null(), 0) };

This will produce:

    error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
     --> lint_example.rs:5:10
      |
    5 | unsafe { slice::from_raw_parts(ptr::null(), 0) };
      |          ^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
      |                                |
      |                                null pointer originates from here
      |
      = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
      = note: `#[deny(invalid_null_arguments)]` on by default

### Explanation

Calling methods whos safety invariants requires non-null ptr with a null pointer is Undefined Behavior!

## 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 generic parameters are not allowed here
     --> 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.

## legacy-derive-helpers

The `legacy_derive_helpers` lint detects derive helper attributes that are used before they are introduced.

### Example

    #[serde(rename_all = "camelCase")]
    #[derive(Deserialize)]
    struct S { /* fields */ }

produces:

    warning: derive helper attribute is used before it is introduced
      --> $DIR/legacy-derive-helpers.rs:1:3
       |
     1 | #[serde(rename_all = "camelCase")]
       |   ^^^^^
    ...
     2 | #[derive(Deserialize)]
       |          ----------- the attribute is introduced here

### Explanation

Attributes like this work for historical reasons, but attribute expansion works in left-to-right order in general, so, to resolve `#[serde]`, compiler has to try to "look into the future" at not yet expanded part of the item , but such attempts are not always reliable.

To fix the warning place the helper attribute after its corresponding derive.

    #[derive(Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct S { /* fields */ }

## 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 -     let _ = data.lock().unwrap();
    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.

## 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`.

## out-of-scope-macro-calls

The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope, above their definition, which may happen in key-value attributes.

### Example

    #![doc = in_root!()]

    macro_rules! in_root { () => { "" } }

    fn main() {}

This will produce:

    error: cannot find macro `in_root` in the current scope when looking from the crate root
     --> lint_example.rs:1:10
      |
    1 | #![doc = in_root!()]
      |          ^^^^^^^ not found from the crate root
      |
      = 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 #124535 <https://github.com/rust-lang/rust/issues/124535>
      = help: import `macro_rules` with `use` to make it callable above its definition
      = note: `#[deny(out_of_scope_macro_calls)]` on by default

### Explanation

The scope in which a `macro_rules` item is visible starts at that item and continues below it. This is more similar to `let` than to other items, which are in scope both above and below their definition. Due to a bug `macro_rules` were accidentally in scope inside some key-value attributes above their definition. The lint catches such cases. To address the issue turn the `macro_rules` into a regularly scoped item by importing it with `use`.

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

## overflowing-literals

The `overflowing_literals` lint detects literals out of range for their 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 its type Change either the literal or its type such that the literal is within the range of its type.

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

## private-macro-use

The `private_macro_use` lint detects private macros that are imported with `#[macro_use]`.

### Example

    // extern_macro.rs
    macro_rules! foo_ { () => {}; }
    use foo_ as foo;

    // code.rs

    #![deny(private_macro_use)]

    #[macro_use]
    extern crate extern_macro;

    fn main() {
        foo!();
    }

This will produce:

    error: cannot find macro `foo` in this scope

### Explanation

This lint arises from overlooking visibility checks for macros in an external crate.

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

## 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 publically 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.

## semicolon-in-expressions-from-macros

The `semicolon_in_expressions_from_macros` lint detects trailing semicolons in macro bodies when the macro is invoked in expression position. This was previous accepted, but is being phased out.

### Example

    #![deny(semicolon_in_expressions_from_macros)]
    macro_rules! foo {
        () => { true; }
    }

    fn main() {
        let val = match true {
            true => false,
            _ => foo!()
        };
    }

This will produce:

    error: trailing semicolon in macro used in expression position
     --> lint_example.rs:3:17
      |
    3 |     () => { true; }
      |                 ^
    ...
    9 |         _ => foo!()
      |              ------ in this macro invocation
      |
      = 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 #79813 <https://github.com/rust-lang/rust/issues/79813>
    note: the lint level is defined here
     --> lint_example.rs:1:9
      |
    1 | #![deny(semicolon_in_expressions_from_macros)]
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)

### Explanation

Previous, Rust ignored trailing semicolon in a macro body when a macro was invoked in expression position. However, this makes the treatment of semicolons in the language inconsistent, and could lead to unexpected runtime behavior in some circumstances (e.g. if the macro author expects a value to be dropped).

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

## soft-unstable

The `soft_unstable` lint detects unstable features that were unintentionally allowed on stable. 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

    // This lint is intentionally used to test the compiler's behavior
    // when an unstable lint is enabled without the corresponding feature gate.
    #![allow(test_unstable_lint)]

This will produce:

    warning: unknown lint: `test_unstable_lint`
     --> lint_example.rs:4:10
      |
    4 | #![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 2025-08-15; 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!("{:?}", '�');
    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: `#[deprecated]` attribute cannot be used on trait impl blocks
     --> lint_example.rs:4:1
      |
    4 | #[deprecated = "message"]
      | ^^^^^^^^^^^^^^^^^^^^^^^^^
      |
      = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
      = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
      = note: `#[deny(useless_deprecated)]` on by default

### Explanation

Deprecation attributes have no effect on trait implementations.