Warn-by-default Lints

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

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.

ambiguous-glob-reexports

The ambiguous_glob_reexports lint detects cases where names re-exported via globs collide. Downstream users trying to use the same name re-exported from multiple globs will receive a warning pointing out redefinition of the same name.

Example

#![deny(ambiguous_glob_reexports)]
pub mod foo {
    pub type X = u8;
}

pub mod bar {
    pub type Y = u8;
    pub type X = u8;
}

pub use foo::*;
pub use bar::*;


pub fn main() {}

This will produce:

error: ambiguous glob re-exports
  --> lint_example.rs:11:9
   |
11 | pub use foo::*;
   |         ^^^^^^ the name `X` in the type namespace is first re-exported here
12 | pub use bar::*;
   |         ------ but the name `X` in the type namespace is also re-exported here
   |
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(ambiguous_glob_reexports)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

This was previously accepted but it could silently break a crate's downstream users code. For example, if foo::* and bar::* were re-exported before bar::X was added to the re-exports, down stream users could use this_crate::X without problems. However, adding bar::X would cause compilation errors in downstream crates because X is defined multiple times in the same namespace of this_crate.

ambiguous-wide-pointer-comparisons

The ambiguous_wide_pointer_comparisons lint checks comparison of *const/*mut ?Sized as the operands.

Example

struct A;
struct B;

trait T {}
impl T for A {}
impl T for B {}

let ab = (A, B);
let a = &ab.0 as *const dyn T;
let b = &ab.1 as *const dyn T;

let _ = a == b;

This will produce:

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
  --> lint_example.rs:13:9
   |
13 | let _ = a == b;
   |         ^^^^^^
   |
   = note: `#[warn(ambiguous_wide_pointer_comparisons)]` on by default
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
   |
13 | let _ = std::ptr::addr_eq(a, b);
   |         ++++++++++++++++++ ~  +

Explanation

The comparison includes metadata which may not be expected.

anonymous-parameters

The anonymous_parameters lint detects anonymous parameters in trait definitions.

Example

#![deny(anonymous_parameters)]
// edition 2015
pub trait Foo {
    fn foo(usize);
}
fn main() {}

This will produce:

error: anonymous parameters are deprecated and will be removed in the next edition
 --> lint_example.rs:4:12
  |
4 |     fn foo(usize);
  |            ^^^^^ help: try naming the parameter or explicitly ignoring it: `_: usize`
  |
  = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
  = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(anonymous_parameters)]
  |         ^^^^^^^^^^^^^^^^^^^^

Explanation

This syntax is mostly a historical accident, and can be worked around quite easily by adding an _ pattern or a descriptive identifier:

trait Foo {
    fn foo(_: usize);
}

This syntax is now a hard error in the 2018 edition. In the 2015 edition, this lint is "warn" by default. This lint enables the cargo fix tool with the --edition flag to automatically transition old code from the 2015 edition to 2018. The tool will run this lint and automatically apply the suggested fix from the compiler (which is to add _ to each parameter). This provides a completely automated way to update old code for a new edition. See issue #41686 for more details.

array-into-iter

The array_into_iter lint detects calling into_iter on arrays.

Example

#![allow(unused)]
[1, 2, 3].into_iter().for_each(|n| { *n; });

This will produce:

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
 --> lint_example.rs:3:11
  |
3 | [1, 2, 3].into_iter().for_each(|n| { *n; });
  |           ^^^^^^^^^
  |
  = warning: this changes meaning in Rust 2021
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
  = note: `#[warn(array_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
  |
3 | [1, 2, 3].iter().for_each(|n| { *n; });
  |           ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
  |
3 | IntoIterator::into_iter([1, 2, 3]).for_each(|n| { *n; });
  | ++++++++++++++++++++++++         ~

Explanation

Since Rust 1.53, arrays implement IntoIterator. However, to avoid breakage, array.into_iter() in Rust 2015 and 2018 code will still behave as (&array).into_iter(), returning an iterator over references, just like in Rust 1.52 and earlier. This only applies to the method call syntax array.into_iter(), not to any other syntax such as for _ in array or IntoIterator::into_iter(array).

asm-sub-register

The asm_sub_register lint detects using only a subset of a register for inline asm inputs.

Example

#[cfg(target_arch="x86_64")]
use std::arch::asm;

fn main() {
    #[cfg(target_arch="x86_64")]
    unsafe {
        asm!("mov {0}, {0}", in(reg) 0i16);
    }
}

This will produce:

warning: formatting may not be suitable for sub-register argument
 --> src/main.rs:7:19
  |
7 |         asm!("mov {0}, {0}", in(reg) 0i16);
  |                   ^^^  ^^^           ---- for this argument
  |
  = note: `#[warn(asm_sub_register)]` on by default
  = help: use the `x` modifier to have the register formatted as `ax`
  = help: or use the `r` modifier to keep the default formatting of `rax`

Explanation

Registers on some architectures can use different names to refer to a subset of the register. By default, the compiler will use the name for the full register size. To explicitly use a subset of the register, you can override the default by using a modifier on the template string operand to specify when subregister to use. This lint is issued if you pass in a value with a smaller data type than the default register size, to alert you of possibly using the incorrect width. To fix this, add the suggested modifier to the template, or cast the value to the correct size.

See register template modifiers in the reference for more details.

async-fn-in-trait

The async_fn_in_trait lint detects use of async fn in the definition of a publicly-reachable trait.

Example

pub trait Trait {
    async fn method(&self);
}
fn main() {}

This will produce:

warning: use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
 --> lint_example.rs:2:5
  |
2 |     async fn method(&self);
  |     ^^^^^
  |
  = note: you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
  = note: `#[warn(async_fn_in_trait)]` on by default
help: you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change
  |
2 -     async fn method(&self);
2 +     fn method(&self) -> impl std::future::Future<Output = ()> + Send;
  |

Explanation

When async fn is used in a trait definition, the trait does not promise that the opaque Future returned by the associated function or method will implement any auto traits such as Send. This may be surprising and may make the associated functions or methods on the trait less useful than intended. On traits exposed publicly from a crate, this may affect downstream crates whose authors cannot alter the trait definition.

For example, this code is invalid:

pub trait Trait {
    async fn method(&self) {}
}

fn test<T: Trait>(x: T) {
    fn spawn<T: Send>(_: T) {}
    spawn(x.method()); // Not OK.
}

This lint exists to warn authors of publicly-reachable traits that they may want to consider desugaring the async fn to a normal fn that returns an opaque impl Future<..> + Send type.

For example, instead of:

pub trait Trait {
    async fn method(&self) {}
}

The author of the trait may want to write:

use core::future::Future;
pub trait Trait {
    fn method(&self) -> impl Future<Output = ()> + Send { async {} }
}

This still allows the use of async fn within impls of the trait. However, it also means that the trait will never be compatible with impls where the returned Future of the method does not implement Send.

Conversely, if the trait is used only locally, if it is never used in generic functions, or if it is only used in single-threaded contexts that do not care whether the returned Future implements Send, then the lint may be suppressed.

bad-asm-style

The bad_asm_style lint detects the use of the .intel_syntax and .att_syntax directives.

Example

#[cfg(target_arch="x86_64")]
use std::arch::asm;

fn main() {
    #[cfg(target_arch="x86_64")]
    unsafe {
        asm!(
            ".att_syntax",
            "movq %{0}, %{0}", in(reg) 0usize
        );
    }
}

This will produce:

warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
 --> src/main.rs:8:14
  |
8 |             ".att_syntax",
  |              ^^^^^^^^^^^
  |
  = note: `#[warn(bad_asm_style)]` on by default

Explanation

On x86, asm! uses the intel assembly syntax by default. While this can be switched using assembler directives like .att_syntax, using the att_syntax option is recommended instead because it will also properly prefix register placeholders with % as required by AT&T syntax.

bare-trait-object

The lint bare-trait-object has been renamed to bare-trait-objects.

bare-trait-objects

The bare_trait_objects lint suggests using dyn Trait for trait objects.

Example

trait Trait { }

fn takes_trait_object(_: Box<Trait>) {
}

This will produce:

warning: trait objects without an explicit `dyn` are deprecated
 --> lint_example.rs:4:30
  |
4 | fn takes_trait_object(_: Box<Trait>) {
  |                              ^^^^^
  |
  = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
  = note: `#[warn(bare_trait_objects)]` on by default
help: if this is a dyn-compatible trait, use `dyn`
  |
4 | fn takes_trait_object(_: Box<dyn Trait>) {
  |                              +++

Explanation

Without the dyn indicator, it can be ambiguous or confusing when reading code as to whether or not you are looking at a trait object. The dyn keyword makes it explicit, and adds a symmetry to contrast with impl Trait.

boxed-slice-into-iter

The boxed_slice_into_iter lint detects calling into_iter on boxed slices.

Example

#![allow(unused)]
vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; });

This will produce:

warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
 --> lint_example.rs:3:34
  |
3 | vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; });
  |                                  ^^^^^^^^^
  |
  = warning: this changes meaning in Rust 2024
  = note: `#[warn(boxed_slice_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
  |
3 | vec![1, 2, 3].into_boxed_slice().iter().for_each(|n| { *n; });
  |                                  ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
  |
3 | IntoIterator::into_iter(vec![1, 2, 3].into_boxed_slice()).for_each(|n| { *n; });
  | ++++++++++++++++++++++++                                ~

Explanation

Since Rust 1.80.0, boxed slices implement IntoIterator. However, to avoid breakage, boxed_slice.into_iter() in Rust 2015, 2018, and 2021 code will still behave as (&boxed_slice).into_iter(), returning an iterator over references, just like in Rust 1.79.0 and earlier. This only applies to the method call syntax boxed_slice.into_iter(), not to any other syntax such as for _ in boxed_slice or IntoIterator::into_iter(boxed_slice).

break-with-label-and-loop

The break_with_label_and_loop lint detects labeled break expressions with an unlabeled loop as their value expression.

Example

'label: loop {
    break 'label loop { break 42; };
};

This will produce:

warning: this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression
 --> lint_example.rs:3:5
  |
3 |     break 'label loop { break 42; };
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(break_with_label_and_loop)]` on by default
help: wrap this expression in parentheses
  |
3 |     break 'label (loop { break 42; });
  |                  +                  +

Explanation

In Rust, loops can have a label, and break expressions can refer to that label to break out of specific loops (and not necessarily the innermost one). break expressions can also carry a value expression, which can be another loop. A labeled break with an unlabeled loop as its value expression is easy to confuse with an unlabeled break with a labeled loop and is thus discouraged (but allowed for compatibility); use parentheses around the loop expression to silence this warning. Unlabeled break expressions with labeled loops yield a hard error, which can also be silenced by wrapping the expression in parentheses.

clashing-extern-declarations

The clashing_extern_declarations lint detects when an extern fn has been declared with the same name but different types.

Example

mod m {
    extern "C" {
        fn foo();
    }
}

extern "C" {
    fn foo(_: u32);
}

This will produce:

warning: `foo` redeclared with a different signature
 --> lint_example.rs:9:5
  |
4 |         fn foo();
  |         --------- `foo` previously declared here
...
9 |     fn foo(_: u32);
  |     ^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
  |
  = note: expected `unsafe extern "C" fn()`
             found `unsafe extern "C" fn(u32)`
  = note: `#[warn(clashing_extern_declarations)]` on by default

Explanation

Because two symbols of the same name cannot be resolved to two different functions at link time, and one function cannot possibly have two types, a clashing extern declaration is almost certainly a mistake. Check to make sure that the extern definitions are correct and equivalent, and possibly consider unifying them in one location.

This lint does not run between crates because a project may have dependencies which both rely on the same extern function, but declare it in a different (but valid) way. For example, they may both declare an opaque type for one or more of the arguments (which would end up distinct types), or use types that are valid conversions in the language the extern fn is defined in. In these cases, the compiler can't say that the clashing declaration is incorrect.

coherence-leak-check

The coherence_leak_check lint detects conflicting implementations of a trait that are only distinguished by the old leak-check code.

Example

trait SomeTrait { }
impl SomeTrait for for<'a> fn(&'a u8) { }
impl<'a> SomeTrait for fn(&'a u8) { }

This will produce:

warning: conflicting implementations of trait `SomeTrait` for type `for<'a> fn(&'a u8)`
 --> lint_example.rs:4:1
  |
3 | impl SomeTrait for for<'a> fn(&'a u8) { }
  | ------------------------------------- first implementation here
4 | impl<'a> SomeTrait for fn(&'a u8) { }
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a u8)`
  |
  = warning: the behavior may change in a future release
  = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
  = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
  = note: `#[warn(coherence_leak_check)]` on by default

Explanation

In the past, the compiler would accept trait implementations for identical functions that differed only in where the lifetime binder appeared. Due to a change in the borrow checker implementation to fix several bugs, this is no longer allowed. However, since this affects existing code, this is a future-incompatible lint to transition this to a hard error in the future.

Code relying on this pattern should introduce "newtypes", like struct Foo(for<'a> fn(&'a u8)).

See issue #56105 for more details.

confusable-idents

The confusable_idents lint detects visually confusable pairs between identifiers.

Example

// Latin Capital Letter E With Caron
pub const Ě: i32 = 1;
// Latin Capital Letter E With Breve
pub const Ĕ: i32 = 2;

This will produce:

warning: found both `Ě` and `Ĕ` as identifiers, which look alike
 --> lint_example.rs:5:11
  |
3 | pub const Ě: i32 = 1;
  |           - other identifier used here
4 | // Latin Capital Letter E With Breve
5 | pub const Ĕ: i32 = 2;
  |           ^ this identifier can be confused with `Ě`
  |
  = note: `#[warn(confusable_idents)]` on by default

Explanation

This lint warns when different identifiers may appear visually similar, which can cause confusion.

The confusable detection algorithm is based on Unicode® Technical Standard #39 Unicode Security Mechanisms Section 4 Confusable Detection. For every distinct identifier X execute the function skeleton(X). If there exist two distinct identifiers X and Y in the same crate where skeleton(X) = skeleton(Y) report it. The compiler uses the same mechanism to check if an identifier is too similar to a keyword.

Note that the set of confusable characters may change over time. Beware that if you "forbid" this lint that existing code may fail in the future.

const-evaluatable-unchecked

The const_evaluatable_unchecked lint detects a generic constant used in a type.

Example

const fn foo<T>() -> usize {
    if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
        4
    } else {
        8
    }
}

fn test<T>() {
    let _ = [0; foo::<T>()];
}

This will produce:

warning: cannot use constants which depend on generic parameters in types
  --> lint_example.rs:11:17
   |
11 |     let _ = [0; foo::<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 #76200 <https://github.com/rust-lang/rust/issues/76200>
   = note: `#[warn(const_evaluatable_unchecked)]` on by default

Explanation

In the 1.43 release, some uses of generic parameters in array repeat expressions were accidentally allowed. This is a future-incompatible lint to transition this to a hard error in the future. See issue #76200 for a more detailed description and possible fixes.

const-item-mutation

The const_item_mutation lint detects attempts to mutate a const item.

Example

const FOO: [i32; 1] = [0];

fn main() {
    FOO[0] = 1;
    // This will print "[0]".
    println!("{:?}", FOO);
}

This will produce:

warning: attempting to modify a `const` item
 --> lint_example.rs:4:5
  |
4 |     FOO[0] = 1;
  |     ^^^^^^^^^^
  |
  = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
note: `const` item defined here
 --> lint_example.rs:1:1
  |
1 | const FOO: [i32; 1] = [0];
  | ^^^^^^^^^^^^^^^^^^^
  = note: `#[warn(const_item_mutation)]` on by default

Explanation

Trying to directly mutate a const item is almost always a mistake. What is happening in the example above is that a temporary copy of the const is mutated, but the original const is not. Each time you refer to the const by name (such as FOO in the example above), a separate copy of the value is inlined at that location.

This lint checks for writing directly to a field (FOO.field = some_value) or array entry (FOO[0] = val), or taking a mutable reference to the const item (&mut FOO), including through an autoderef (FOO.some_mut_self_method()).

There are various alternatives depending on what you are trying to accomplish:

  • First, always reconsider using mutable globals, as they can be difficult to use correctly, and can make the code more difficult to use or understand.
  • If you are trying to perform a one-time initialization of a global:
    • If the value can be computed at compile-time, consider using const-compatible values (see Constant Evaluation).
    • For more complex single-initialization cases, consider using std::sync::LazyLock.
  • If you truly need a mutable global, consider using a static, which has a variety of options:
    • Simple data types can be directly defined and mutated with an atomic type.
    • More complex types can be placed in a synchronization primitive like a Mutex, which can be initialized with one of the options listed above.
    • A mutable static is a low-level primitive, requiring unsafe. Typically This should be avoided in preference of something higher-level like one of the above.

dead-code

The dead_code lint detects unused, unexported items.

Example

fn foo() {}

This will produce:

warning: function `foo` is never used
 --> lint_example.rs:2:4
  |
2 | fn foo() {}
  |    ^^^
  |
  = note: `#[warn(dead_code)]` on by default

Explanation

Dead code may signal a mistake or unfinished code. To silence the warning for individual items, prefix the name with an underscore such as _foo. If it was intended to expose the item outside of the crate, consider adding a visibility modifier like pub.

To preserve the numbering of tuple structs with unused fields, change the unused fields to have unit type or use PhantomData.

Otherwise consider removing the unused code.

Limitations

Removing fields that are only used for side-effects and never read will result in behavioral changes. Examples of this include:

  • If a field's value performs an action when it is dropped.
  • If a field's type does not implement an auto trait (e.g. Send, Sync, Unpin).

For side-effects from dropping field values, this lint should be allowed on those fields. For side-effects from containing field types, PhantomData should be used.

dependency-on-unit-never-type-fallback

The dependency_on_unit_never_type_fallback lint detects cases where code compiles with never type fallback being (), but will stop compiling with fallback being !.

Example

#![deny(dependency_on_unit_never_type_fallback)]
fn main() {
    if true {
        // return has type `!` which, is some cases, causes never type fallback
        return
    } else {
        // the type produced by this call is not specified explicitly,
        // so it will be inferred from the previous branch
        Default::default()
    };
    // depending on the fallback, this may compile (because `()` implements `Default`),
    // or it may not (because `!` does not implement `Default`)
}

This will produce:

error: this function depends on never type fallback being `()`
 --> lint_example.rs:2:1
  |
2 | fn main() {
  | ^^^^^^^^^
  |
  = 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 #123748 <https://github.com/rust-lang/rust/issues/123748>
  = help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
 --> lint_example.rs:9:9
  |
9 |         Default::default()
  |         ^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(dependency_on_unit_never_type_fallback)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

Due to historic reasons never type fallback was (), meaning that ! got spontaneously coerced to (). There are plans to change that, but they may make the code such as above not compile. Instead of depending on the fallback, you should specify the type explicitly:

if true {
    return
} else {
    // type is explicitly specified, fallback can't hurt us no more
    <() as Default>::default()
};

See Tracking Issue for making ! fall back to !.

deprecated

The deprecated lint detects use of deprecated items.

Example

#[deprecated]
fn foo() {}

fn bar() {
    foo();
}

This will produce:

warning: use of deprecated function `main::foo`
 --> lint_example.rs:6:5
  |
6 |     foo();
  |     ^^^
  |
  = note: `#[warn(deprecated)]` on by default

Explanation

Items may be marked "deprecated" with the deprecated attribute to indicate that they should no longer be used. Usually the attribute should include a note on what to use instead, or check the documentation.

deprecated-where-clause-location

The deprecated_where_clause_location lint detects when a where clause in front of the equals in an associated type.

Example

trait Trait {
  type Assoc<'a> where Self: 'a;
}

impl Trait for () {
  type Assoc<'a> where Self: 'a = ();
}

This will produce:

warning: where clause not allowed here
 --> lint_example.rs:7:18
  |
7 |   type Assoc<'a> where Self: 'a = ();
  |                  ^^^^^^^^^^^^^^
  |
  = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
  = note: `#[warn(deprecated_where_clause_location)]` on by default
help: move it to the end of the type declaration
  |
7 -   type Assoc<'a> where Self: 'a = ();
7 +   type Assoc<'a>  = () where Self: 'a;
  |

Explanation

The preferred location for where clauses on associated types is after the type. However, for most of generic associated types development, it was only accepted before the equals. To provide a transition period and further evaluate this change, both are currently accepted. At some point in the future, this may be disallowed at an edition boundary; but, that is undecided currently.

deref-into-dyn-supertrait

The deref_into_dyn_supertrait lint is output whenever there is a use of the Deref implementation with a dyn SuperTrait type as Output.

These implementations will become shadowed when the trait_upcasting feature is stabilized. The deref functions will no longer be called implicitly, so there might be behavior change.

Example

#![deny(deref_into_dyn_supertrait)]
#![allow(dead_code)]

use core::ops::Deref;

trait A {}
trait B: A {}
impl<'a> Deref for dyn 'a + B {
    type Target = dyn A;
    fn deref(&self) -> &Self::Target {
        todo!()
    }
}

fn take_a(_: &dyn A) { }

fn take_b(b: &dyn B) {
    take_a(b);
}

This will produce:

error: this `Deref` implementation is covered by an implicit supertrait coercion
  --> lint_example.rs:9:1
   |
9  | impl<'a> Deref for dyn 'a + B {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
10 |     type Target = dyn A;
   |     -------------------- target type is a supertrait of `dyn B`
   |
   = warning: this will change its meaning in a future release!
   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(deref_into_dyn_supertrait)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

The dyn upcasting coercion feature adds new coercion rules, taking priority over certain other coercion rules, which will cause some behavior change.

deref-nullptr

The deref_nullptr lint detects when an null pointer is dereferenced, which causes undefined behavior.

Example

#![allow(unused)]
use std::ptr;
unsafe {
    let x = &*ptr::null::<i32>();
    let x = ptr::addr_of!(*ptr::null::<i32>());
    let x = *(0 as *const i32);
}

This will produce:

warning: dereferencing a null pointer
 --> lint_example.rs:5:14
  |
5 |     let x = &*ptr::null::<i32>();
  |              ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
  |
  = note: `#[warn(deref_nullptr)]` on by default


warning: dereferencing a null pointer
 --> lint_example.rs:6:27
  |
6 |     let x = ptr::addr_of!(*ptr::null::<i32>());
  |                           ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed


warning: dereferencing a null pointer
 --> lint_example.rs:7:13
  |
7 |     let x = *(0 as *const i32);
  |             ^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed

Explanation

Dereferencing a null pointer causes undefined behavior even as a place expression, like &*(0 as *const i32) or addr_of!(*(0 as *const i32)).

drop-bounds

The drop_bounds lint checks for generics with std::ops::Drop as bounds.

Example

fn foo<T: Drop>() {}

This will produce:

warning: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
 --> lint_example.rs:2:11
  |
2 | fn foo<T: Drop>() {}
  |           ^^^^
  |
  = note: `#[warn(drop_bounds)]` on by default

Explanation

A generic trait bound of the form T: Drop is most likely misleading and not what the programmer intended (they probably should have used std::mem::needs_drop instead).

Drop bounds do not actually indicate whether a type can be trivially dropped or not, because a composite type containing Drop types does not necessarily implement Drop itself. Naïvely, one might be tempted to write an implementation that assumes that a type can be trivially dropped while also supplying a specialization for T: Drop that actually calls the destructor. However, this breaks down e.g. when T is String, which does not implement Drop itself but contains a Vec, which does implement Drop, so assuming T can be trivially dropped would lead to a memory leak here.

Furthermore, the Drop trait only contains one method, Drop::drop, which may not be called explicitly in user code (E0040), so there is really no use case for using Drop in trait bounds, save perhaps for some obscure corner cases, which can use #[allow(drop_bounds)].

dropping-copy-types

The dropping_copy_types lint checks for calls to std::mem::drop with a value that derives the Copy trait.

Example

let x: i32 = 42; // i32 implements Copy
std::mem::drop(x); // A copy of x is passed to the function, leaving the
                   // original unaffected

This will produce:

warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing
 --> lint_example.rs:3:1
  |
3 | std::mem::drop(x); // A copy of x is passed to the function, leaving the
  | ^^^^^^^^^^^^^^^-^
  |                |
  |                argument has type `i32`
  |
  = note: `#[warn(dropping_copy_types)]` on by default
help: use `let _ = ...` to ignore the expression or result
  |
3 - std::mem::drop(x); // A copy of x is passed to the function, leaving the
3 + let _ = x; // A copy of x is passed to the function, leaving the
  |

Explanation

Calling std::mem::drop does nothing for types that implement Copy, since the value will be copied and moved into the function on invocation.

dropping-references

The dropping_references lint checks for calls to std::mem::drop with a reference instead of an owned value.

Example

fn operation_that_requires_mutex_to_be_unlocked() {} // just to make it compile
let mutex = std::sync::Mutex::new(1); // just to make it compile
let mut lock_guard = mutex.lock();
std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex
// still locked
operation_that_requires_mutex_to_be_unlocked();

This will produce:

warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing
 --> lint_example.rs:5:1
  |
5 | std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex
  | ^^^^^^^^^^^^^^^-----------^
  |                |
  |                argument has type `&Result<MutexGuard<'_, i32>, PoisonError<MutexGuard<'_, i32>>>`
  |
  = note: `#[warn(dropping_references)]` on by default
help: use `let _ = ...` to ignore the expression or result
  |
5 - std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex
5 + let _ = &lock_guard; // Should have been drop(lock_guard), mutex
  |

Explanation

Calling drop on a reference will only drop the reference itself, which is a no-op. It will not call the drop method (from the Drop trait implementation) on the underlying referenced value, which is likely what was intended.

duplicate-macro-attributes

The duplicate_macro_attributes lint detects when a #[test]-like built-in macro attribute is duplicated on an item. This lint may trigger on bench, cfg_eval, test and test_case.

Example

#[test]
#[test]
fn foo() {}

This will produce:

warning: duplicated attribute
 --> src/lib.rs:2:1
  |
2 | #[test]
  | ^^^^^^^
  |
  = note: `#[warn(duplicate_macro_attributes)]` on by default

Explanation

A duplicated attribute may erroneously originate from a copy-paste and the effect of it being duplicated may not be obvious or desirable.

For instance, doubling the #[test] attributes registers the test to be run twice with no change to its environment.

dyn-drop

The dyn_drop lint checks for trait objects with std::ops::Drop.

Example

fn foo(_x: Box<dyn Drop>) {}

This will produce:

warning: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped
 --> lint_example.rs:2:20
  |
2 | fn foo(_x: Box<dyn Drop>) {}
  |                    ^^^^
  |
  = note: `#[warn(dyn_drop)]` on by default

Explanation

A trait object bound of the form dyn Drop is most likely misleading and not what the programmer intended.

Drop bounds do not actually indicate whether a type can be trivially dropped or not, because a composite type containing Drop types does not necessarily implement Drop itself. Naïvely, one might be tempted to write a deferred drop system, to pull cleaning up memory out of a latency-sensitive code path, using dyn Drop trait objects. However, this breaks down e.g. when T is String, which does not implement Drop, but should probably be accepted.

To write a trait object bound that accepts anything, use a placeholder trait with a blanket implementation.

trait Placeholder {}
impl<T> Placeholder for T {}
fn foo(_x: Box<dyn Placeholder>) {}

elided-named-lifetimes

The elided_named_lifetimes lint detects when an elided lifetime ends up being a named lifetime, such as 'static or some lifetime parameter 'a.

Example

#[cfg_attr(bootstrap)] compile_error!(); // Remove this in bootstrap bump.
#![deny(elided_named_lifetimes)]
struct Foo;
impl Foo {
    pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
        unsafe { &mut *(x as *mut _) }
    }
}

This will produce:

warning: elided lifetime has a name
 --> lint_example.rs:6:50
  |
6 |     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
  |                                                  ^ this elided lifetime gets resolved as `'static`
  |
  = note: `#[warn(elided_named_lifetimes)]` on by default
help: consider specifying it explicitly
  |
6 |     pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
  |                                                   +++++++

Explanation

Lifetime elision is quite useful, because it frees you from having to give each lifetime its own name, but sometimes it can produce somewhat surprising resolutions. In safe code, it is mostly okay, because the borrow checker prevents any unsoundness, so the worst case scenario is you get a confusing error message in some other place. But with unsafe code, such unexpected resolutions may lead to unsound code.

ellipsis-inclusive-range-patterns

The ellipsis_inclusive_range_patterns lint detects the ... range pattern, which is deprecated.

Example

let x = 123;
match x {
    0...100 => {}
    _ => {}
}

This will produce:

warning: `...` range patterns are deprecated
 --> lint_example.rs:4:6
  |
4 |     0...100 => {}
  |      ^^^ help: use `..=` for an inclusive range
  |
  = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
  = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default

Explanation

The ... range pattern syntax was changed to ..= to avoid potential confusion with the .. range expression. Use the new form instead.

exported-private-dependencies

The exported_private_dependencies lint detects private dependencies that are exposed in a public interface.

Example

pub fn foo() -> Option<some_private_dependency::Thing> {
    None
}

This will produce:

warning: type `bar::Thing` from private dependency 'bar' in public interface
 --> src/lib.rs:3:1
  |
3 | pub fn foo() -> Option<bar::Thing> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(exported_private_dependencies)]` on by default

Explanation

Dependencies can be marked as "private" to indicate that they are not exposed in the public interface of a crate. This can be used by Cargo to independently resolve those dependencies because it can assume it does not need to unify them with other packages using that same dependency. This lint is an indication of a violation of that contract.

To fix this, avoid exposing the dependency in your public interface. Or, switch the dependency to a public dependency.

Note that support for this is only available on the nightly channel. See RFC 1977 for more details, as well as the Cargo documentation.

for-loops-over-fallibles

The for_loops_over_fallibles lint checks for for loops over Option or Result values.

Example

let opt = Some(1);
for x in opt { /* ... */}

This will produce:

warning: for loop over an `Option`. This is more readably written as an `if let` statement
 --> lint_example.rs:3:10
  |
3 | for x in opt { /* ... */}
  |          ^^^
  |
  = note: `#[warn(for_loops_over_fallibles)]` on by default
help: to check pattern in a loop use `while let`
  |
3 | while let Some(x) = opt { /* ... */}
  | ~~~~~~~~~~~~~~~ ~~~
help: consider using `if let` to clear intent
  |
3 | if let Some(x) = opt { /* ... */}
  | ~~~~~~~~~~~~ ~~~

Explanation

Both Option and Result implement IntoIterator trait, which allows using them in a for loop. for loop over Option or Result will iterate either 0 (if the value is None/Err(_)) or 1 time (if the value is Some(_)/Ok(_)). This is not very useful and is more clearly expressed via if let.

for loop can also be accidentally written with the intention to call a function multiple times, while the function returns Some(_), in these cases while let loop should be used instead.

The "intended" use of IntoIterator implementations for Option and Result is passing them to generic code that expects something implementing IntoIterator. For example using .chain(option) to optionally add a value to an iterator.

forbidden-lint-groups

The forbidden_lint_groups lint detects violations of forbid applied to a lint group. Due to a bug in the compiler, these used to be overlooked entirely. They now generate a warning.

