Skip to content

Commit c6cb0e9

Browse files
committed
[unnecessary_cast]: Avoid breaking precedence
If the whole cast expression is a unary expression (`(*x as T)`) or an addressof expression (`(&x as T)`), then not surrounding the suggestion into a block risks us changing the precedence of operators if the cast expression is followed by an operation with higher precedence than the unary operator (`(*x as T).foo()` would become `*x.foo()`, which changes what the `*` applies on). The same is true if the expression encompassing the cast expression is a unary expression or an addressof expression. The lint supports the latter case, but missed the former one. This PR fixes that. Fixes #11968
1 parent 1013617 commit c6cb0e9

File tree

4 files changed

+31
-2
lines changed

4 files changed

+31
-2
lines changed

clippy_lints/src/casts/unnecessary_cast.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,24 @@ pub(super) fn check<'tcx>(
151151
return false;
152152
}
153153

154+
// If the whole cast expression is a unary expression (`(*x as T)`) or an addressof
155+
// expression (`(&x as T)`), then not surrounding the suggestion into a block risks us
156+
// changing the precedence of operators if the cast expression is followed by an operation
157+
// with higher precedence than the unary operator (`(*x as T).foo()` would become
158+
// `*x.foo()`, which changes what the `*` applies on).
159+
// The same is true if the expression encompassing the cast expression is a unary
160+
// expression or an addressof expression.
161+
let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
162+
|| get_parent_expr(cx, expr)
163+
.map_or(false, |e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
164+
154165
span_lint_and_sugg(
155166
cx,
156167
UNNECESSARY_CAST,
157168
expr.span,
158169
&format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
159170
"try",
160-
if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(..))) {
171+
if needs_block {
161172
format!("{{ {cast_str} }}")
162173
} else {
163174
cast_str

tests/ui/unnecessary_cast.fixed

+6
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,10 @@ mod fixable {
221221
fn issue_9603() {
222222
let _: f32 = -0x400 as f32;
223223
}
224+
225+
// Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
226+
// `*x.pow(2)` which tries to dereference the return value rather than `x`.
227+
fn issue_11968(x: &usize) -> usize {
228+
{ *x }.pow(2)
229+
}
224230
}

tests/ui/unnecessary_cast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,10 @@ mod fixable {
221221
fn issue_9603() {
222222
let _: f32 = -0x400 as f32;
223223
}
224+
225+
// Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
226+
// `*x.pow(2)` which tries to dereference the return value rather than `x`.
227+
fn issue_11968(x: &usize) -> usize {
228+
(*x as usize).pow(2)
229+
}
224230
}

tests/ui/unnecessary_cast.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -241,5 +241,11 @@ error: casting to the same type is unnecessary (`f32` -> `f32`)
241241
LL | let _num = foo() as f32;
242242
| ^^^^^^^^^^^^ help: try: `foo()`
243243

244-
error: aborting due to 40 previous errors
244+
error: casting to the same type is unnecessary (`usize` -> `usize`)
245+
--> tests/ui/unnecessary_cast.rs:228:9
246+
|
247+
LL | (*x as usize).pow(2)
248+
| ^^^^^^^^^^^^^ help: try: `{ *x }`
249+
250+
error: aborting due to 41 previous errors
245251

0 commit comments

Comments
 (0)