-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Kani function that checks if the range of a float is valid for …
…conversion to int (#3742) This introduces a new generic Kani function, `kani::float::float_to_int_in_range`, that can be used for checking if a floating-point value satisfies the range requirement of the `to_int_unchecked` methods, e.g https://doc.rust-lang.org/std/primitive.f32.html#method.to_int_unchecked and https://doc.rust-lang.org/std/primitive.f64.html#method.to_int_unchecked. Resolves #3711 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
- Loading branch information
1 parent
17f4ff1
commit e53511e
Showing
11 changed files
with
166 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! This module contains functions useful for float-related checks | ||
#[allow(clippy::crate_in_macro_def)] | ||
#[macro_export] | ||
macro_rules! generate_float { | ||
($core:path) => { | ||
use super::kani_intrinsic; | ||
use core::convert::FloatToInt; | ||
/// Returns whether the given float `value` satisfies the range | ||
/// condition of the `to_int_unchecked` methods, namely that the `value` | ||
/// after truncation is in range of the target `Int` | ||
/// | ||
/// # Example: | ||
/// | ||
/// ```no_run | ||
/// let f: f32 = 145.7; | ||
/// let fits_in_i8 = kani::float::float_to_int_in_range::<f32, i8>(f); | ||
/// // doesn't fit in `i8` because the value after truncation (`145.0`) is larger than `i8::MAX` | ||
/// assert!(!fits_in_i8); | ||
/// | ||
/// let f: f64 = 1e6; | ||
/// let fits_in_u32 = kani::float::float_to_int_in_range::<f64, u32>(f); | ||
/// // fits in `u32` because the value after truncation (`1e6`) is smaller than `u32::MAX` | ||
/// assert!(fits_in_u32); | ||
/// ``` | ||
#[crate::kani::unstable_feature( | ||
feature = "float-lib", | ||
issue = "none", | ||
reason = "experimental floating-point API" | ||
)] | ||
#[kanitool::fn_marker = "FloatToIntInRangeHook"] | ||
#[inline(never)] | ||
pub fn float_to_int_in_range<Float, Int>(value: Float) -> bool | ||
where | ||
Float: FloatToInt<Int>, | ||
{ | ||
kani_intrinsic() | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
error[E0277]: the trait bound `i32: std::convert::FloatToInt<u8>` is not satisfied | ||
invalid_float.rs: | ||
| let _c = kani::float::float_to_int_in_range::<i32, u8>(i); | ||
| ^^^ the trait `std::convert::FloatToInt<u8>` is not implemented for `i32` | ||
| |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! This test checks that Kani emits an error when | ||
//! `kani::float::float_to_int_in_range` is instantiated with a non-float type | ||
#[kani::proof] | ||
fn check_invalid_float() { | ||
let i: i32 = 5; | ||
let _c = kani::float::float_to_int_in_range::<i32, u8>(i); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
error[E0277]: the trait bound `f32: std::convert::FloatToInt<bool>` is not satisfied | ||
invalid_int.rs: | ||
| let _c = kani::float::float_to_int_in_range::<f32, bool>(f); | ||
| ^^^ the trait `std::convert::FloatToInt<bool>` is not implemented for `f32` | ||
| |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! This test checks that Kani emits an error when | ||
//! `kani::float::float_to_int_in_range` is instantiated with a non-integer type | ||
#[kani::proof] | ||
fn check_invalid_integer() { | ||
let f: f32 = kani::any(); | ||
let _c = kani::float::float_to_int_in_range::<f32, bool>(f); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// kani-flags: -Zfloat-lib | ||
|
||
//! This test checks that `kani::float::float_to_int_in_range` works as expected | ||
#[kani::proof] | ||
fn check_float_to_int_in_range() { | ||
let f: f32 = 5.6; | ||
let fits_in_u16 = kani::float::float_to_int_in_range::<f32, u16>(f); | ||
assert!(fits_in_u16); | ||
let i: u16 = unsafe { f.to_int_unchecked() }; | ||
assert_eq!(i, 5); | ||
|
||
let f: f32 = 145.7; | ||
let fits_in_i8 = kani::float::float_to_int_in_range::<f32, i8>(f); | ||
// doesn't fit in `i8` because the value after truncation (`145.0`) is larger than `i8::MAX` | ||
assert!(!fits_in_i8); | ||
|
||
let f: f64 = 1e6; | ||
let fits_in_u32 = kani::float::float_to_int_in_range::<f64, u32>(f); | ||
// fits in `u32` because the value after truncation (`1e6`) is smaller than `u32::MAX` | ||
assert!(fits_in_u32); | ||
let i: u32 = unsafe { f.to_int_unchecked() }; | ||
assert_eq!(i, 1_000_000); | ||
} |