Skip to content

Commit 6367b54

Browse files
committed
librustc_middle: Add function for computing unsigned abs
This is tricky to get right if we want to avoid panicking or wrapping. Signed-off-by: Joe Richey <[email protected]>
1 parent 55577b4 commit 6367b54

File tree

2 files changed

+14
-8
lines changed

2 files changed

+14
-8
lines changed

src/librustc_middle/mir/interpret/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,12 @@ pub fn truncate(value: u128, size: Size) -> u128 {
598598
// Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
599599
(value << shift) >> shift
600600
}
601+
602+
/// Computes the unsigned absolute value without wrapping or panicking.
603+
#[inline]
604+
pub fn uabs(value: i64) -> u64 {
605+
// The only tricky part here is if value == i64::MIN. In that case,
606+
// wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64
607+
// gives 2^63, the correct value.
608+
value.wrapping_abs() as u64
609+
}

src/librustc_middle/mir/interpret/pointer.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{AllocId, InterpResult};
1+
use super::{uabs, AllocId, InterpResult};
22

33
use rustc_macros::HashStable;
44
use rustc_target::abi::{HasDataLayout, Size};
@@ -48,15 +48,12 @@ pub trait PointerArithmetic: HasDataLayout {
4848

4949
#[inline]
5050
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
51-
if i < 0 {
52-
// Trickery to ensure that `i64::MIN` works fine: compute `n = -i`.
53-
// This formula only works for true negative values; it overflows for zero!
54-
let n = u64::MAX - (i as u64) + 1;
51+
let n = uabs(i);
52+
if i >= 0 {
53+
self.overflowing_offset(val, n)
54+
} else {
5555
let res = val.overflowing_sub(n);
5656
self.truncate_to_ptr(res)
57-
} else {
58-
// `i >= 0`, so the cast is safe.
59-
self.overflowing_offset(val, i as u64)
6057
}
6158
}
6259

0 commit comments

Comments
 (0)