Rollup merge of #150385 - fix-expr-can-have-side-effects, r=jdonszelmann,samueltardieu

fix `Expr::can_have_side_effects` for `[x; N]` style array literal and binary expressions

AFAIK `[0; 3]` is basically a syntax sugar for `[0, 0, 0]` so it should return whether the repeat's element can have side effects, like what it does on arrays.
And it seems that the rule for unary operators and indexings can be applied to binary operators as well.
This commit is contained in:
Guillaume Gomez
2026-01-09 11:59:58 +01:00
committed by GitHub
11 changed files with 127 additions and 41 deletions
+7 -2
View File
@@ -2625,6 +2625,12 @@ pub fn can_have_side_effects(&self) -> bool {
// them being used only for its side-effects.
base.can_have_side_effects()
}
ExprKind::Binary(_, lhs, rhs) => {
// This isn't exactly true for all `Binary`, but we are using this
// method exclusively for diagnostics and there's a *cultural* pressure against
// them being used only for its side-effects.
lhs.can_have_side_effects() || rhs.can_have_side_effects()
}
ExprKind::Struct(_, fields, init) => {
let init_side_effects = match init {
StructTailExpr::Base(init) => init.can_have_side_effects(),
@@ -2647,13 +2653,13 @@ pub fn can_have_side_effects(&self) -> bool {
},
args,
) => args.iter().any(|arg| arg.can_have_side_effects()),
ExprKind::Repeat(arg, _) => arg.can_have_side_effects(),
ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::MethodCall(..)
| ExprKind::Call(..)
| ExprKind::Closure { .. }
| ExprKind::Block(..)
| ExprKind::Repeat(..)
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
@@ -2664,7 +2670,6 @@ pub fn can_have_side_effects(&self) -> bool {
| ExprKind::InlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::ConstBlock(..)
| ExprKind::Binary(..)
| ExprKind::Yield(..)
| ExprKind::DropTemps(..)
| ExprKind::Err(_) => true,
+2 -1
View File
@@ -4,7 +4,8 @@
dead_code,
clippy::unnecessary_operation,
clippy::no_effect,
clippy::if_same_then_else
clippy::if_same_then_else,
clippy::needless_match
)]
use std::cmp::{max as cmp_max, min as cmp_min};
+2 -1
View File
@@ -4,7 +4,8 @@
dead_code,
clippy::unnecessary_operation,
clippy::no_effect,
clippy::if_same_then_else
clippy::if_same_then_else,
clippy::needless_match
)]
use std::cmp::{max as cmp_max, min as cmp_min};
+35 -35
View File
@@ -1,5 +1,5 @@
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:212:5
--> tests/ui/manual_clamp.rs:213:5
|
LL | / if x9 < CONST_MIN {
LL | |
@@ -15,7 +15,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]`
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:230:5
--> tests/ui/manual_clamp.rs:231:5
|
LL | / if x11 > CONST_MAX {
LL | |
@@ -29,7 +29,7 @@ LL | | }
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:240:5
--> tests/ui/manual_clamp.rs:241:5
|
LL | / if CONST_MIN > x12 {
LL | |
@@ -43,7 +43,7 @@ LL | | }
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:250:5
--> tests/ui/manual_clamp.rs:251:5
|
LL | / if CONST_MAX < x13 {
LL | |
@@ -57,7 +57,7 @@ LL | | }
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:363:5
--> tests/ui/manual_clamp.rs:364:5
|
LL | / if CONST_MAX < x35 {
LL | |
@@ -71,7 +71,7 @@ LL | | }
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:144:14
--> tests/ui/manual_clamp.rs:145:14
|
LL | let x0 = if CONST_MAX < input {
| ______________^
@@ -86,7 +86,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:154:14
--> tests/ui/manual_clamp.rs:155:14
|
LL | let x1 = if input > CONST_MAX {
| ______________^
@@ -101,7 +101,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:164:14
--> tests/ui/manual_clamp.rs:165:14
|
LL | let x2 = if input < CONST_MIN {
| ______________^
@@ -116,7 +116,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:174:14
--> tests/ui/manual_clamp.rs:175:14
|
LL | let x3 = if CONST_MIN > input {
| ______________^
@@ -131,7 +131,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:184:14
--> tests/ui/manual_clamp.rs:185:14
|
LL | let x4 = input.max(CONST_MIN).min(CONST_MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -139,7 +139,7 @@ LL | let x4 = input.max(CONST_MIN).min(CONST_MAX);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:187:14
--> tests/ui/manual_clamp.rs:188:14
|
LL | let x5 = input.min(CONST_MAX).max(CONST_MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -147,7 +147,7 @@ LL | let x5 = input.min(CONST_MAX).max(CONST_MIN);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:190:14
--> tests/ui/manual_clamp.rs:191:14
|
LL | let x6 = match input {
| ______________^
@@ -161,7 +161,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:197:14
--> tests/ui/manual_clamp.rs:198:14
|
LL | let x7 = match input {
| ______________^
@@ -175,7 +175,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:204:14
--> tests/ui/manual_clamp.rs:205:14
|
LL | let x8 = match input {
| ______________^
@@ -189,7 +189,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:221:15
--> tests/ui/manual_clamp.rs:222:15
|
LL | let x10 = match input {
| _______________^
@@ -203,7 +203,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:259:15
--> tests/ui/manual_clamp.rs:260:15
|
LL | let x14 = if input > CONST_MAX {
| _______________^
@@ -218,7 +218,7 @@ LL | | };
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:270:19
--> tests/ui/manual_clamp.rs:271:19
|
LL | let x15 = if input > CONST_F64_MAX {
| ___________________^
@@ -234,7 +234,7 @@ LL | | };
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:283:19
--> tests/ui/manual_clamp.rs:284:19
|
LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -242,7 +242,7 @@ LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:286:19
--> tests/ui/manual_clamp.rs:287:19
|
LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -250,7 +250,7 @@ LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:289:19
--> tests/ui/manual_clamp.rs:290:19
|
LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -258,7 +258,7 @@ LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:292:19
--> tests/ui/manual_clamp.rs:293:19
|
LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -266,7 +266,7 @@ LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:295:19
--> tests/ui/manual_clamp.rs:296:19
|
LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -274,7 +274,7 @@ LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:298:19
--> tests/ui/manual_clamp.rs:299:19
|
LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -282,7 +282,7 @@ LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:301:19
--> tests/ui/manual_clamp.rs:302:19
|
LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -290,7 +290,7 @@ LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:304:19
--> tests/ui/manual_clamp.rs:305:19
|
LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -298,7 +298,7 @@ LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:308:19
--> tests/ui/manual_clamp.rs:309:19
|
LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -307,7 +307,7 @@ LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:311:19
--> tests/ui/manual_clamp.rs:312:19
|
LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -316,7 +316,7 @@ LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:314:19
--> tests/ui/manual_clamp.rs:315:19
|
LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -325,7 +325,7 @@ LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:317:19
--> tests/ui/manual_clamp.rs:318:19
|
LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -334,7 +334,7 @@ LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:320:19
--> tests/ui/manual_clamp.rs:321:19
|
LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -343,7 +343,7 @@ LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:323:19
--> tests/ui/manual_clamp.rs:324:19
|
LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -352,7 +352,7 @@ LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:326:19
--> tests/ui/manual_clamp.rs:327:19
|
LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -361,7 +361,7 @@ LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:329:19
--> tests/ui/manual_clamp.rs:330:19
|
LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -370,7 +370,7 @@ LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
= note: clamp returns NaN if the input is NaN
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:333:5
--> tests/ui/manual_clamp.rs:334:5
|
LL | / if x32 < CONST_MIN {
LL | |
@@ -384,7 +384,7 @@ LL | | }
= note: clamp will panic if max < min
error: clamp-like pattern without using clamp function
--> tests/ui/manual_clamp.rs:525:13
--> tests/ui/manual_clamp.rs:526:13
|
LL | let _ = if input > CONST_MAX {
| _____________^
@@ -34,7 +34,9 @@ fn main() {
println!("true") // This is a const method call
}
if y & (0 < 1) {
// Resolved
if y && (0 < 1) {
//~^ needless_bitwise_bool
println!("true") // This is a BinOp with no side effects
}
}
@@ -34,7 +34,9 @@ fn main() {
println!("true") // This is a const method call
}
// Resolved
if y & (0 < 1) {
//~^ needless_bitwise_bool
println!("true") // This is a BinOp with no side effects
}
}
@@ -7,5 +7,11 @@ LL | if y & !x {
= note: `-D clippy::needless-bitwise-bool` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::needless_bitwise_bool)]`
error: aborting due to 1 previous error
error: use of bitwise operator instead of lazy operator between booleans
--> tests/ui/needless_bitwise_bool.rs:38:8
|
LL | if y & (0 < 1) {
| ^^^^^^^^^^^ help: try: `y && (0 < 1)`
error: aborting due to 2 previous errors
@@ -0,0 +1,23 @@
//@ check-pass
#![allow(unused)]
// Test if `Expr::can_have_side_effects` considers operands of binary operators.
fn drop_repeat_in_arm_body() {
// Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects`
// (See rust-clippy#9482 and rust#113231)
match () {
() => drop(5 % 3), // No side effects
//~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing
}
match () {
() => drop(5 % calls_are_considered_side_effects()), // Definitely has side effects
}
}
fn calls_are_considered_side_effects() -> i32 {
3
}
fn main() {}
@@ -0,0 +1,13 @@
warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing
--> $DIR/can-have-side-effects-consider-operands.rs:12:15
|
LL | () => drop(5 % 3), // No side effects
| ^^^^^-----^
| |
| argument has type `i32`
|
= note: use `let _ = ...` to ignore the expression or result
= note: `#[warn(dropping_copy_types)]` on by default
warning: 1 warning emitted
@@ -0,0 +1,20 @@
//@ check-pass
#![allow(unused)]
// Test if `Expr::can_have_side_effects` considers element of repeat expressions.
fn drop_repeat_in_arm_body() {
// Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects`
// (See rust-clippy#9482 and rust#113231)
match () {
() => drop([0; 1]), // No side effects
//~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing
}
match () {
() => drop([return; 1]), // Definitely has side effects
}
}
fn main() {}
@@ -0,0 +1,13 @@
warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing
--> $DIR/can-have-side-effects-consider-element.rs:12:15
|
LL | () => drop([0; 1]), // No side effects
| ^^^^^------^
| |
| argument has type `[i32; 1]`
|
= note: use `let _ = ...` to ignore the expression or result
= note: `#[warn(dropping_copy_types)]` on by default
warning: 1 warning emitted