Skip to content

Commit dd826b4

Browse files
committed
Auto merge of rust-lang#6305 - smoelius:master, r=flip1995
Add `let_underscore_drop` This line generalizes `let_underscore_lock` (rust-lang#5101) to warn about any initializer expression that implements `Drop`. So, for example, the following would generate a warning: ```rust struct Droppable; impl Drop for Droppable { fn drop(&mut self) {} } let _ = Droppable; ``` I tried to preserve the original `let_underscore_lock` functionality in the sense that the warning generated for ```rust let _ = mutex.lock(); ``` should be unchanged. *Please keep the line below* changelog: Add lint [`let_underscore_drop`]
2 parents d212c38 + 4852cca commit dd826b4

14 files changed

+139
-18
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: 62 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,48 @@ 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+
/// {
83+
/// let _ = Droppable;
84+
/// // ^ dropped here
85+
/// /* more code */
86+
/// }
87+
/// ```
88+
///
89+
/// Good:
90+
/// ```rust,ignore
91+
/// {
92+
/// let _droppable = Droppable;
93+
/// /* more code */
94+
/// // dropped at end of scope
95+
/// }
96+
/// ```
97+
pub LET_UNDERSCORE_DROP,
98+
pedantic,
99+
"non-binding let on a type that implements `Drop`"
100+
}
101+
102+
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
62103

63104
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
64105
&paths::MUTEX_GUARD,
@@ -84,6 +125,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
84125

85126
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
86127
});
128+
let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
129+
init_ty.walk().any(|inner| match inner.unpack() {
130+
GenericArgKind::Type(inner_ty) => {
131+
implements_trait(cx, inner_ty, drop_trait, &[])
132+
},
133+
134+
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
135+
})
136+
);
87137
if contains_sync_guard {
88138
span_lint_and_help(
89139
cx,
@@ -94,6 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
94144
"consider using an underscore-prefixed named \
95145
binding or dropping explicitly with `std::mem::drop`"
96146
)
147+
} else if implements_drop {
148+
span_lint_and_help(
149+
cx,
150+
LET_UNDERSCORE_DROP,
151+
local.span,
152+
"non-binding `let` on a type that implements `Drop`",
153+
None,
154+
"consider using an underscore-prefixed named \
155+
binding or dropping explicitly with `std::mem::drop`"
156+
)
97157
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
98158
span_lint_and_help(
99159
cx,

clippy_lints/src/lib.rs

Lines changed: 2 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,
@@ -1240,6 +1241,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12401241
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
12411242
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
12421243
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
1244+
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
12431245
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
12441246
LintId::of(&literal_representation::UNREADABLE_LITERAL),
12451247
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),

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: "pedantic",
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/filter_methods.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::all, clippy::pedantic)]
2+
#![allow(clippy::clippy::let_underscore_drop)]
23
#![allow(clippy::missing_docs_in_private_items)]
34

45
fn main() {

tests/ui/filter_methods.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: called `filter(..).map(..)` on an `Iterator`
2-
--> $DIR/filter_methods.rs:5:21
2+
--> $DIR/filter_methods.rs:6:21
33
|
44
LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x *
88
= help: this is more succinctly expressed by calling `.filter_map(..)` instead
99

1010
error: called `filter(..).flat_map(..)` on an `Iterator`
11-
--> $DIR/filter_methods.rs:7:21
11+
--> $DIR/filter_methods.rs:8:21
1212
|
1313
LL | let _: Vec<_> = vec![5_i8; 6]
1414
| _____________________^
@@ -20,7 +20,7 @@ LL | | .flat_map(|x| x.checked_mul(2))
2020
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
2121

2222
error: called `filter_map(..).flat_map(..)` on an `Iterator`
23-
--> $DIR/filter_methods.rs:13:21
23+
--> $DIR/filter_methods.rs:14:21
2424
|
2525
LL | let _: Vec<_> = vec![5_i8; 6]
2626
| _____________________^
@@ -32,7 +32,7 @@ LL | | .flat_map(|x| x.checked_mul(2))
3232
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
3333

3434
error: called `filter_map(..).map(..)` on an `Iterator`
35-
--> $DIR/filter_methods.rs:19:21
35+
--> $DIR/filter_methods.rs:20:21
3636
|
3737
LL | let _: Vec<_> = vec![5_i8; 6]
3838
| _____________________^

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+

tests/ui/map_clone.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![warn(clippy::all, clippy::pedantic)]
33
#![allow(clippy::iter_cloned_collect)]
44
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
5+
#![allow(clippy::let_underscore_drop)]
56
#![allow(clippy::missing_docs_in_private_items)]
67
#![allow(clippy::redundant_closure_for_method_calls)]
78
#![allow(clippy::many_single_char_names)]

tests/ui/map_clone.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![warn(clippy::all, clippy::pedantic)]
33
#![allow(clippy::iter_cloned_collect)]
44
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
5+
#![allow(clippy::let_underscore_drop)]
56
#![allow(clippy::missing_docs_in_private_items)]
67
#![allow(clippy::redundant_closure_for_method_calls)]
78
#![allow(clippy::many_single_char_names)]

tests/ui/map_clone.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
error: you are using an explicit closure for copying elements
2-
--> $DIR/map_clone.rs:10:22
2+
--> $DIR/map_clone.rs:11:22
33
|
44
LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
66
|
77
= note: `-D clippy::map-clone` implied by `-D warnings`
88

99
error: you are using an explicit closure for cloning elements
10-
--> $DIR/map_clone.rs:11:26
10+
--> $DIR/map_clone.rs:12:26
1111
|
1212
LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
1414

1515
error: you are using an explicit closure for copying elements
16-
--> $DIR/map_clone.rs:12:23
16+
--> $DIR/map_clone.rs:13:23
1717
|
1818
LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
2020

2121
error: you are using an explicit closure for copying elements
22-
--> $DIR/map_clone.rs:14:26
22+
--> $DIR/map_clone.rs:15:26
2323
|
2424
LL | let _: Option<u64> = Some(&16).map(|b| *b);
2525
| ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
2626

2727
error: you are using an explicit closure for copying elements
28-
--> $DIR/map_clone.rs:15:25
28+
--> $DIR/map_clone.rs:16:25
2929
|
3030
LL | let _: Option<u8> = Some(&1).map(|x| x.clone());
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
3232

3333
error: you are needlessly cloning iterator elements
34-
--> $DIR/map_clone.rs:26:29
34+
--> $DIR/map_clone.rs:27:29
3535
|
3636
LL | let _ = std::env::args().map(|v| v.clone());
3737
| ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call

tests/ui/map_flatten.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// run-rustfix
22

33
#![warn(clippy::all, clippy::pedantic)]
4+
#![allow(clippy::let_underscore_drop)]
45
#![allow(clippy::missing_docs_in_private_items)]
56
#![allow(clippy::map_identity)]
67

tests/ui/map_flatten.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// run-rustfix
22

33
#![warn(clippy::all, clippy::pedantic)]
4+
#![allow(clippy::let_underscore_drop)]
45
#![allow(clippy::missing_docs_in_private_items)]
56
#![allow(clippy::map_identity)]
67

tests/ui/map_flatten.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
error: called `map(..).flatten()` on an `Iterator`
2-
--> $DIR/map_flatten.rs:14:46
2+
--> $DIR/map_flatten.rs:15:46
33
|
44
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
66
|
77
= note: `-D clippy::map-flatten` implied by `-D warnings`
88

99
error: called `map(..).flatten()` on an `Iterator`
10-
--> $DIR/map_flatten.rs:15:46
10+
--> $DIR/map_flatten.rs:16:46
1111
|
1212
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
1414

1515
error: called `map(..).flatten()` on an `Iterator`
16-
--> $DIR/map_flatten.rs:16:46
16+
--> $DIR/map_flatten.rs:17:46
1717
|
1818
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
2020

2121
error: called `map(..).flatten()` on an `Iterator`
22-
--> $DIR/map_flatten.rs:17:46
22+
--> $DIR/map_flatten.rs:18:46
2323
|
2424
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
2626

2727
error: called `map(..).flatten()` on an `Iterator`
28-
--> $DIR/map_flatten.rs:20:46
28+
--> $DIR/map_flatten.rs:21:46
2929
|
3030
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
3232

3333
error: called `map(..).flatten()` on an `Option`
34-
--> $DIR/map_flatten.rs:23:39
34+
--> $DIR/map_flatten.rs:24:39
3535
|
3636
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
3737
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`

0 commit comments

Comments
 (0)