Skip to content

Commit 9204497

Browse files
committed
Allow const assignment for int saturating_add() calls for #58030
1 parent 3e58dab commit 9204497

File tree

6 files changed

+91
-12
lines changed

6 files changed

+91
-12
lines changed

src/libcore/num/mod.rs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -882,17 +882,37 @@ $EndFeature, "
882882
```"),
883883
#[stable(feature = "rust1", since = "1.0.0")]
884884
#[inline]
885+
#[cfg(stage0)]
885886
pub fn saturating_add(self, rhs: Self) -> Self {
886-
#[cfg(stage0)]
887887
match self.checked_add(rhs) {
888888
Some(x) => x,
889889
None if rhs >= 0 => Self::max_value(),
890890
None => Self::min_value(),
891891
}
892-
#[cfg(not(stage0))]
893-
{
894-
intrinsics::saturating_add(self, rhs)
895-
}
892+
}
893+
894+
}
895+
896+
doc_comment! {
897+
concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
898+
bounds instead of overflowing.
899+
900+
# Examples
901+
902+
Basic usage:
903+
904+
```
905+
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
906+
assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT),
907+
"::max_value());",
908+
$EndFeature, "
909+
```"),
910+
911+
#[stable(feature = "rust1", since = "1.0.0")]
912+
#[inline]
913+
#[cfg(not(stage0))]
914+
pub const fn saturating_add(self, rhs: Self) -> Self {
915+
intrinsics::saturating_add(self, rhs)
896916
}
897917
}
898918

@@ -2753,16 +2773,33 @@ assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
27532773
```"),
27542774
#[stable(feature = "rust1", since = "1.0.0")]
27552775
#[inline]
2776+
#[cfg(stage0)]
27562777
pub fn saturating_add(self, rhs: Self) -> Self {
2757-
#[cfg(stage0)]
27582778
match self.checked_add(rhs) {
27592779
Some(x) => x,
27602780
None => Self::max_value(),
27612781
}
2762-
#[cfg(not(stage0))]
2763-
{
2764-
intrinsics::saturating_add(self, rhs)
2765-
}
2782+
}
2783+
}
2784+
2785+
doc_comment! {
2786+
concat!("Saturating integer addition. Computes `self + rhs`, saturating at
2787+
the numeric bounds instead of overflowing.
2788+
2789+
# Examples
2790+
2791+
Basic usage:
2792+
2793+
```
2794+
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
2795+
assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
2796+
```"),
2797+
2798+
#[stable(feature = "rust1", since = "1.0.0")]
2799+
#[inline]
2800+
#[cfg(not(stage0))]
2801+
pub const fn saturating_add(self, rhs: Self) -> Self {
2802+
intrinsics::saturating_add(self, rhs)
27662803
}
27672804
}
27682805

src/librustc/mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,4 @@ pub fn truncate(value: u128, size: Size) -> u128 {
418418
let shift = 128 - size;
419419
// truncate (shift left to drop out leftover values, shift right to fill with zeroes)
420420
(value << shift) >> shift
421-
}
421+
}

src/librustc_mir/interpret/intrinsics.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use syntax::symbol::Symbol;
66
use rustc::ty;
7-
use rustc::ty::layout::{LayoutOf, Primitive};
7+
use rustc::ty::layout::{LayoutOf, Primitive, Size};
88
use rustc::mir::BinOp;
99
use rustc::mir::interpret::{
1010
EvalResult, EvalErrorKind, Scalar,
@@ -122,6 +122,33 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
122122
self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
123123
}
124124
}
125+
"saturating_add" => {
126+
let l = self.read_immediate(args[0])?;
127+
let r = self.read_immediate(args[1])?;
128+
let (val, overflowed) = self.binary_op_imm(BinOp::Add, l, r)?;
129+
if overflowed {
130+
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
131+
let num_bits = l.layout.size.bits();
132+
let val = if l.layout.abi.is_signed() {
133+
// For signed addition the saturated value depends on the sign of either term
134+
if first_term & (1 << (num_bits-1)) == 0 { // signed term is positive
135+
Scalar::from_uint((1u128 << (num_bits - 1)) - 1, Size::from_bits(num_bits)) // max signed val
136+
} else { // signed term is negative
137+
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) // min signed val
138+
}
139+
} else {
140+
if num_bits == 128 { // General bit shift method causes overflow for u128 terms
141+
Scalar::from_uint(u128::max_value(), Size::from_bits(128))
142+
} else {
143+
Scalar::from_uint(u128::max_value() & ((1 << num_bits) - 1),
144+
Size::from_bits(num_bits))
145+
}
146+
};
147+
self.write_scalar(val, dest)?;
148+
} else {
149+
self.write_scalar(val, dest)?;
150+
}
151+
}
125152
"unchecked_shl" | "unchecked_shr" => {
126153
let l = self.read_immediate(args[0])?;
127154
let r = self.read_immediate(args[1])?;

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
820820
| "add_with_overflow"
821821
| "sub_with_overflow"
822822
| "mul_with_overflow"
823+
| "saturating_add"
823824
// no need to check feature gates, intrinsics are only callable
824825
// from the libstd or with forever unstable feature gates
825826
=> is_const_fn = true,

src/librustc_mir/transform/qualify_min_const_fn.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool
374374
| "overflowing_add" // ~> .wrapping_add
375375
| "overflowing_sub" // ~> .wrapping_sub
376376
| "overflowing_mul" // ~> .wrapping_mul
377+
| "saturating_add" // ~> .saturating_add
377378
| "unchecked_shl" // ~> .wrapping_shl
378379
| "unchecked_shr" // ~> .wrapping_shr
379380
| "rotate_left" // ~> .rotate_left
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const INT_U32_NO: u32 = (42 as u32).saturating_add(2);
2+
const INT_U32: u32 = u32::max_value().saturating_add(1);
3+
const INT_U128: u128 = u128::max_value().saturating_add(1);
4+
const INT_I128: i128 = i128::max_value().saturating_add(1);
5+
const INT_I128_NEG: i128 = i128::min_value().saturating_add(-1);
6+
7+
fn main() {
8+
assert_eq!(INT_U32_NO, 44);
9+
assert_eq!(INT_U32, u32::max_value());
10+
assert_eq!(INT_U128, u128::max_value());
11+
assert_eq!(INT_I128, i128::max_value());
12+
assert_eq!(INT_I128_NEG, i128::min_value());
13+
}

0 commit comments

Comments
 (0)