From 5960968ac052c36dfae43f6ed297898e43df840d Mon Sep 17 00:00:00 2001 From: Michiel De Muynck Date: Sun, 16 Apr 2017 19:39:06 +0200 Subject: [PATCH 1/4] Allow T op= &T for built-in numeric types T Currently, there are 4 ways to add two i32's together: a + b, a + &b, &a + b and &a + &b. The same is possible for all other binary operators and for all built-in numeric types that support those binary operators. Similarly, unary operators also have both a ref and a non-ref version, e.g., -7 == -&7. However, the assignment versions of these binary operators don't allow a ref right-hand side. This commit fixes that inconsistency by implementing these operators. These changes should be fully backwards compatible. --- src/libcore/internal_macros.rs | 18 ++++++++++++++++++ src/libcore/ops.rs | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index 9a7914064fdd5..6612ed6ec17f9 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -68,3 +68,21 @@ macro_rules! forward_ref_binop { } } } + +// implements "T op= &U", based on "T op= U" +// where U is expected to be `Copy`able +macro_rules! forward_ref_op_assign { + (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { + forward_ref_op_assign!(impl $imp, $method for $t, $u, + #[stable(feature = "op_assign_builtins_by_ref", since = "1.18.0")]); + }; + (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => { + #[$attr] + impl<'a> $imp<&'a $u> for $t { + #[inline] + fn $method(&mut self, other: &'a $u) { + $imp::$method(self, *other); + } + } + } +} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 175b3a5a69ac1..14f0e7f4e8442 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1346,6 +1346,8 @@ macro_rules! add_assign_impl { #[rustc_inherit_overflow_checks] fn add_assign(&mut self, other: $t) { *self += other } } + + forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t } )+) } @@ -1403,6 +1405,8 @@ macro_rules! sub_assign_impl { #[rustc_inherit_overflow_checks] fn sub_assign(&mut self, other: $t) { *self -= other } } + + forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t } )+) } @@ -1449,6 +1453,8 @@ macro_rules! mul_assign_impl { #[rustc_inherit_overflow_checks] fn mul_assign(&mut self, other: $t) { *self *= other } } + + forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t } )+) } @@ -1494,6 +1500,8 @@ macro_rules! div_assign_impl { #[inline] fn div_assign(&mut self, other: $t) { *self /= other } } + + forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t } )+) } @@ -1539,6 +1547,8 @@ macro_rules! rem_assign_impl { #[inline] fn rem_assign(&mut self, other: $t) { *self %= other } } + + forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t } )+) } @@ -1626,6 +1636,8 @@ macro_rules! bitand_assign_impl { #[inline] fn bitand_assign(&mut self, other: $t) { *self &= other } } + + forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t } )+) } @@ -1671,6 +1683,8 @@ macro_rules! bitor_assign_impl { #[inline] fn bitor_assign(&mut self, other: $t) { *self |= other } } + + forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t } )+) } @@ -1716,6 +1730,8 @@ macro_rules! bitxor_assign_impl { #[inline] fn bitxor_assign(&mut self, other: $t) { *self ^= other } } + + forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t } )+) } @@ -1764,6 +1780,8 @@ macro_rules! shl_assign_impl { *self <<= other } } + + forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f } ) } @@ -1830,6 +1848,8 @@ macro_rules! shr_assign_impl { *self >>= other } } + + forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f } ) } From 5b3458b49a5bfb929479be234904b4e5882f458c Mon Sep 17 00:00:00 2001 From: Michiel De Muynck Date: Sun, 16 Apr 2017 21:19:14 +0200 Subject: [PATCH 2/4] Also allow Wrapping op= &Wrapping Similarly to the built-in numeric types, Wrapping supports reference arguments for unary and binary operators, but not for the assignment versions of binary operators. This commit fixes that. --- src/libcore/num/wrapping.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 013f02685bad1..2448e15b6b71a 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -35,6 +35,7 @@ macro_rules! sh_impl_signed { *self = *self << other; } } + forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f } #[stable(feature = "rust1", since = "1.0.0")] impl Shr<$f> for Wrapping<$t> { @@ -57,6 +58,7 @@ macro_rules! sh_impl_signed { *self = *self >> other; } } + forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f } ) } @@ -79,6 +81,7 @@ macro_rules! sh_impl_unsigned { *self = *self << other; } } + forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f } #[stable(feature = "rust1", since = "1.0.0")] impl Shr<$f> for Wrapping<$t> { @@ -97,6 +100,7 @@ macro_rules! sh_impl_unsigned { *self = *self >> other; } } + forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f } ) } @@ -141,6 +145,7 @@ macro_rules! wrapping_impl { *self = *self + other; } } + forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl Sub for Wrapping<$t> { @@ -161,6 +166,7 @@ macro_rules! wrapping_impl { *self = *self - other; } } + forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl Mul for Wrapping<$t> { @@ -181,6 +187,7 @@ macro_rules! wrapping_impl { *self = *self * other; } } + forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "wrapping_div", since = "1.3.0")] impl Div for Wrapping<$t> { @@ -201,6 +208,7 @@ macro_rules! wrapping_impl { *self = *self / other; } } + forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "wrapping_impls", since = "1.7.0")] impl Rem for Wrapping<$t> { @@ -221,6 +229,7 @@ macro_rules! wrapping_impl { *self = *self % other; } } + forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl Not for Wrapping<$t> { @@ -253,6 +262,7 @@ macro_rules! wrapping_impl { *self = *self ^ other; } } + forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl BitOr for Wrapping<$t> { @@ -273,6 +283,7 @@ macro_rules! wrapping_impl { *self = *self | other; } } + forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl BitAnd for Wrapping<$t> { @@ -293,6 +304,7 @@ macro_rules! wrapping_impl { *self = *self & other; } } + forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "wrapping_neg", since = "1.10.0")] impl Neg for Wrapping<$t> { From 0d5984e68630a2145203e647732009805b2514c8 Mon Sep 17 00:00:00 2001 From: Michiel De Muynck Date: Sun, 16 Apr 2017 23:58:17 +0200 Subject: [PATCH 3/4] Add test for built-in numeric types --- .../run-pass/op-assign-builtins-by-ref.rs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/test/run-pass/op-assign-builtins-by-ref.rs diff --git a/src/test/run-pass/op-assign-builtins-by-ref.rs b/src/test/run-pass/op-assign-builtins-by-ref.rs new file mode 100644 index 0000000000000..77023a566794f --- /dev/null +++ b/src/test/run-pass/op-assign-builtins-by-ref.rs @@ -0,0 +1,84 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + // test compound assignment operators with ref as right-hand side, + // for each operator, with various types as operands. + + // test AddAssign + { + let mut x = 3i8; + x += &2i8; + assert_eq!(x, 5i8); + } + + // test SubAssign + { + let mut x = 7i16; + x -= &4; + assert_eq!(x, 3i16); + } + + // test MulAssign + { + let mut x = 3f32; + x *= &3f32; + assert_eq!(x, 9f32); + } + + // test DivAssign + { + let mut x = 6f64; + x /= &2f64; + assert_eq!(x, 3f64); + } + + // test RemAssign + { + let mut x = 7i64; + x %= &4i64; + assert_eq!(x, 3i64); + } + + // test BitOrAssign + { + let mut x = 0b1010u8; + x |= &0b1100u8; + assert_eq!(x, 0b1110u8); + } + + // test BitAndAssign + { + let mut x = 0b1010u16; + x &= &0b1100u16; + assert_eq!(x, 0b1000u16); + } + + // test BitXorAssign + { + let mut x = 0b1010u32; + x ^= &0b1100u32; + assert_eq!(x, 0b0110u32); + } + + // test ShlAssign + { + let mut x = 0b1010u64; + x <<= &2u32; + assert_eq!(x, 0b101000u64); + } + + // test ShrAssign + { + let mut x = 0b1010u64; + x >>= &2i16; + assert_eq!(x, 0b10u64); + } +} \ No newline at end of file From e47c971830f8ba7aa99e8808a8ecf2f1b2aa7630 Mon Sep 17 00:00:00 2001 From: Michiel De Muynck Date: Mon, 17 Apr 2017 00:11:40 +0200 Subject: [PATCH 4/4] Add test for Wrapping --- src/test/run-pass/num-wrapping.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/run-pass/num-wrapping.rs b/src/test/run-pass/num-wrapping.rs index 143759e271561..20c7f27336e25 100644 --- a/src/test/run-pass/num-wrapping.rs +++ b/src/test/run-pass/num-wrapping.rs @@ -173,6 +173,15 @@ fn test_op_assigns() { tmp.$op(Wrapping($rhs)); assert_eq!(black_box(tmp), Wrapping($ans)); } + + // also test that a &Wrapping right-hand side is possible + { + let mut tmp = Wrapping($initial); + tmp = black_box(tmp); + tmp.$op(&Wrapping($rhs)); + assert_eq!(black_box(tmp), Wrapping($ans)); + } + // FIXME(30524): Uncomment this test /* {