From 2a74b62c26724ff9c67e4e3ad05378a1af53f195 Mon Sep 17 00:00:00 2001 From: yvt Date: Wed, 23 Feb 2022 19:19:16 -0800 Subject: [PATCH 01/12] Suppress `clippy::unneeded_wildcard_pattern` (#64) --- src/raw_field.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/raw_field.rs b/src/raw_field.rs index a8dd2b3..3a9e62b 100644 --- a/src/raw_field.rs +++ b/src/raw_field.rs @@ -64,6 +64,17 @@ macro_rules! _memoffset__field_check { } /// Deref-coercion protection macro. +#[cfg(allow_clippy)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_tuple { + ($type:ty, $field:tt) => { + // Make sure the type argument is a tuple + #[allow(clippy::unneeded_wildcard_pattern)] + let (_, ..): $type; + }; +} +#[cfg(not(allow_clippy))] #[macro_export] #[doc(hidden)] macro_rules! _memoffset__field_check_tuple { From cb61d3768bfee06961740c1a8ec8ccd85060ecd2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Mar 2022 13:16:23 -0500 Subject: [PATCH 02/12] update Miri CI config --- .github/workflows/ci.yml | 9 ++++++++- ci/miri.sh | 14 -------------- 2 files changed, 8 insertions(+), 15 deletions(-) delete mode 100755 ci/miri.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97fcf98..ea6b607 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,8 +67,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + rustup override set nightly + cargo miri setup - name: Test with Miri - run: ci/miri.sh + run: | + cargo miri test + cargo miri test --all-features style: name: lints and formatting diff --git a/ci/miri.sh b/ci/miri.sh deleted file mode 100755 index 5aea2ec..0000000 --- a/ci/miri.sh +++ /dev/null @@ -1,14 +0,0 @@ -set -ex - -# Install Miri. -MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) -echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" -rustup default "$MIRI_NIGHTLY" -rustup component add miri - -# Run tests. -cargo miri test -cargo miri test --all-features - -# Restore old state in case Travis uses this cache for other jobs. -rustup default nightly From 71c39fbdfbada0a9df7973324d91c8490081c0be Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 10 Oct 2022 17:48:18 +0300 Subject: [PATCH 03/12] Support unions in offset_of(_union) --- src/offset_of.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ src/raw_field.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/src/offset_of.rs b/src/offset_of.rs index 8596e45..54fd3e0 100644 --- a/src/offset_of.rs +++ b/src/offset_of.rs @@ -121,6 +121,39 @@ macro_rules! offset_of_tuple { }}; } +/// Calculates the offset of the specified union member from the start of the union. +/// +/// ## Examples +/// ``` +/// use memoffset::offset_of_union; +/// +/// #[repr(C, packed)] +/// union Foo { +/// foo32: i32, +/// foo64: i64, +/// } +/// +/// fn main() { +/// assert!(offset_of_union!(Foo, foo64) == 0); +/// } +/// ``` +/// +/// ## Note +/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. +/// Using this macro for a single-field struct will still work, but might lead to a future +/// compatibility problem if the struct gains more fields. +#[macro_export(local_inner_macros)] +macro_rules! offset_of_union { + ($parent:path, $field:tt) => {{ + // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). + _memoffset__let_base_ptr!(base_ptr, $parent); + // Get field pointer. + let field_ptr = raw_field_union!(base_ptr, $parent, $field); + // Compute offset. + _memoffset_offset_from_unsafe!(field_ptr, base_ptr) + }}; +} + #[cfg(test)] mod tests { #[test] @@ -161,6 +194,21 @@ mod tests { assert_eq!(offset_of!(Tup, 1), 4); } + #[test] + fn offset_union() { + // Since we're specifying repr(C), all fields are supposed to be at offset 0 + #[repr(C)] + union Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(offset_of_union!(Foo, a), 0); + assert_eq!(offset_of_union!(Foo, b), 0); + assert_eq!(offset_of_union!(Foo, c), 0); + } + #[test] fn path() { mod sub { @@ -238,6 +286,22 @@ mod tests { ); } + #[test] + fn test_raw_field_union() { + #[repr(C)] + union Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + let f = Foo { a: 0 }; + let f_ptr = &f as *const _; + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize); + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize); + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize); + } + #[cfg(feature = "unstable_const")] #[test] fn const_offset() { diff --git a/src/raw_field.rs b/src/raw_field.rs index 3a9e62b..c938bb4 100644 --- a/src/raw_field.rs +++ b/src/raw_field.rs @@ -84,6 +84,41 @@ macro_rules! _memoffset__field_check_tuple { }; } +/// Deref-coercion protection macro for unions. +/// Unfortunately accepts single-field structs as well, which is not ideal, +/// but ultimately pretty harmless. +#[cfg(allow_clippy)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_union { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + #[allow(clippy::unneeded_wildcard_pattern)] + // rustc1.19 requires unsafe here for the pattern; not needed in newer versions + #[allow(unused_unsafe)] + unsafe { + let $type { $field: _ }; + } + }; +} +#[cfg(not(allow_clippy))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_union { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + // rustc1.19 requires unsafe here for the pattern; not needed in newer versions + #[allow(unused_unsafe)] + unsafe { + let $type { $field: _ }; + } + }; +} + /// Computes a const raw pointer to the given field of the given base pointer /// to the given parent type. /// @@ -126,3 +161,31 @@ macro_rules! raw_field_tuple { } }}; } + +/// Computes a const raw pointer to the given field of the given base pointer +/// to the given parent tuple typle. +/// +/// The `base` pointer *must not* be dangling, but it *may* point to +/// uninitialized memory. +/// +/// ## Note +/// This macro is the same as `raw_field`, except for a different Deref-coercion check that +/// supports unions. +/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. +/// Using this macro for a single-field struct will still work, but might lead to a future +/// compatibility problem if the struct gains more fields. +#[macro_export(local_inner_macros)] +macro_rules! raw_field_union { + ($base:expr, $parent:path, $field:tt) => {{ + _memoffset__field_check_union!($parent, $field); + let base = $base; // evaluate $base outside the `unsafe` block + + // Get the field address. + // Crucially, we know that this will not trigger a deref coercion because + // of the field check we did above. + #[allow(unused_unsafe)] // for when the macro is used in an unsafe block + unsafe { + _memoffset__addr_of!((*(base as *const $parent)).$field) + } + }}; +} From b17ae388df6388ec2e98e34e7553f17f2f023550 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 10 Oct 2022 20:45:55 +0300 Subject: [PATCH 04/12] Update src/offset_of.rs Co-authored-by: Ralf Jung --- src/offset_of.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/offset_of.rs b/src/offset_of.rs index 54fd3e0..f2800de 100644 --- a/src/offset_of.rs +++ b/src/offset_of.rs @@ -139,9 +139,9 @@ macro_rules! offset_of_tuple { /// ``` /// /// ## Note -/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. -/// Using this macro for a single-field struct will still work, but might lead to a future -/// compatibility problem if the struct gains more fields. +/// Due to macro_rules limitations, this macro will accept structs with a single field as well as unions. +/// This is not a stable guarantee, and future versions of this crate might fail +/// on any use of this macro with a struct, without a semver bump. #[macro_export(local_inner_macros)] macro_rules! offset_of_union { ($parent:path, $field:tt) => {{ From 6a48918fd10380a8429b6ebe7fd500a86fe4138a Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 10 Oct 2022 20:46:09 +0300 Subject: [PATCH 05/12] Update src/raw_field.rs Co-authored-by: Ralf Jung --- src/raw_field.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raw_field.rs b/src/raw_field.rs index c938bb4..c804b39 100644 --- a/src/raw_field.rs +++ b/src/raw_field.rs @@ -172,8 +172,8 @@ macro_rules! raw_field_tuple { /// This macro is the same as `raw_field`, except for a different Deref-coercion check that /// supports unions. /// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. -/// Using this macro for a single-field struct will still work, but might lead to a future -/// compatibility problem if the struct gains more fields. +/// This is not a stable guarantee, and future versions of this crate might fail +/// on any use of this macro with a struct, without a semver bump. #[macro_export(local_inner_macros)] macro_rules! raw_field_union { ($base:expr, $parent:path, $field:tt) => {{ From af6689589f2cdabe5c32c2e0fd777afa6ff68195 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 10 Oct 2022 22:00:44 +0300 Subject: [PATCH 06/12] Add some compile-fail tests. (#68) Ticket: - https://github.com/Gilnaa/memoffset/issues/23 --- src/raw_field.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/raw_field.rs b/src/raw_field.rs index c804b39..e16df9f 100644 --- a/src/raw_field.rs +++ b/src/raw_field.rs @@ -39,6 +39,21 @@ macro_rules! _memoffset__addr_of { } /// Deref-coercion protection macro. +/// +/// Prevents complilation if the specified field name is not a part of the +/// struct definition. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check; +/// +/// struct Foo { +/// foo: i32, +/// } +/// +/// type BoxedFoo = Box; +/// +/// _memoffset__field_check!(BoxedFoo, foo); +/// ``` #[cfg(allow_clippy)] #[macro_export] #[doc(hidden)] @@ -64,6 +79,14 @@ macro_rules! _memoffset__field_check { } /// Deref-coercion protection macro. +/// +/// Prevents complilation if the specified type is not a tuple. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check_tuple; +/// +/// _memoffset__field_check_tuple!(i32, 0); +/// ``` #[cfg(allow_clippy)] #[macro_export] #[doc(hidden)] @@ -87,6 +110,18 @@ macro_rules! _memoffset__field_check_tuple { /// Deref-coercion protection macro for unions. /// Unfortunately accepts single-field structs as well, which is not ideal, /// but ultimately pretty harmless. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check_union; +/// +/// union Foo { +/// variant_a: i32, +/// } +/// +/// type BoxedFoo = Box; +/// +/// _memoffset__field_check_union!(BoxedFoo, variant_a); +/// ``` #[cfg(allow_clippy)] #[macro_export] #[doc(hidden)] From eb2a79cb6dfefdb15e81f59424ba4d4835f3b2ac Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Sun, 16 Oct 2022 17:49:41 +0300 Subject: [PATCH 07/12] Update docs WRT repr(Rust) (#69) Issue: - https://github.com/Gilnaa/memoffset/issues/59 --- src/offset_of.rs | 10 ++++++++++ src/span_of.rs | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/offset_of.rs b/src/offset_of.rs index f2800de..d070181 100644 --- a/src/offset_of.rs +++ b/src/offset_of.rs @@ -86,6 +86,16 @@ macro_rules! _memoffset_offset_from_unsafe { /// assert_eq!(offset_of!(Foo, b), 4); /// } /// ``` +/// +/// ## Notes +/// Rust's ABI is unstable, and [type layout can be changed with each +/// compilation](https://doc.rust-lang.org/reference/type-layout.html). +/// +/// Using `offset_of!` with a `repr(Rust)` struct will return the correct offset of the +/// specified `field` for a particular compilation, but the exact value may change +/// based on the compiler version, concrete struct type, time of day, or rustc's mood. +/// +/// As a result, the value should not be retained and used between different compilations. #[macro_export(local_inner_macros)] macro_rules! offset_of { ($parent:path, $field:tt) => {{ diff --git a/src/span_of.rs b/src/span_of.rs index aab9d0a..89fccce 100644 --- a/src/span_of.rs +++ b/src/span_of.rs @@ -52,11 +52,18 @@ macro_rules! _memoffset__compile_error { /// span_of!(Struct, start ..) /// ``` /// -/// *Note*: +/// ### Note /// This macro uses recursion in order to resolve the range expressions, so there is a limit to /// the complexity of the expression. /// In order to raise the limit, the compiler's recursion limit should be lifted. /// +/// ### Safety +/// The inter-field form mentioned above assumes that the first field is positioned before the +/// second. +/// This is only guarenteed for `repr(C)` structs. +/// Usage with `repr(Rust)` structs may yield unexpected results, like downward-going ranges, +/// spans that include unexpected fields, empty spans, or spans that include *unexpected* padding bytes. +/// /// ## Examples /// ``` /// use memoffset::span_of; From f1ae392759c8b5efb5d7c31cd4889f0837fcfe4e Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 17 Oct 2022 09:25:20 +0300 Subject: [PATCH 08/12] Version 0.7.0 Support unions and update docs: - https://github.com/Gilnaa/memoffset/issues/66 - https://github.com/Gilnaa/memoffset/issues/23 - https://github.com/Gilnaa/memoffset/issues/59 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7a62858..c4bd710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "memoffset" -version = "0.6.5" +version = "0.7.0" authors = ["Gilad Naaman "] description = "offset_of functionality for Rust structs." license = "MIT" From b94d014a25251a0a69a38e788357a1984f31dd64 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 17 Oct 2022 09:28:40 +0300 Subject: [PATCH 09/12] Updated version in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e93c2b..e297b33 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `Cargo.toml`: ```toml [dependencies] -memoffset = "0.6" +memoffset = "0.7" ``` These versions will compile fine with rustc versions greater or equal to 1.19. @@ -55,7 +55,7 @@ In order to use it, you must enable the `unstable_const` crate feature and sever Cargo.toml: ```toml [dependencies.memoffset] -version = "0.6" +version = "0.7" features = ["unstable_const"] ``` From d8accb76712984e2ab069193f392e5a7b6c5e78c Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Mon, 17 Oct 2022 09:29:35 +0300 Subject: [PATCH 10/12] Version 0.7.1 Re-publish with updated README --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c4bd710..90620e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "memoffset" -version = "0.7.0" +version = "0.7.1" authors = ["Gilad Naaman "] description = "offset_of functionality for Rust structs." license = "MIT" From 923a5f23860346088fa4e3a41ad42165bad44a00 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Sun, 11 Dec 2022 21:53:36 +0200 Subject: [PATCH 11/12] Automatically enable const evaluation When running on a compiler newer than 1.65, automatically enable usage of the macro in const contexts. Closes https://github.com/Gilnaa/memoffset/issues/4 --- .github/workflows/ci.yml | 1 + README.md | 27 +++++++++++++++++++++++---- build.rs | 3 +++ src/lib.rs | 5 +++-- src/offset_of.rs | 8 ++++---- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea6b607..f82f7f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: - 1.36.0 # Oldest supported with MaybeUninit - 1.40.0 # Oldest supported with cfg(doctest) - 1.51.0 # Oldest supported with ptr::addr_of! + - 1.65.0 # Oldest supported with stable const evaluation (sans cell) - stable - beta - nightly diff --git a/README.md b/README.md index e297b33..2df877a 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,23 @@ fn main() { } ``` -## Feature flags ## +## Usage in constants ## +`memoffset` has support for compile-time `offset_of!` on rust>=1.65, or on older nightly compilers. -### Usage in constants ### -`memoffset` has **experimental** support for compile-time `offset_of!` on a nightly compiler. +### Usage on stable Rust ### +Constant evaluation is automatically enabled and avilable on stable compilers starting with rustc 1.65. -In order to use it, you must enable the `unstable_const` crate feature and several compiler features. +This is an incomplete implementation with one caveat: +Due to dependence on [`#![feature(const_refs_to_cell)]`](https://github.com/rust-lang/rust/issues/80384), you cannot get the offset of a `Cell` field in a const-context. + +This means that if need to get the offset of a cell, you'll have to remain on nightly for now. + +### Usage on recent nightlies ### + +If you're using a new-enough nightly and you require the ability to get the offset of a `Cell`, +you'll have to enable the `unstable_const` cargo feature, as well as enabling `const_refs_to_cell` in your crate root. + +Do note that `unstable_const` is an unstable feature that is set to be removed in a future version of `memoffset`. Cargo.toml: ```toml @@ -59,6 +70,14 @@ version = "0.7" features = ["unstable_const"] ``` +Your crate root: (`lib.rs`/`main.rs`) +```rust,ignore +#![feature(const_refs_to_cell)] +``` + +### Usage on older nightlies ### +In order to use it on an older nightly compiler, you must enable the `unstable_const` crate feature and several compiler features. + Your crate root: (`lib.rs`/`main.rs`) ```rust,ignore #![feature(const_ptr_offset_from, const_refs_to_cell)] diff --git a/build.rs b/build.rs index 0604c19..e18810f 100644 --- a/build.rs +++ b/build.rs @@ -19,4 +19,7 @@ fn main() { if ac.probe_rustc_version(1, 51) { println!("cargo:rustc-cfg=raw_ref_macros"); } + if ac.probe_rustc_version(1, 65) { + println!("cargo:rustc-cfg=stable_const"); + } } diff --git a/src/lib.rs b/src/lib.rs index d80ff17..72736aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,9 +57,10 @@ #![no_std] #![cfg_attr( - feature = "unstable_const", - feature(const_ptr_offset_from, const_refs_to_cell) + all(feature = "unstable_const", not(stable_const)), + feature(const_ptr_offset_from) )] +#![cfg_attr(feature = "unstable_const", feature(const_refs_to_cell))] #[macro_use] #[cfg(doctests)] diff --git a/src/offset_of.rs b/src/offset_of.rs index d070181..9ce4ae2 100644 --- a/src/offset_of.rs +++ b/src/offset_of.rs @@ -46,7 +46,7 @@ macro_rules! _memoffset__let_base_ptr { } /// Macro to compute the distance between two pointers. -#[cfg(feature = "unstable_const")] +#[cfg(any(feature = "unstable_const", stable_const))] #[macro_export] #[doc(hidden)] macro_rules! _memoffset_offset_from_unsafe { @@ -58,7 +58,7 @@ macro_rules! _memoffset_offset_from_unsafe { unsafe { (field as *const u8).offset_from(base as *const u8) as usize } }}; } -#[cfg(not(feature = "unstable_const"))] +#[cfg(not(any(feature = "unstable_const", stable_const)))] #[macro_export] #[doc(hidden)] macro_rules! _memoffset_offset_from_unsafe { @@ -312,7 +312,7 @@ mod tests { assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize); } - #[cfg(feature = "unstable_const")] + #[cfg(any(feature = "unstable_const", stable_const))] #[test] fn const_offset() { #[repr(C)] @@ -337,7 +337,7 @@ mod tests { assert_eq!([0; offset_of!(Foo, b)].len(), 4); } - #[cfg(feature = "unstable_const")] + #[cfg(any(feature = "unstable_const", stable_const))] #[test] fn const_fn_offset() { const fn test_fn() -> usize { From 0fac3ac6642dd017a36268c4cdba2f04ec050d11 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Thu, 15 Dec 2022 20:24:05 +0200 Subject: [PATCH 12/12] Version 0.8.0 Support for const-eval on stable --- Cargo.toml | 2 +- README.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 90620e2..71bdc9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "memoffset" -version = "0.7.1" +version = "0.8.0" authors = ["Gilad Naaman "] description = "offset_of functionality for Rust structs." license = "MIT" diff --git a/README.md b/README.md index 2df877a..b0bfd10 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ C-Like `offset_of` functionality for Rust structs. Introduces the following macros: * `offset_of!` for obtaining the offset of a member of a struct. * `offset_of_tuple!` for obtaining the offset of a member of a tuple. (Requires Rust 1.20+) + * `offset_of_union!` for obtaining the offset of a member of a union. * `span_of!` for obtaining the range that a field, or fields, span. `memoffset` works under `no_std` environments. @@ -16,7 +17,7 @@ Add the following dependency to your `Cargo.toml`: ```toml [dependencies] -memoffset = "0.7" +memoffset = "0.8" ``` These versions will compile fine with rustc versions greater or equal to 1.19. @@ -66,7 +67,7 @@ Do note that `unstable_const` is an unstable feature that is set to be removed i Cargo.toml: ```toml [dependencies.memoffset] -version = "0.7" +version = "0.8" features = ["unstable_const"] ```