about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-09-02 07:48:21 +0200
committerGitHub <noreply@github.com>2023-09-02 07:48:21 +0200
commit1df0c21af1db9b44de8b8866132534a7fd976b4a (patch)
treea0d7a697e0357b545a4012e23a37140f7ebf2e6b
parent4e2231803b4d4223552bbee675242e5959e11444 (diff)
parent107cd8e2678a3e3c5058f37e16ff998bbeda36f5 (diff)
downloadrust-1df0c21af1db9b44de8b8866132534a7fd976b4a.tar.gz
rust-1df0c21af1db9b44de8b8866132534a7fd976b4a.zip
Rollup merge of #114845 - scottmcm:npo-align, r=WaffleLapkin
Add alignment to the NPO guarantee

This PR [changes](https://github.com/rust-lang/rust/pull/114845#discussion_r1294363357) "same size" to "same size and alignment" in the option module's null pointer optimization docs in <https://doc.rust-lang.org/std/option/#representation>.

As far as I know, this has been true for a long time in the actual rustc implementation, but it's not in the text of those docs, so I figured I'd bring this up to FCP it.

I also see no particular reason that we'd ever *want* to have higher alignment on these.  In many of the cases it's impossible, as the minimum alignment is already the size of the type, but even if we *could* do things like on 32-bit we could say that `NonZeroU64` is 4-align but `Option<NonZeroU64>` is 8-align, I just don't see any value in doing that, so feel completely fine closing this door for the few things on which the NPO is already guaranteed.  These are basically all primitives, and should end up with the same size & alignment as those primitives.

(There's no layout guarantee for something like `Option<[u8; 3]>`, where it'd be at least plausible to consider raising the alignment from 1 to 4 on, say, some hypothetical target that doesn't have efficient unaligned 4-byte load/stores.  And even if we ever did start to offer some kind of guarantee around such a type, I doubt we'd put it under the "null pointer" optimization header.)

Screenshots for the new examples:
![image](https://github.com/rust-lang/rust/assets/18526288/a7dbff42-50b4-462e-9e27-00d511b58763)
![image](https://github.com/rust-lang/rust/assets/18526288/dfd55288-80fb-419a-bc11-26198c27f9f9)
-rw-r--r--library/core/src/num/nonzero.rs14
-rw-r--r--library/core/src/option.rs2
-rw-r--r--library/core/src/ptr/non_null.rs18
3 files changed, 33 insertions, 1 deletions
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 5939dedbd1d..7f8d673c179 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -41,6 +41,20 @@ macro_rules! nonzero_integers {
             /// with the exception that `0` is not a valid instance.
             #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")]
             /// including in FFI.
+            ///
+            /// Thanks to the [null pointer optimization],
+            #[doc = concat!("`", stringify!($Ty), "` and `Option<", stringify!($Ty), ">`")]
+            /// are guaranteed to have the same size and alignment:
+            ///
+            /// ```
+            /// # use std::mem::{size_of, align_of};
+            #[doc = concat!("use std::num::", stringify!($Ty), ";")]
+            ///
+            #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::<Option<", stringify!($Ty), ">>());")]
+            #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
+            /// ```
+            ///
+            /// [null pointer optimization]: crate::option#representation
             #[$stability]
             #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
             #[repr(transparent)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index becb6330997..f2909a81d49 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -119,7 +119,7 @@
 //! # Representation
 //!
 //! Rust guarantees to optimize the following types `T` such that
-//! [`Option<T>`] has the same size as `T`:
+//! [`Option<T>`] has the same size and alignment as `T`:
 //!
 //! * [`Box<U>`]
 //! * `&U`
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e0fd347a049..6b3c4343ed3 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -43,9 +43,27 @@ use crate::slice::{self, SliceIndex};
 /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
 /// is never used for mutation.
 ///
+/// # Representation
+///
+/// Thanks to the [null pointer optimization],
+/// `NonNull<T>` and `Option<NonNull<T>>`
+/// are guaranteed to have the same size and alignment:
+///
+/// ```
+/// # use std::mem::{size_of, align_of};
+/// use std::ptr::NonNull;
+///
+/// assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>());
+/// assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>());
+///
+/// assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>());
+/// assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>());
+/// ```
+///
 /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
 /// [`PhantomData`]: crate::marker::PhantomData
 /// [`UnsafeCell<T>`]: crate::cell::UnsafeCell
+/// [null pointer optimization]: crate::option#representation
 #[stable(feature = "nonnull", since = "1.25.0")]
 #[repr(transparent)]
 #[rustc_layout_scalar_valid_range_start(1)]