Example

#![forbid(warnings)]
#![deny(bad_style)]

fn main() {}

This will produce:

warning: deny(bad_style) incompatible with previous forbid
 --> lint_example.rs:2:9
  |
1 | #![forbid(warnings)]
  |           -------- `forbid` level set here
2 | #![deny(bad_style)]
  |         ^^^^^^^^^ overruled by previous forbid
  |
  = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
  = note: `#[warn(forbidden_lint_groups)]` on by default

If your crate is using #![forbid(warnings)], we recommend that you change to #![deny(warnings)].

Explanation

Due to a compiler bug, applying forbid to lint groups previously had no effect. The bug is now fixed but instead of enforcing forbid we issue this future-compatibility warning to avoid breaking existing crates.

forgetting-copy-types

The forgetting_copy_types lint checks for calls to std::mem::forget with a value that derives the Copy trait.

Example

let x: i32 = 42; // i32 implements Copy
std::mem::forget(x); // A copy of x is passed to the function, leaving the
                     // original unaffected

This will produce:

warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing
 --> lint_example.rs:3:1
  |
3 | std::mem::forget(x); // A copy of x is passed to the function, leaving the
  | ^^^^^^^^^^^^^^^^^-^
  |                  |
  |                  argument has type `i32`
  |
  = note: `#[warn(forgetting_copy_types)]` on by default
help: use `let _ = ...` to ignore the expression or result
  |
3 - std::mem::forget(x); // A copy of x is passed to the function, leaving the
3 + let _ = x; // A copy of x is passed to the function, leaving the
  |

Explanation

Calling std::mem::forget does nothing for types that implement Copy since the value will be copied and moved into the function on invocation.

An alternative, but also valid, explanation is that Copy types do not implement the Drop trait, which means they have no destructors. Without a destructor, there is nothing for std::mem::forget to ignore.

forgetting-references

The forgetting_references lint checks for calls to std::mem::forget with a reference instead of an owned value.

Example

let x = Box::new(1);
std::mem::forget(&x); // Should have been forget(x), x will still be dropped

This will produce:

warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing
 --> lint_example.rs:3:1
  |
3 | std::mem::forget(&x); // Should have been forget(x), x will still be dropped
  | ^^^^^^^^^^^^^^^^^--^
  |                  |
  |                  argument has type `&Box<i32>`
  |
  = note: `#[warn(forgetting_references)]` on by default
help: use `let _ = ...` to ignore the expression or result
  |
3 - std::mem::forget(&x); // Should have been forget(x), x will still be dropped
3 + let _ = &x; // Should have been forget(x), x will still be dropped
  |

Explanation

Calling forget on a reference will only forget the reference itself, which is a no-op. It will not forget the underlying referenced value, which is likely what was intended.

function-item-references

The function_item_references lint detects function references that are formatted with fmt::Pointer or transmuted.

Example

fn foo() { }

fn main() {
    println!("{:p}", &foo);
}

This will produce:

warning: taking a reference to a function item does not give a function pointer
 --> lint_example.rs:4:22
  |
4 |     println!("{:p}", &foo);
  |                      ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn()`
  |
  = note: `#[warn(function_item_references)]` on by default

Explanation

Taking a reference to a function may be mistaken as a way to obtain a pointer to that function. This can give unexpected results when formatting the reference as a pointer or transmuting it. This lint is issued when function references are formatted as pointers, passed as arguments bound by fmt::Pointer or transmuted.

hidden-glob-reexports

The hidden_glob_reexports lint detects cases where glob re-export items are shadowed by private items.

Example

#![deny(hidden_glob_reexports)]

pub mod upstream {
    mod inner { pub struct Foo {}; pub struct Bar {}; }
    pub use self::inner::*;
    struct Foo {} // private item shadows `inner::Foo`
}

// mod downstream {
//     fn test() {
//         let _ = crate::upstream::Foo; // inaccessible
//     }
// }

pub fn main() {}

This will produce:

error: private item shadows public glob re-export
 --> lint_example.rs:6:5
  |
6 |     struct Foo {} // private item shadows `inner::Foo`
  |     ^^^^^^^^^^^^^
  |
note: the name `Foo` in the type namespace is supposed to be publicly re-exported here
 --> lint_example.rs:5:13
  |
5 |     pub use self::inner::*;
  |             ^^^^^^^^^^^^^^
note: but the private item here shadows it
 --> lint_example.rs:6:5
  |
6 |     struct Foo {} // private item shadows `inner::Foo`
  |     ^^^^^^^^^^^^^
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(hidden_glob_reexports)]
  |         ^^^^^^^^^^^^^^^^^^^^^

Explanation

This was previously accepted without any errors or warnings but it could silently break a crate's downstream user code. If the struct Foo was added, dep::inner::Foo would silently become inaccessible and trigger a "struct Foo is private" visibility error at the downstream use site.

impl-trait-redundant-captures

The impl_trait_redundant_captures lint warns against cases where use of the precise capturing use<...> syntax is not needed.

In the 2024 edition, impl Traits will capture all lifetimes in scope. If precise-capturing use<...> syntax is used, and the set of parameters that are captures are equal to the set of parameters in scope, then the syntax is redundant, and can be removed.

Example

#![feature(lifetime_capture_rules_2024)]
#![deny(impl_trait_redundant_captures)]
fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }

This will produce:

error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
 --> lint_example.rs:4:28
  |
4 | fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
  |                            ^^^^^^^^^^^^^-------
  |                                         |
  |                                         help: remove the `use<...>` syntax
  |
note: the lint level is defined here
 --> lint_example.rs:2:9
  |
2 | #![deny(impl_trait_redundant_captures)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

To fix this, remove the use<'a>, since the lifetime is already captured since it is in scope.

improper-ctypes

The improper_ctypes lint detects incorrect use of types in foreign modules.

Example

extern "C" {
    static STATIC: String;
}

This will produce:

warning: `extern` block uses type `String`, which is not FFI-safe
 --> lint_example.rs:3:20
  |
3 |     static STATIC: String;
  |                    ^^^^^^ not FFI-safe
  |
  = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
  = note: this struct has unspecified layout
  = note: `#[warn(improper_ctypes)]` on by default

Explanation

The compiler has several checks to verify that types used in extern blocks are safe and follow certain rules to ensure proper compatibility with the foreign interfaces. This lint is issued when it detects a probable mistake in a definition. The lint usually should provide a description of the issue, along with possibly a hint on how to resolve it.

improper-ctypes-definitions

The improper_ctypes_definitions lint detects incorrect use of extern function definitions.

Example

#![allow(unused)]
pub extern "C" fn str_type(p: &str) { }

This will produce:

warning: `extern` fn uses type `str`, which is not FFI-safe
 --> lint_example.rs:3:31
  |
3 | pub extern "C" fn str_type(p: &str) { }
  |                               ^^^^ not FFI-safe
  |
  = help: consider using `*const u8` and a length instead
  = note: string slices have no C equivalent
  = note: `#[warn(improper_ctypes_definitions)]` on by default

Explanation

There are many parameter and return types that may be specified in an extern function that are not compatible with the given ABI. This lint is an alert that these types should not be used. The lint usually should provide a description of the issue, along with possibly a hint on how to resolve it.

incomplete-features

The incomplete_features lint detects unstable features enabled with the feature attribute that may function improperly in some or all cases.

Example

#![feature(generic_const_exprs)]

This will produce:

warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
 --> lint_example.rs:1:12
  |
1 | #![feature(generic_const_exprs)]
  |            ^^^^^^^^^^^^^^^^^^^
  |
  = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
  = note: `#[warn(incomplete_features)]` on by default

Explanation

Although it is encouraged for people to experiment with unstable features, some of them are known to be incomplete or faulty. This lint is a signal that the feature has not yet been finished, and you may experience problems with it.

inline-no-sanitize

The inline_no_sanitize lint detects incompatible use of #[inline(always)] and #[no_sanitize(...)].

Example

#![feature(no_sanitize)]

#[inline(always)]
#[no_sanitize(address)]
fn x() {}

fn main() {
    x()
}

This will produce:

warning: `no_sanitize` will have no effect after inlining
 --> lint_example.rs:4:1
  |
4 | #[no_sanitize(address)]
  | ^^^^^^^^^^^^^^^^^^^^^^^
  |
note: inlining requested here
 --> lint_example.rs:3:1
  |
3 | #[inline(always)]
  | ^^^^^^^^^^^^^^^^^
  = note: `#[warn(inline_no_sanitize)]` on by default

Explanation

The use of the #[inline(always)] attribute prevents the the #[no_sanitize(...)] attribute from working. Consider temporarily removing inline attribute.

