Skip to content

Commit f8e47c6

Browse files
authored
Unrolled build for rust-lang#121201
Rollup merge of rust-lang#121201 - RalfJung:align_offset_contract, r=cuviper align_offset, align_to: no longer allow implementations to spuriously fail to align For a long time, we have allowed `align_offset` to fail to compute a properly aligned offset, and `align_to` to return a smaller-than-maximal "middle slice". This was done to cover the implementation of `align_offset` in const-eval and Miri. See rust-lang#62420 for more background. For about the same amount of time, this has caused confusion and surprise, where people didn't realize they have to write their code to be defensive against `align_offset` failures. Another way to put this is: the specification is effectively non-deterministic, and non-determinism is hard to test for -- in particular if the implementation everyone uses to test always produces the same reliable result, and nobody expects it to be non-deterministic to begin with. With rust-lang#117840, Miri has stopped making use of this liberty in the spec; it now always behaves like rustc. That only leaves const-eval as potential motivation for this behavior. I do not think this is sufficient motivation. Currently, none of the relevant functions are stably const: `align_offset` is unstably const, `align_to` is not const at all. I propose that if we ever want to make these const-stable, we just accept the fact that they can behave differently at compile-time vs at run-time. This is not the end of the world, and it seems to be much less surprising to programmers than unexpected non-determinism. (Related: rust-lang/rfcs#3352.) `@thomcc` has repeatedly made it clear that they strongly dislike the non-determinism in align_offset, so I expect they will support this. `@oli-obk,` what do you think? Also, whom else should we involve? The primary team responsible is clearly libs-api, so I will nominate this for them. However, allowing const-evaluated code to behave different from run-time code is t-lang territory. The thing is, this is not stabilizing anything t-lang-worthy immediately, but it still does make a decision we will be bound to: if we accept this change, then - either `align_offset`/`align_to` can never be called in const fn, - or we allow compile-time behavior to differ from run-time behavior. So I will nominate for t-lang as well, with the question being: are you okay with accepting either of these outcomes (without committing to which one, just accepting that it has to be one of them)? This closes the door to "have `align_offset` and `align_to` at compile-time and also always have compile-time behavior match run-time behavior". Closes rust-lang#62420
2 parents a655e64 + 507583a commit f8e47c6

File tree

3 files changed

+24
-16
lines changed

3 files changed

+24
-16
lines changed

library/core/src/ptr/const_ptr.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1326,9 +1326,7 @@ impl<T: ?Sized> *const T {
13261326
/// `align`.
13271327
///
13281328
/// If it is not possible to align the pointer, the implementation returns
1329-
/// `usize::MAX`. It is permissible for the implementation to *always*
1330-
/// return `usize::MAX`. Only your algorithm's performance can depend
1331-
/// on getting a usable offset here, not its correctness.
1329+
/// `usize::MAX`.
13321330
///
13331331
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
13341332
/// used with the `wrapping_add` method.
@@ -1337,6 +1335,15 @@ impl<T: ?Sized> *const T {
13371335
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
13381336
/// the returned offset is correct in all terms other than alignment.
13391337
///
1338+
/// When this is called during compile-time evaluation (which is unstable), the implementation
1339+
/// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
1340+
/// actual alignment of pointers is not known yet during compile-time, so an offset with
1341+
/// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
1342+
/// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
1343+
/// known, so the execution has to be correct for either choice. It is therefore impossible to
1344+
/// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
1345+
/// for unstable APIs.)
1346+
///
13401347
/// # Panics
13411348
///
13421349
/// The function panics if `align` is not a power-of-two.

library/core/src/ptr/mut_ptr.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1589,9 +1589,7 @@ impl<T: ?Sized> *mut T {
15891589
/// `align`.
15901590
///
15911591
/// If it is not possible to align the pointer, the implementation returns
1592-
/// `usize::MAX`. It is permissible for the implementation to *always*
1593-
/// return `usize::MAX`. Only your algorithm's performance can depend
1594-
/// on getting a usable offset here, not its correctness.
1592+
/// `usize::MAX`.
15951593
///
15961594
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
15971595
/// used with the `wrapping_add` method.
@@ -1600,6 +1598,15 @@ impl<T: ?Sized> *mut T {
16001598
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
16011599
/// the returned offset is correct in all terms other than alignment.
16021600
///
1601+
/// When this is called during compile-time evaluation (which is unstable), the implementation
1602+
/// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
1603+
/// actual alignment of pointers is not known yet during compile-time, so an offset with
1604+
/// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
1605+
/// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
1606+
/// known, so the execution has to be correct for either choice. It is therefore impossible to
1607+
/// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
1608+
/// for unstable APIs.)
1609+
///
16031610
/// # Panics
16041611
///
16051612
/// The function panics if `align` is not a power-of-two.

library/core/src/slice/mod.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -3786,11 +3786,8 @@ impl<T> [T] {
37863786
/// maintained.
37873787
///
37883788
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
3789-
/// slice of a new type, and the suffix slice. How exactly the slice is split up is not
3790-
/// specified; the middle part may be smaller than necessary. However, if this fails to return a
3791-
/// maximal middle part, that is because code is running in a context where performance does not
3792-
/// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
3793-
/// in a default (debug or release) execution *will* return a maximal middle part.
3789+
/// slice of a new type, and the suffix slice. The middle part will be as big as possible under
3790+
/// the given alignment constraint and element size.
37943791
///
37953792
/// This method has no purpose when either input element `T` or output element `U` are
37963793
/// zero-sized and will return the original slice without splitting anything.
@@ -3854,11 +3851,8 @@ impl<T> [T] {
38543851
/// types is maintained.
38553852
///
38563853
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
3857-
/// slice of a new type, and the suffix slice. How exactly the slice is split up is not
3858-
/// specified; the middle part may be smaller than necessary. However, if this fails to return a
3859-
/// maximal middle part, that is because code is running in a context where performance does not
3860-
/// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
3861-
/// in a default (debug or release) execution *will* return a maximal middle part.
3854+
/// slice of a new type, and the suffix slice. The middle part will be as big as possible under
3855+
/// the given alignment constraint and element size.
38623856
///
38633857
/// This method has no purpose when either input element `T` or output element `U` are
38643858
/// zero-sized and will return the original slice without splitting anything.

0 commit comments

Comments
 (0)