]>
Commit | Line | Data |
---|---|---|
b7449926 | 1 | // run-pass |
abe05a73 XL |
2 | // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. |
3 | // compile-flags: -Z saturating-float-casts | |
4 | ||
0531ce1d | 5 | #![feature(test, stmt_expr_attributes)] |
abe05a73 XL |
6 | #![deny(overflowing_literals)] |
7 | extern crate test; | |
8 | ||
9 | use std::{f32, f64}; | |
10 | use std::{u8, i8, u16, i16, u32, i32, u64, i64}; | |
11 | #[cfg(not(target_os="emscripten"))] | |
12 | use std::{u128, i128}; | |
13 | use test::black_box; | |
14 | ||
15 | macro_rules! test { | |
16 | ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( | |
17 | // black_box disables constant evaluation to test run-time conversions: | |
18 | assert_eq!(black_box::<$src_ty>($val) as $dest_ty, $expected, | |
19 | "run-time {} -> {}", stringify!($src_ty), stringify!($dest_ty)); | |
20 | ); | |
21 | ||
22 | ($fval:expr, f* -> $ity:ident, $ival:expr) => ( | |
23 | test!($fval, f32 -> $ity, $ival); | |
24 | test!($fval, f64 -> $ity, $ival); | |
25 | ) | |
26 | } | |
27 | ||
28 | // This macro tests const eval in addition to run-time evaluation. | |
29 | // If and when saturating casts are adopted, this macro should be merged with test!() to ensure | |
30 | // that run-time and const eval agree on inputs that currently trigger a const eval error. | |
31 | macro_rules! test_c { | |
32 | ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ({ | |
33 | test!($val, $src_ty -> $dest_ty, $expected); | |
34 | { | |
35 | const X: $src_ty = $val; | |
36 | const Y: $dest_ty = X as $dest_ty; | |
37 | assert_eq!(Y, $expected, | |
38 | "const eval {} -> {}", stringify!($src_ty), stringify!($dest_ty)); | |
39 | } | |
40 | }); | |
41 | ||
42 | ($fval:expr, f* -> $ity:ident, $ival:expr) => ( | |
43 | test_c!($fval, f32 -> $ity, $ival); | |
44 | test_c!($fval, f64 -> $ity, $ival); | |
45 | ) | |
46 | } | |
47 | ||
48 | macro_rules! common_fptoi_tests { | |
49 | ($fty:ident -> $($ity:ident)+) => ({ $( | |
50 | test!($fty::NAN, $fty -> $ity, 0); | |
51 | test!($fty::INFINITY, $fty -> $ity, $ity::MAX); | |
52 | test!($fty::NEG_INFINITY, $fty -> $ity, $ity::MIN); | |
53 | // These two tests are not solely float->int tests, in particular the latter relies on | |
54 | // `u128::MAX as f32` not being UB. But that's okay, since this file tests int->float | |
55 | // as well, the test is just slightly misplaced. | |
56 | test!($ity::MIN as $fty, $fty -> $ity, $ity::MIN); | |
57 | test!($ity::MAX as $fty, $fty -> $ity, $ity::MAX); | |
58 | test_c!(0., $fty -> $ity, 0); | |
59 | test_c!($fty::MIN_POSITIVE, $fty -> $ity, 0); | |
60 | test!(-0.9, $fty -> $ity, 0); | |
61 | test_c!(1., $fty -> $ity, 1); | |
62 | test_c!(42., $fty -> $ity, 42); | |
63 | )+ }); | |
64 | ||
65 | (f* -> $($ity:ident)+) => ({ | |
66 | common_fptoi_tests!(f32 -> $($ity)+); | |
67 | common_fptoi_tests!(f64 -> $($ity)+); | |
68 | }) | |
69 | } | |
70 | ||
71 | macro_rules! fptoui_tests { | |
72 | ($fty: ident -> $($ity: ident)+) => ({ $( | |
73 | test!(-0., $fty -> $ity, 0); | |
74 | test!(-$fty::MIN_POSITIVE, $fty -> $ity, 0); | |
75 | test!(-0.99999994, $fty -> $ity, 0); | |
76 | test!(-1., $fty -> $ity, 0); | |
77 | test!(-100., $fty -> $ity, 0); | |
78 | test!(#[allow(overflowing_literals)] -1e50, $fty -> $ity, 0); | |
79 | test!(#[allow(overflowing_literals)] -1e130, $fty -> $ity, 0); | |
80 | )+ }); | |
81 | ||
82 | (f* -> $($ity:ident)+) => ({ | |
83 | fptoui_tests!(f32 -> $($ity)+); | |
84 | fptoui_tests!(f64 -> $($ity)+); | |
85 | }) | |
86 | } | |
87 | ||
88 | pub fn main() { | |
89 | common_fptoi_tests!(f* -> i8 i16 i32 i64 u8 u16 u32 u64); | |
90 | fptoui_tests!(f* -> u8 u16 u32 u64); | |
91 | // FIXME emscripten does not support i128 | |
92 | #[cfg(not(target_os="emscripten"))] { | |
93 | common_fptoi_tests!(f* -> i128 u128); | |
94 | fptoui_tests!(f* -> u128); | |
95 | } | |
96 | ||
97 | // The following tests cover edge cases for some integer types. | |
98 | ||
99 | // # u8 | |
100 | test_c!(254., f* -> u8, 254); | |
101 | test!(256., f* -> u8, 255); | |
102 | ||
103 | // # i8 | |
104 | test_c!(-127., f* -> i8, -127); | |
105 | test!(-129., f* -> i8, -128); | |
106 | test_c!(126., f* -> i8, 126); | |
107 | test!(128., f* -> i8, 127); | |
108 | ||
109 | // # i32 | |
110 | // -2147483648. is i32::MIN (exactly) | |
111 | test_c!(-2147483648., f* -> i32, i32::MIN); | |
112 | // 2147483648. is i32::MAX rounded up | |
113 | test!(2147483648., f32 -> i32, 2147483647); | |
114 | // With 24 significand bits, floats with magnitude in [2^30 + 1, 2^31] are rounded to | |
115 | // multiples of 2^7. Therefore, nextDown(round(i32::MAX)) is 2^31 - 128: | |
116 | test_c!(2147483520., f32 -> i32, 2147483520); | |
117 | // Similarly, nextUp(i32::MIN) is i32::MIN + 2^8 and nextDown(i32::MIN) is i32::MIN - 2^7 | |
118 | test!(-2147483904., f* -> i32, i32::MIN); | |
119 | test_c!(-2147483520., f* -> i32, -2147483520); | |
120 | ||
121 | // # u32 | |
122 | // round(MAX) and nextUp(round(MAX)) | |
123 | test_c!(4294967040., f* -> u32, 4294967040); | |
124 | test!(4294967296., f* -> u32, 4294967295); | |
125 | ||
126 | // # u128 | |
127 | #[cfg(not(target_os="emscripten"))] | |
128 | { | |
129 | // float->int: | |
130 | test_c!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); | |
131 | // nextDown(f32::MAX) = 2^128 - 2 * 2^104 | |
132 | const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; | |
133 | test_c!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); | |
134 | } | |
135 | } |