Skip to content

Commit 2b29f3e

Browse files
wedsonafDarksonn
authored andcommitted
rust: add offset_of! macro
This macro is used to compute the offset of a field in a struct. This commit enables two unstable features that are 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 features 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]>
1 parent 480f8c5 commit 2b29f3e

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

rust/kernel/lib.rs

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

scripts/Makefile.build

+1-1
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 := core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro
280+
rust_allowed_features := const_ptr_offset_from,const_refs_to_cell,core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro
281281

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

0 commit comments

Comments
 (0)