Skip to content

Commit a82ad23

Browse files
committed
offset_of
1 parent ced93c7 commit a82ad23

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

core/src/mem/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,3 +1279,45 @@ pub trait SizedTypeProperties: Sized {
12791279
#[doc(hidden)]
12801280
#[unstable(feature = "sized_type_properties", issue = "none")]
12811281
impl<T> SizedTypeProperties for T {}
1282+
1283+
/// Expands to the offset in bytes of a field from the beginning of the given type.
1284+
///
1285+
/// Only structs, unions and tuples are supported.
1286+
///
1287+
/// Nested field accesses may be used, but not array indexes like in `C`'s `offsetof`.
1288+
///
1289+
/// Note that the output of this macro is not stable, except for `#[repr(C)]` types.
1290+
///
1291+
/// # Examples
1292+
///
1293+
/// ```
1294+
/// #![feature(offset_of)]
1295+
///
1296+
/// use std::mem;
1297+
/// #[repr(C)]
1298+
/// struct FieldStruct {
1299+
/// first: u8,
1300+
/// second: u16,
1301+
/// third: u8
1302+
/// }
1303+
///
1304+
/// assert_eq!(mem::offset_of!(FieldStruct, first), 0);
1305+
/// assert_eq!(mem::offset_of!(FieldStruct, second), 2);
1306+
/// assert_eq!(mem::offset_of!(FieldStruct, third), 4);
1307+
///
1308+
/// #[repr(C)]
1309+
/// struct NestedA {
1310+
/// b: NestedB
1311+
/// }
1312+
///
1313+
/// #[repr(C)]
1314+
/// struct NestedB(u8);
1315+
///
1316+
/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
1317+
/// ```
1318+
#[unstable(feature = "offset_of", issue = "106655")]
1319+
#[rustc_builtin_macro]
1320+
#[cfg(not(bootstrap))]
1321+
pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
1322+
// ...implementation defined...
1323+
}

core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
#![feature(utf8_chunks)]
110110
#![feature(is_ascii_octdigit)]
111111
#![feature(get_many_mut)]
112+
#![cfg_attr(not(bootstrap), feature(offset_of))]
112113
#![deny(unsafe_op_in_unsafe_fn)]
113114
#![deny(fuzzy_provenance_casts)]
114115

core/tests/mem.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,77 @@ fn const_maybe_uninit() {
364364

365365
assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
366366
}
367+
368+
#[test]
369+
#[cfg(not(bootstrap))]
370+
fn offset_of() {
371+
#[repr(C)]
372+
struct Foo {
373+
x: u8,
374+
y: u16,
375+
z: Bar,
376+
}
377+
378+
#[repr(C)]
379+
struct Bar(u8, u8);
380+
381+
assert_eq!(offset_of!(Foo, x), 0);
382+
assert_eq!(offset_of!(Foo, y), 2);
383+
assert_eq!(offset_of!(Foo, z.0), 4);
384+
assert_eq!(offset_of!(Foo, z.1), 5);
385+
386+
// Layout of tuples is unstable
387+
assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1);
388+
assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2);
389+
}
390+
391+
#[test]
392+
#[cfg(not(bootstrap))]
393+
fn const_offset_of() {
394+
#[repr(C)]
395+
struct Foo {
396+
x: u8,
397+
y: u16,
398+
}
399+
400+
const X_OFFSET: usize = offset_of!(Foo, x);
401+
const Y_OFFSET: usize = offset_of!(Foo, y);
402+
403+
assert_eq!(X_OFFSET, 0);
404+
assert_eq!(Y_OFFSET, 2);
405+
}
406+
407+
#[test]
408+
#[cfg(not(bootstrap))]
409+
fn offset_of_without_const_promotion() {
410+
#[repr(C)]
411+
struct Foo<SuppressConstPromotion> {
412+
x: u8,
413+
y: u16,
414+
_scp: SuppressConstPromotion,
415+
}
416+
417+
// Normally, offset_of is always const promoted.
418+
// The generic parameter prevents this from happening.
419+
// This is needed to test the codegen impl of offset_of
420+
fn inner<SuppressConstPromotion>() {
421+
assert_eq!(offset_of!(Foo<SuppressConstPromotion>, x), 0);
422+
assert_eq!(offset_of!(Foo<SuppressConstPromotion>, y), 2);
423+
}
424+
425+
inner::<()>();
426+
}
427+
428+
#[test]
429+
#[cfg(not(bootstrap))]
430+
fn offset_of_dst() {
431+
#[repr(C)]
432+
struct Foo {
433+
x: u8,
434+
y: u16,
435+
slice: [u8],
436+
}
437+
438+
assert_eq!(offset_of!(Foo, x), 0);
439+
assert_eq!(offset_of!(Foo, y), 2);
440+
}

0 commit comments

Comments
 (0)