Auto merge of #78259 - plaflamme:fix-49660, r=KodrAus
Fix #49660 - Adds checks to ensure existence of arithmetic trait implementations The first 2 commits fix an issue with the existing `wrapping.rs` tests. It wasn't referred to from the module, so the file was being ignored. This is fixed in872dc60ed2
This surfaced a bug in its macro which is fixed in8ddad18283
Lastly, commit64d695b753
is the actual tests for fixing #49660 The following checks are done: * `Add`, `Sub`, `Mul`, `Div`, `Rem` * `T op T`, `T op &T`, `&T op T` and `&T op &T` * for all integer and floating point types * `AddAssign`, `SubAssign`, `MulAssign`, `DivAssign`, `RemAssign` * `&mut T op T` and `&mut T op &T` * for all integer and floating point types * `Neg` * `op T` and `op &T` * for all signed integer and floating point types * `Not` * `op T` and `op &T` * for `bool` * `BitAnd`, `BitOr`, `BitXor` * `T op T`, `T op &T`, `&T op T` and `&T op &T` * for all integer types and bool * `BitAndAssign`, `BitOrAssign`, `BitXorAssign` * `&mut T op T` and `&mut T op &T` * for all integer types and bool * `Shl`, `Shr` * `L op R`, `L op &R`, `&L op R` and `&L op &R` * for all pairs of integer types * `ShlAssign`, `ShrAssign` * `&mut L op R`, `&mut L op &R` * for all pairs of integer types NOTE: I'd like some feedback on improving the macros. I'm not familiar with the idioms and patterns there and composing them has been a challenge for me. [EDIT]: updated links to commits after rebase.
This commit is contained in:
commit
a4f022e109
3 changed files with 261 additions and 14 deletions
|
@ -29,6 +29,8 @@ mod u8;
|
|||
mod bignum;
|
||||
mod dec2flt;
|
||||
mod flt2dec;
|
||||
mod ops;
|
||||
mod wrapping;
|
||||
|
||||
mod nan;
|
||||
|
||||
|
|
244
library/core/tests/num/ops.rs
Normal file
244
library/core/tests/num/ops.rs
Normal file
|
@ -0,0 +1,244 @@
|
|||
use core::ops::*;
|
||||
|
||||
// For types L and R, checks that a trait implementation exists for
|
||||
// * binary ops: L op R, L op &R, &L op R and &L op &R
|
||||
// * assign ops: &mut L op R, &mut L op &R
|
||||
macro_rules! impl_defined {
|
||||
($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => {
|
||||
let lhs = $lhs as $lt;
|
||||
let rhs = $rhs as $rt;
|
||||
assert_eq!($result as $lt, $op::$method(lhs, rhs));
|
||||
assert_eq!($result as $lt, $op::$method(lhs, &rhs));
|
||||
assert_eq!($result as $lt, $op::$method(&lhs, rhs));
|
||||
assert_eq!($result as $lt, $op::$method(&lhs, &rhs));
|
||||
};
|
||||
($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => {
|
||||
let rhs = $rhs as $rt;
|
||||
let mut lhs = $lhs as $lt;
|
||||
$op::$method(&mut lhs, rhs);
|
||||
assert_eq!($result as $lt, lhs);
|
||||
|
||||
let mut lhs = $lhs as $lt;
|
||||
$op::$method(&mut lhs, &rhs);
|
||||
assert_eq!($result as $lt, lhs);
|
||||
};
|
||||
}
|
||||
|
||||
// For all specified types T, checks that a trait implementation exists for
|
||||
// * binary ops: T op T, T op &T, &T op T and &T op &T
|
||||
// * assign ops: &mut T op T, &mut T op &T
|
||||
// * unary ops: op T and op &T
|
||||
macro_rules! impls_defined {
|
||||
($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$(
|
||||
impl_defined!($op, $method($lhs, $rhs), $result, $t, $t);
|
||||
)+};
|
||||
($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$(
|
||||
impl_defined!($op, $method(&mut $lhs, $rhs), $result, $t, $t);
|
||||
)+};
|
||||
($op:ident, $method:ident($operand:literal), $result:literal, $($t:ty),+) => {$(
|
||||
let operand = $operand as $t;
|
||||
assert_eq!($result as $t, $op::$method(operand));
|
||||
assert_eq!($result as $t, $op::$method(&operand));
|
||||
)+};
|
||||
}
|
||||
|
||||
macro_rules! test_op {
|
||||
($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
|
||||
#[test]
|
||||
fn $fn_name() {
|
||||
impls_defined!($op, $method($lhs, $rhs), $result, $($t),+);
|
||||
}
|
||||
};
|
||||
($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {
|
||||
#[test]
|
||||
fn $fn_name() {
|
||||
impls_defined!($op, $method(&mut $lhs, $rhs), $result, $($t),+);
|
||||
}
|
||||
};
|
||||
($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => {
|
||||
#[test]
|
||||
fn $fn_name() {
|
||||
impls_defined!($op, $method($lhs), $result, $($t),+);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, f32, f64);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_op!(test_neg_defined_128, Neg::neg(0), 0, i128);
|
||||
|
||||
test_op!(test_not_defined_bool, Not::not(true), false, bool);
|
||||
|
||||
macro_rules! test_arith_op {
|
||||
($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal)) => {
|
||||
#[test]
|
||||
fn $fn_name() {
|
||||
impls_defined!(
|
||||
$op,
|
||||
$method($lhs, $rhs),
|
||||
0,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
usize,
|
||||
f32,
|
||||
f64
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method($lhs, $rhs), 0, i128, u128);
|
||||
}
|
||||
};
|
||||
($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => {
|
||||
#[test]
|
||||
fn $fn_name() {
|
||||
impls_defined!(
|
||||
$op,
|
||||
$method(&mut $lhs, $rhs),
|
||||
0,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
usize,
|
||||
f32,
|
||||
f64
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(&mut $lhs, $rhs), 0, i128, u128);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_arith_op!(test_add_defined, Add::add(0, 0));
|
||||
test_arith_op!(test_add_assign_defined, AddAssign::add_assign(&mut 0, 0));
|
||||
test_arith_op!(test_sub_defined, Sub::sub(0, 0));
|
||||
test_arith_op!(test_sub_assign_defined, SubAssign::sub_assign(&mut 0, 0));
|
||||
test_arith_op!(test_mul_defined, Mul::mul(0, 0));
|
||||
test_arith_op!(test_mul_assign_defined, MulAssign::mul_assign(&mut 0, 0));
|
||||
test_arith_op!(test_div_defined, Div::div(0, 1));
|
||||
test_arith_op!(test_div_assign_defined, DivAssign::div_assign(&mut 0, 1));
|
||||
test_arith_op!(test_rem_defined, Rem::rem(0, 1));
|
||||
test_arith_op!(test_rem_assign_defined, RemAssign::rem_assign(&mut 0, 1));
|
||||
|
||||
macro_rules! test_bitop {
|
||||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
impls_defined!(
|
||||
$op,
|
||||
$method(0, 0),
|
||||
0,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
usize
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(0, 0), 0, i128, u128);
|
||||
impls_defined!($op, $method(false, false), false, bool);
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! test_bitop_assign {
|
||||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
impls_defined!(
|
||||
$op,
|
||||
$method(&mut 0, 0),
|
||||
0,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
usize
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(&mut 0, 0), 0, i128, u128);
|
||||
impls_defined!($op, $method(&mut false, false), false, bool);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_bitop!(test_bitand_defined, BitAnd::bitand);
|
||||
test_bitop_assign!(test_bitand_assign_defined, BitAndAssign::bitand_assign);
|
||||
test_bitop!(test_bitor_defined, BitOr::bitor);
|
||||
test_bitop_assign!(test_bitor_assign_defined, BitOrAssign::bitor_assign);
|
||||
test_bitop!(test_bitxor_defined, BitXor::bitxor);
|
||||
test_bitop_assign!(test_bitxor_assign_defined, BitXorAssign::bitxor_assign);
|
||||
|
||||
macro_rules! test_shift_inner {
|
||||
($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => {
|
||||
$(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+
|
||||
};
|
||||
($op:ident::$method:ident, $lt:ty) => {
|
||||
test_shift_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_inner!($op::$method, $lt, i128, u128);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_shift {
|
||||
($op:ident::$method:ident, $($lt:ty),+) => {
|
||||
$(test_shift_inner!($op::$method, $lt);)+
|
||||
};
|
||||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
test_shift!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift!($op::$method, i128, u128);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_shift_assign_inner {
|
||||
($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => {
|
||||
$(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+
|
||||
};
|
||||
($op:ident::$method:ident, $lt:ty) => {
|
||||
test_shift_assign_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_assign_inner!($op::$method, $lt, i128, u128);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_shift_assign {
|
||||
($op:ident::$method:ident, $($lt:ty),+) => {
|
||||
$(test_shift_assign_inner!($op::$method, $lt);)+
|
||||
};
|
||||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
test_shift_assign!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_assign!($op::$method, i128, u128);
|
||||
}
|
||||
};
|
||||
}
|
||||
test_shift!(test_shl_defined, Shl::shl);
|
||||
test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign);
|
||||
test_shift!(test_shr_defined, Shr::shr);
|
||||
test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign);
|
|
@ -26,9 +26,9 @@ macro_rules! wrapping_assignment {
|
|||
}
|
||||
|
||||
macro_rules! wrapping_test {
|
||||
($type:ty, $min:expr, $max:expr) => {
|
||||
($fn_name:ident, $type:ty, $min:expr, $max:expr) => {
|
||||
#[test]
|
||||
fn wrapping_$type() {
|
||||
fn $fn_name() {
|
||||
let zero: Wrapping<$type> = Wrapping(0);
|
||||
let one: Wrapping<$type> = Wrapping(1);
|
||||
let min: Wrapping<$type> = Wrapping($min);
|
||||
|
@ -60,23 +60,24 @@ macro_rules! wrapping_test {
|
|||
};
|
||||
}
|
||||
|
||||
wrapping_test!(i8, i8::MIN, i8::MAX);
|
||||
wrapping_test!(i16, i16::MIN, i16::MAX);
|
||||
wrapping_test!(i32, i32::MIN, i32::MAX);
|
||||
wrapping_test!(i64, i64::MIN, i64::MAX);
|
||||
wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX);
|
||||
wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX);
|
||||
wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX);
|
||||
wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(i128, i128::MIN, i128::MAX);
|
||||
wrapping_test!(isize, isize::MIN, isize::MAX);
|
||||
wrapping_test!(u8, u8::MIN, u8::MAX);
|
||||
wrapping_test!(u16, u16::MIN, u16::MAX);
|
||||
wrapping_test!(u32, u32::MIN, u32::MAX);
|
||||
wrapping_test!(u64, u64::MIN, u64::MAX);
|
||||
wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX);
|
||||
wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX);
|
||||
wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX);
|
||||
wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX);
|
||||
wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX);
|
||||
wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(u128, u128::MIN, u128::MAX);
|
||||
wrapping_test!(usize, usize::MIN, usize::MAX);
|
||||
wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX);
|
||||
wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX);
|
||||
|
||||
// Don't warn about overflowing ops on 32-bit platforms
|
||||
#[cfg_attr(target_pointer_width = "32", allow(const_err))]
|
||||
#[test]
|
||||
fn wrapping_int_api() {
|
||||
assert_eq!(i8::MAX.wrapping_add(1), i8::MIN);
|
||||
assert_eq!(i16::MAX.wrapping_add(1), i16::MIN);
|
||||
|
|
Loading…
Reference in a new issue