Skip to content

Commit

Permalink
Do not change semantics of as; make wrapping methods inherent methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Mar 26, 2015
1 parent 67c2c29 commit 9f2c7f0
Showing 1 changed file with 49 additions and 37 deletions.
86 changes: 49 additions & 37 deletions text/0560-integer-overflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,9 @@ follows. The intention is that the defined results are the same as the
defined results today. The only change is that now a panic may result.

- The operations `+`, `-`, `*`, `/`, `%` can underflow and
overflow. Shift operations (`<<`, `>>`) can shift a value of width `N` by more
than `N` bits. In these cases, the result is the same as the pre-existing,
wrapping semantics.
- When truncating, the casting operation `as` can overflow if the
truncated bits contain non-zero values. If no panic occurs, the
result of such an operation is defined to be the same as wrapping.
overflow.
- Shift operations (`<<`, `>>`) can shift a value of width `N` by more
than `N` bits.

## Enabling overflow checking

Expand All @@ -146,9 +143,9 @@ The goal of this rule is to ensure that, during debugging and normal
development, overflow detection is on, so that users can be alerted to
potential overflow (and, in particular, for code where overflow is
expected and normal, they will be immediately guided to use the
`WrappingOps` traits introduced below). However, because these checks
will be compiled out whenever an optimized build is produced, final
code wilil not pay a performance penalty.
wrapping methods introduced below). However, because these checks will
be compiled out whenever an optimized build is produced, final code
wilil not pay a performance penalty.

In the future, we may add additional means to control when overflow is
checked, such as scoped attributes or a global, independent
Expand All @@ -168,15 +165,15 @@ coallesced into a single check. Another useful example might be that,
when summing a vector, the final overflow check could be deferred
until the summation is complete.

## `WrappingOps` trait for explicit wrapping arithmetic
## Methods for explicit wrapping arithmetic

For those use cases where explicit wraparound on overflow is required,
such as hash functions, we must provide operations with such
semantics. Accomplish this by providing the following trait and impls
in the `std::num` module.
semantics. Accomplish this by providing the following methods defined
in the inherent impls for the various integral types.

```rust
pub trait WrappingOps {
impl i32 { // and i8, i16, i64, isize, u8, u32, u64, usize
fn wrapping_add(self, rhs: Self) -> Self;
fn wrapping_sub(self, rhs: Self) -> Self;
fn wrapping_mul(self, rhs: Self) -> Self;
Expand All @@ -185,30 +182,7 @@ pub trait WrappingOps {

fn wrapping_lshift(self, amount: u32) -> Self;
fn wrapping_rshift(self, amount: u32) -> Self;

fn wrapping_as_u8(self, rhs: Self) -> u8;
fn wrapping_as_u16(self, rhs: Self) -> u16;
fn wrapping_as_u32(self, rhs: Self) -> u32
fn wrapping_as_u64(self, rhs: Self) -> u64;
fn wrapping_as_usize(self, rhs: Self) -> usize;

fn wrapping_as_i8(self, rhs: Self) -> i8;
fn wrapping_as_i16(self, rhs: Self) -> i16;
fn wrapping_as_i32(self, rhs: Self) -> i32
fn wrapping_as_i64(self, rhs: Self) -> i64;
fn wrapping_as_isize(self, rhs: Self) -> isize;
}

impl WrappingOps for isize
impl WrappingOps for usize
impl WrappingOps for i8
impl WrappingOps for u8
impl WrappingOps for i16
impl WrappingOps for u16
impl WrappingOps for i32
impl WrappingOps for u32
impl WrappingOps for i64
impl WrappingOps for u64
```

These are implemented to preserve the pre-existing, wrapping semantics
Expand Down Expand Up @@ -448,6 +422,33 @@ Reasons this was not pursued: Wrong defaults. Doesn't enable distinguishing

Reasons this was not pursued: My brain melted. :(

## Making `as` be checked

The RFC originally specified that using `as` to convert between types
would cause checked semantics. However, we now use `as` as a primitive
type operator. This decision was discussed on the
[discuss message board][as].

The key points in favor of reverting `as` to its original semantics
were:

1. `as` is already a fairly low-level operator that can be used (for
example) to convert between `*mut T` and `*mut U`.
2. `as` is the only way to convert types in constants, and hence it is
important that it covers all possibilities that constants might
need (eventually, [const fn][911] or other approaches may change
this, but those are not going to be stable for 1.0).
3. The [type ascription RFC][803] set the precedent that `as` is used
for "dangerous" coercions that require care.
4. Eventually, checked numeric conversions (and perhaps most or all
uses of `as`) can be ergonomically added as methods. The precise
form of this will be resolved in the future. [const fn][911] can
then allow these to be used in constant expressions.

[as]: http://internals.rust-lang.org/t/on-casts-and-checked-overflow/1710/
[803]: https://github.com/rust-lang/rfcs/pull/803
[911]: https://github.com/rust-lang/rfcs/pull/911

# Unresolved questions

The C semantics of wrapping operations in some cases are undefined:
Expand Down Expand Up @@ -480,7 +481,18 @@ overflow.
[CZ22]: https://mail.mozilla.org/pipermail/rust-dev/2014-June/010483.html
[JR23_2]: https://mail.mozilla.org/pipermail/rust-dev/2014-June/010527.html

## Acknowledgements and further reading
# Updates since being accepted

Since it was accepted, the RFC has been updated as follows:

1. The wrapping methods were moved to be inherent, since we gained the
capability for libstd to declare inherent methods on primitive
integral types.
2. `as` was changed to restore the behavior before the RFC (that is,
it truncates, as a C cast would).


# Acknowledgements and further reading

This RFC was [initially written by Gábor Lehel][GH] and was since
edited by Nicholas Matsakis into its current form. Although the text
Expand Down

0 comments on commit 9f2c7f0

Please sign in to comment.