Skip to content

Commit 45140f3

Browse files
committed
fix infinite loop when peeling unwrap method calls
1 parent b5dcaae commit 45140f3

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

clippy_lints/src/casts/cast_sign_loss.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ enum Sign {
118118
Uncertain,
119119
}
120120

121-
fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
121+
fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
122122
// Try evaluate this expr first to see if it's positive
123123
if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
124124
return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
@@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
134134
// Peel unwrap(), expect(), etc.
135135
while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
136136
&& let Some(arglist) = method_chain_args(expr, &[found_name])
137-
&& let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
137+
&& let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind
138138
{
139139
// The original type has changed, but we can't use `ty` here anyway, because it has been
140140
// moved.
141141
method_name = inner_path.ident.name.as_str();
142+
expr = recv
142143
}
143144

144145
if METHODS_POW.iter().any(|&name| method_name == name)

tests/ui/cast.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99
clippy::cast_sign_loss,
1010
clippy::cast_possible_wrap
1111
)]
12-
#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
12+
#![allow(
13+
clippy::cast_abs_to_unsigned,
14+
clippy::no_effect,
15+
clippy::unnecessary_operation,
16+
clippy::unnecessary_literal_unwrap
17+
)]
1318

1419
fn main() {
1520
// Test clippy::cast_precision_loss
@@ -457,3 +462,8 @@ fn issue11642() {
457462
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
458463
}
459464
}
465+
466+
fn issue12506() -> usize {
467+
let bar: Result<Option<i64>, u32> = Ok(Some(10));
468+
bar.unwrap().unwrap() as usize
469+
}

tests/ui/cast.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,5 +650,23 @@ error: casting `i32` to `u32` may lose the sign of the value
650650
LL | (a.abs() * b.pow(2) / c.abs()) as u32
651651
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
652652

653-
error: aborting due to 85 previous errors
653+
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
654+
--> tests/ui/cast.rs:463:5
655+
|
656+
LL | bar.unwrap().unwrap() as usize
657+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
658+
|
659+
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
660+
help: ... or use `try_from` and handle the error accordingly
661+
|
662+
LL | usize::try_from(bar.unwrap().unwrap())
663+
|
664+
665+
error: casting `i64` to `usize` may lose the sign of the value
666+
--> tests/ui/cast.rs:463:5
667+
|
668+
LL | bar.unwrap().unwrap() as usize
669+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
670+
671+
error: aborting due to 87 previous errors
654672

0 commit comments

Comments
 (0)