Skip to content

Commit

Permalink
Auto merge of #12508 - y21:issue12506, r=llogiq
Browse files Browse the repository at this point in the history
Fix infinite loop in `cast_sign_loss` when peeling unwrap method calls

Fixes #12506

The lint wants to peel method calls but didn't actually reassign the expression, leading to an infinite loop.

changelog: Fix infinite loop in [`cast_sign_loss`] when having two chained `.unwrap()` calls
  • Loading branch information
bors committed Mar 20, 2024
2 parents 89aba8d + 3930f8b commit 3fa5ce8
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 89 deletions.
5 changes: 3 additions & 2 deletions clippy_lints/src/casts/cast_sign_loss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ enum Sign {
Uncertain,
}

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

if METHODS_POW.iter().any(|&name| method_name == name)
Expand Down
12 changes: 11 additions & 1 deletion tests/ui/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
clippy::cast_sign_loss,
clippy::cast_possible_wrap
)]
#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
#![allow(
clippy::cast_abs_to_unsigned,
clippy::no_effect,
clippy::unnecessary_operation,
clippy::unnecessary_literal_unwrap
)]

fn main() {
// Test clippy::cast_precision_loss
Expand Down Expand Up @@ -457,3 +462,8 @@ fn issue11642() {
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
}
}

fn issue12506() -> usize {
let bar: Result<Option<i64>, u32> = Ok(Some(10));
bar.unwrap().unwrap() as usize
}
Loading

0 comments on commit 3fa5ce8

Please sign in to comment.