internal-features

The internal_features lint detects unstable features enabled with the feature attribute that are internal to the compiler or standard library.

Example

#![feature(rustc_attrs)]

This will produce:

warning: the feature `rustc_attrs` is internal to the compiler or standard library
 --> lint_example.rs:1:12
  |
1 | #![feature(rustc_attrs)]
  |            ^^^^^^^^^^^
  |
  = note: using it is strongly discouraged
  = note: `#[warn(internal_features)]` on by default

Explanation

These features are an implementation detail of the compiler and standard library and are not supposed to be used in user code.

invalid-from-utf8

The invalid_from_utf8 lint checks for calls to std::str::from_utf8 and std::str::from_utf8_mut with a known invalid UTF-8 value.

Example

#[allow(unused)]
std::str::from_utf8(b"Ru\x82st");

This will produce:

warning: calls to `std::str::from_utf8` with a invalid literal always return an error
 --> lint_example.rs:3:1
  |
3 | std::str::from_utf8(b"Ru\x82st");
  | ^^^^^^^^^^^^^^^^^^^^-----------^
  |                     |
  |                     the literal was valid UTF-8 up to the 2 bytes
  |
  = note: `#[warn(invalid_from_utf8)]` on by default

Explanation

Trying to create such a str would always return an error as per documentation for std::str::from_utf8 and std::str::from_utf8_mut.

invalid-macro-export-arguments

The invalid_macro_export_arguments lint detects cases where #[macro_export] is being used with invalid arguments.

Example

#![deny(invalid_macro_export_arguments)]

#[macro_export(invalid_parameter)]
macro_rules! myMacro {
   () => {
        // [...]
   }
}

#[macro_export(too, many, items)]

This will produce:

error: `invalid_parameter` isn't a valid `#[macro_export]` argument
 --> lint_example.rs:4:16
  |
4 | #[macro_export(invalid_parameter)]
  |                ^^^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(invalid_macro_export_arguments)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

The only valid argument is #[macro_export(local_inner_macros)] or no argument (#[macro_export]). You can't have multiple arguments in a #[macro_export(..)], or mention arguments other than local_inner_macros.

invalid-nan-comparisons

The invalid_nan_comparisons lint checks comparison with f32::NAN or f64::NAN as one of the operand.

Example

let a = 2.3f32;
if a == f32::NAN {}

This will produce:

warning: incorrect NaN comparison, NaN cannot be directly compared to itself
 --> lint_example.rs:3:4
  |
3 | if a == f32::NAN {}
  |    ^^^^^^^^^^^^^
  |
  = note: `#[warn(invalid_nan_comparisons)]` on by default
help: use `f32::is_nan()` or `f64::is_nan()` instead
  |
3 - if a == f32::NAN {}
3 + if a.is_nan() {}
  |

Explanation

NaN does not compare meaningfully to anything – not even itself – so those comparisons are always false.

invalid-value

The invalid_value lint detects creating a value that is not valid, such as a null reference.

Example

#![allow(unused)]
unsafe {
    let x: &'static i32 = std::mem::zeroed();
}

This will produce:

warning: the type `&i32` does not permit zero-initialization
 --> lint_example.rs:4:27
  |
4 |     let x: &'static i32 = std::mem::zeroed();
  |                           ^^^^^^^^^^^^^^^^^^
  |                           |
  |                           this code causes undefined behavior when executed
  |                           help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: references must be non-null
  = note: `#[warn(invalid_value)]` on by default

Explanation

In some situations the compiler can detect that the code is creating an invalid value, which should be avoided.

In particular, this lint will check for improper use of mem::zeroed, mem::uninitialized, mem::transmute, and MaybeUninit::assume_init that can cause undefined behavior. The lint should provide extra information to indicate what the problem is and a possible solution.

irrefutable-let-patterns

The irrefutable_let_patterns lint detects irrefutable patterns in if lets, while lets, and if let guards.

Example

if let _ = 123 {
    println!("always runs!");
}

This will produce:

warning: irrefutable `if let` pattern
 --> lint_example.rs:2:4
  |
2 | if let _ = 123 {
  |    ^^^^^^^^^^^
  |
  = note: this pattern will always match, so the `if let` is useless
  = help: consider replacing the `if let` with a `let`
  = note: `#[warn(irrefutable_let_patterns)]` on by default

Explanation

There usually isn't a reason to have an irrefutable pattern in an if let or while let statement, because the pattern will always match successfully. A let or loop statement will suffice. However, when generating code with a macro, forbidding irrefutable patterns would require awkward workarounds in situations where the macro doesn't know if the pattern is refutable or not. This lint allows macros to accept this form, while alerting for a possibly incorrect use in normal code.

See RFC 2086 for more details.

large-assignments

The large_assignments lint detects when objects of large types are being moved around.

Example

let x = [0; 50000];
let y = x;

produces:

warning: moving a large value
  --> $DIR/move-large.rs:1:3
  let y = x;
          - Copied large value here

Explanation

When using a large type in a plain assignment or in a function argument, idiomatic code can be inefficient. Ideally appropriate optimizations would resolve this, but such optimizations are only done in a best-effort manner. This lint will trigger on all sites of large moves and thus allow the user to resolve them in code.

late-bound-lifetime-arguments

The late_bound_lifetime_arguments lint detects generic lifetime arguments in path segments with late bound lifetime parameters.

Example

struct S;

impl S {
    fn late(self, _: &u8, _: &u8) {}
}

fn main() {
    S.late::<'static>(&0, &0);
}

This will produce:

warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
 --> lint_example.rs:8:14
  |
4 |     fn late(self, _: &u8, _: &u8) {}
  |                      - the late bound lifetime parameter is introduced here
...
8 |     S.late::<'static>(&0, &0);
  |              ^^^^^^^
  |
  = 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 #42868 <https://github.com/rust-lang/rust/issues/42868>
  = note: `#[warn(late_bound_lifetime_arguments)]` on by default

Explanation

It is not clear how to provide arguments for early-bound lifetime parameters if they are intermixed with late-bound parameters in the same list. For now, providing any explicit arguments will trigger this lint if late-bound parameters are present, so in the future a solution can be adopted without hitting backward compatibility issues. This is a future-incompatible lint to transition this to a hard error in the future. See issue #42868 for more details, along with a description of the difference between early and late-bound parameters.

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 */ }

map-unit-fn

The map_unit_fn lint checks for Iterator::map receive a callable that returns ().

Example

fn foo(items: &mut Vec<u8>) {
    items.sort();
}

fn main() {
    let mut x: Vec<Vec<u8>> = vec![
        vec![0, 2, 1],
        vec![5, 4, 3],
    ];
    x.iter_mut().map(foo);
}

This will produce:

warning: `Iterator::map` call that discard the iterator's values
  --> lint_example.rs:10:18
   |
1  | fn foo(items: &mut Vec<u8>) {
   | --------------------------- this function returns `()`, which is likely not what you wanted
...
10 |     x.iter_mut().map(foo);
   |                  ^^^^---^
   |                  |   |
   |                  |   called `Iterator::map` with callable that returns `()`
   |                  after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
   |
   = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
   = note: `#[warn(map_unit_fn)]` on by default
help: you might have meant to use `Iterator::for_each`
   |
10 |     x.iter_mut().for_each(foo);
   |                  ~~~~~~~~

Explanation

Mapping to () is almost always a mistake.

mixed-script-confusables

The mixed_script_confusables lint detects visually confusable characters in identifiers between different scripts.

Example

// The Japanese katakana character エ can be confused with the Han character 工.
const エ: &'static str = "アイウ";

This will produce:

warning: the usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables
 --> lint_example.rs:3:7
  |
3 | const エ: &'static str = "アイウ";
  |       ^^
  |
  = note: the usage includes 'エ' (U+30A8)
  = note: please recheck to make sure their usages are indeed what you want
  = note: `#[warn(mixed_script_confusables)]` on by default

Explanation

This lint warns when characters between different scripts may appear visually similar, which can cause confusion.

If the crate contains other identifiers in the same script that have non-confusable characters, then this lint will not be issued. For example, if the example given above has another identifier with katakana characters (such as let カタカナ = 123;), then this indicates that you are intentionally using katakana, and it will not warn about it.

Note that the set of confusable characters may change over time. Beware that if you "forbid" this lint that existing code may fail in the future.

named-arguments-used-positionally

The named_arguments_used_positionally lint detects cases where named arguments are only used positionally in format strings. This usage is valid but potentially very confusing.

Example

#![deny(named_arguments_used_positionally)]
fn main() {
    let _x = 5;
    println!("{}", _x = 1); // Prints 1, will trigger lint

    println!("{}", _x); // Prints 5, no lint emitted
    println!("{_x}", _x = _x); // Prints 5, no lint emitted
}

This will produce:

error: named argument `_x` is not used by name
 --> lint_example.rs:4:20
  |
4 |     println!("{}", _x = 1); // Prints 1, will trigger lint
  |               --   ^^ this named argument is referred to by position in formatting string
  |               |
  |               this formatting argument uses named argument `_x` by position
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(named_arguments_used_positionally)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use the named argument by name to avoid ambiguity
  |
4 |     println!("{_x}", _x = 1); // Prints 1, will trigger lint
  |                ++

Explanation

Rust formatting strings can refer to named arguments by their position, but this usage is potentially confusing. In particular, readers can incorrectly assume that the declaration of named arguments is an assignment (which would produce the unit type). For backwards compatibility, this is not a hard error.

never-type-fallback-flowing-into-unsafe

The never_type_fallback_flowing_into_unsafe lint detects cases where never type fallback affects unsafe function calls.

Never type fallback

When the compiler sees a value of type ! it implicitly inserts a coercion (if possible), to allow type check to infer any type:

// this
let x: u8 = panic!();

// is (essentially) turned by the compiler into
let x: u8 = absurd(panic!());

// where absurd is a function with the following signature
// (it's sound, because `!` always marks unreachable code):
fn absurd<T>(never: !) -> T { ... }

While it's convenient to be able to use non-diverging code in one of the branches (like if a { b } else { return }) this could lead to compilation errors:

// this
{ panic!() };

// gets turned into this
{ absurd(panic!()) }; // error: can't infer the type of `absurd`

To prevent such errors, compiler remembers where it inserted absurd calls, and if it can't infer their type, it sets the type to fallback. { absurd::<Fallback>(panic!()) };. This is what is known as "never type fallback".

Example

#![deny(never_type_fallback_flowing_into_unsafe)]
fn main() {
    if true {
        // return has type `!` which, is some cases, causes never type fallback
        return
    } else {
        // `zeroed` is an unsafe function, which returns an unbounded type
        unsafe { std::mem::zeroed() }
    };
    // depending on the fallback, `zeroed` may create `()` (which is completely sound),
    // or `!` (which is instant undefined behavior)
}

This will produce:

error: never type fallback affects this call to an `unsafe` function
 --> lint_example.rs:8:18
  |
8 |         unsafe { std::mem::zeroed() }
  |                  ^^^^^^^^^^^^^^^^^^
  |
  = warning: this will change its meaning in a future release!
  = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
  = help: specify the type explicitly
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(never_type_fallback_flowing_into_unsafe)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

Due to historic reasons never type fallback was (), meaning that ! got spontaneously coerced to (). There are plans to change that, but they may make the code such as above unsound. Instead of depending on the fallback, you should specify the type explicitly:

if true {
    return
} else {
    // type is explicitly specified, fallback can't hurt us no more
    unsafe { std::mem::zeroed::<()>() }
};

See Tracking Issue for making ! fall back to !.

no-mangle-generic-items

The no_mangle_generic_items lint detects generic items that must be mangled.

Example

#[no_mangle]
fn foo<T>(t: T) {

}

This will produce:

warning: functions generic over types or consts must be mangled
 --> lint_example.rs:3:1
  |
2 |   #[no_mangle]
  |   ------------ help: remove this attribute
3 | / fn foo<T>(t: T) {
4 | |
5 | | }
  | |_^
  |
  = note: `#[warn(no_mangle_generic_items)]` on by default

Explanation

A function with generics must have its symbol mangled to accommodate the generic parameter. The no_mangle attribute has no effect in this situation, and should be removed.

non-fmt-panic

The lint non-fmt-panic has been renamed to non-fmt-panics.

non-camel-case-types

The non_camel_case_types lint detects types, variants, traits and type parameters that don't have camel case names.

Example

struct my_struct;

This will produce:

warning: type `my_struct` should have an upper camel case name
 --> lint_example.rs:2:8
  |
2 | struct my_struct;
  |        ^^^^^^^^^ help: convert the identifier to upper camel case: `MyStruct`
  |
  = note: `#[warn(non_camel_case_types)]` on by default

Explanation

The preferred style for these identifiers is to use "camel case", such as MyStruct, where the first letter should not be lowercase, and should not use underscores between letters. Underscores are allowed at the beginning and end of the identifier, as well as between non-letters (such as X86_64).

non-contiguous-range-endpoints

The non_contiguous_range_endpoints lint detects likely off-by-one errors when using exclusive range patterns.

Example

let x = 123u32;
match x {
    0..100 => { println!("small"); }
    101..1000 => { println!("large"); }
    _ => { println!("larger"); }
}

This will produce:

warning: multiple ranges are one apart
 --> lint_example.rs:4:5
  |
4 |     0..100 => { println!("small"); }
  |     ^^^^^^
  |     |
  |     this range doesn't match `100_u32` because `..` is an exclusive range
  |     help: use an inclusive range instead: `0_u32..=100_u32`
5 |     101..1000 => { println!("large"); }
  |     --------- this could appear to continue range `0_u32..100_u32`, but `100_u32` isn't matched by either of them
  |
  = note: `#[warn(non_contiguous_range_endpoints)]` on by default

Explanation

It is likely a mistake to have range patterns in a match expression that miss out a single number. Check that the beginning and end values are what you expect, and keep in mind that with ..= the right bound is inclusive, and with .. it is exclusive.

non-fmt-panics

The non_fmt_panics lint detects panic!(..) invocations where the first argument is not a formatting string.

Example

panic!("{}");
panic!(123);

This will produce:

warning: panic message contains an unused formatting placeholder
 --> lint_example.rs:2:9
  |
2 | panic!("{}");
  |         ^^
  |
  = note: this message is not used as a format string when given without arguments, but will be in Rust 2021
  = note: `#[warn(non_fmt_panics)]` on by default
help: add the missing argument
  |
2 | panic!("{}", ...);
  |            +++++
help: or add a "{}" format string to use the message literally
  |
2 | panic!("{}", "{}");
  |        +++++


warning: panic message is not a string literal
 --> lint_example.rs:3:8
  |
3 | panic!(123);
  |        ^^^
  |
  = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to `Display` the message
  |
3 | panic!("{}", 123);
  |        +++++
help: or use std::panic::panic_any instead
  |
3 | std::panic::panic_any(123);
  | ~~~~~~~~~~~~~~~~~~~~~

Explanation

In Rust 2018 and earlier, panic!(x) directly uses x as the message. That means that panic!("{}") panics with the message "{}" instead of using it as a formatting string, and panic!(123) will panic with an i32 as message.

Rust 2021 always interprets the first argument as format string.

non-local-definitions

The non_local_definitions lint checks for impl blocks and #[macro_export] macro inside bodies (functions, enum discriminant, ...).

Example

#![warn(non_local_definitions)]
trait MyTrait {}
struct MyStruct;

fn foo() {
    impl MyTrait for MyStruct {}
}

This will produce:

warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
 --> lint_example.rs:7:5
  |
6 | fn foo() {
  | -------- move the `impl` block outside of this function `foo` and up 2 bodies
7 |     impl MyTrait for MyStruct {}
  |     ^^^^^-------^^^^^--------
  |          |           |
  |          |           `MyStruct` is not local
  |          `MyTrait` is not local
  |
  = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![warn(non_local_definitions)]
  |         ^^^^^^^^^^^^^^^^^^^^^

Explanation

Creating non-local definitions go against expectation and can create discrepancies in tooling. It should be avoided. It may become deny-by-default in edition 2024 and higher, see the tracking issue https://github.com/rust-lang/rust/issues/120363.

An impl definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the impl block.

All nested bodies (functions, enum discriminant, array length, consts) (expect for const _: Ty = { ... } in top-level module, which is still undecided) are checked.

non-shorthand-field-patterns

The non_shorthand_field_patterns lint detects using Struct { x: x } instead of Struct { x } in a pattern.

Example

struct Point {
    x: i32,
    y: i32,
}


fn main() {
    let p = Point {
        x: 5,
        y: 5,
    };

    match p {
        Point { x: x, y: y } => (),
    }
}

This will produce:

warning: the `x:` in this pattern is redundant
  --> lint_example.rs:14:17
   |
14 |         Point { x: x, y: y } => (),
   |                 ^^^^ help: use shorthand field pattern: `x`
   |
   = note: `#[warn(non_shorthand_field_patterns)]` on by default


warning: the `y:` in this pattern is redundant
  --> lint_example.rs:14:23
   |
14 |         Point { x: x, y: y } => (),
   |                       ^^^^ help: use shorthand field pattern: `y`

Explanation

The preferred style is to avoid the repetition of specifying both the field name and the binding name if both identifiers are the same.

non-snake-case

The non_snake_case lint detects variables, methods, functions, lifetime parameters and modules that don't have snake case names.

Example

let MY_VALUE = 5;

This will produce:

warning: variable `MY_VALUE` should have a snake case name
 --> lint_example.rs:2:5
  |
2 | let MY_VALUE = 5;
  |     ^^^^^^^^ help: convert the identifier to snake case: `my_value`
  |
  = note: `#[warn(non_snake_case)]` on by default

Explanation

The preferred style for these identifiers is to use "snake case", where all the characters are in lowercase, with words separated with a single underscore, such as my_value.

non-upper-case-globals

The non_upper_case_globals lint detects static items that don't have uppercase identifiers.

Example

static max_points: i32 = 5;

This will produce:

warning: static variable `max_points` should have an upper case name
 --> lint_example.rs:2:8
  |
2 | static max_points: i32 = 5;
  |        ^^^^^^^^^^ help: convert the identifier to upper case: `MAX_POINTS`
  |
  = note: `#[warn(non_upper_case_globals)]` on by default

Explanation

The preferred style is for static item names to use all uppercase letters such as MAX_POINTS.

noop-method-call

The noop_method_call lint detects specific calls to noop methods such as a calling <&T as Clone>::clone where T: !Clone.

Example

#![allow(unused)]
struct Foo;
let foo = &Foo;
let clone: &Foo = foo.clone();

This will produce:

warning: call to `.clone()` on a reference in this situation does nothing
 --> lint_example.rs:5:22
  |
5 | let clone: &Foo = foo.clone();
  |                      ^^^^^^^^
  |
  = note: the type `Foo` does not implement `Clone`, so calling `clone` on `&Foo` copies the reference, which does not do anything and can be removed
  = note: `#[warn(noop_method_call)]` on by default
help: remove this redundant call
  |
5 - let clone: &Foo = foo.clone();
5 + let clone: &Foo = foo;
  |
help: if you meant to clone `Foo`, implement `Clone` for it
  |
3 + #[derive(Clone)]
4 | struct Foo;
  |

Explanation

Some method calls are noops meaning that they do nothing. Usually such methods are the result of blanket implementations that happen to create some method invocations that end up not doing anything. For instance, Clone is implemented on all &T, but calling clone on a &T where T does not implement clone, actually doesn't do anything as references are copy. This lint detects these calls and warns the user about them.

opaque-hidden-inferred-bound

The opaque_hidden_inferred_bound lint detects cases in which nested impl Trait in associated type bounds are not written generally enough to satisfy the bounds of the associated type.

Explanation

This functionality was removed in #97346, but then rolled back in #99860 because it caused regressions.

We plan on reintroducing this as a hard error, but in the meantime, this lint serves to warn and suggest fixes for any use-cases which rely on this behavior.

Example

#![feature(type_alias_impl_trait)]

trait Duh {}

impl Duh for i32 {}

trait Trait {
    type Assoc: Duh;
}

impl<F: Duh> Trait for F {
    type Assoc = F;
}

type Tait = impl Sized;

fn test() -> impl Trait<Assoc = Tait> {
    42
}

fn main() {}

This will produce:

warning: opaque type `impl Trait<Assoc = Tait>` does not satisfy its associated type bounds
  --> lint_example.rs:17:25
   |
8  |     type Assoc: Duh;
   |                 --- this associated type bound is unsatisfied for `Tait`
...
17 | fn test() -> impl Trait<Assoc = Tait> {
   |                         ^^^^^^^^^^^^
   |
   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default

In this example, test declares that the associated type Assoc for impl Trait is impl Sized, which does not satisfy the bound Duh on the associated type.

Although the hidden type, i32 does satisfy this bound, we do not consider the return type to be well-formed with this lint. It can be fixed by changing Tait = impl Sized into Tait = impl Sized + Duh.

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:

warning: cannot find macro `in_root` in this scope
 --> lint_example.rs:1:10
  |
1 | #![doc = in_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: `#[warn(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.

overlapping-patterns

The lint overlapping-patterns has been renamed to overlapping-range-endpoints.

overlapping-range-endpoints

The overlapping_range_endpoints lint detects match arms that have range patterns that overlap on their endpoints.

Example

let x = 123u8;
match x {
    0..=100 => { println!("small"); }
    100..=255 => { println!("large"); }
}

This will produce:

warning: multiple patterns overlap on their endpoints
 --> lint_example.rs:5:5
  |
4 |     0..=100 => { println!("small"); }
  |     ------- this range overlaps on `100_u8`...
5 |     100..=255 => { println!("large"); }
  |     ^^^^^^^^^ ... with this range
  |
  = note: you likely meant to write mutually exclusive ranges
  = note: `#[warn(overlapping_range_endpoints)]` on by default

Explanation

It is likely a mistake to have range patterns in a match expression that overlap in this way. Check that the beginning and end values are what you expect, and keep in mind that with ..= the left and right bounds are inclusive.

path-statements

The path_statements lint detects path statements with no effect.

Example

let x = 42;

x;

This will produce:

warning: path statement with no effect
 --> lint_example.rs:4:1
  |
4 | x;
  | ^^
  |
  = note: `#[warn(path_statements)]` on by default

Explanation

It is usually a mistake to have a statement that has no effect.

private-bounds

The private_bounds lint detects types in a secondary interface of an item, that are more private than the item itself. Secondary interface of an item consists of bounds on generic parameters and where clauses, including supertraits for trait items.

Example

#![allow(unused)]
#![deny(private_bounds)]

struct PrivTy;
pub struct S
    where PrivTy:
{}
fn main() {}

This will produce:

error: type `PrivTy` is more private than the item `S`
 --> lint_example.rs:5:1
  |
5 | pub struct S
  | ^^^^^^^^^^^^ struct `S` is reachable at visibility `pub`
  |
note: but type `PrivTy` is only usable at visibility `pub(crate)`
 --> lint_example.rs:4:1
  |
4 | struct PrivTy;
  | ^^^^^^^^^^^^^
note: the lint level is defined here
 --> lint_example.rs:2:9
  |
2 | #![deny(private_bounds)]
  |         ^^^^^^^^^^^^^^

Explanation

Having private types or traits in item bounds makes it less clear what interface the item actually provides.

private-interfaces

The private_interfaces lint detects types in a primary interface of an item, that are more private than the item itself. Primary interface of an item is all its interface except for bounds on generic parameters and where clauses.

Example

#![allow(unused)]
#![deny(private_interfaces)]
struct SemiPriv;

mod m1 {
    struct Priv;
    impl crate::SemiPriv {
        pub fn f(_: Priv) {}
    }
}

fn main() {}

This will produce:

error: type `Priv` is more private than the item `m1::<impl SemiPriv>::f`
 --> lint_example.rs:8:9
  |
8 |         pub fn f(_: Priv) {}
  |         ^^^^^^^^^^^^^^^^^ associated function `m1::<impl SemiPriv>::f` is reachable at visibility `pub(crate)`
  |
note: but type `Priv` is only usable at visibility `pub(self)`
 --> lint_example.rs:6:5
  |
6 |     struct Priv;
  |     ^^^^^^^^^^^
note: the lint level is defined here
 --> lint_example.rs:2:9
  |
2 | #![deny(private_interfaces)]
  |         ^^^^^^^^^^^^^^^^^^

Explanation

Having something private in primary interface guarantees that the item will be unusable from outer modules due to type privacy.

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.

ptr-cast-add-auto-to-object

The ptr_cast_add_auto_to_object lint detects casts of raw pointers to trait objects, which add auto traits.

Example

let ptr: *const dyn core::any::Any = &();
_ = ptr as *const dyn core::any::Any + Send;

This will produce:

warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
 --> lint_example.rs:3:5
  |
3 | _ = ptr as *const dyn core::any::Any + Send;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = 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 #127323 <https://github.com/rust-lang/rust/issues/127323>
  = note: `#[warn(ptr_cast_add_auto_to_object)]` on by default

Explanation

Adding an auto trait can make the vtable invalid, potentially causing UB in safe code afterwards. For example:

#![feature(arbitrary_self_types)]

trait Trait {
    fn f(self: *const Self)
    where
        Self: Send;
}

impl Trait for *const () {
    fn f(self: *const Self) {
        unreachable!()
    }
}

fn main() {
    let unsend: *const () = &();
    let unsend: *const dyn Trait = &unsend;
    let send_bad: *const (dyn Trait + Send) = unsend as _;
    send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f`
}

Generally you must ensure that vtable is right for the pointer's type, before passing the pointer to safe code.

ptr-to-integer-transmute-in-consts

The ptr_to_integer_transmute_in_consts lint detects pointer to integer transmute in const functions and associated constants.

Example

const fn foo(ptr: *const u8) -> usize {
   unsafe {
       std::mem::transmute::<*const u8, usize>(ptr)
   }
}

This will produce:

warning: pointers cannot be transmuted to integers during const eval
 --> lint_example.rs:4:8
  |
4 |        std::mem::transmute::<*const u8, usize>(ptr)
  |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: at compile-time, pointers do not have an integer value
  = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
  = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
  = note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default

Explanation

Transmuting pointers to integers in a const context is undefined behavior. Any attempt to use the resulting integer will abort const-evaluation.

But sometimes the compiler might not emit an error for pointer to integer transmutes inside const functions and associated consts because they are evaluated only when referenced. Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior from compiling without any warnings or errors.

See std::mem::transmute in the reference for more details.

redundant-semicolon

The lint redundant-semicolon has been renamed to redundant-semicolons.

redundant-semicolons

The redundant_semicolons lint detects unnecessary trailing semicolons.

Example

let _ = 123;;

This will produce:

warning: unnecessary trailing semicolon
 --> lint_example.rs:2:13
  |
2 | let _ = 123;;
  |             ^ help: remove this semicolon
  |
  = note: `#[warn(redundant_semicolons)]` on by default

Explanation

Extra semicolons are not needed, and may be removed to avoid confusion and visual clutter.

refining-impl-trait-internal

The refining_impl_trait_internal lint detects impl Trait return types in method signatures that are refined by a trait implementation, meaning the implementation adds information about the return type that is not present in the trait.

Example

#![deny(refining_impl_trait)]

use std::fmt::Display;

trait AsDisplay {
    fn as_display(&self) -> impl Display;
}

impl<'s> AsDisplay for &'s str {
    fn as_display(&self) -> Self {
        *self
    }
}

fn main() {
    // users can observe that the return type of
    // `<&str as AsDisplay>::as_display()` is `&str`.
    let _x: &str = "".as_display();
}

This will produce:

error: impl trait in impl method signature does not match trait method signature
  --> lint_example.rs:10:29
   |
6  |     fn as_display(&self) -> impl Display;
   |                             ------------ return type from trait method defined here
...
10 |     fn as_display(&self) -> Self {
   |                             ^^^^
   |
   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(refining_impl_trait)]
   |         ^^^^^^^^^^^^^^^^^^^
   = note: `#[deny(refining_impl_trait_internal)]` implied by `#[deny(refining_impl_trait)]`
help: replace the return type so that it matches the trait
   |
10 |     fn as_display(&self) -> impl std::fmt::Display {
   |                             ~~~~~~~~~~~~~~~~~~~~~~

Explanation

Callers of methods for types where the implementation is known are able to observe the types written in the impl signature. This may be intended behavior, but may also lead to implementation details being revealed unintentionally. In particular, it may pose a semver hazard for authors of libraries who do not wish to make stronger guarantees about the types than what is written in the trait signature.

refining_impl_trait is a lint group composed of two lints:

  • refining_impl_trait_reachable, for refinements that are publically reachable outside a crate, and
  • refining_impl_trait_internal, for refinements that are only visible within a crate.

We are seeking feedback on each of these lints; see issue #121718 for more information.

refining-impl-trait-reachable

The refining_impl_trait_reachable lint detects impl Trait return types in method signatures that are refined by a publically reachable trait implementation, meaning the implementation adds information about the return type that is not present in the trait.

Example

#![deny(refining_impl_trait)]

use std::fmt::Display;

pub trait AsDisplay {
    fn as_display(&self) -> impl Display;
}

impl<'s> AsDisplay for &'s str {
    fn as_display(&self) -> Self {
        *self
    }
}

fn main() {
    // users can observe that the return type of
    // `<&str as AsDisplay>::as_display()` is `&str`.
    let _x: &str = "".as_display();
}

This will produce:

error: impl trait in impl method signature does not match trait method signature
  --> lint_example.rs:10:29
   |
6  |     fn as_display(&self) -> impl Display;
   |                             ------------ return type from trait method defined here
...
10 |     fn as_display(&self) -> Self {
   |                             ^^^^
   |
   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(refining_impl_trait)]
   |         ^^^^^^^^^^^^^^^^^^^
   = note: `#[deny(refining_impl_trait_reachable)]` implied by `#[deny(refining_impl_trait)]`
help: replace the return type so that it matches the trait
   |
10 |     fn as_display(&self) -> impl std::fmt::Display {
   |                             ~~~~~~~~~~~~~~~~~~~~~~

Explanation

Callers of methods for types where the implementation is known are able to observe the types written in the impl signature. This may be intended behavior, but may also lead to implementation details being revealed unintentionally. In particular, it may pose a semver hazard for authors of libraries who do not wish to make stronger guarantees about the types than what is written in the trait signature.

refining_impl_trait is a lint group composed of two lints:

  • refining_impl_trait_reachable, for refinements that are publically reachable outside a crate, and
  • refining_impl_trait_internal, for refinements that are only visible within a crate.

We are seeking feedback on each of these lints; see issue #121718 for more information.

renamed-and-removed-lints

The renamed_and_removed_lints lint detects lints that have been renamed or removed.

Example

#![deny(raw_pointer_derive)]

This will produce:

warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
 --> lint_example.rs:1:9
  |
1 | #![deny(raw_pointer_derive)]
  |         ^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(renamed_and_removed_lints)]` on by default

Explanation

To fix this, either remove the lint or use the new name. This can help avoid confusion about lints that are no longer valid, and help maintain consistency for renamed lints.

repr-transparent-external-private-fields

The repr_transparent_external_private_fields lint detects types marked #[repr(transparent)] that (transitively) contain an external ZST type marked #[non_exhaustive] or containing private fields

Example

#![deny(repr_transparent_external_private_fields)]
use foo::NonExhaustiveZst;

#[repr(transparent)]
struct Bar(u32, ([u32; 0], NonExhaustiveZst));

This will produce:

error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
 --> src/main.rs:5:28
  |
5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst));
  |                            ^^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> src/main.rs:1:9
  |
1 | #![deny(repr_transparent_external_private_fields)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
  = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

Explanation

Previous, Rust accepted fields that contain external private zero-sized types, even though it should not be a breaking change to add a non-zero-sized field to that private type.

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

self-constructor-from-outer-item

The self_constructor_from_outer_item lint detects cases where the Self constructor was silently allowed due to a bug in the resolver, and which may produce surprising and unintended behavior.

Using a Self type alias from an outer item was never intended, but was silently allowed. This is deprecated -- and is a hard error when the Self type alias references generics that are not in scope.

Example

#![deny(self_constructor_from_outer_item)]

struct S0(usize);

impl S0 {
    fn foo() {
        const C: S0 = Self(0);
        fn bar() -> S0 {
            Self(0)
        }
    }
}

This will produce:

error: can't reference `Self` constructor from outer item
 --> lint_example.rs:8:23
  |
6 | impl S0 {
  | ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
7 |     fn foo() {
8 |         const C: S0 = Self(0);
  |                       ^^^^ help: replace `Self` with the actual type: `S0`
  |
  = 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 #124186 <https://github.com/rust-lang/rust/issues/124186>
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(self_constructor_from_outer_item)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


error: can't reference `Self` constructor from outer item
  --> lint_example.rs:10:13
   |
6  | impl S0 {
   | ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
...
10 |             Self(0)
   |             ^^^^ help: replace `Self` with the actual type: `S0`
   |
   = 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 #124186 <https://github.com/rust-lang/rust/issues/124186>

Explanation

The Self type alias should not be reachable because nested items are not associated with the scope of the parameters from the parent item.

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.

special-module-name

The special_module_name lint detects module declarations for files that have a special meaning.

Example

mod lib;

fn main() {
    lib::run();
}

This will produce:

warning: found module declaration for lib.rs
 --> lint_example.rs:1:1
  |
1 | mod lib;
  | ^^^^^^^^
  |
  = note: lib.rs is the root of this crate's library target
  = help: to refer to it from other targets, use the library's name as the path
  = note: `#[warn(special_module_name)]` on by default

Explanation

Cargo recognizes lib.rs and main.rs as the root of a library or binary crate, so declaring them as modules will lead to miscompilation of the crate unless configured explicitly.

To access a library from a binary target within the same crate, use your_crate_name:: as the path instead of lib:::

// bar/src/lib.rs
fn run() {
    // ...
}

// bar/src/main.rs
fn main() {
    bar::run();
}

Binary targets cannot be used as libraries and so declaring one as a module is not allowed.

stable-features

The stable_features lint detects a feature attribute that has since been made stable.

Example

#![feature(test_accepted_feature)]
fn main() {}

This will produce:

warning: the feature `test_accepted_feature` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> lint_example.rs:1:12
  |
1 | #![feature(test_accepted_feature)]
  |            ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(stable_features)]` on by default

Explanation

When a feature is stabilized, it is no longer necessary to include a #![feature] attribute for it. To fix, simply remove the #![feature] attribute.

static-mut-ref

The lint static-mut-ref has been renamed to static-mut-refs.

static-mut-refs

The static_mut_refs lint checks for shared or mutable references of mutable static inside unsafe blocks and unsafe functions.

Example

fn main() {
    static mut X: i32 = 23;
    static mut Y: i32 = 24;

    unsafe {
        let y = &X;
        let ref x = X;
        let (x, y) = (&X, &Y);
        foo(&X);
    }
}

unsafe fn _foo() {
    static mut X: i32 = 23;
    static mut Y: i32 = 24;

    let y = &X;
    let ref x = X;
    let (x, y) = (&X, &Y);
    foo(&X);
}

fn foo<'a>(_x: &'a i32) {}

This will produce:

warning: creating a shared reference to mutable static is discouraged
 --> lint_example.rs:6:17
  |
6 |         let y = &X;
  |                 ^^ shared reference to mutable static
  |
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
  = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
  = note: `#[warn(static_mut_refs)]` on by default
help: use `&raw const` instead to create a raw pointer
  |
6 |         let y = &raw const X;
  |                 ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
 --> lint_example.rs:7:21
  |
7 |         let ref x = X;
  |                     ^ shared reference to mutable static
  |
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
  = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives


warning: creating a shared reference to mutable static is discouraged
 --> lint_example.rs:8:23
  |
8 |         let (x, y) = (&X, &Y);
  |                       ^^ shared reference to mutable static
  |
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
  = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
  |
8 |         let (x, y) = (&raw const X, &Y);
  |                       ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
 --> lint_example.rs:8:27
  |
8 |         let (x, y) = (&X, &Y);
  |                           ^^ shared reference to mutable static
  |
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
  = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
  |
8 |         let (x, y) = (&X, &raw const Y);
  |                           ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
 --> lint_example.rs:9:13
  |
9 |         foo(&X);
  |             ^^ shared reference to mutable static
  |
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
  = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
  |
9 |         foo(&raw const X);
  |             ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
  --> lint_example.rs:17:13
   |
17 |     let y = &X;
   |             ^^ shared reference to mutable static
   |
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
   = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
   |
17 |     let y = &raw const X;
   |             ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
  --> lint_example.rs:18:17
   |
18 |     let ref x = X;
   |                 ^ shared reference to mutable static
   |
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
   = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives


warning: creating a shared reference to mutable static is discouraged
  --> lint_example.rs:19:19
   |
19 |     let (x, y) = (&X, &Y);
   |                   ^^ shared reference to mutable static
   |
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
   = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
   |
19 |     let (x, y) = (&raw const X, &Y);
   |                   ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
  --> lint_example.rs:19:23
   |
19 |     let (x, y) = (&X, &Y);
   |                       ^^ shared reference to mutable static
   |
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
   = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
   |
19 |     let (x, y) = (&X, &raw const Y);
   |                       ~~~~~~~~~~


warning: creating a shared reference to mutable static is discouraged
  --> lint_example.rs:20:9
   |
20 |     foo(&X);
   |         ^^ shared reference to mutable static
   |
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
   = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
help: use `&raw const` instead to create a raw pointer
   |
20 |     foo(&raw const X);
   |         ~~~~~~~~~~

Explanation

Shared or mutable references of mutable static are almost always a mistake and can lead to undefined behavior and various other problems in your code.

This lint is "warn" by default on editions up to 2021, in 2024 is "deny".

suspicious-double-ref-op

The suspicious_double_ref_op lint checks for usage of .clone()/.borrow()/.deref() on an &&T when T: !Deref/Borrow/Clone, which means the call will return the inner &T, instead of performing the operation on the underlying T and can be confusing.

Example

#![allow(unused)]
struct Foo;
let foo = &&Foo;
let clone: &Foo = foo.clone();

This will produce:

warning: using `.clone()` on a double reference, which returns `&Foo` instead of cloning the inner type
 --> lint_example.rs:5:22
  |
5 | let clone: &Foo = foo.clone();
  |                      ^^^^^^^^
  |
  = note: `#[warn(suspicious_double_ref_op)]` on by default

Explanation

Since Foo doesn't implement Clone, running .clone() only dereferences the double reference, instead of cloning the inner type which should be what was intended.

temporary-cstring-as-ptr

The temporary_cstring_as_ptr lint detects getting the inner pointer of a temporary CString.

Example

#![allow(unused)]
use std::ffi::CString;
let c_str = CString::new("foo").unwrap().as_ptr();

This will produce:

warning: getting the inner pointer of a temporary `CString`
 --> lint_example.rs:4:42
  |
4 | let c_str = CString::new("foo").unwrap().as_ptr();
  |             ---------------------------- ^^^^^^ this pointer will be invalid
  |             |
  |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
  |
  = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
  = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
  = note: `#[warn(temporary_cstring_as_ptr)]` on by default

Explanation

The inner pointer of a CString lives only as long as the CString it points to. Getting the inner pointer of a temporary CString allows the CString to be dropped at the end of the statement, as it is not being referenced as far as the typesystem is concerned. This means outside of the statement the pointer will point to freed memory, which causes undefined behavior if the pointer is later dereferenced.

trivial-bounds

The trivial_bounds lint detects trait bounds that don't depend on any type parameters.

Example

#![feature(trivial_bounds)]
pub struct A where i32: Copy;

This will produce:

warning: trait bound i32: Copy does not depend on any type or lifetime parameters
 --> lint_example.rs:3:25
  |
3 | pub struct A where i32: Copy;
  |                         ^^^^
  |
  = note: `#[warn(trivial_bounds)]` on by default

Explanation

Usually you would not write a trait bound that you know is always true, or never true. However, when using macros, the macro may not know whether or not the constraint would hold or not at the time when generating the code. Currently, the compiler does not alert you if the constraint is always true, and generates an error if it is never true. The trivial_bounds feature changes this to be a warning in both cases, giving macros more freedom and flexibility to generate code, while still providing a signal when writing non-macro code that something is amiss.

See RFC 2056 for more details. This feature is currently only available on the nightly channel, see tracking issue #48214.

type-alias-bounds

The type_alias_bounds lint detects bounds in type aliases.

Example

type SendVec<T: Send> = Vec<T>;

This will produce:

warning: bounds on generic parameters in type aliases are not enforced
 --> lint_example.rs:2:17
  |
2 | type SendVec<T: Send> = Vec<T>;
  |               --^^^^
  |               | |
  |               | will not be checked at usage sites of the type alias
  |               help: remove this bound
  |
  = note: this is a known limitation of the type checker that may be lifted in a future edition.
          see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
  = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics
  = note: `#[warn(type_alias_bounds)]` on by default

Explanation

Trait and lifetime bounds on generic parameters and in where clauses of type aliases are not checked at usage sites of the type alias. Moreover, they are not thoroughly checked for correctness at their definition site either similar to the aliased type.

This is a known limitation of the type checker that may be lifted in a future edition. Permitting such bounds in light of this was unintentional.

While these bounds may have secondary effects such as enabling the use of "shorthand" associated type paths1 and affecting the default trait object lifetime2 of trait object types passed to the type alias, this should not have been allowed until the aforementioned restrictions of the type checker have been lifted.

Using such bounds is highly discouraged as they are actively misleading.

1

I.e., paths of the form T::Assoc where T is a type parameter bounded by trait Trait which defines an associated type called Assoc as opposed to a fully qualified path of the form <T as Trait>::Assoc.

tyvar-behind-raw-pointer

The tyvar_behind_raw_pointer lint detects raw pointer to an inference variable.

Example

// edition 2015
let data = std::ptr::null();
let _ = &data as *const *const ();

if data.is_null() {}

This will produce:

warning: type annotations needed
 --> lint_example.rs:6:9
  |
6 | if data.is_null() {}
  |         ^^^^^^^
  |
  = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
  = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
  = note: `#[warn(tyvar_behind_raw_pointer)]` on by default

Explanation

This kind of inference was previously allowed, but with the future arrival of arbitrary self types, this can introduce ambiguity. To resolve this, use an explicit type instead of relying on type inference.

This is a future-incompatible lint to transition this to a hard error in the 2018 edition. See issue #46906 for more details. This is currently a hard-error on the 2018 edition, and is "warn" by default in the 2015 edition.

uncommon-codepoints

The uncommon_codepoints lint detects uncommon Unicode codepoints in identifiers.

Example

#![allow(unused)]
const µ: f64 = 0.000001;

This will produce:

warning: identifier contains a non normalized (NFKC) character: 'µ'
 --> lint_example.rs:3:7
  |
3 | const µ: f64 = 0.000001;
  |       ^
  |
  = note: this character is included in the Not_NFKC Unicode general security profile
  = note: `#[warn(uncommon_codepoints)]` on by default

Explanation

This lint warns about using characters which are not commonly used, and may cause visual confusion.

This lint is triggered by identifiers that contain a codepoint that is not part of the set of "Allowed" codepoints as described by Unicode® Technical Standard #39 Unicode Security Mechanisms Section 3.1 General Security Profile for Identifiers.

Note that the set of uncommon codepoints may change over time. Beware that if you "forbid" this lint that existing code may fail in the future.

unconditional-recursion

The unconditional_recursion lint detects functions that cannot return without calling themselves.

Example

fn foo() {
    foo();
}

This will produce:

warning: function cannot return without recursing
 --> lint_example.rs:2:1
  |
2 | fn foo() {
  | ^^^^^^^^ cannot return without recursing
3 |     foo();
  |     ----- recursive call site
  |
  = help: a `loop` may express intention better if this is on purpose
  = note: `#[warn(unconditional_recursion)]` on by default

Explanation

It is usually a mistake to have a recursive call that does not have some condition to cause it to terminate. If you really intend to have an infinite loop, using a loop expression is recommended.

uncovered-param-in-projection

The uncovered_param_in_projection lint detects a violation of one of Rust's orphan rules for foreign trait implementations that concerns the use of type parameters inside trait associated type paths ("projections") whose output may not be a local type that is mistakenly considered to "cover" said parameters which is unsound and which may be rejected by a future version of the compiler.

Originally reported in #99554.

Example

// dependency.rs
#![crate_type = "lib"]

pub trait Trait<T, U> {}
// dependent.rs
trait Identity {
    type Output;
}

impl<T> Identity for T {
    type Output = T;
}

struct Local;

impl<T> dependency::Trait<Local, T> for <T as Identity>::Output {}

fn main() {}

This will produce:

warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
  --> dependent.rs:11:6
   |
11 | impl<T> dependency::Trait<Local, T> for <T as Identity>::Output {}
   |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
   |
   = 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 #124559 <https://github.com/rust-lang/rust/issues/124559>
   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
   = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
   = note: `#[warn(uncovered_param_in_projection)]` on by default

Explanation

FIXME(fmease): Write explainer.

undefined-naked-function-abi

The undefined_naked_function_abi lint detects naked function definitions that either do not specify an ABI or specify the Rust ABI.

Example

#![feature(asm_experimental_arch, naked_functions)]

use std::arch::naked_asm;

#[naked]
pub fn default_abi() -> u32 {
    unsafe { naked_asm!(""); }
}

#[naked]
pub extern "Rust" fn rust_abi() -> u32 {
    unsafe { naked_asm!(""); }
}

This will produce:

warning: Rust ABI is unsupported in naked functions
 --> lint_example.rs:7:1
  |
7 | pub fn default_abi() -> u32 {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(undefined_naked_function_abi)]` on by default


warning: Rust ABI is unsupported in naked functions
  --> lint_example.rs:12:1
   |
12 | pub extern "Rust" fn rust_abi() -> u32 {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation

The Rust ABI is currently undefined. Therefore, naked functions should specify a non-Rust ABI.

unexpected-cfgs

The unexpected_cfgs lint detects unexpected conditional compilation conditions.

Example

rustc --check-cfg 'cfg()'
#[cfg(widnows)]
fn foo() {}

This will produce:

warning: unexpected `cfg` condition name: `widnows`
 --> lint_example.rs:1:7
  |
1 | #[cfg(widnows)]
  |       ^^^^^^^
  |
  = note: `#[warn(unexpected_cfgs)]` on by default

Explanation

This lint is only active when --check-cfg arguments are being passed to the compiler and triggers whenever an unexpected condition name or value is used.

See the Checking Conditional Configurations section for more details.

See the Cargo Specifics section for configuring this lint in Cargo.toml.

unfulfilled-lint-expectations

The unfulfilled_lint_expectations lint detects when a lint expectation is unfulfilled.

Example

#[expect(unused_variables)]
let x = 10;
println!("{}", x);

This will produce:

warning: this lint expectation is unfulfilled
 --> lint_example.rs:2:10
  |
2 | #[expect(unused_variables)]
  |          ^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unfulfilled_lint_expectations)]` on by default

Explanation

The #[expect] attribute can be used to create a lint expectation. The expectation is fulfilled, if a #[warn] attribute at the same location would result in a lint emission. If the expectation is unfulfilled, because no lint was emitted, this lint will be emitted on the attribute.

ungated-async-fn-track-caller

The ungated_async_fn_track_caller lint warns when the #[track_caller] attribute is used on an async function without enabling the corresponding unstable feature flag.

Example

#[track_caller]
async fn foo() {}

This will produce:

warning: `#[track_caller]` on async functions is a no-op
 --> lint_example.rs:2:1
  |
2 | #[track_caller]
  | ^^^^^^^^^^^^^^^
3 | async fn foo() {}
  | ----------------- this function will not propagate the caller location
  |
  = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
  = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
  = note: this compiler was built on 2024-11-26; consider upgrading it if it is out of date
  = note: `#[warn(ungated_async_fn_track_caller)]` on by default

Explanation

The attribute must be used in conjunction with the async_fn_track_caller feature flag. Otherwise, the #[track_caller] annotation will function as a no-op.

uninhabited-static

The uninhabited_static lint detects uninhabited statics.

Example

enum Void {}
extern {
    static EXTERN: Void;
}

This will produce:

warning: static of uninhabited type
 --> lint_example.rs:4:5
  |
4 |     static EXTERN: Void;
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = 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 #74840 <https://github.com/rust-lang/rust/issues/74840>
  = note: uninhabited statics cannot be initialized, and any access would be an immediate error
  = note: `#[warn(uninhabited_static)]` on by default

Explanation

Statics with an uninhabited type can never be initialized, so they are impossible to define. However, this can be side-stepped with an extern static, leading to problems later in the compiler which assumes that there are no initialized uninhabited places (such as locals or statics). This was accidentally allowed, but is being phased out.

unknown-lints

The unknown_lints lint detects unrecognized lint attributes.

Example

#![allow(not_a_real_lint)]

This will produce:

warning: unknown lint: `not_a_real_lint`
 --> lint_example.rs:1:10
  |
1 | #![allow(not_a_real_lint)]
  |          ^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unknown_lints)]` on by default

Explanation

It is usually a mistake to specify a lint that does not exist. Check the spelling, and check the lint listing for the correct name. Also consider if you are using an old version of the compiler, and the lint is only available in a newer version.

unknown-or-malformed-diagnostic-attributes

The unknown_or_malformed_diagnostic_attributes lint detects unrecognized or otherwise malformed diagnostic attributes.

Example

#![feature(diagnostic_namespace)]
#[diagnostic::does_not_exist]
struct Foo;

This will produce:

warning: unknown diagnostic attribute
 --> lint_example.rs:3:15
  |
3 | #[diagnostic::does_not_exist]
  |               ^^^^^^^^^^^^^^
  |
  = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default

Explanation

It is usually a mistake to specify a diagnostic attribute that does not exist. Check the spelling, and check the diagnostic attribute listing for the correct name. Also consider if you are using an old version of the compiler, and the attribute is only available in a newer version.

unnameable-test-items

The unnameable_test_items lint detects #[test] functions that are not able to be run by the test harness because they are in a position where they are not nameable.

Example

fn main() {
    #[test]
    fn foo() {
        // This test will not fail because it does not run.
        assert_eq!(1, 2);
    }
}

This will produce:

warning: cannot test inner items
 --> lint_example.rs:2:5
  |
2 |     #[test]
  |     ^^^^^^^
  |
  = note: `#[warn(unnameable_test_items)]` on by default
  = note: this warning originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

Explanation

In order for the test harness to run a test, the test function must be located in a position where it can be accessed from the crate root. This generally means it must be defined in a module, and not anywhere else such as inside another function. The compiler previously allowed this without an error, so a lint was added as an alert that a test is not being used. Whether or not this should be allowed has not yet been decided, see RFC 2471 and issue #36629.

unreachable-code

The unreachable_code lint detects unreachable code paths.

Example

panic!("we never go past here!");

let x = 5;

This will produce:

warning: unreachable statement
 --> lint_example.rs:4:1
  |
2 | panic!("we never go past here!");
  | -------------------------------- any code following this expression is unreachable
3 |
4 | let x = 5;
  | ^^^^^^^^^^ unreachable statement
  |
  = note: `#[warn(unreachable_code)]` on by default

Explanation

Unreachable code may signal a mistake or unfinished code. If the code is no longer in use, consider removing it.

unreachable-patterns

The unreachable_patterns lint detects unreachable patterns.

Example

let x = 5;
match x {
    y => (),
    5 => (),
}

This will produce:

warning: unreachable pattern
 --> lint_example.rs:5:5
  |
4 |     y => (),
  |     - matches any value
5 |     5 => (),
  |     ^ no value can reach this
  |
  = note: `#[warn(unreachable_patterns)]` on by default

Explanation

This usually indicates a mistake in how the patterns are specified or ordered. In this example, the y pattern will always match, so the five is impossible to reach. Remember, match arms match in order, you probably wanted to put the 5 case above the y case.

unstable-name-collision

The lint unstable-name-collision has been renamed to unstable-name-collisions.

unstable-name-collisions

The unstable_name_collisions lint detects that you have used a name that the standard library plans to add in the future.

Example

trait MyIterator : Iterator {
    // is_partitioned is an unstable method that already exists on the Iterator trait
    fn is_partitioned<P>(self, predicate: P) -> bool
    where
        Self: Sized,
        P: FnMut(Self::Item) -> bool,
    {true}
}

impl<T: ?Sized> MyIterator for T where T: Iterator { }

let x = vec![1, 2, 3];
let _ = x.iter().is_partitioned(|_| true);

This will produce:

warning: a method with this name may be added to the standard library in the future
  --> lint_example.rs:14:18
   |
14 | let _ = x.iter().is_partitioned(|_| true);
   |                  ^^^^^^^^^^^^^^
   |
   = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
   = note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
   = help: call with fully qualified syntax `MyIterator::is_partitioned(...)` to keep using the current method
   = note: `#[warn(unstable_name_collisions)]` on by default
help: add `#![feature(iter_is_partitioned)]` to the crate attributes to enable `is_partitioned`
   |
1  + #![feature(iter_is_partitioned)]
   |

Explanation

When new methods are added to traits in the standard library, they are usually added in an "unstable" form which is only available on the nightly channel with a feature attribute. If there is any preexisting code which extends a trait to have a method with the same name, then the names will collide. In the future, when the method is stabilized, this will cause an error due to the ambiguity. This lint is an early-warning to let you know that there may be a collision in the future. This can be avoided by adding type annotations to disambiguate which trait method you intend to call, such as MyIterator::is_partitioned(my_iter, my_predicate) or renaming or removing the method.

unstable-syntax-pre-expansion

The unstable_syntax_pre_expansion lint detects the use of unstable syntax that is discarded during attribute expansion.

Example

#[cfg(FALSE)]
macro foo() {}

This will produce:

warning: `macro` is experimental
 --> lint_example.rs:3:1
  |
3 | macro foo() {}
  | ^^^^^^^^^^^^^^
  |
  = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
  = help: add `#![feature(decl_macro)]` to the crate attributes to enable
  = note: this compiler was built on 2024-11-26; consider upgrading it if it is out of date
  = warning: unstable syntax can change at any point in the future, causing a hard error!
  = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>

Explanation

The input to active attributes such as #[cfg] or procedural macro attributes is required to be valid syntax. Previously, the compiler only gated the use of unstable syntax features after resolving #[cfg] gates and expanding procedural macros.

To avoid relying on unstable syntax, move the use of unstable syntax into a position where the compiler does not parse the syntax, such as a functionlike macro.

#![deny(unstable_syntax_pre_expansion)]

macro_rules! identity {
   ( $($tokens:tt)* ) => { $($tokens)* }
}

#[cfg(FALSE)]
identity! {
   macro foo() {}
}

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

unsupported-calling-conventions

The unsupported_calling_conventions lint is output whenever there is a use of the stdcall, fastcall, thiscall, vectorcall calling conventions (or their unwind variants) on targets that cannot meaningfully be supported for the requested target.

For example stdcall does not make much sense for a x86_64 or, more apparently, powerpc code, because this calling convention was never specified for those targets.

Historically MSVC toolchains have fallen back to the regular C calling convention for targets other than x86, but Rust doesn't really see a similar need to introduce a similar hack across many more targets.

Example

extern "stdcall" fn stdcall() {}

This will produce:

warning: use of calling convention not supported on this target
  --> $DIR/unsupported.rs:39:1
   |
LL | extern "stdcall" fn stdcall() {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unsupported_calling_conventions)]` 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 ...

Explanation

On most of the targets the behaviour of stdcall and similar calling conventions is not defined at all, but was previously accepted due to a bug in the implementation of the compiler.

unsupported-fn-ptr-calling-conventions

The unsupported_fn_ptr_calling_conventions lint is output whenever there is a use of a target dependent calling convention on a target that does not support this calling convention on a function pointer.

For example stdcall does not make much sense for a x86_64 or, more apparently, powerpc code, because this calling convention was never specified for those targets.

Example

fn stdcall_ptr(f: extern "stdcall" fn ()) {
    f()
}

This will produce:

warning: use of calling convention not supported on this target on function pointer
  --> $DIR/unsupported.rs:34:15
   |
LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
   |               ^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default

Explanation

On most of the targets the behaviour of stdcall and similar calling conventions is not defined at all, but was previously accepted due to a bug in the implementation of the compiler.

unused-doc-comment

The lint unused-doc-comment has been renamed to unused-doc-comments.

unused-tuple-struct-fields

The lint unused-tuple-struct-fields has been renamed to dead-code.

unused-allocation

The unused_allocation lint detects unnecessary allocations that can be eliminated.

Example

fn main() {
    let a = Box::new([1, 2, 3]).len();
}

This will produce:

warning: unnecessary allocation, use `&` instead
 --> lint_example.rs:2:13
  |
2 |     let a = Box::new([1, 2, 3]).len();
  |             ^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_allocation)]` on by default

Explanation

When a box expression is immediately coerced to a reference, then the allocation is unnecessary, and a reference (using & or &mut) should be used instead to avoid the allocation.

unused-assignments

The unused_assignments lint detects assignments that will never be read.

Example

let mut x = 5;
x = 6;

This will produce:

warning: value assigned to `x` is never read
 --> lint_example.rs:3:1
  |
3 | x = 6;
  | ^
  |
  = help: maybe it is overwritten before being read?
  = note: `#[warn(unused_assignments)]` on by default

Explanation

Unused assignments may signal a mistake or unfinished code. If the variable is never used after being assigned, then the assignment can be removed. Variables with an underscore prefix such as _x will not trigger this lint.

unused-associated-type-bounds

The unused_associated_type_bounds lint is emitted when an associated type bound is added to a trait object, but the associated type has a where Self: Sized bound, and is thus unavailable on the trait object anyway.

Example

trait Foo {
    type Bar where Self: Sized;
}
type Mop = dyn Foo<Bar = ()>;

This will produce:

warning: unnecessary associated type bound for dyn-incompatible associated type
 --> lint_example.rs:5:20
  |
5 | type Mop = dyn Foo<Bar = ()>;
  |                    ^^^^^^^^ help: remove this bound
  |
  = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
  = note: `#[warn(unused_associated_type_bounds)]` on by default

