-
Notifications
You must be signed in to change notification settings - Fork 22
actually checked bitshifts #570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Here's two possible implementations: pub fn check_shl_overflow_reshift(n: u64, shift_amount: u32) -> Option<u64> {
let r = n << shift_amount;
if r >> shift_amount == n {
Some(r)
} else {
None
}
}
pub fn check_shl_overflow_rotate(n: u64, shift_amount: u32) -> Option<u64> {
let r = n.rotate_left(shift_amount);
if r & ((shift_amount-1) as u64) == 0 {
Some(r)
} else {
None
}
} |
imo |
There are the recently stabilized We could add a |
@pitaj is it more of a mouthful than |
I wasn't saying we should block this proposal based on the name, just maybe think if better names exist. One alternative I thought of is Also note on implementation, you should be able to implement |
|
What OP wanted is not any existing Rust stdlib variant of bit shift, which shifting bits beyond out of MSB is a well-defined and valid behavior, but a weird version like (Not sure what the "weird_checked" version of "shr" looks like.) |
Yeah the |
maybe name it |
|
though if we use |
@kennytm It's the reverse, where shifting bits off the right rerurns None. basically, if the result would have less bits set than the input, |
I'd say no. To me, the point of it is that a large shift isn't an error, so it doesn't need to be checked in debug (and checking would be a breaking change, arguably) and doesn't need all the extra variants as a result. If you want to be inspired by LLVM and its unsafe versions of shifts, they have |
So essentially " My intuition is that shifts are supposed to treat zeros and ones identically, so shifting out ones (or zeros, in the case of signed types) from either end is not an "overflow" per se but rather the expected semantics – rather "overflow" is defined as trying to shift a number of bits greater than the width of the type of the LHS, due to the way common hardware works. If we had |
the points is that there are some usecases, such as number decoding and when using shifts to multiply by a power of two, where losing data in this way is undesirable. maybe name it |
The motivating use cases are not really clear to me. It's not even clear to me what semantics an "actually checked" right shift should have. Yes, the meaning of overflow checks on shifts (and hence For left shifts, the analogy to "multiplication by power of two" at least suggests a clear meaning: For right shifts, it's more complicated because there's at least two different meanings an "actually checked" right shift could have: lossless in the sense of not shifting out any 1 bits, or analogous to division by a power of two (and thus, compatible with the story about left shifts). Neither option seems great:
|
To elaborate on @scottmcm's comment, LLVM has the following:
If we were to do something here, it would seem worth doing what would allow for lowering cleanly to these. |
We discussed this in the @rust-lang/libs-api meeting. We do think there is a strong motivation for adding these: even though it can be emulated with Regarding the names, we preferred calling these "exact" shifts just like impl iX/uX {
// Shift succeeds if `shift < Self::BITS` and right shifting the result returns the original value.
fn exact_shl(self, shift: u32) -> Option<Self>;
unsafe fn exact_shl_unchecked(self, shift: u32) -> Self;
// Shift succeeds if `shift < Self::BITS` and left shifting the result returns the original value.
fn exact_shr(self, shift: u32) -> Option<Self>;
unsafe fn exact_shr_unchecked(self, shift: u32) -> Self;
} |
Please open a tracking issue and open a PR to rust-lang/rust to add it as an unstable feature. You can close this ACP once the tracking issue has been created. |
Uh oh!
There was an error while loading. Please reload this page.
Proposal
Problem statement
For every integer operation with a symbolic operator, there is a corresponding
checked_*
method that returnsNone
if an overflow occurs...except for bitshifts, whose
checked_*
functions do something entirely different.For example,
255_u8.checked_shl(1)
evaluates toSome(254)
.The closest existing functions areEDIT: theoverflowing_{shl,shr}
, but those must also return a result in the overflowing case, ruling out implementations that check for overflow before doing the shift.overflowing_*
functions ALSO don't do what you would expect.Motivating examples or use cases
This could be used to detect overflow when parsing certain types of positional integer notation, from ascii decimal to certain VLQs.
Solution Sketch
checked_shr
andchecked_shl
and give them less confusing names.None
on overflowLinks and related work
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution:
The text was updated successfully, but these errors were encountered: