From 58d4395c1ac791dba1da4ca3149a5809693edb7d Mon Sep 17 00:00:00 2001
From: Kevin Reid <kpreid@switchb.org>
Date: Mon, 10 Mar 2025 16:01:20 -0700
Subject: [PATCH 1/2] Expand and organize `offset_of!` documentation.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Give example of how to get the offset of an unsized tail field
  (prompted by discussion <https://github.com/rust-lang/rust/pull/133055#discussion_r1986422206>).
* Specify the return type.
* Add section headings.
* Reduce “Visibility is respected…”, to a single sentence.
---
 library/core/src/mem/mod.rs | 62 ++++++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 21 deletions(-)

diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index caab7a6ddb52f..1ebe3f977fdd7 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1249,42 +1249,60 @@ impl<T> SizedTypeProperties for T {}
 
 /// Expands to the offset in bytes of a field from the beginning of the given type.
 ///
-/// Structs, enums, unions and tuples are supported.
+/// The type may be a `struct`, `enum`, `union`, or tuple.
 ///
-/// Nested field accesses may be used, but not array indexes.
+/// The field may be a nested field (`field1.field2`), but not an array index.
+/// The field must be visible to the call site.
+///
+/// The offset is returned as a [`usize`].
 ///
 /// If the nightly-only feature `offset_of_enum` is enabled,
-/// variants may be traversed as if they were fields.
+/// `enum` variants may be traversed as if they were fields.
 /// Variants themselves do not have an offset.
 ///
-/// Visibility is respected - all types and fields must be visible to the call site:
-///
-/// ```
-/// mod nested {
-///     #[repr(C)]
-///     pub struct Struct {
-///         private: u8,
-///     }
-/// }
+/// # Offsets of, and in, dynamically sized types
 ///
-/// // assert_eq!(mem::offset_of!(nested::Struct, private), 0);
-/// // ^^^ error[E0616]: field `private` of struct `Struct` is private
-/// ```
+/// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container.
+/// If the field type is dynamically sized, then you cannot use `offset_of!` (since the field's
+/// alignment, and therefore its offset, may also be dynamic) and must take the offset from an
+/// actual pointer to the container instead.
 ///
-/// Only [`Sized`] fields are supported, but the container may be unsized:
 /// ```
 /// # use core::mem;
+/// # use core::fmt::Debug;
 /// #[repr(C)]
-/// pub struct Struct {
+/// pub struct Struct<T: ?Sized> {
 ///     a: u8,
-///     b: [u8],
+///     b: T,
 /// }
 ///
-/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK
-/// // assert_eq!(mem::offset_of!(Struct, b), 1);
-/// // ^^^ error[E0277]: doesn't have a size known at compile-time
+/// #[derive(Debug)]
+/// #[repr(C, align(4))]
+/// struct Align4(u32);
+///
+/// assert_eq!(mem::offset_of!(Struct<dyn Debug>, a), 0); // OK — Sized field
+/// assert_eq!(mem::offset_of!(Struct<Align4>, b), 4); // OK — not DST
+///
+/// // assert_eq!(mem::offset_of!(Struct<dyn Debug>, b), 1);
+/// // ^^^ error[E0277]: ... cannot be known at compilation time
+///
+/// // To obtain the offset of a !Sized field, examine a concrete value
+/// // instead of using offset_of!.
+/// let value: Struct<Align4> = Struct { a: 1, b: Align4(2) };
+/// let ref_unsized: &Struct<dyn Debug> = &value;
+/// let offset_of_b = unsafe {
+///     (&raw const ref_unsized.b).byte_offset_from_unsigned(ref_unsized)
+/// };
+/// assert_eq!(offset_of_b, 4);
 /// ```
 ///
+/// If you need to obtain the offset of a field of a `!Sized` type, then, since the offset may
+/// depend on the particular value being stored (in particular, `dyn Trait` values have a
+/// dynamically-determined alignment), you must retrieve the offset from a specific reference
+/// or pointer, and so you cannot use `offset_of!` to work without one.
+///
+/// # Layout is subject to change
+///
 /// Note that type layout is, in general, [subject to change and
 /// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If
 /// layout stability is required, consider using an [explicit `repr` attribute].
@@ -1358,6 +1376,8 @@ impl<T> SizedTypeProperties for T {}
 ///
 /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
 /// ```
+///
+/// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
 #[stable(feature = "offset_of", since = "1.77.0")]
 #[allow_internal_unstable(builtin_syntax)]
 pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {

From 8f3254714762438639010efd90a721a133e23cec Mon Sep 17 00:00:00 2001
From: Kevin Reid <kpreid@switchb.org>
Date: Mon, 10 Mar 2025 17:27:30 -0700
Subject: [PATCH 2/2] Move `offset_of_enum` documentation to unstable book; add
 `offset_of_slice`.

---
 library/core/src/mem/mod.rs                   | 26 ++++++----------
 .../src/language-features/offset-of-enum.md   | 29 ++++++++++++++++++
 .../src/language-features/offset-of-slice.md  | 30 +++++++++++++++++++
 3 files changed, 68 insertions(+), 17 deletions(-)
 create mode 100644 src/doc/unstable-book/src/language-features/offset-of-enum.md
 create mode 100644 src/doc/unstable-book/src/language-features/offset-of-slice.md

diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 1ebe3f977fdd7..caf973c53882d 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1256,10 +1256,6 @@ impl<T> SizedTypeProperties for T {}
 ///
 /// The offset is returned as a [`usize`].
 ///
-/// If the nightly-only feature `offset_of_enum` is enabled,
-/// `enum` variants may be traversed as if they were fields.
-/// Variants themselves do not have an offset.
-///
 /// # Offsets of, and in, dynamically sized types
 ///
 /// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container.
@@ -1338,11 +1334,16 @@ impl<T> SizedTypeProperties for T {}
 ///
 /// [explicit `repr` attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations
 ///
+/// # Unstable features
+///
+/// The following unstable features expand the functionality of `offset_of!`:
+///
+/// * [`offset_of_enum`] — allows `enum` variants to be traversed as if they were fields.
+/// * [`offset_of_slice`] — allows getting the offset of a field of type `[T]`.
+///
 /// # Examples
 ///
 /// ```
-/// #![feature(offset_of_enum)]
-///
 /// use std::mem;
 /// #[repr(C)]
 /// struct FieldStruct {
@@ -1364,20 +1365,11 @@ impl<T> SizedTypeProperties for T {}
 /// struct NestedB(u8);
 ///
 /// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
-///
-/// #[repr(u8)]
-/// enum Enum {
-///     A(u8, u16),
-///     B { one: u8, two: u16 },
-/// }
-///
-/// assert_eq!(mem::offset_of!(Enum, A.0), 1);
-/// assert_eq!(mem::offset_of!(Enum, B.two), 2);
-///
-/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
 /// ```
 ///
 /// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
+/// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html
+/// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html
 #[stable(feature = "offset_of", since = "1.77.0")]
 #[allow_internal_unstable(builtin_syntax)]
 pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
diff --git a/src/doc/unstable-book/src/language-features/offset-of-enum.md b/src/doc/unstable-book/src/language-features/offset-of-enum.md
new file mode 100644
index 0000000000000..1960d6299eb00
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/offset-of-enum.md
@@ -0,0 +1,29 @@
+# `offset_of_slice`
+
+The tracking issue for this feature is: [#120141]
+
+[#120141]: https://github.com/rust-lang/rust/issues/120141
+
+------------------------
+
+When the `offset_of_enum` feature is enabled, the [`offset_of!`] macro may be used to obtain the
+offsets of fields of `enum`s; to express this, `enum` variants may be traversed as if they were
+fields. Variants themselves do not have an offset, so they cannot appear as the last path component.
+
+```rust
+#![feature(offset_of_enum)]
+use std::mem;
+
+#[repr(u8)]
+enum Enum {
+    A(u8, u16),
+    B { one: u8, two: u16 },
+}
+
+assert_eq!(mem::offset_of!(Enum, A.0), 1);
+assert_eq!(mem::offset_of!(Enum, B.two), 2);
+
+assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
+```
+
+[`offset_of!`]: ../../std/mem/macro.offset_of.html
diff --git a/src/doc/unstable-book/src/language-features/offset-of-slice.md b/src/doc/unstable-book/src/language-features/offset-of-slice.md
new file mode 100644
index 0000000000000..c887fa07f67e1
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/offset-of-slice.md
@@ -0,0 +1,30 @@
+# `offset_of_slice`
+
+The tracking issue for this feature is: [#126151]
+
+[#126151]: https://github.com/rust-lang/rust/issues/126151
+
+------------------------
+
+When the `offset_of_slice` feature is enabled, the [`offset_of!`] macro may be used to determine
+the offset of fields whose type is `[T]`, that is, a slice of dynamic size.
+
+In general, fields whose type is dynamically sized do not have statically known offsets because
+they do not have statically known alignments. However, `[T]` has the same alignment as `T`, so
+it specifically may be allowed.
+
+```rust
+#![feature(offset_of_slice)]
+
+#[repr(C)]
+pub struct Struct {
+    head: u32,
+    tail: [u8],
+}
+
+fn main() {
+    assert_eq!(std::mem::offset_of!(Struct, tail), 4);
+}
+```
+
+[`offset_of!`]: ../../std/mem/macro.offset_of.html