Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8112a0c

Browse files
authoredMar 16, 2025
Rollup merge of rust-lang#138323 - kpreid:offset-of-doc, r=Mark-Simulacrum
Expand and organize `offset_of!` documentation. * Give example of how to get the offset of an unsized tail field (prompted by discussion <rust-lang#133055 (comment)>). * Specify the return type. * Add section headings. * Reduce “Visibility is respected…”, to a single sentence. * Move `offset_of_enum` documentation to unstable book (with link to it). * Add `offset_of_slice` documentation in unstable book. r? Mark-Simulacrum
2 parents 7098dd7 + 8cb1b55 commit 8112a0c

File tree

1 file changed

+48
-36
lines changed

1 file changed

+48
-36
lines changed
 

‎core/src/mem/mod.rs

+48-36
Original file line numberDiff line numberDiff line change
@@ -1254,42 +1254,56 @@ impl<T> SizedTypeProperties for T {}
12541254

12551255
/// Expands to the offset in bytes of a field from the beginning of the given type.
12561256
///
1257-
/// Structs, enums, unions and tuples are supported.
1257+
/// The type may be a `struct`, `enum`, `union`, or tuple.
12581258
///
1259-
/// Nested field accesses may be used, but not array indexes.
1259+
/// The field may be a nested field (`field1.field2`), but not an array index.
1260+
/// The field must be visible to the call site.
12601261
///
1261-
/// If the nightly-only feature `offset_of_enum` is enabled,
1262-
/// variants may be traversed as if they were fields.
1263-
/// Variants themselves do not have an offset.
1262+
/// The offset is returned as a [`usize`].
12641263
///
1265-
/// Visibility is respected - all types and fields must be visible to the call site:
1264+
/// # Offsets of, and in, dynamically sized types
12661265
///
1267-
/// ```
1268-
/// mod nested {
1269-
/// #[repr(C)]
1270-
/// pub struct Struct {
1271-
/// private: u8,
1272-
/// }
1273-
/// }
1266+
/// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container.
1267+
/// If the field type is dynamically sized, then you cannot use `offset_of!` (since the field's
1268+
/// alignment, and therefore its offset, may also be dynamic) and must take the offset from an
1269+
/// actual pointer to the container instead.
12741270
///
1275-
/// // assert_eq!(mem::offset_of!(nested::Struct, private), 0);
1276-
/// // ^^^ error[E0616]: field `private` of struct `Struct` is private
1277-
/// ```
1278-
///
1279-
/// Only [`Sized`] fields are supported, but the container may be unsized:
12801271
/// ```
12811272
/// # use core::mem;
1273+
/// # use core::fmt::Debug;
12821274
/// #[repr(C)]
1283-
/// pub struct Struct {
1275+
/// pub struct Struct<T: ?Sized> {
12841276
/// a: u8,
1285-
/// b: [u8],
1277+
/// b: T,
12861278
/// }
12871279
///
1288-
/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK
1289-
/// // assert_eq!(mem::offset_of!(Struct, b), 1);
1290-
/// // ^^^ error[E0277]: doesn't have a size known at compile-time
1280+
/// #[derive(Debug)]
1281+
/// #[repr(C, align(4))]
1282+
/// struct Align4(u32);
1283+
///
1284+
/// assert_eq!(mem::offset_of!(Struct<dyn Debug>, a), 0); // OK — Sized field
1285+
/// assert_eq!(mem::offset_of!(Struct<Align4>, b), 4); // OK — not DST
1286+
///
1287+
/// // assert_eq!(mem::offset_of!(Struct<dyn Debug>, b), 1);
1288+
/// // ^^^ error[E0277]: ... cannot be known at compilation time
1289+
///
1290+
/// // To obtain the offset of a !Sized field, examine a concrete value
1291+
/// // instead of using offset_of!.
1292+
/// let value: Struct<Align4> = Struct { a: 1, b: Align4(2) };
1293+
/// let ref_unsized: &Struct<dyn Debug> = &value;
1294+
/// let offset_of_b = unsafe {
1295+
/// (&raw const ref_unsized.b).byte_offset_from_unsigned(ref_unsized)
1296+
/// };
1297+
/// assert_eq!(offset_of_b, 4);
12911298
/// ```
12921299
///
1300+
/// If you need to obtain the offset of a field of a `!Sized` type, then, since the offset may
1301+
/// depend on the particular value being stored (in particular, `dyn Trait` values have a
1302+
/// dynamically-determined alignment), you must retrieve the offset from a specific reference
1303+
/// or pointer, and so you cannot use `offset_of!` to work without one.
1304+
///
1305+
/// # Layout is subject to change
1306+
///
12931307
/// Note that type layout is, in general, [subject to change and
12941308
/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If
12951309
/// layout stability is required, consider using an [explicit `repr` attribute].
@@ -1325,11 +1339,16 @@ impl<T> SizedTypeProperties for T {}
13251339
///
13261340
/// [explicit `repr` attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations
13271341
///
1342+
/// # Unstable features
1343+
///
1344+
/// The following unstable features expand the functionality of `offset_of!`:
1345+
///
1346+
/// * [`offset_of_enum`] — allows `enum` variants to be traversed as if they were fields.
1347+
/// * [`offset_of_slice`] — allows getting the offset of a field of type `[T]`.
1348+
///
13281349
/// # Examples
13291350
///
13301351
/// ```
1331-
/// #![feature(offset_of_enum)]
1332-
///
13331352
/// use std::mem;
13341353
/// #[repr(C)]
13351354
/// struct FieldStruct {
@@ -1351,18 +1370,11 @@ impl<T> SizedTypeProperties for T {}
13511370
/// struct NestedB(u8);
13521371
///
13531372
/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
1354-
///
1355-
/// #[repr(u8)]
1356-
/// enum Enum {
1357-
/// A(u8, u16),
1358-
/// B { one: u8, two: u16 },
1359-
/// }
1360-
///
1361-
/// assert_eq!(mem::offset_of!(Enum, A.0), 1);
1362-
/// assert_eq!(mem::offset_of!(Enum, B.two), 2);
1363-
///
1364-
/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
13651373
/// ```
1374+
///
1375+
/// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
1376+
/// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html
1377+
/// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html
13661378
#[stable(feature = "offset_of", since = "1.77.0")]
13671379
#[allow_internal_unstable(builtin_syntax)]
13681380
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {

0 commit comments

Comments
 (0)
Failed to load comments.