Skip to content

Commit f1f780c

Browse files
committed
Add let_underscore_drop
1 parent 96d5f45 commit f1f780c

File tree

6 files changed

+111
-2
lines changed

6 files changed

+111
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,7 @@ Released 2018-09-13
17871787
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
17881788
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
17891789
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
1790+
[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
17901791
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
17911792
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
17921793
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value

clippy_lints/src/let_underscore.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro;
55
use rustc_middle::ty::subst::GenericArgKind;
66
use rustc_session::{declare_lint_pass, declare_tool_lint};
77

8-
use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
8+
use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
99

1010
declare_clippy_lint! {
1111
/// **What it does:** Checks for `let _ = <expr>`
@@ -58,7 +58,40 @@ declare_clippy_lint! {
5858
"non-binding let on a synchronization lock"
5959
}
6060

61-
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]);
61+
declare_clippy_lint! {
62+
/// **What it does:** Checks for `let _ = <expr>`
63+
/// where expr has a type that implements `Drop`
64+
///
65+
/// **Why is this bad?** This statement immediately drops the initializer
66+
/// expression instead of extending its lifetime to the end of the scope, which
67+
/// is often not intended. To extend the expression's lifetime to the end of the
68+
/// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
69+
/// explicitly drop the expression, `std::mem::drop` conveys your intention
70+
/// better and is less error-prone.
71+
///
72+
/// **Known problems:** None.
73+
///
74+
/// **Example:**
75+
///
76+
/// Bad:
77+
/// ```rust,ignore
78+
/// struct Droppable;
79+
/// impl Drop for Droppable {
80+
/// fn drop(&mut self) {}
81+
/// }
82+
/// let _ = Droppable;
83+
/// ```
84+
///
85+
/// Good:
86+
/// ```rust,ignore
87+
/// let _droppable = Droppable;
88+
/// ```
89+
pub LET_UNDERSCORE_DROP,
90+
correctness,
91+
"non-binding let on a type that implements `Drop`"
92+
}
93+
94+
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
6295

6396
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
6497
&paths::MUTEX_GUARD,
@@ -84,6 +117,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
84117

85118
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
86119
});
120+
let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
121+
init_ty.walk().any(|inner| match inner.unpack() {
122+
GenericArgKind::Type(inner_ty) => {
123+
implements_trait(cx, inner_ty, drop_trait, &[])
124+
},
125+
126+
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
127+
})
128+
);
87129
if contains_sync_guard {
88130
span_lint_and_help(
89131
cx,
@@ -94,6 +136,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
94136
"consider using an underscore-prefixed named \
95137
binding or dropping explicitly with `std::mem::drop`"
96138
)
139+
} else if implements_drop {
140+
span_lint_and_help(
141+
cx,
142+
LET_UNDERSCORE_DROP,
143+
local.span,
144+
"non-binding let on a type that implements `Drop`",
145+
None,
146+
"consider using an underscore-prefixed named \
147+
binding or dropping explicitly with `std::mem::drop`"
148+
)
97149
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
98150
span_lint_and_help(
99151
cx,

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
622622
&len_zero::LEN_WITHOUT_IS_EMPTY,
623623
&len_zero::LEN_ZERO,
624624
&let_if_seq::USELESS_LET_IF_SEQ,
625+
&let_underscore::LET_UNDERSCORE_DROP,
625626
&let_underscore::LET_UNDERSCORE_LOCK,
626627
&let_underscore::LET_UNDERSCORE_MUST_USE,
627628
&lifetimes::EXTRA_UNUSED_LIFETIMES,
@@ -1383,6 +1384,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13831384
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
13841385
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
13851386
LintId::of(&len_zero::LEN_ZERO),
1387+
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
13861388
LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
13871389
LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
13881390
LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
@@ -1809,6 +1811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
18091811
LintId::of(&infinite_iter::INFINITE_ITER),
18101812
LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
18111813
LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
1814+
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
18121815
LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
18131816
LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
18141817
LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,13 @@ vec![
11171117
deprecation: None,
11181118
module: "returns",
11191119
},
1120+
Lint {
1121+
name: "let_underscore_drop",
1122+
group: "correctness",
1123+
desc: "non-binding let on a type that implements `Drop`",
1124+
deprecation: None,
1125+
module: "let_underscore",
1126+
},
11201127
Lint {
11211128
name: "let_underscore_lock",
11221129
group: "correctness",

tests/ui/let_underscore_drop.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![warn(clippy::let_underscore_drop)]
2+
3+
struct Droppable;
4+
5+
impl Drop for Droppable {
6+
fn drop(&mut self) {}
7+
}
8+
9+
fn main() {
10+
let unit = ();
11+
let boxed = Box::new(());
12+
let droppable = Droppable;
13+
let optional = Some(Droppable);
14+
15+
let _ = ();
16+
let _ = Box::new(());
17+
let _ = Droppable;
18+
let _ = Some(Droppable);
19+
}

tests/ui/let_underscore_drop.stderr

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: non-binding let on a type that implements `Drop`
2+
--> $DIR/let_underscore_drop.rs:16:5
3+
|
4+
LL | let _ = Box::new(());
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::let-underscore-drop` implied by `-D warnings`
8+
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
9+
10+
error: non-binding let on a type that implements `Drop`
11+
--> $DIR/let_underscore_drop.rs:17:5
12+
|
13+
LL | let _ = Droppable;
14+
| ^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
17+
18+
error: non-binding let on a type that implements `Drop`
19+
--> $DIR/let_underscore_drop.rs:18:5
20+
|
21+
LL | let _ = Some(Droppable);
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
25+
26+
error: aborting due to 3 previous errors
27+

0 commit comments

Comments
 (0)