Auto merge of #12126 - teor2345:patch-1, r=llogiq

Fix sign-handling bugs and false negatives in `cast_sign_loss`

**Note: anyone should feel free to move this PR forward, I might not see notifications from reviewers.**

changelog: [`cast_sign_loss`]: Fix sign-handling bugs and false negatives

This PR fixes some arithmetic bugs and false negatives in PR #11883 (and maybe earlier PRs).
Cc `@J-ZhengLi`

I haven't updated the tests yet. I was hoping for some initial feedback before adding tests to cover the cases listed below.

Here are the issues I've attempted to fix:

#### `abs()` can return a negative value in release builds

Example:
```rust
i32::MIN.abs()
```
https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=022d200f9ef6ee72f629c0c9c1af11b8

Docs: https://doc.rust-lang.org/std/primitive.i32.html#method.abs

Other overflows that produce negative values could cause false negatives (and underflows could produce false positives), but they're harder to detect.

#### Values with uncertain signs can be positive or negative

Any number of values with uncertain signs cause the whole expression to have an uncertain sign, because an uncertain sign can be positive or negative.

Example (from UI tests):
```rust
fn main() {
    foo(a: i32, b: i32, c: i32) -> u32 {
        (a * b * c * c) as u32
        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
    }

    println!("{}", foo(1, -1, 1));
}
```
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=165d2e2676ee8343b1b9fe60db32aadd

#### Handle `expect()` the same way as `unwrap()`

Since we're ignoring `unwrap()` we might as well do the same with `expect()`.

This doesn't seem to have tests but I'm happy to add some like `Some(existing_test).unwrap() as u32`.

#### A negative base to an odd exponent is guaranteed to be negative

An integer `pow()`'s sign is only uncertain when its operants are uncertain. (Ignoring overflow.)

Example:
```rust
((-2_i32).pow(3) * -2) as u32
```

This offsets some of the false positives created by one or more uncertain signs producing an uncertain sign. (Rather than just an odd number of uncertain signs.)

#### Both sides of a multiply or divide should be peeled recursively

I'm not sure why the lhs was peeled recursively, and the rhs was left intact. But the sign of any sequence of multiplies and divides is determined by the signs of its operands. (Ignoring overflow.)

I'm not sure what to use as an example here, because most expressions I want to use are const-evaluable.

