about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
authorDrMeepster <19316085+DrMeepster@users.noreply.github.com>2022-09-11 00:37:49 -0700
committerDrMeepster <19316085+DrMeepster@users.noreply.github.com>2023-04-21 02:14:02 -0700
commit511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5 (patch)
tree9aed1b0210cfd3c784a7c5cc89646b8d9dad5427 /library/core
parentb92a41c6760801a7128ca0ec69ba4ba9c9194054 (diff)
downloadrust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.tar.gz
rust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.zip
offset_of
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/mem/mod.rs42
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/mem.rs74
3 files changed, 117 insertions, 0 deletions
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 30ec73cabf8..85745334e9f 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1279,3 +1279,45 @@ pub trait SizedTypeProperties: Sized {
 #[doc(hidden)]
 #[unstable(feature = "sized_type_properties", issue = "none")]
 impl<T> SizedTypeProperties for T {}
+
+/// Expands to the offset in bytes of a field from the beginning of the given type.
+///
+/// Only structs, unions and tuples are supported.
+///
+/// Nested field accesses may be used, but not array indexes like in `C`'s `offsetof`.
+///
+/// Note that the output of this macro is not stable, except for `#[repr(C)]` types.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(offset_of)]
+///
+/// use std::mem;
+/// #[repr(C)]
+/// struct FieldStruct {
+///     first: u8,
+///     second: u16,
+///     third: u8
+/// }
+///
+/// assert_eq!(mem::offset_of!(FieldStruct, first), 0);
+/// assert_eq!(mem::offset_of!(FieldStruct, second), 2);
+/// assert_eq!(mem::offset_of!(FieldStruct, third), 4);
+///
+/// #[repr(C)]
+/// struct NestedA {
+///     b: NestedB
+/// }
+///
+/// #[repr(C)]
+/// struct NestedB(u8);
+///
+/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
+/// ```
+#[unstable(feature = "offset_of", issue = "106655")]
+#[rustc_builtin_macro]
+#[cfg(not(bootstrap))]
+pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
+    // ...implementation defined...
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index f460da35dd3..84859a54c26 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -109,6 +109,7 @@
 #![feature(utf8_chunks)]
 #![feature(is_ascii_octdigit)]
 #![feature(get_many_mut)]
+#![cfg_attr(not(bootstrap), feature(offset_of))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(fuzzy_provenance_casts)]
 
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index f7740a114e7..c08fc6fd2fb 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -364,3 +364,77 @@ fn const_maybe_uninit() {
 
     assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
 }
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of() {
+    #[repr(C)]
+    struct Foo {
+        x: u8,
+        y: u16,
+        z: Bar,
+    }
+
+    #[repr(C)]
+    struct Bar(u8, u8);
+
+    assert_eq!(offset_of!(Foo, x), 0);
+    assert_eq!(offset_of!(Foo, y), 2);
+    assert_eq!(offset_of!(Foo, z.0), 4);
+    assert_eq!(offset_of!(Foo, z.1), 5);
+
+    // Layout of tuples is unstable
+    assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1);
+    assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn const_offset_of() {
+    #[repr(C)]
+    struct Foo {
+        x: u8,
+        y: u16,
+    }
+
+    const X_OFFSET: usize = offset_of!(Foo, x);
+    const Y_OFFSET: usize = offset_of!(Foo, y);
+
+    assert_eq!(X_OFFSET, 0);
+    assert_eq!(Y_OFFSET, 2);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_without_const_promotion() {
+    #[repr(C)]
+    struct Foo<SuppressConstPromotion> {
+        x: u8,
+        y: u16,
+        _scp: SuppressConstPromotion,
+    }
+
+    // Normally, offset_of is always const promoted.
+    // The generic parameter prevents this from happening.
+    // This is needed to test the codegen impl of offset_of
+    fn inner<SuppressConstPromotion>() {
+        assert_eq!(offset_of!(Foo<SuppressConstPromotion>, x), 0);
+        assert_eq!(offset_of!(Foo<SuppressConstPromotion>, y), 2);
+    }
+
+    inner::<()>();
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn offset_of_dst() {
+    #[repr(C)]
+    struct Foo {
+        x: u8,
+        y: u16,
+        slice: [u8],
+    }
+
+    assert_eq!(offset_of!(Foo, x), 0);
+    assert_eq!(offset_of!(Foo, y), 2);
+}