Skip to content

Commit e2c3014

Browse files
wedsonafintel-lab-lkp
authored andcommitted
rust: add offset_of! macro
This macro is used to compute the offset of a field in a struct. This commit enables an unstable feature that is necessary for using the macro in a constant. However, this is not a problem as the macro will become available from the Rust standard library soon [1]. The unstable feature can be disabled again once that happens. The macro in this patch does not support sub-fields. That is, you cannot write `offset_of!(MyStruct, field.sub_field)` to get the offset of `sub_field` with `field`'s type being a struct with a field called `sub_field`. This is because `field` might be a `Box<SubStruct>`, which means that you would be trying to compute the offset to something in an entirely different allocation. There's no easy way to fix the current macro to support subfields, but the version being added to the standard library should support it, so the limitation is temporary and not a big deal. Link: rust-lang/rust#106655 [1] Signed-off-by: Wedson Almeida Filho <[email protected]> Co-developed-by: Alice Ryhl <[email protected]> Signed-off-by: Alice Ryhl <[email protected]> Reviewed-by: Martin Rodriguez Reboredo <[email protected]>
1 parent 0adc884 commit e2c3014

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

rust/kernel/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![no_std]
1515
#![feature(allocator_api)]
1616
#![feature(coerce_unsized)]
17+
#![feature(const_refs_to_cell)]
1718
#![feature(dispatch_from_dyn)]
1819
#![feature(new_uninit)]
1920
#![feature(receiver_trait)]
@@ -98,3 +99,37 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
9899
// instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
99100
loop {}
100101
}
102+
103+
/// Calculates the offset of a field from the beginning of the struct it belongs to.
104+
///
105+
/// # Examples
106+
///
107+
/// ```
108+
/// #[repr(C)]
109+
/// struct Test {
110+
/// a: u64,
111+
/// b: u32,
112+
/// }
113+
///
114+
/// assert_eq!(kernel::offset_of!(Test, b), 8);
115+
/// ```
116+
#[macro_export]
117+
macro_rules! offset_of {
118+
($type:path, $field:ident) => {{
119+
let $type { $field: _, .. };
120+
let tmp = ::core::mem::MaybeUninit::<$type>::uninit();
121+
let outer = tmp.as_ptr();
122+
// To avoid warnings when nesting `unsafe` blocks.
123+
#[allow(unused_unsafe)]
124+
// SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
125+
// we don't actually read from `outer` (which would be UB) nor create an intermediate
126+
// reference.
127+
let inner = unsafe { ::core::ptr::addr_of!((*outer).$field) } as *const u8;
128+
// To avoid warnings when nesting `unsafe` blocks.
129+
#[allow(unused_unsafe)]
130+
// SAFETY: The two pointers are within the same allocation block.
131+
unsafe {
132+
inner.offset_from(outer as *const u8) as usize
133+
}
134+
}};
135+
}

scripts/Makefile.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE
277277
# Compile Rust sources (.rs)
278278
# ---------------------------------------------------------------------------
279279

280-
rust_allowed_features := new_uninit
280+
rust_allowed_features := const_refs_to_cell,new_uninit
281281

282282
rust_common_cmd = \
283283
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \

0 commit comments

Comments
 (0)