But if `p()` is [a non-const function that returns a positive value](https://doc.rust-lang.org/std/primitive.i32.html#method.isqrt), and if the lint handles unary negation, these should all lint:
```rust
fn peel_all(x: i32) {
    (-p(x) * -p(x) * -p(x)) as u32;
    ((-p(x) * -p(x)) * -p(x)) as u32;
    (-p(x) * (-p(x) * -p(x))) as u32;
}
```

#### The right hand side of a Rem doesn't change the sign

Unlike Mul and Div,
> Given remainder = dividend % divisor, the remainder will have the same sign as the dividend.
https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators

I'm not sure what to use as an example here, because most expressions I want to use are const-evaluable.

But if `p()` is [a non-const function that returns a positive value](https://doc.rust-lang.org/std/primitive.i32.html#method.isqrt), and if the lint handles unary negation, only the first six expressions should lint.

The expressions that start with a constant should lint (or not lint) regardless of whether the lint supports `p()` or unary negation, because only the dividend's sign matters.

Example:
```rust
fn rem_lhs(x: i32) {
    (-p(x) % -1) as u32;
    (-p(x) % 1) as u32;
    (-1 % -p(x)) as u32;
    (-1 % p(x)) as u32;
    (-1 % -x) as u32;
    (-1 % x) as u32;
    // These shouldn't lint:
    (p(x) % -1) as u32;
    (p(x) % 1) as u32;
    (1 % -p(x)) as u32;
    (1 % p(x)) as u32;
    (1 % -x) as u32;
    (1 % x) as u32;
}
```

#### There's no need to bail on other expressions

When peeling, any other operators or expressions can be left intact and sent to the constant evaluator.

If these expressions can be evaluated, this offsets some of the false positives created by one or more uncertain signs producing an uncertain sign. If not, they end up marked as having uncertain sign.
This commit is contained in:
bors 2024-02-27 05:38:40 +00:00
commit e33cba523a
3 changed files with 505 additions and 146 deletions

View File

@ -1,15 +1,47 @@
use std::convert::Infallible;
use std::ops::ControlFlow;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{clip, method_chain_args, sext};
use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{method_chain_args, sext};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, UintTy};
use rustc_middle::ty::{self, Ty};
use super::CAST_SIGN_LOSS;
const METHODS_RET_POSITIVE: &[&str] = &["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
/// A list of methods that can never return a negative value.
/// Includes methods that panic rather than returning a negative value.
///
/// Methods that can overflow and return a negative value must not be included in this list,
/// because casting their return values can still result in sign loss.
const METHODS_RET_POSITIVE: &[&str] = &[
"checked_abs",
"saturating_abs",
"isqrt",
"checked_isqrt",
"rem_euclid",
"checked_rem_euclid",
"wrapping_rem_euclid",
];
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
/// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details.
///
/// Methods that can overflow and return a negative value must not be included in this list,
/// because casting their return values can still result in sign loss.
const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"];
/// A list of methods that act like `unwrap()`, and don't change the sign of the inner value.
const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"];
pub(super) fn check<'cx>(
cx: &LateContext<'cx>,
expr: &Expr<'_>,
cast_op: &Expr<'_>,
cast_from: Ty<'cx>,
cast_to: Ty<'_>,
) {
if should_lint(cx, cast_op, cast_from, cast_to) {
span_lint(
cx,
@ -20,35 +52,27 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c
}
}
fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool {
fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx>, cast_to: Ty<'_>) -> bool {
match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
if !cast_from.is_signed() || cast_to.is_signed() {
return false;
}
// Don't lint if `cast_op` is known to be positive.
// Don't lint if `cast_op` is known to be positive, ignoring overflow.
if let Sign::ZeroOrPositive = expr_sign(cx, cast_op, cast_from) {
return false;
}
let (mut uncertain_count, mut negative_count) = (0, 0);
// Peel off possible binary expressions, e.g. x * x * y => [x, x, y]
let Some(exprs) = exprs_with_selected_binop_peeled(cast_op) else {
// Assume cast sign lose if we cannot determine the sign of `cast_op`
return true;
};
for expr in exprs {
let ty = cx.typeck_results().expr_ty(expr);
match expr_sign(cx, expr, ty) {
Sign::Negative => negative_count += 1,
Sign::Uncertain => uncertain_count += 1,
Sign::ZeroOrPositive => (),
};
if let Sign::ZeroOrPositive = expr_muldiv_sign(cx, cast_op) {
return false;
}
// Lint if there are odd number of uncertain or negative results
uncertain_count % 2 == 1 || negative_count % 2 == 1
if let Sign::ZeroOrPositive = expr_add_sign(cx, cast_op) {
return false;
}
true
},
(false, true) => !cast_to.is_signed(),
@ -57,7 +81,13 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
}
}
fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Option<i128> {
fn get_const_signed_int_eval<'cx>(
cx: &LateContext<'cx>,
expr: &Expr<'_>,
ty: impl Into<Option<Ty<'cx>>>,
) -> Option<i128> {
let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
&& let ty::Int(ity) = *ty.kind()
{
@ -66,29 +96,52 @@ fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Opti
None
}
fn get_const_unsigned_int_eval<'cx>(
cx: &LateContext<'cx>,
expr: &Expr<'_>,
ty: impl Into<Option<Ty<'cx>>>,
) -> Option<u128> {
let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
&& let ty::Uint(_ity) = *ty.kind()
{
return Some(n);
}
None
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Sign {
ZeroOrPositive,
Negative,
Uncertain,
}
fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign {
fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
// Try evaluate this expr first to see if it's positive
if let Some(val) = get_const_int_eval(cx, expr, ty) {
if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
}
if let Some(_val) = get_const_unsigned_int_eval(cx, expr, None) {
return Sign::ZeroOrPositive;
}
// Calling on methods that always return non-negative values.
if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind {
let mut method_name = path.ident.name.as_str();
if method_name == "unwrap"
&& let Some(arglist) = method_chain_args(expr, &["unwrap"])
// 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
{
// 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();
}
if method_name == "pow"
if METHODS_POW.iter().any(|&name| method_name == name)
&& let [arg] = args
{
return pow_call_result_sign(cx, caller, arg);
@ -100,53 +153,182 @@ fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign {
Sign::Uncertain
}
/// Return the sign of the `pow` call's result.
/// Return the sign of the `pow` call's result, ignoring overflow.
///
/// If the caller is a positive number, the result is always positive,
/// If the `power_of` is a even number, the result is always positive as well,
/// Otherwise a [`Sign::Uncertain`] will be returned.
fn pow_call_result_sign(cx: &LateContext<'_>, caller: &Expr<'_>, power_of: &Expr<'_>) -> Sign {
let caller_ty = cx.typeck_results().expr_ty(caller);
if let Some(caller_val) = get_const_int_eval(cx, caller, caller_ty)
&& caller_val >= 0
{
return Sign::ZeroOrPositive;
/// If the base is positive, the result is always positive.
/// If the exponent is a even number, the result is always positive,
/// Otherwise, if the base is negative, and the exponent is an odd number, the result is always
/// negative.
///
/// Otherwise, returns [`Sign::Uncertain`].
fn pow_call_result_sign(cx: &LateContext<'_>, base: &Expr<'_>, exponent: &Expr<'_>) -> Sign {
let base_sign = expr_sign(cx, base, None);
// Rust's integer pow() functions take an unsigned exponent.
let exponent_val = get_const_unsigned_int_eval(cx, exponent, None);
let exponent_is_even = exponent_val.map(|val| val % 2 == 0);
match (base_sign, exponent_is_even) {
// Non-negative bases always return non-negative results, ignoring overflow.
(Sign::ZeroOrPositive, _) |
// Any base raised to an even exponent is non-negative.
// These both hold even if we don't know the value of the base.
(_, Some(true))
=> Sign::ZeroOrPositive,
// A negative base raised to an odd exponent is non-negative.
(Sign::Negative, Some(false)) => Sign::Negative,
// Negative/unknown base to an unknown exponent, or unknown base to an odd exponent.
// Could be negative or positive depending on the actual values.
(Sign::Negative | Sign::Uncertain, None) |
(Sign::Uncertain, Some(false)) => Sign::Uncertain,
}
}
/// Peels binary operators such as [`BinOpKind::Mul`] or [`BinOpKind::Rem`],
/// where the result could always be positive. See [`exprs_with_muldiv_binop_peeled()`] for details.
///
/// Returns the sign of the list of peeled expressions.
fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
let mut negative_count = 0;
// Peel off possible binary expressions, for example:
// x * x / y => [x, x, y]
// a % b => [a]
let exprs = exprs_with_muldiv_binop_peeled(expr);
for expr in exprs {
match expr_sign(cx, expr, None) {
Sign::Negative => negative_count += 1,
// A mul/div is:
// - uncertain if there are any uncertain values (because they could be negative or positive),
Sign::Uncertain => return Sign::Uncertain,
Sign::ZeroOrPositive => (),
};
}
if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), power_of)
&& clip(cx.tcx, n, UintTy::U32) % 2 == 0
{
return Sign::ZeroOrPositive;
// A mul/div is:
// - negative if there are an odd number of negative values,
// - positive or zero otherwise.
if negative_count % 2 == 1 {
Sign::Negative
} else {
Sign::ZeroOrPositive
}
}
/// Peels binary operators such as [`BinOpKind::Add`], where the result could always be positive.
/// See [`exprs_with_add_binop_peeled()`] for details.
///
/// Returns the sign of the list of peeled expressions.
fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
let mut negative_count = 0;
let mut positive_count = 0;
// Peel off possible binary expressions, for example:
// a + b + c => [a, b, c]
let exprs = exprs_with_add_binop_peeled(expr);
for expr in exprs {
match expr_sign(cx, expr, None) {
Sign::Negative => negative_count += 1,
// A sum is:
// - uncertain if there are any uncertain values (because they could be negative or positive),
Sign::Uncertain => return Sign::Uncertain,
Sign::ZeroOrPositive => positive_count += 1,
};
}
// A sum is:
// - positive or zero if there are only positive (or zero) values,
// - negative if there are only negative (or zero) values, or
// - uncertain if there are both.
// We could split Zero out into its own variant, but we don't yet.
if negative_count == 0 {
Sign::ZeroOrPositive
} else if positive_count == 0 {
Sign::Negative
} else {
Sign::Uncertain
}
}
/// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`],
/// which the result could always be positive under certain condition.
/// where the result depends on:
/// - the number of negative values in the entire expression, or
/// - the number of negative values on the left hand side of the expression.
/// Ignores overflow.
///
/// Other operators such as `+`/`-` causing the result's sign hard to determine, which we will
/// return `None`
fn exprs_with_selected_binop_peeled<'a>(expr: &'a Expr<'_>) -> Option<Vec<&'a Expr<'a>>> {
#[inline]
fn collect_operands<'a>(expr: &'a Expr<'a>, operands: &mut Vec<&'a Expr<'a>>) -> Option<()> {
match expr.kind {
ExprKind::Binary(op, lhs, rhs) => {
if matches!(op.node, BinOpKind::Mul | BinOpKind::Div | BinOpKind::Rem) {
collect_operands(lhs, operands);
operands.push(rhs);
} else {
// Things are complicated when there are other binary ops exist,
// abort checking by returning `None` for now.
return None;
}
},
_ => operands.push(expr),
}
Some(())
}
///
/// Expressions using other operators are preserved, so we can try to evaluate them later.
fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> {
let mut res = vec![];
collect_operands(expr, &mut res)?;
Some(res)
for_each_expr(expr, |sub_expr| -> ControlFlow<Infallible, Descend> {
// We don't check for mul/div/rem methods here, but we could.
if let ExprKind::Binary(op, lhs, _rhs) = sub_expr.kind {
if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) {
// For binary operators where both sides contribute to the sign of the result,
// collect all their operands, recursively. This ignores overflow.
ControlFlow::Continue(Descend::Yes)
} else if matches!(op.node, BinOpKind::Rem | BinOpKind::Shr) {
// For binary operators where the left hand side determines the sign of the result,
// only collect that side, recursively. Overflow panics, so this always holds.
//
// Large left shifts turn negatives into zeroes, so we can't use it here.
//
// > Given remainder = dividend % divisor, the remainder will have the same sign as the dividend
// > ...
// > Arithmetic right shift on signed integer types
// https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
// We want to descend into the lhs, but skip the rhs.
// That's tricky to do using for_each_expr(), so we just keep the lhs intact.
res.push(lhs);
ControlFlow::Continue(Descend::No)
} else {
// The sign of the result of other binary operators depends on the values of the operands,
// so try to evaluate the expression.
res.push(sub_expr);
ControlFlow::Continue(Descend::No)
}
} else {
// For other expressions, including unary operators and constants, try to evaluate the expression.
res.push(sub_expr);
ControlFlow::Continue(Descend::No)
}
});
res
}
/// Peels binary operators such as [`BinOpKind::Add`], where the result depends on:
/// - all the expressions being positive, or
/// - all the expressions being negative.
/// Ignores overflow.
///
/// Expressions using other operators are preserved, so we can try to evaluate them later.
fn exprs_with_add_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> {
let mut res = vec![];
for_each_expr(expr, |sub_expr| -> ControlFlow<Infallible, Descend> {
// We don't check for add methods here, but we could.
if let ExprKind::Binary(op, _lhs, _rhs) = sub_expr.kind {
if matches!(op.node, BinOpKind::Add) {
// For binary operators where both sides contribute to the sign of the result,
// collect all their operands, recursively. This ignores overflow.
ControlFlow::Continue(Descend::Yes)
} else {
// The sign of the result of other binary operators depends on the values of the operands,
// so try to evaluate the expression.
res.push(sub_expr);
ControlFlow::Continue(Descend::No)
}
} else {
// For other expressions, including unary operators and constants, try to evaluate the expression.
res.push(sub_expr);
ControlFlow::Continue(Descend::No)
}
});
res
}

View File

@ -1,6 +1,7 @@
//@no-rustfix
#![feature(repr128)]
#![feature(isqrt)]
#![allow(incomplete_features)]
#![warn(
clippy::cast_precision_loss,
@ -116,20 +117,40 @@ fn main() {
i64::MAX as u64;
i128::MAX as u128;
(-1i8).abs() as u8;
(-1i16).abs() as u16;
(-1i32).abs() as u32;
(-1i8).saturating_abs() as u8;
// abs() can return a negative value in release builds
(i8::MIN).abs() as u8;
//~^ ERROR: casting `i8` to `u8` may lose the sign of the value
(-1i16).saturating_abs() as u16;
(-1i32).saturating_abs() as u32;
(-1i64).abs() as u64;
(-1isize).abs() as usize;
(-1i8).checked_abs().unwrap() as u8;
(i8::MIN).checked_abs().unwrap() as u8;
(-1i16).checked_abs().unwrap() as u16;
(-1i32).checked_abs().unwrap() as u32;
(-1i64).checked_abs().unwrap() as u64;
(-1isize).checked_abs().unwrap() as usize;
// SAFETY: -1 is a small number which will always return Some
(unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
(-1isize).checked_abs().expect("-1 is a small number") as usize;
(-1i8).isqrt() as u8;
(i8::MIN).isqrt() as u8;
(-1i16).isqrt() as u16;
(-1i32).isqrt() as u32;
(-1i64).isqrt() as u64;
(-1isize).isqrt() as usize;
(-1i8).checked_isqrt().unwrap() as u8;
(i8::MIN).checked_isqrt().unwrap() as u8;
(-1i16).checked_isqrt().unwrap() as u16;
(-1i32).checked_isqrt().unwrap() as u32;
// SAFETY: -1 is a small number which will always return Some
(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
(-1isize).checked_isqrt().expect("-1 is a small number") as usize;
(-1i8).rem_euclid(1i8) as u8;
(-1i8).rem_euclid(1i8) as u16;
(-1i8).wrapping_rem_euclid(1i8) as u16;
(-1i16).rem_euclid(1i16) as u16;
(-1i16).rem_euclid(1i16) as u32;
(-1i32).rem_euclid(1i32) as u32;
@ -138,7 +159,7 @@ fn main() {
(-1i64).rem_euclid(1i64) as u128;
(-1isize).rem_euclid(1isize) as usize;
(1i8).rem_euclid(-1i8) as u8;
(1i8).rem_euclid(-1i8) as u16;
(1i8).wrapping_rem_euclid(-1i8) as u16;
(1i16).rem_euclid(-1i16) as u16;
(1i16).rem_euclid(-1i16) as u32;
(1i32).rem_euclid(-1i32) as u32;
@ -371,14 +392,25 @@ fn issue11642() {
let x = x as i32;
(x * x) as u32;
x.pow(2) as u32;
(-2_i32).pow(2) as u32
(-2_i32).saturating_pow(2) as u32
}
let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
(2_i32).checked_pow(3).unwrap() as u32;
(-2_i32).pow(3) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(3_i32 % 2) as u32;
(3_i32 % -2) as u32;
(-5_i32 % 2) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(-5_i32 % -2) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(2_i32 >> 1) as u32;
(-2_i32 >> 1) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
let x: i32 = 10;
(x * x) as u32;
(x * x * x) as u32;
@ -387,12 +419,22 @@ fn issue11642() {
let y: i16 = -2;
(y * y * y * y * -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y * y * y * y * 2) as u16;
(y * y * y * 2) as u16;
(y * y * y / y * 2) as u16;
(y * y / y * 2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y * y * y * -2) as u16;
(y / y * y * -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y + y + y + -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y + y + y + 2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
let z: i16 = 2;
(z + -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(z + z + 2) as u16;
fn foo(a: i32, b: i32, c: i32) -> u32 {
(a * a * b * b * c * c) as u32;
(a * b * c) as u32;
@ -409,8 +451,9 @@ fn issue11642() {
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a / b + b * c) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
a.pow(3) as u32;
a.saturating_pow(3) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a.abs() * b.pow(2) / c.abs()) as u32
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
}
}

View File

@ -1,5 +1,5 @@
error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:16:5
--> tests/ui/cast.rs:17:5
|
LL | x0 as f32;
| ^^^^^^^^^
@ -8,37 +8,37 @@ LL | x0 as f32;
= help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:20:5
--> tests/ui/cast.rs:21:5
|
LL | x1 as f32;
| ^^^^^^^^^
error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> tests/ui/cast.rs:22:5
--> tests/ui/cast.rs:23:5
|
LL | x1 as f64;
| ^^^^^^^^^
error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:25:5
--> tests/ui/cast.rs:26:5
|
LL | x2 as f32;
| ^^^^^^^^^
error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:28:5
--> tests/ui/cast.rs:29:5
|
LL | x3 as f32;
| ^^^^^^^^^
error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> tests/ui/cast.rs:30:5
--> tests/ui/cast.rs:31:5
|
LL | x3 as f64;
| ^^^^^^^^^
error: casting `f32` to `i32` may truncate the value
--> tests/ui/cast.rs:33:5
--> tests/ui/cast.rs:34:5
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@ -48,7 +48,7 @@ LL | 1f32 as i32;
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
error: casting `f32` to `u32` may truncate the value
--> tests/ui/cast.rs:35:5
--> tests/ui/cast.rs:36:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@ -56,7 +56,7 @@ LL | 1f32 as u32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:35:5
--> tests/ui/cast.rs:36:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@ -65,7 +65,7 @@ LL | 1f32 as u32;
= help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
error: casting `f64` to `f32` may truncate the value
--> tests/ui/cast.rs:39:5
--> tests/ui/cast.rs:40:5
|
LL | 1f64 as f32;
| ^^^^^^^^^^^
@ -73,7 +73,7 @@ LL | 1f64 as f32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `i32` to `i8` may truncate the value
--> tests/ui/cast.rs:41:5
--> tests/ui/cast.rs:42:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^
@ -85,7 +85,7 @@ LL | i8::try_from(1i32);
| ~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u8` may truncate the value
--> tests/ui/cast.rs:43:5
--> tests/ui/cast.rs:44:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^
@ -97,7 +97,7 @@ LL | u8::try_from(1i32);
| ~~~~~~~~~~~~~~~~~~
error: casting `f64` to `isize` may truncate the value
--> tests/ui/cast.rs:45:5
--> tests/ui/cast.rs:46:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^
@ -105,7 +105,7 @@ LL | 1f64 as isize;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may truncate the value
--> tests/ui/cast.rs:47:5
--> tests/ui/cast.rs:48:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
@ -113,13 +113,13 @@ LL | 1f64 as usize;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:47:5
--> tests/ui/cast.rs:48:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
error: casting `u32` to `u16` may truncate the value
--> tests/ui/cast.rs:50:5
--> tests/ui/cast.rs:51:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^^^^^^^^
@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may truncate the value
--> tests/ui/cast.rs:50:5
--> tests/ui/cast.rs:51:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:50:5
--> tests/ui/cast.rs:51:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
error: casting `i32` to `i8` may truncate the value
--> tests/ui/cast.rs:55:22
--> tests/ui/cast.rs:56:22
|
LL | let _x: i8 = 1i32 as _;
| ^^^^^^^^^
@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into();
| ~~~~~~~~~~~~~~~
error: casting `f32` to `i32` may truncate the value
--> tests/ui/cast.rs:57:9
--> tests/ui/cast.rs:58:9
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@ -165,7 +165,7 @@ LL | 1f32 as i32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `i32` may truncate the value
--> tests/ui/cast.rs:59:9
--> tests/ui/cast.rs:60:9
|
LL | 1f64 as i32;
| ^^^^^^^^^^^
@ -173,7 +173,7 @@ LL | 1f64 as i32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may truncate the value
--> tests/ui/cast.rs:61:9
--> tests/ui/cast.rs:62:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
@ -181,13 +181,13 @@ LL | 1f32 as u8;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may lose the sign of the value
--> tests/ui/cast.rs:61:9
--> tests/ui/cast.rs:62:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
error: casting `u8` to `i8` may wrap around the value
--> tests/ui/cast.rs:66:5
--> tests/ui/cast.rs:67:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
@ -196,31 +196,31 @@ LL | 1u8 as i8;
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
error: casting `u16` to `i16` may wrap around the value
--> tests/ui/cast.rs:69:5
--> tests/ui/cast.rs:70:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value
--> tests/ui/cast.rs:71:5
--> tests/ui/cast.rs:72:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value
--> tests/ui/cast.rs:73:5
--> tests/ui/cast.rs:74:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value
--> tests/ui/cast.rs:75:5
--> tests/ui/cast.rs:76:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^
error: casting `usize` to `i8` may truncate the value
--> tests/ui/cast.rs:78:5
--> tests/ui/cast.rs:79:5
|
LL | 1usize as i8;
| ^^^^^^^^^^^^
@ -232,7 +232,7 @@ LL | i8::try_from(1usize);
| ~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i16` may truncate the value
--> tests/ui/cast.rs:81:5
--> tests/ui/cast.rs:82:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@ -244,7 +244,7 @@ LL | i16::try_from(1usize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
--> tests/ui/cast.rs:81:5
--> tests/ui/cast.rs:82:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@ -253,7 +253,7 @@ LL | 1usize as i16;
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:86:5
--> tests/ui/cast.rs:87:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
@ -265,19 +265,19 @@ LL | i32::try_from(1usize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:86:5
--> tests/ui/cast.rs:87:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:90:5
--> tests/ui/cast.rs:91:5
|
LL | 1usize as i64;
| ^^^^^^^^^^^^^
error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
--> tests/ui/cast.rs:95:5
--> tests/ui/cast.rs:96:5
|
LL | 1u16 as isize;
| ^^^^^^^^^^^^^
@ -286,13 +286,13 @@ LL | 1u16 as isize;
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:99:5
--> tests/ui/cast.rs:100:5
|
LL | 1u32 as isize;
| ^^^^^^^^^^^^^
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:102:5
--> tests/ui/cast.rs:103:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
@ -304,25 +304,55 @@ LL | isize::try_from(1u64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:102:5
--> tests/ui/cast.rs:103:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:107:5
--> tests/ui/cast.rs:108:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:110:5
--> tests/ui/cast.rs:111:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: casting `i8` to `u8` may lose the sign of the value
--> tests/ui/cast.rs:122:5
|
LL | (i8::MIN).abs() as u8;
| ^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:126:5
|
LL | (-1i64).abs() as u64;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:127:5
|
LL | (-1isize).abs() as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:134:5
|
LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:149:5
|
LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value
--> tests/ui/cast.rs:179:5
--> tests/ui/cast.rs:200:5
|
LL | (-99999999999i64).min(1) as i8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -334,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `u8` may truncate the value
--> tests/ui/cast.rs:193:5
--> tests/ui/cast.rs:214:5
|
LL | 999999u64.clamp(0, 256) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -346,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E2` to `u8` may truncate the value
--> tests/ui/cast.rs:216:21
--> tests/ui/cast.rs:237:21
|
LL | let _ = self as u8;
| ^^^^^^^^^^
@ -358,7 +388,7 @@ LL | let _ = u8::try_from(self);
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E2::B` to `u8` will truncate the value
--> tests/ui/cast.rs:218:21
--> tests/ui/cast.rs:239:21
|
LL | let _ = Self::B as u8;
| ^^^^^^^^^^^^^
@ -367,7 +397,7 @@ LL | let _ = Self::B as u8;
= help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
error: casting `main::E5` to `i8` may truncate the value
--> tests/ui/cast.rs:260:21
--> tests/ui/cast.rs:281:21
|
LL | let _ = self as i8;
| ^^^^^^^^^^
@ -379,13 +409,13 @@ LL | let _ = i8::try_from(self);
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E5::A` to `i8` will truncate the value
--> tests/ui/cast.rs:262:21
--> tests/ui/cast.rs:283:21
|
LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value
--> tests/ui/cast.rs:279:21
--> tests/ui/cast.rs:300:21
|
LL | let _ = self as i16;
| ^^^^^^^^^^^
@ -397,7 +427,7 @@ LL | let _ = i16::try_from(self);
| ~~~~~~~~~~~~~~~~~~~
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:298:21
--> tests/ui/cast.rs:319:21
|
LL | let _ = self as usize;
| ^^^^^^^^^^^^^
@ -409,7 +439,7 @@ LL | let _ = usize::try_from(self);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E10` to `u16` may truncate the value
--> tests/ui/cast.rs:345:21
--> tests/ui/cast.rs:366:21
|
LL | let _ = self as u16;
| ^^^^^^^^^^^
@ -421,7 +451,7 @@ LL | let _ = u16::try_from(self);
| ~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:356:13
--> tests/ui/cast.rs:377:13
|
LL | let c = (q >> 16) as u8;
| ^^^^^^^^^^^^^^^
@ -433,7 +463,7 @@ LL | let c = u8::try_from(q >> 16);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:360:13
--> tests/ui/cast.rs:381:13
|
LL | let c = (q / 1000) as u8;
| ^^^^^^^^^^^^^^^^
@ -445,76 +475,180 @@ LL | let c = u8::try_from(q / 1000);
| ~~~~~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:379:5
--> tests/ui/cast.rs:393:9
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:398:32
|
LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:400:5
|
LL | (2_i32).checked_pow(3).unwrap() as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:401:5
|
LL | (-2_i32).pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:384:5
--> tests/ui/cast.rs:406:5
|
LL | (-5_i32 % 2) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:408:5
|
LL | (-5_i32 % -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:411:5
|
LL | (-2_i32 >> 1) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:415:5
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:416:5
|
LL | (x * x * x) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:388:5
--> tests/ui/cast.rs:420:5
|
LL | (y * y * y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:391:5
--> tests/ui/cast.rs:422:5
|
LL | (y * y * y * 2) as u16;
LL | (y * y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:423:5
|
LL | (y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:393:5
--> tests/ui/cast.rs:425:5
|
LL | (y * y * y * -2) as u16;
LL | (y / y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `/`
--> tests/ui/cast.rs:425:6
|
LL | (y / y * y * -2) as u16;
| ^^^^^
|
= note: `#[deny(clippy::eq_op)]` on by default
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:428:5
|
LL | (y + y + y + -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:430:5
|
LL | (y + y + y + 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:434:5
|
LL | (z + -2) as u16;
| ^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:436:5
|
LL | (z + z + 2) as u16;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:398:9
--> tests/ui/cast.rs:439:9
|
LL | (a * a * b * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:440:9
|
LL | (a * b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:400:9
--> tests/ui/cast.rs:442:9
|
LL | (a * -b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:403:9
--> tests/ui/cast.rs:444:9
|
LL | (a * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:445:9
|
LL | (a * -2) as u32;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:405:9
--> tests/ui/cast.rs:447:9
|
LL | (a * b * c * -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:408:9
--> tests/ui/cast.rs:449:9
|
LL | (a / b) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:450:9
|
LL | (a / b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:410:9
--> tests/ui/cast.rs:452:9
|
LL | (a / b + b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:412:9
--> tests/ui/cast.rs:454:9
|
LL | a.pow(3) as u32;
| ^^^^^^^^^^^^^^^
LL | a.saturating_pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 63 previous errors
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:456:9
|
LL | (a.abs() * b.pow(2) / c.abs()) as u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 85 previous errors