Skip to content

Commit 9f2c7f0

Browse files
committed
Do not change semantics of as; make wrapping methods inherent methods.
1 parent 67c2c29 commit 9f2c7f0

File tree

1 file changed

+49
-37
lines changed

1 file changed

+49
-37
lines changed

text/0560-integer-overflow.md

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,9 @@ follows. The intention is that the defined results are the same as the
126126
defined results today. The only change is that now a panic may result.
127127

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

136133
## Enabling overflow checking
137134

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

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

171-
## `WrappingOps` trait for explicit wrapping arithmetic
168+
## Methods for explicit wrapping arithmetic
172169

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

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

186183
fn wrapping_lshift(self, amount: u32) -> Self;
187184
fn wrapping_rshift(self, amount: u32) -> Self;
188-
189-
fn wrapping_as_u8(self, rhs: Self) -> u8;
190-
fn wrapping_as_u16(self, rhs: Self) -> u16;
191-
fn wrapping_as_u32(self, rhs: Self) -> u32
192-
fn wrapping_as_u64(self, rhs: Self) -> u64;
193-
fn wrapping_as_usize(self, rhs: Self) -> usize;
194-
195-
fn wrapping_as_i8(self, rhs: Self) -> i8;
196-
fn wrapping_as_i16(self, rhs: Self) -> i16;
197-
fn wrapping_as_i32(self, rhs: Self) -> i32
198-
fn wrapping_as_i64(self, rhs: Self) -> i64;
199-
fn wrapping_as_isize(self, rhs: Self) -> isize;
200185
}
201-
202-
impl WrappingOps for isize
203-
impl WrappingOps for usize
204-
impl WrappingOps for i8
205-
impl WrappingOps for u8
206-
impl WrappingOps for i16
207-
impl WrappingOps for u16
208-
impl WrappingOps for i32
209-
impl WrappingOps for u32
210-
impl WrappingOps for i64
211-
impl WrappingOps for u64
212186
```
213187

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

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

425+
## Making `as` be checked
426+
427+
The RFC originally specified that using `as` to convert between types
428+
would cause checked semantics. However, we now use `as` as a primitive
429+
type operator. This decision was discussed on the
430+
[discuss message board][as].
431+
432+
The key points in favor of reverting `as` to its original semantics
433+
were:
434+
435+
1. `as` is already a fairly low-level operator that can be used (for
436+
example) to convert between `*mut T` and `*mut U`.
437+
2. `as` is the only way to convert types in constants, and hence it is
438+
important that it covers all possibilities that constants might
439+
need (eventually, [const fn][911] or other approaches may change
440+
this, but those are not going to be stable for 1.0).
441+
3. The [type ascription RFC][803] set the precedent that `as` is used
442+
for "dangerous" coercions that require care.
443+
4. Eventually, checked numeric conversions (and perhaps most or all
444+
uses of `as`) can be ergonomically added as methods. The precise
445+
form of this will be resolved in the future. [const fn][911] can
446+
then allow these to be used in constant expressions.
447+
448+
[as]: http://internals.rust-lang.org/t/on-casts-and-checked-overflow/1710/
449+
[803]: https://github.com/rust-lang/rfcs/pull/803
450+
[911]: https://github.com/rust-lang/rfcs/pull/911
451+
451452
# Unresolved questions
452453

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

483-
## Acknowledgements and further reading
484+
# Updates since being accepted
485+
486+
Since it was accepted, the RFC has been updated as follows:
487+
488+
1. The wrapping methods were moved to be inherent, since we gained the
489+
capability for libstd to declare inherent methods on primitive
490+
integral types.
491+
2. `as` was changed to restore the behavior before the RFC (that is,
492+
it truncates, as a C cast would).
493+
494+
495+
# Acknowledgements and further reading
484496

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

0 commit comments

Comments
 (0)