Explanation

Just like methods with Self: Sized bounds are unavailable on trait objects, associated types can be removed from the trait object.

unused-attributes

The unused_attributes lint detects attributes that were not used by the compiler.

Example

#![ignore]

This will produce:

warning: `#[ignore]` only has an effect on functions
 --> lint_example.rs:1:1
  |
1 | #![ignore]
  | ^^^^^^^^^^
  |
  = note: `#[warn(unused_attributes)]` on by default

Explanation

Unused attributes may indicate the attribute is placed in the wrong position. Consider removing it, or placing it in the correct position. Also consider if you intended to use an inner attribute (with a ! such as #![allow(unused)]) which applies to the item the attribute is within, or an outer attribute (without a ! such as #[allow(unused)]) which applies to the item following the attribute.

unused-braces

The unused_braces lint detects unnecessary braces around an expression.

Example

if { true } {
    // ...
}

This will produce:

warning: unnecessary braces around `if` condition
 --> lint_example.rs:2:4
  |
2 | if { true } {
  |    ^^    ^^
  |
  = note: `#[warn(unused_braces)]` on by default
help: remove these braces
  |
2 - if { true } {
2 + if true {
  |

Explanation

The braces are not needed, and should be removed. This is the preferred style for writing these expressions.

unused-comparisons

The unused_comparisons lint detects comparisons made useless by limits of the types involved.

Example

fn foo(x: u8) {
    x >= 0;
}

This will produce:

warning: comparison is useless due to type limits
 --> lint_example.rs:3:5
  |
3 |     x >= 0;
  |     ^^^^^^
  |
  = note: `#[warn(unused_comparisons)]` on by default

Explanation

A useless comparison may indicate a mistake, and should be fixed or removed.

unused-doc-comments

The unused_doc_comments lint detects doc comments that aren't used by rustdoc.

Example

/// docs for x
let x = 12;

This will produce:

warning: unused doc comment
 --> lint_example.rs:2:1
  |
2 | /// docs for x
  | ^^^^^^^^^^^^^^
3 | let x = 12;
  | ----------- rustdoc does not generate documentation for statements
  |
  = help: use `//` for a plain comment
  = note: `#[warn(unused_doc_comments)]` on by default

Explanation

rustdoc does not use doc comments in all positions, and so the doc comment will be ignored. Try changing it to a normal comment with // to avoid the warning.

unused-features

The unused_features lint detects unused or unknown features found in crate-level feature attributes.

Note: This lint is currently not functional, see issue #44232 for more details.

unused-imports

The unused_imports lint detects imports that are never used.

Example

use std::collections::HashMap;

This will produce:

warning: unused import: `std::collections::HashMap`
 --> lint_example.rs:2:5
  |
2 | use std::collections::HashMap;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

Explanation

Unused imports may signal a mistake or unfinished code, and clutter the code, and should be removed. If you intended to re-export the item to make it available outside of the module, add a visibility modifier like pub.

unused-labels

The unused_labels lint detects labels that are never used.

Example

'unused_label: loop {}

This will produce:

warning: unused label
 --> lint_example.rs:2:1
  |
2 | 'unused_label: loop {}
  | ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_labels)]` on by default

Explanation

Unused labels may signal a mistake or unfinished code. To silence the warning for the individual label, prefix it with an underscore such as '_my_label:.

unused-macros

The unused_macros lint detects macros that were not used.

Note that this lint is distinct from the unused_macro_rules lint, which checks for single rules that never match of an otherwise used macro, and thus never expand.

Example

macro_rules! unused {
    () => {};
}

fn main() {
}

This will produce:

warning: unused macro definition: `unused`
 --> lint_example.rs:1:14
  |
1 | macro_rules! unused {
  |              ^^^^^^
  |
  = note: `#[warn(unused_macros)]` on by default

Explanation

Unused macros may signal a mistake or unfinished code. To silence the warning for the individual macro, prefix the name with an underscore such as _my_macro. If you intended to export the macro to make it available outside of the crate, use the macro_export attribute.

unused-must-use

The unused_must_use lint detects unused result of a type flagged as #[must_use].

Example

fn returns_result() -> Result<(), ()> {
    Ok(())
}

fn main() {
    returns_result();
}

This will produce:

warning: unused `Result` that must be used
 --> lint_example.rs:6:5
  |
6 |     returns_result();
  |     ^^^^^^^^^^^^^^^^
  |
  = note: this `Result` may be an `Err` variant, which should be handled
  = note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
  |
6 |     let _ = returns_result();
  |     +++++++

Explanation

The #[must_use] attribute is an indicator that it is a mistake to ignore the value. See the reference for more details.

unused-mut

The unused_mut lint detects mut variables which don't need to be mutable.

Example

let mut x = 5;

This will produce:

warning: variable does not need to be mutable
 --> lint_example.rs:2:5
  |
2 | let mut x = 5;
  |     ----^
  |     |
  |     help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

Explanation

The preferred style is to only mark variables as mut if it is required.

unused-parens

The unused_parens lint detects if, match, while and return with parentheses; they do not need them.

Examples

if(true) {}

This will produce:

warning: unnecessary parentheses around `if` condition
 --> lint_example.rs:2:3
  |
2 | if(true) {}
  |   ^    ^
  |
  = note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
  |
2 - if(true) {}
2 + if true {}
  |

Explanation

The parentheses are not needed, and should be removed. This is the preferred style for writing these expressions.

unused-unsafe

The unused_unsafe lint detects unnecessary use of an unsafe block.

Example

unsafe {}

This will produce:

warning: unnecessary `unsafe` block
 --> lint_example.rs:2:1
  |
2 | unsafe {}
  | ^^^^^^ unnecessary `unsafe` block
  |
  = note: `#[warn(unused_unsafe)]` on by default

Explanation

If nothing within the block requires unsafe, then remove the unsafe marker because it is not required and may cause confusion.

unused-variables

The unused_variables lint detects variables which are not used in any way.

Example

let x = 5;

This will produce:

warning: unused variable: `x`
 --> lint_example.rs:2:5
  |
2 | let x = 5;
  |     ^ help: if this is intentional, prefix it with an underscore: `_x`
  |
  = note: `#[warn(unused_variables)]` on by default

Explanation

Unused variables may signal a mistake or unfinished code. To silence the warning for the individual variable, prefix it with an underscore such as _x.

useless-ptr-null-checks

The useless_ptr_null_checks lint checks for useless null checks against pointers obtained from non-null types.

Example

fn test() {}
let fn_ptr: fn() = /* somehow obtained nullable function pointer */
  test;

if (fn_ptr as *const ()).is_null() { /* ... */ }

This will produce:

warning: function pointers are not nullable, so checking them for null will always return false
 --> lint_example.rs:6:4
  |
6 | if (fn_ptr as *const ()).is_null() { /* ... */ }
  |    ^------^^^^^^^^^^^^^^^^^^^^^^^^
  |     |
  |     expression has type `fn()`
  |
  = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
  = note: `#[warn(useless_ptr_null_checks)]` on by default

Explanation

Function pointers and references are assumed to be non-null, checking them for null will always return false.

warnings

The warnings lint allows you to change the level of other lints which produce warnings.

Example

#![deny(warnings)]
fn foo() {}

This will produce:

error: function `foo` is never used
 --> lint_example.rs:3:4
  |
3 | fn foo() {}
  |    ^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(warnings)]
  |         ^^^^^^^^
  = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`

Explanation

The warnings lint is a bit special; by changing its level, you change every other warning that would produce a warning to whatever value you'd like. As such, you won't ever trigger this lint in your code directly.

while-true

The while_true lint detects while true { }.

Example

while true {

}

This will produce:

warning: denote infinite loops with `loop { ... }`
 --> lint_example.rs:2:1
  |
2 | while true {
  | ^^^^^^^^^^ help: use `loop`
  |
  = note: `#[warn(while_true)]` on by default

Explanation

while true should be replaced with loop. A loop expression is the preferred way to write an infinite loop because it more directly expresses the intent of the loop.