Skip to content

Commit 47a68bb

Browse files
committed
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.
1 parent 0b6a207 commit 47a68bb

File tree

1 file changed

+41
-21
lines changed

1 file changed

+41
-21
lines changed

core/src/mem/mod.rs

+41-21
Original file line numberDiff line numberDiff line change
@@ -1249,42 +1249,60 @@ impl<T> SizedTypeProperties for T {}
12491249

12501250
/// Expands to the offset in bytes of a field from the beginning of the given type.
12511251
///
1252-
/// Structs, enums, unions and tuples are supported.
1252+
/// The type may be a `struct`, `enum`, `union`, or tuple.
12531253
///
1254-
/// Nested field accesses may be used, but not array indexes.
1254+
/// The field may be a nested field (`field1.field2`), but not an array index.
1255+
/// The field must be visible to the call site.
1256+
///
1257+
/// The offset is returned as a [`usize`].
12551258
///
12561259
/// If the nightly-only feature `offset_of_enum` is enabled,
1257-
/// variants may be traversed as if they were fields.
1260+
/// `enum` variants may be traversed as if they were fields.
12581261
/// Variants themselves do not have an offset.
12591262
///
1260-
/// Visibility is respected - all types and fields must be visible to the call site:
1261-
///
1262-
/// ```
1263-
/// mod nested {
1264-
/// #[repr(C)]
1265-
/// pub struct Struct {
1266-
/// private: u8,
1267-
/// }
1268-
/// }
1263+
/// # Offsets of, and in, dynamically sized types
12691264
///
1270-
/// // assert_eq!(mem::offset_of!(nested::Struct, private), 0);
1271-
/// // ^^^ error[E0616]: field `private` of struct `Struct` is private
1272-
/// ```
1265+
/// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container.
1266+
/// If the field type is dynamically sized, then you cannot use `offset_of!` (since the field's
1267+
/// alignment, and therefore its offset, may also be dynamic) and must take the offset from an
1268+
/// actual pointer to the container instead.
12731269
///
1274-
/// Only [`Sized`] fields are supported, but the container may be unsized:
12751270
/// ```
12761271
/// # use core::mem;
1272+
/// # use core::fmt::Debug;
12771273
/// #[repr(C)]
1278-
/// pub struct Struct {
1274+
/// pub struct Struct<T: ?Sized> {
12791275
/// a: u8,
1280-
/// b: [u8],
1276+
/// b: T,
12811277
/// }
12821278
///
1283-
/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK
1284-
/// // assert_eq!(mem::offset_of!(Struct, b), 1);
1285-
/// // ^^^ error[E0277]: doesn't have a size known at compile-time
1279+
/// #[derive(Debug)]
1280+
/// #[repr(C, align(4))]
1281+
/// struct Align4(u32);
1282+
///
1283+
/// assert_eq!(mem::offset_of!(Struct<dyn Debug>, a), 0); // OK — Sized field
1284+
/// assert_eq!(mem::offset_of!(Struct<Align4>, b), 4); // OK — not DST
1285+
///
1286+
/// // assert_eq!(mem::offset_of!(Struct<dyn Debug>, b), 1);
1287+
/// // ^^^ error[E0277]: ... cannot be known at compilation time
1288+
///
1289+
/// // To obtain the offset of a !Sized field, examine a concrete value
1290+
/// // instead of using offset_of!.
1291+
/// let value: Struct<Align4> = Struct { a: 1, b: Align4(2) };
1292+
/// let ref_unsized: &Struct<dyn Debug> = &value;
1293+
/// let offset_of_b = unsafe {
1294+
/// (&raw const ref_unsized.b).byte_offset_from_unsigned(ref_unsized)
1295+
/// };
1296+
/// assert_eq!(offset_of_b, 4);
12861297
/// ```
12871298
///
1299+
/// If you need to obtain the offset of a field of a `!Sized` type, then, since the offset may
1300+
/// depend on the particular value being stored (in particular, `dyn Trait` values have a
1301+
/// dynamically-determined alignment), you must retrieve the offset from a specific reference
1302+
/// or pointer, and so you cannot use `offset_of!` to work without one.
1303+
///
1304+
/// # Layout is subject to change
1305+
///
12881306
/// Note that type layout is, in general, [subject to change and
12891307
/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If
12901308
/// layout stability is required, consider using an [explicit `repr` attribute].
@@ -1358,6 +1376,8 @@ impl<T> SizedTypeProperties for T {}
13581376
///
13591377
/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
13601378
/// ```
1379+
///
1380+
/// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
13611381
#[stable(feature = "offset_of", since = "1.77.0")]
13621382
#[allow_internal_unstable(builtin_syntax)]
13631383
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {

0 commit comments

Comments
 (0)