Deny-by-default Lints
These lints are all set to the 'deny' level by default.
ambiguous_associated_items
arithmetic_overflow
binary_asm_labels
bindings_with_variant_name
cenum_impl_drop_cast
conflicting_repr_hints
elided_lifetimes_in_associated_constant
enum_intrinsics_non_enums
exceeding-bitshifts
explicit_builtin_cfgs_in_flags
ill_formed_attribute_input
incomplete_include
ineffective_unstable_trait_impl
invalid_atomic_ordering
invalid_doc_attributes
invalid_from_utf8_unchecked
invalid_reference_casting
invalid_type_param_default
let_underscore_lock
long_running_const_eval
macro_expanded_macro_exports_accessed_by_absolute_paths
missing_fragment_specifier
mutable_transmutes
named_asm_labels
no_mangle_const_items
order_dependent_trait_objects
overflowing_literals
patterns_in_fns_without_body
proc_macro_derive_resolution_fallback
pub_use_of_private_extern_crate
soft_unstable
test_unstable_lint
text_direction_codepoint_in_comment
text_direction_codepoint_in_literal
unconditional_panic
undropped_manually_drops
unknown_crate_types
useless_deprecated
wasm_c_abi
ambiguous-associated-items
The ambiguous_associated_items
lint detects ambiguity between
associated items and enum variants.
Example
enum E {
V
}
trait Tr {
type V;
fn foo() -> Self::V;
}
impl Tr for E {
type V = u8;
// `Self::V` is ambiguous because it may refer to the associated type or
// the enum variant.
fn foo() -> Self::V { 0 }
}
This will produce:
error: ambiguous associated item
--> lint_example.rs:15:17
|
15 | fn foo() -> Self::V { 0 }
| ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
note: `V` could refer to the variant defined here
--> lint_example.rs:3:5
|
3 | V
| ^
note: `V` could also refer to the associated type defined here
--> lint_example.rs:7:5
|
7 | type V;
| ^^^^^^
= note: `#[deny(ambiguous_associated_items)]` on by default
Explanation
Previous versions of Rust did not allow accessing enum variants through type aliases. When this ability was added (see RFC 2338), this introduced some situations where it can be ambiguous what a type was referring to.
To fix this ambiguity, you should use a qualified path to explicitly
state which type to use. For example, in the above example the
function can be written as fn f() -> <Self as Tr>::V { 0 }
to
specifically refer to the associated type.
This is a future-incompatible lint to transition this to a hard error in the future. See issue #57644 for more details.
arithmetic-overflow
The arithmetic_overflow
lint detects that an arithmetic operation
will overflow.
Example
1_i32 << 32;
This will produce:
error: this arithmetic operation will overflow
--> lint_example.rs:2:1
|
2 | 1_i32 << 32;
| ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
Explanation
It is very likely a mistake to perform an arithmetic operation that overflows its value. If the compiler is able to detect these kinds of overflows at compile-time, it will trigger this lint. Consider adjusting the expression to avoid overflow, or use a data type that will not overflow.
binary-asm-labels
The binary_asm_labels
lint detects the use of numeric labels containing only binary
digits in the inline asm!
macro.
Example
#![cfg(target_arch = "x86_64")]
use std::arch::asm;
fn main() {
unsafe {
asm!("0: jmp 0b");
}
}
This will produce:
error: avoid using labels containing only the digits `0` and `1` in inline assembly
--> <source>:7:15
|
7 | asm!("0: jmp 0b");
| ^ use a different label that doesn't start with `0` or `1`
|
= help: start numbering with `2` instead
= note: an LLVM bug makes these labels ambiguous with a binary literal number on x86
= note: see <https://github.com/llvm/llvm-project/issues/99547> for more information
= note: `#[deny(binary_asm_labels)]` on by default
Explanation
An LLVM bug causes this code to fail to compile because it interprets the 0b
as a binary
literal instead of a reference to the previous local label 0
. To work around this bug,
don't use labels that could be confused with a binary literal.
This behavior is platform-specific to x86 and x86-64.
See the explanation in Rust By Example for more details.
bindings-with-variant-name
The bindings_with_variant_name
lint detects pattern bindings with
the same name as one of the matched variants.
Example
pub enum Enum {
Foo,
Bar,
}
pub fn foo(x: Enum) {
match x {
Foo => {}
Bar => {}
}
}
This will produce:
error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `main::Enum`
--> lint_example.rs:9:9
|
9 | Foo => {}
| ^^^ help: to match on the variant, qualify the path: `main::Enum::Foo`
|
= note: `#[deny(bindings_with_variant_name)]` on by default
Explanation
It is usually a mistake to specify an enum variant name as an
identifier pattern. In the example above, the match
arms are
specifying a variable name to bind the value of x
to. The second arm
is ignored because the first one matches all values. The likely
intent is that the arm was intended to match on the enum variant.
Two possible solutions are:
- Specify the enum variant using a path pattern, such as
Enum::Foo
. - Bring the enum variants into local scope, such as adding
use Enum::*;
to the beginning of thefoo
function in the example above.
cenum-impl-drop-cast
The cenum_impl_drop_cast
lint detects an as
cast of a field-less
enum
that implements Drop
.
Example
#![allow(unused)]
enum E {
A,
}
impl Drop for E {
fn drop(&mut self) {
println!("Drop");
}
}
fn main() {
let e = E::A;
let i = e as u32;
}
This will produce:
error: cannot cast enum `E` into integer `u32` because it implements `Drop`
--> lint_example.rs:14:13
|
14 | let i = e as u32;
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #73333 <https://github.com/rust-lang/rust/issues/73333>
= note: `#[deny(cenum_impl_drop_cast)]` on by default
Explanation
Casting a field-less enum
that does not implement Copy
to an
integer moves the value without calling drop
. This can result in
surprising behavior if it was expected that drop
should be called.
Calling drop
automatically would be inconsistent with other move
operations. Since neither behavior is clear or consistent, it was
decided that a cast of this nature will no longer be allowed.
This is a future-incompatible lint to transition this to a hard error in the future. See issue #73333 for more details.
conflicting-repr-hints
The conflicting_repr_hints
lint detects repr
attributes with
conflicting hints.
Example
#[repr(u32, u64)]
enum Foo {
Variant1,
}
This will produce:
error[E0566]: conflicting representation hints
--> lint_example.rs:2:8
|
2 | #[repr(u32, u64)]
| ^^^ ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
= note: `#[deny(conflicting_repr_hints)]` on by default
Explanation
The compiler incorrectly accepted these conflicting representations in the past. This is a future-incompatible lint to transition this to a hard error in the future. See issue #68585 for more details.
To correct the issue, remove one of the conflicting hints.
elided-lifetimes-in-associated-constant
The elided_lifetimes_in_associated_constant
lint detects elided lifetimes
in associated constants when there are other lifetimes in scope. This was
accidentally supported, and this lint was later relaxed to allow eliding
lifetimes to 'static
when there are no lifetimes in scope.
Example
#![deny(elided_lifetimes_in_associated_constant)]
struct Foo<'a>(&'a ());
impl<'a> Foo<'a> {
const STR: &str = "hello, world";
}
This will produce:
error: `&` without an explicit lifetime name cannot be used here
--> lint_example.rs:7:16
|
7 | const STR: &str = "hello, world";
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
note: cannot automatically infer `'static` because of other lifetimes in scope
--> lint_example.rs:6:6
|
6 | impl<'a> Foo<'a> {
| ^^
note: the lint level is defined here
--> lint_example.rs:1:9
|
1 | #![deny(elided_lifetimes_in_associated_constant)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use the `'static` lifetime
|
7 | const STR: &'static str = "hello, world";
| +++++++
Explanation
Previous version of Rust
Implicit static-in-const behavior was decided against for associated constants because of ambiguity. This, however, regressed and the compiler erroneously treats elided lifetimes in associated constants as lifetime parameters on the impl.
This is a future-incompatible lint to transition this to a hard error in the future.
enum-intrinsics-non-enums
The enum_intrinsics_non_enums
lint detects calls to
intrinsic functions that require an enum (core::mem::discriminant
,
core::mem::variant_count
), but are called with a non-enum type.
Example
#![deny(enum_intrinsics_non_enums)]
core::mem::discriminant::<i32>(&123);
This will produce:
error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
--> lint_example.rs:3:1
|
3 | core::mem::discriminant::<i32>(&123);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum
--> lint_example.rs:3:32
|
3 | core::mem::discriminant::<i32>(&123);
| ^^^^
note: the lint level is defined here
--> lint_example.rs:1:9
|
1 | #![deny(enum_intrinsics_non_enums)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
Explanation
In order to accept any enum, the mem::discriminant
and
mem::variant_count
functions are generic over a type T
.
This makes it technically possible for T
to be a non-enum,
in which case the return value is unspecified.
This lint prevents such incorrect usage of these functions.
exceeding-bitshifts
The lint exceeding-bitshifts
has been renamed to arithmetic-overflow
.
explicit-builtin-cfgs-in-flags
The explicit_builtin_cfgs_in_flags
lint detects builtin cfgs set via the --cfg
flag.
Example
rustc --cfg unix
fn main() {}
This will produce:
error: unexpected `--cfg unix` flag
|
= note: config `unix` is only supposed to be controlled by `--target`
= note: manually setting a built-in cfg can and does create incoherent behaviors
= note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
Explanation
Setting builtin cfgs can and does produce incoherent behavior, it's better to the use
the appropriate rustc
flag that controls the config. For example setting the windows
cfg but on Linux based target.
ill-formed-attribute-input
The ill_formed_attribute_input
lint detects ill-formed attribute
inputs that were previously accepted and used in practice.
Example
#[inline = "this is not valid"]
fn foo() {}
This will produce:
error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
--> lint_example.rs:2:1
|
2 | #[inline = "this is not valid"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
= note: `#[deny(ill_formed_attribute_input)]` on by default
Explanation
Previously, inputs for many built-in attributes weren't validated and nonsensical attribute inputs were accepted. After validation was added, it was determined that some existing projects made use of these invalid forms. This is a future-incompatible lint to transition this to a hard error in the future. See issue #57571 for more details.
Check the attribute reference for details on the valid inputs for attributes.
incomplete-include
The incomplete_include
lint detects the use of the include!
macro with a file that contains more than one expression.
Example
fn main() {
include!("foo.txt");
}
where the file foo.txt
contains:
println!("hi!");
produces:
error: include macro expected single expression in source
--> foo.txt:1:14
|
1 | println!("1");
| ^
|
= note: `#[deny(incomplete_include)]` on by default
Explanation
The include!
macro is currently only intended to be used to
include a single expression or multiple items. Historically it
would ignore any contents after the first expression, but that can be
confusing. In the example above, the println!
expression ends just
before the semicolon, making the semicolon "extra" information that is
ignored. Perhaps even more surprising, if the included file had
multiple print statements, the subsequent ones would be ignored!
One workaround is to place the contents in braces to create a block expression. Also consider alternatives, like using functions to encapsulate the expressions, or use proc-macros.
This is a lint instead of a hard error because existing projects were
found to hit this error. To be cautious, it is a lint for now. The
future semantics of the include!
macro are also uncertain, see
issue #35560.
ineffective-unstable-trait-impl
The ineffective_unstable_trait_impl
lint detects #[unstable]
attributes which are not used.
Example
#![feature(staged_api)]
#[derive(Clone)]
#[stable(feature = "x", since = "1")]
struct S {}
#[unstable(feature = "y", issue = "none")]
impl Copy for S {}
This will produce:
error: an `#[unstable]` annotation here has no effect
--> lint_example.rs:8:1
|
8 | #[unstable(feature = "y", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
Explanation
staged_api
does not currently support using a stability attribute on impl
blocks.
impl
s are always stable if both the type and trait are stable, and always unstable otherwise.
invalid-atomic-ordering
The invalid_atomic_ordering
lint detects passing an Ordering
to an atomic operation that does not support that ordering.
Example
use core::sync::atomic::{AtomicU8, Ordering};
let atom = AtomicU8::new(0);
let value = atom.load(Ordering::Release);
let _ = value;
This will produce:
error: atomic loads cannot have `Release` or `AcqRel` ordering
--> lint_example.rs:4:23
|
4 | let value = atom.load(Ordering::Release);
| ^^^^^^^^^^^^^^^^^
|
= help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
= note: `#[deny(invalid_atomic_ordering)]` on by default
Explanation
Some atomic operations are only supported for a subset of the
atomic::Ordering
variants. Passing an unsupported variant will cause
an unconditional panic at runtime, which is detected by this lint.
This lint will trigger in the following cases: (where AtomicType
is an
atomic type from core::sync::atomic
, such as AtomicBool
,
AtomicPtr
, AtomicUsize
, or any of the other integer atomics).
-
Passing
Ordering::Acquire
orOrdering::AcqRel
toAtomicType::store
. -
Passing
Ordering::Release
orOrdering::AcqRel
toAtomicType::load
. -
Passing
Ordering::Relaxed
tocore::sync::atomic::fence
orcore::sync::atomic::compiler_fence
. -
Passing
Ordering::Release
orOrdering::AcqRel
as the failure ordering for any ofAtomicType::compare_exchange
,AtomicType::compare_exchange_weak
, orAtomicType::fetch_update
.
invalid-doc-attributes
The invalid_doc_attributes
lint detects when the #[doc(...)]
is
misused.
Example
#![deny(warnings)]
pub mod submodule {
#![doc(test(no_crate_inject))]
}
This will produce:
error: this attribute can only be applied at the crate level
--> lint_example.rs:5:12
|
5 | #![doc(test(no_crate_inject))]
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
= note: `#[deny(invalid_doc_attributes)]` on by default
Explanation
Previously, incorrect usage of the #[doc(..)]
attribute was not
being validated. Usually these should be rejected as a hard error,
but this lint was introduced to avoid breaking any existing
crates which included them.
invalid-from-utf8-unchecked
The invalid_from_utf8_unchecked
lint checks for calls to
std::str::from_utf8_unchecked
and std::str::from_utf8_unchecked_mut
with a known invalid UTF-8 value.
Example
#[allow(unused)]
unsafe {
std::str::from_utf8_unchecked(b"Ru\x82st");
}
This will produce:
error: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior
--> lint_example.rs:4:5
|
4 | std::str::from_utf8_unchecked(b"Ru\x82st");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^
| |
| the literal was valid UTF-8 up to the 2 bytes
|
= note: `#[deny(invalid_from_utf8_unchecked)]` on by default
Explanation
Creating such a str
would result in undefined behavior as per documentation
for std::str::from_utf8_unchecked
and std::str::from_utf8_unchecked_mut
.
invalid-reference-casting
The invalid_reference_casting
lint checks for casts of &T
to &mut T
without using interior mutability.
Example
fn x(r: &i32) {
unsafe {
*(r as *const i32 as *mut i32) += 1;
}
}
This will produce:
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
--> lint_example.rs:4:9
|
4 | *(r as *const i32 as *mut i32) += 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
= note: `#[deny(invalid_reference_casting)]` on by default
Explanation
Casting &T
to &mut T
without using interior mutability is undefined behavior,
as it's a violation of Rust reference aliasing requirements.
UnsafeCell
is the only way to obtain aliasable data that is considered
mutable.
invalid-type-param-default
The invalid_type_param_default
lint detects type parameter defaults
erroneously allowed in an invalid location.
Example
fn foo<T=i32>(t: T) {}
This will produce:
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> lint_example.rs:2:8
|
2 | fn foo<T=i32>(t: T) {}
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
= note: `#[deny(invalid_type_param_default)]` on by default
Explanation
Default type parameters were only intended to be allowed in certain situations, but historically the compiler allowed them everywhere. This is a future-incompatible lint to transition this to a hard error in the future. See issue #36887 for more details.
let-underscore-lock
The let_underscore_lock
lint checks for statements which don't bind
a mutex to anything, causing the lock to be released immediately instead
of at end of scope, which is typically incorrect.
Example
use std::sync::{Arc, Mutex};
use std::thread;
let data = Arc::new(Mutex::new(0));
thread::spawn(move || {
// The lock is immediately released instead of at the end of the
// scope, which is probably not intended.
let _ = data.lock().unwrap();
println!("doing some work");
let mut lock = data.lock().unwrap();
*lock += 1;
});
This will produce:
error: non-binding let on a synchronization lock
--> lint_example.rs:9:9
|
9 | let _ = data.lock().unwrap();
| ^ this lock is not assigned to a binding and is immediately dropped
|
= note: `#[deny(let_underscore_lock)]` on by default
help: consider binding to an unused variable to avoid immediately dropping the value
|
9 | let _unused = data.lock().unwrap();
| ~~~~~~~
help: consider immediately dropping the value
|
9 | drop(data.lock().unwrap());
| ~~~~~ +
Explanation
Statements which assign an expression to an underscore causes the
expression to immediately drop instead of extending the expression's
lifetime to the end of the scope. This is usually unintended,
especially for types like MutexGuard
, which are typically used to
lock a mutex for the duration of an entire scope.
If you want to extend the expression's lifetime to the end of the scope,
assign an underscore-prefixed name (such as _foo
) to the expression.
If you do actually want to drop the expression immediately, then
calling std::mem::drop
on the expression is clearer and helps convey
intent.
long-running-const-eval
The long_running_const_eval
lint is emitted when const
eval is running for a long time to ensure rustc terminates
even if you accidentally wrote an infinite loop.
Example
const FOO: () = loop {};
This will produce:
error: constant evaluation is taking a long time
--> lint_example.rs:2:17
|
2 | const FOO: () = loop {};
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
help: the constant being evaluated
--> lint_example.rs:2:1
|
2 | const FOO: () = loop {};
| ^^^^^^^^^^^^^
= note: `#[deny(long_running_const_eval)]` on by default
Explanation
Loops allow const evaluation to compute arbitrary code, but may also cause infinite loops or just very long running computations. Users can enable long running computations by allowing the lint on individual constants or for entire crates.
Unconditional warnings
Note that regardless of whether the lint is allowed or set to warn, the compiler will issue warnings if constant evaluation runs significantly longer than this lint's limit. These warnings are also shown to downstream users from crates.io or similar registries. If you are above the lint's limit, both you and downstream users might be exposed to these warnings. They might also appear on compiler updates, as the compiler makes minor changes about how complexity is measured: staying below the limit ensures that there is enough room, and given that the lint is disabled for people who use your dependency it means you will be the only one to get the warning and can put out an update in your own time.
macro-expanded-macro-exports-accessed-by-absolute-paths
The macro_expanded_macro_exports_accessed_by_absolute_paths
lint
detects macro-expanded macro_export
macros from the current crate
that cannot be referred to by absolute paths.
Example
macro_rules! define_exported {
() => {
#[macro_export]
macro_rules! exported {
() => {};
}
};
}
define_exported!();
fn main() {
crate::exported!();
}
This will produce:
error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
--> lint_example.rs:13:5
|
13 | crate::exported!();
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
--> lint_example.rs:4:9
|
4 | / macro_rules! exported {
5 | | () => {};
6 | | }
| |_________^
...
10 | define_exported!();
| ------------------ in this macro invocation
= note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
Explanation
The intent is that all macros marked with the #[macro_export]
attribute are made available in the root of the crate. However, when a
macro_rules!
definition is generated by another macro, the macro
expansion is unable to uphold this rule. This is a
future-incompatible lint to transition this to a hard error in the
future. See issue #53495 for more details.
missing-fragment-specifier
The missing_fragment_specifier
lint is issued when an unused pattern in a
macro_rules!
macro definition has a meta-variable (e.g. $e
) that is not
followed by a fragment specifier (e.g. :expr
).
This warning can always be fixed by removing the unused pattern in the
macro_rules!
macro definition.
Example
macro_rules! foo {
() => {};
($name) => { };
}
fn main() {
foo!();
}
This will produce:
error: missing fragment specifier
--> lint_example.rs:3:5
|
3 | ($name) => { };
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
Explanation
To fix this, remove the unused pattern from the macro_rules!
macro definition:
macro_rules! foo {
() => {};
}
fn main() {
foo!();
}
mutable-transmutes
The mutable_transmutes
lint catches transmuting from &T
to &mut T
because it is undefined behavior.
Example
unsafe {
let y = std::mem::transmute::<&i32, &mut i32>(&5);
}
This will produce:
error: transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
--> lint_example.rs:3:13
|
3 | let y = std::mem::transmute::<&i32, &mut i32>(&5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(mutable_transmutes)]` on by default
Explanation
Certain assumptions are made about aliasing of data, and this transmute
violates those assumptions. Consider using UnsafeCell
instead.
named-asm-labels
The named_asm_labels
lint detects the use of named labels in the
inline asm!
macro.
Example
#![feature(asm_experimental_arch)]
use std::arch::asm;
fn main() {
unsafe {
asm!("foo: bar");
}
}
This will produce:
error: avoid using named labels in inline assembly
--> lint_example.rs:6:15
|
6 | asm!("foo: bar");
| ^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
= note: `#[deny(named_asm_labels)]` on by default
Explanation
LLVM is allowed to duplicate inline assembly blocks for any reason, for example when it is in a function that gets inlined. Because of this, GNU assembler local labels must be used instead of labels with a name. Using named labels might cause assembler or linker errors.
See the explanation in Rust By Example for more details.
no-mangle-const-items
The no_mangle_const_items
lint detects any const
items with the
no_mangle
attribute.
Example
#[no_mangle]
const FOO: i32 = 5;
This will produce:
error: const items should never be `#[no_mangle]`
--> lint_example.rs:3:1
|
3 | const FOO: i32 = 5;
| -----^^^^^^^^^^^^^^
| |
| help: try a static value: `pub static`
|
= note: `#[deny(no_mangle_const_items)]` on by default
Explanation
Constants do not have their symbols exported, and therefore, this
probably means you meant to use a static
, not a const
.
order-dependent-trait-objects
The order_dependent_trait_objects
lint detects a trait coherency
violation that would allow creating two trait impls for the same
dynamic trait object involving marker traits.
Example
pub trait Trait {}
impl Trait for dyn Send + Sync { }
impl Trait for dyn Sync + Send { }
This will produce:
error: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
--> lint_example.rs:5:1
|
4 | impl Trait for dyn Send + Sync { }
| ------------------------------ first implementation here
5 | impl Trait for dyn Sync + Send { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
= note: `#[deny(order_dependent_trait_objects)]` on by default
Explanation
A previous bug caused the compiler to interpret traits with different
orders (such as Send + Sync
and Sync + Send
) as distinct types
when they were intended to be treated the same. This allowed code to
define separate trait implementations when there should be a coherence
error. This is a future-incompatible lint to transition this to a
hard error in the future. See issue #56484 for more details.
overflowing-literals
The overflowing_literals
lint detects literal out of range for its
type.
Example
let x: u8 = 1000;
This will produce:
error: literal out of range for `u8`
--> lint_example.rs:2:13
|
2 | let x: u8 = 1000;
| ^^^^
|
= note: the literal `1000` does not fit into the type `u8` whose range is `0..=255`
= note: `#[deny(overflowing_literals)]` on by default
Explanation
It is usually a mistake to use a literal that overflows the type where it is used. Either use a literal that is within range, or change the type to be within the range of the literal.
patterns-in-fns-without-body
The patterns_in_fns_without_body
lint detects mut
identifier
patterns as a parameter in functions without a body.
Example
trait Trait {
fn foo(mut arg: u8);
}
This will produce:
error: patterns aren't allowed in functions without bodies
--> lint_example.rs:3:12
|
3 | fn foo(mut arg: u8);
| ^^^^^^^ help: remove `mut` from the parameter: `arg`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
= note: `#[deny(patterns_in_fns_without_body)]` on by default
Explanation
To fix this, remove mut
from the parameter in the trait definition;
it can be used in the implementation. That is, the following is OK:
trait Trait {
fn foo(arg: u8); // Removed `mut` here
}
impl Trait for i32 {
fn foo(mut arg: u8) { // `mut` here is OK
}
}
Trait definitions can define functions without a body to specify a
function that implementors must define. The parameter names in the
body-less functions are only allowed to be _
or an identifier for
documentation purposes (only the type is relevant). Previous versions
of the compiler erroneously allowed identifier patterns with the
mut
keyword, but this was not intended to be allowed. This is a
future-incompatible lint to transition this to a hard error in the
future. See issue #35203 for more details.
proc-macro-derive-resolution-fallback
The proc_macro_derive_resolution_fallback
lint detects proc macro
derives using inaccessible names from parent modules.
Example
// foo.rs
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_derive(Foo)]
pub fn foo1(a: TokenStream) -> TokenStream {
drop(a);
"mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
}
// bar.rs
#[macro_use]
extern crate foo;
struct Something;
#[derive(Foo)]
struct Another;
fn main() {}
This will produce:
warning: cannot find type `Something` in this scope
--> src/main.rs:8:10
|
8 | #[derive(Foo)]
| ^^^ names from parent modules are not accessible without an explicit import
|
= note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
Explanation
If a proc-macro generates a module, the compiler unintentionally allowed items in that module to refer to items in the crate root without importing them. This is a future-incompatible lint to transition this to a hard error in the future. See issue #50504 for more details.
pub-use-of-private-extern-crate
The pub_use_of_private_extern_crate
lint detects a specific
situation of re-exporting a private extern crate
.
Example
extern crate core;
pub use core as reexported_core;
This will produce:
error[E0365]: extern crate `core` is private and cannot be re-exported
--> lint_example.rs:3:9
|
3 | pub use core as reexported_core;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #127909 <https://github.com/rust-lang/rust/issues/127909>
= note: `#[deny(pub_use_of_private_extern_crate)]` on by default
help: consider making the `extern crate` item publicly accessible
|
2 | pub extern crate core;
| +++
Explanation
A public use
declaration should not be used to publicly re-export a
private extern crate
. pub extern crate
should be used instead.
This was historically allowed, but is not the intended behavior according to the visibility rules. This is a future-incompatible lint to transition this to a hard error in the future. See issue #127909 for more details.
soft-unstable
The soft_unstable
lint detects unstable features that were
unintentionally allowed on stable.
Example
#[cfg(test)]
extern crate test;
#[bench]
fn name(b: &mut test::Bencher) {
b.iter(|| 123)
}
This will produce:
error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable
--> lint_example.rs:5:3
|
5 | #[bench]
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>
= note: `#[deny(soft_unstable)]` on by default
Explanation
The bench
attribute was accidentally allowed to be specified on
the stable release channel. Turning this to a hard error would have
broken some projects. This lint allows those projects to continue to
build correctly when --cap-lints
is used, but otherwise signal an
error that #[bench]
should not be used on the stable channel. This
is a future-incompatible lint to transition this to a hard error in
the future. See issue #64266 for more details.
test-unstable-lint
The test_unstable_lint
lint tests unstable lints and is perma-unstable.
Example
#![allow(test_unstable_lint)]
This will produce:
warning: unknown lint: `test_unstable_lint`
--> lint_example.rs:1:1
|
1 | #![allow(test_unstable_lint)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `test_unstable_lint` lint is unstable
= help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
= note: this compiler was built on 2024-12-21; consider upgrading it if it is out of date
= note: `#[warn(unknown_lints)]` on by default
Explanation
In order to test the behavior of unstable lints, a permanently-unstable lint is required. This lint can be used to trigger warnings and errors from the compiler related to unstable lints.
text-direction-codepoint-in-comment
The text_direction_codepoint_in_comment
lint detects Unicode codepoints in comments that
change the visual representation of text on screen in a way that does not correspond to
their on memory representation.
Example
#![deny(text_direction_codepoint_in_comment)]
fn main() {
println!("{:?}"); // '');
}
This will produce:
error: unicode codepoint changing visible direction of text present in comment
--> lint_example.rs:3:23
|
3 | println!("{:?}"); // '�');
| ^^^^-^^^
| | |
| | '\u{202e}'
| this comment contains an invisible unicode text flow control codepoint
|
= note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
note: the lint level is defined here
--> lint_example.rs:1:9
|
1 | #![deny(text_direction_codepoint_in_comment)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: if their presence wasn't intentional, you can remove them
Explanation
Unicode allows changing the visual flow of text on screen in order to support scripts that are written right-to-left, but a specially crafted comment can make code that will be compiled appear to be part of a comment, depending on the software used to read the code. To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny their use.
text-direction-codepoint-in-literal
The text_direction_codepoint_in_literal
lint detects Unicode codepoints that change the
visual representation of text on screen in a way that does not correspond to their on
memory representation.
Explanation
The unicode characters \u{202A}
, \u{202B}
, \u{202D}
, \u{202E}
, \u{2066}
,
\u{2067}
, \u{2068}
, \u{202C}
and \u{2069}
make the flow of text on screen change
its direction on software that supports these codepoints. This makes the text "abc" display
as "cba" on screen. By leveraging software that supports these, people can write specially
crafted literals that make the surrounding code seem like it's performing one action, when
in reality it is performing another. Because of this, we proactively lint against their
presence to avoid surprises.
Example
#![deny(text_direction_codepoint_in_literal)]
fn main() {
println!("{:?}", '');
}
This will produce:
error: unicode codepoint changing visible direction of text present in literal
--> lint_example.rs:3:22
|
3 | println!("{:?}", '�');
| ^-^
| ||
| |'\u{202e}'
| this literal contains an invisible unicode text flow control codepoint
|
= note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
note: the lint level is defined here
--> lint_example.rs:1:9
|
1 | #![deny(text_direction_codepoint_in_literal)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: if their presence wasn't intentional, you can remove them
help: if you want to keep them but make them visible in your source code, you can escape them
|
3 | println!("{:?}", '\u{202e}');
| ~~~~~~~~
unconditional-panic
The unconditional_panic
lint detects an operation that will cause a
panic at runtime.
Example
#![allow(unused)]
let x = 1 / 0;
This will produce:
error: this operation will panic at runtime
--> lint_example.rs:3:9
|
3 | let x = 1 / 0;
| ^^^^^ attempt to divide `1_i32` by zero
|
= note: `#[deny(unconditional_panic)]` on by default
Explanation
This lint detects code that is very likely incorrect because it will
always panic, such as division by zero and out-of-bounds array
accesses. Consider adjusting your code if this is a bug, or using the
panic!
or unreachable!
macro instead in case the panic is intended.
undropped-manually-drops
The undropped_manually_drops
lint check for calls to std::mem::drop
with
a value of std::mem::ManuallyDrop
which doesn't drop.
Example
struct S;
drop(std::mem::ManuallyDrop::new(S));
This will produce:
error: calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing
--> lint_example.rs:3:1
|
3 | drop(std::mem::ManuallyDrop::new(S));
| ^^^^^------------------------------^
| |
| argument has type `ManuallyDrop<S>`
|
= note: `#[deny(undropped_manually_drops)]` on by default
help: use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
3 | drop(std::mem::ManuallyDrop::into_inner(std::mem::ManuallyDrop::new(S)));
| +++++++++++++++++++++++++++++++++++ +
Explanation
ManuallyDrop
does not drop it's inner value so calling std::mem::drop
will
not drop the inner value of the ManuallyDrop
either.
unknown-crate-types
The unknown_crate_types
lint detects an unknown crate type found in
a crate_type
attribute.
Example
#![crate_type="lol"]
fn main() {}
This will produce:
error: invalid `crate_type` value
--> lint_example.rs:1:15
|
1 | #![crate_type="lol"]
| ^^^^^
|
= note: `#[deny(unknown_crate_types)]` on by default
Explanation
An unknown value give to the crate_type
attribute is almost
certainly a mistake.
useless-deprecated
The useless_deprecated
lint detects deprecation attributes with no effect.
Example
struct X;
#[deprecated = "message"]
impl Default for X {
fn default() -> Self {
X
}
}
This will produce:
error: this `#[deprecated]` annotation has no effect
--> lint_example.rs:4:1
|
4 | #[deprecated = "message"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute
|
= note: `#[deny(useless_deprecated)]` on by default
Explanation
Deprecation attributes have no effect on trait implementations.
wasm-c-abi
The wasm_c_abi
lint detects crate dependencies that are incompatible
with future versions of Rust that will emit spec-compliant C ABI.
Example
#![deny(wasm_c_abi)]
This will produce:
error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87
|
note: the lint level is defined here
--> src/lib.rs:1:9
|
1 | #![deny(wasm_c_abi)]
| ^^^^^^^^^^
Explanation
Rust has historically emitted non-spec-compliant C ABI. This has caused incompatibilities between other compilers and Wasm targets. In a future version of Rust this will be fixed and therefore dependencies relying on the non-spec-compliant C ABI will stop functioning.