Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit df33aaf

Browse files
authored
Check if dropping an expression may have indirect side-effects (rust-lang#14594)
It is not enough to check if an expression type implements `Drop` to determine whether it can have a significant side-effect. Also, add tests for unchecked cases which were explicitly handled in the code, such as checking for side effect in a `struct`'s fields, or in its base expression. Fix rust-lang/rust-clippy#14592 changelog: [`no_effect_underscore_binding`]: do not propose to remove the assignment of an object if dropping it might indirectly have a visible side effect
2 parents d44e35d + 6fb7d53 commit df33aaf

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

clippy_lints/src/no_effect.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,16 @@ fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
221221
}
222222
}
223223

224+
/// Checks if dropping `expr` might have a visible side effect.
225+
fn expr_ty_has_significant_drop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
226+
let ty = cx.typeck_results().expr_ty(expr);
227+
ty.has_significant_drop(cx.tcx, cx.typing_env())
228+
}
229+
224230
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
225231
match expr.kind {
226232
ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
227-
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
233+
ExprKind::Path(..) => !expr_ty_has_significant_drop(cx, expr),
228234
ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
229235
ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
230236
ExprKind::Repeat(inner, _)
@@ -233,8 +239,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
233239
| ExprKind::Unary(_, inner)
234240
| ExprKind::Field(inner, _)
235241
| ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner),
236-
ExprKind::Struct(_, fields, ref base) => {
237-
!has_drop(cx, cx.typeck_results().expr_ty(expr))
242+
ExprKind::Struct(_, fields, base) => {
243+
!expr_ty_has_significant_drop(cx, expr)
238244
&& fields.iter().all(|field| has_no_effect(cx, field.expr))
239245
&& match &base {
240246
StructTailExpr::None | StructTailExpr::DefaultFields(_) => true,
@@ -252,7 +258,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
252258
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
253259
);
254260
if def_matched || is_range_literal(expr) {
255-
!has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
261+
!expr_ty_has_significant_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
256262
} else {
257263
false
258264
}

tests/ui/no_effect.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,56 @@ fn main() {
221221
Cout << 142;
222222
-Cout;
223223
}
224+
225+
fn issue14592() {
226+
struct MyStruct {
227+
_inner: MyInner,
228+
}
229+
struct MyInner {}
230+
231+
impl Drop for MyInner {
232+
fn drop(&mut self) {
233+
println!("dropping");
234+
}
235+
}
236+
237+
let x = MyStruct { _inner: MyInner {} };
238+
239+
let closure = || {
240+
// Do not lint: dropping the assignment or assigning to `_` would
241+
// change the output.
242+
let _x = x;
243+
};
244+
245+
println!("1");
246+
closure();
247+
println!("2");
248+
249+
struct Innocuous {
250+
a: i32,
251+
}
252+
253+
// Do not lint: one of the fields has a side effect.
254+
let x = MyInner {};
255+
let closure = || {
256+
let _x = Innocuous {
257+
a: {
258+
x;
259+
10
260+
},
261+
};
262+
};
263+
264+
// Do not lint: the base has a side effect.
265+
let x = MyInner {};
266+
let closure = || {
267+
let _x = Innocuous {
268+
..Innocuous {
269+
a: {
270+
x;
271+
10
272+
},
273+
}
274+
};
275+
};
276+
}

tests/ui/single_range_in_vec_init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@aux-build:proc_macros.rs
22
//@no-rustfix: overlapping suggestions
3-
#![allow(clippy::no_effect, clippy::useless_vec, unused)]
3+
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
44
#![warn(clippy::single_range_in_vec_init)]
55
#![feature(generic_arg_infer)]
66

0 commit comments

Comments
 (0)