mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1716518 - Upgrade memoffset to v0.5.6. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D117816
This commit is contained in:
parent
5b6c28d2da
commit
48d7761513
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -3017,11 +3017,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.1"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
|
||||
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"7a81dbe83677240751ea16029792a46d0a776886ecae85f18fbec6c5912543c3","LICENSE":"3234ac55816264ee7b6c7ee27efd61cf0a1fe775806870e3d9b4c41ea73c5cb1","README.md":"f79665fcf1b936024d74465c45f65d6e3157be593b4507be27729d6eff613047","build.rs":"ba401d756f3007247cdc74f2b749deee11cec48d98d6deaa49677c0cfc3ef0ae","src/lib.rs":"278bbe15039e745385f8bf7cf3b005c4c5404e403c732de5aa936b7dd19cd0e9","src/offset_of.rs":"734576bb3f91e33fe2737d8a036623b5d850521401d6321b844a3da418057dee","src/span_of.rs":"84a073a394254b84f52f3d89aafdd7ce7b87f8587f6a41a5868aa428aa740b19"},"package":"ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"}
|
||||
{"files":{"Cargo.toml":"3ba713929bae02b40a2cc5c6cc6a0e07281ddb31cc4532129f3845f18e02f8d7","LICENSE":"3234ac55816264ee7b6c7ee27efd61cf0a1fe775806870e3d9b4c41ea73c5cb1","README.md":"a04fb6dddb88b92e8d9393106f078d320269b4e3efe1242f71a9e2984f6f6afd","build.rs":"c9d1b41b0b915d10f84c02476ec13ef30a887cd0c63a2e54269d907981858b28","ci/miri.sh":"ad7410b0a5bd6e346f55e9d96ec0719a085a2d1ce266bddfe6fe73333a1eb8ec","src/lib.rs":"0621a03c51702403e46846f871bab0f576c9557f33b94c37431a57ce81c665d1","src/offset_of.rs":"bdcd14a2645e53b1199839f927cb10aa26dddc935a131fb1b86c7746bc81d162","src/raw_field.rs":"4263b8071a12b2eb81081091a4217fdfbdfa5254f40c94d4af523e84b8b4fd58","src/span_of.rs":"2d9216b794327e95f55bad04ba7d8e76ff5313713c187b319348d8e5620aa0a9"},"package":"043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"}
|
13
third_party/rust/memoffset/Cargo.toml
vendored
13
third_party/rust/memoffset/Cargo.toml
vendored
@ -12,7 +12,7 @@
|
||||
|
||||
[package]
|
||||
name = "memoffset"
|
||||
version = "0.5.1"
|
||||
version = "0.5.6"
|
||||
authors = ["Gilad Naaman <gilad.naaman@gmail.com>"]
|
||||
description = "offset_of functionality for Rust structs."
|
||||
readme = "README.md"
|
||||
@ -20,5 +20,12 @@ keywords = ["mem", "offset", "offset_of", "offsetof"]
|
||||
categories = ["no-std"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/Gilnaa/memoffset"
|
||||
[build-dependencies.rustc_version]
|
||||
version = "0.2.3"
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3"
|
||||
[build-dependencies.autocfg]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
unstable_const = []
|
||||
unstable_raw = []
|
||||
|
65
third_party/rust/memoffset/README.md
vendored
65
third_party/rust/memoffset/README.md
vendored
@ -15,40 +15,65 @@ Add the following dependency to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
memoffset = "0.3"
|
||||
memoffset = "0.5"
|
||||
```
|
||||
|
||||
Versions ">= 0.3" can be used in a constant expression context (though not in a `const fn`),
|
||||
but require a rust version greater than or equal to 1.33.
|
||||
These versions will compile fine with rustc versions greater or equal to 1.19, but will
|
||||
lack support for constant expression.
|
||||
|
||||
If you wish to use an older rustc version, lock your dependency to "0.2"
|
||||
These versions will compile fine with rustc versions greater or equal to 1.19.
|
||||
|
||||
Add the following lines at the top of your `main.rs` or `lib.rs` files.
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
#[macro_use]
|
||||
extern crate memoffset;
|
||||
```
|
||||
|
||||
## Examples ##
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate memoffset;
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: [u8; 5],
|
||||
d: u32,
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: [u8; 5],
|
||||
d: u32,
|
||||
}
|
||||
|
||||
assert_eq!(offset_of!(Foo, b), 4);
|
||||
assert_eq!(offset_of!(Foo, c[3]), 11);
|
||||
fn main() {
|
||||
assert_eq!(offset_of!(Foo, b), 4);
|
||||
assert_eq!(offset_of!(Foo, d), 4+4+5);
|
||||
|
||||
assert_eq!(span_of!(Foo, a), 0..4);
|
||||
assert_eq!(span_of!(Foo, a .. c), 0..8);
|
||||
assert_eq!(span_of!(Foo, a .. c[1]), 0..9);
|
||||
assert_eq!(span_of!(Foo, a ..= c[1]), 0..10);
|
||||
assert_eq!(span_of!(Foo, ..= d), 0..14);
|
||||
assert_eq!(span_of!(Foo, b ..), 4..17);
|
||||
assert_eq!(span_of!(Foo, a), 0..4);
|
||||
assert_eq!(span_of!(Foo, a .. c), 0..8);
|
||||
assert_eq!(span_of!(Foo, a ..= c), 0..13);
|
||||
assert_eq!(span_of!(Foo, ..= d), 0..17);
|
||||
assert_eq!(span_of!(Foo, b ..), 4..17);
|
||||
}
|
||||
```
|
||||
|
||||
## Feature flags ##
|
||||
|
||||
### Usage in constants ###
|
||||
`memoffset` has **experimental** support for compile-time `offset_of!` on a nightly compiler.
|
||||
|
||||
In order to use it, you must enable the `unstable_const` crate feature and several compiler features.
|
||||
|
||||
Cargo.toml:
|
||||
```toml
|
||||
[dependencies.memoffset]
|
||||
version = "0.5"
|
||||
features = ["unstable_const"]
|
||||
```
|
||||
|
||||
Your crate root: (`lib.rs`/`main.rs`)
|
||||
```rust,ignore
|
||||
#![feature(ptr_offset_from, const_ptr_offset_from, const_maybe_uninit_as_ptr, const_raw_ptr_deref)]
|
||||
```
|
||||
|
||||
If you intend to use `offset_of!` inside a `const fn`, also add the `const_fn` compiler feature.
|
||||
|
||||
### Raw references ###
|
||||
Recent nightlies support [a way to create raw pointers](https://github.com/rust-lang/rust/issues/73394) that avoids creating intermediate safe references.
|
||||
`memoffset` can make use of that feature to avoid what is technically Undefined Behavior.
|
||||
Use the `unstable_raw` feature to enable this.
|
||||
|
18
third_party/rust/memoffset/build.rs
vendored
18
third_party/rust/memoffset/build.rs
vendored
@ -1,12 +1,16 @@
|
||||
extern crate rustc_version;
|
||||
use rustc_version::{version, Version};
|
||||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Assert we haven't travelled back in time
|
||||
assert!(version().unwrap().major >= 1);
|
||||
let ac = autocfg::new();
|
||||
|
||||
// Check for a minimum version
|
||||
if version().unwrap() >= Version::parse("1.36.0").unwrap() {
|
||||
println!("cargo:rustc-cfg=memoffset_maybe_uninit");
|
||||
// Check for a minimum version for a few features
|
||||
if ac.probe_rustc_version(1, 31) {
|
||||
println!("cargo:rustc-cfg=allow_clippy");
|
||||
}
|
||||
if ac.probe_rustc_version(1, 36) {
|
||||
println!("cargo:rustc-cfg=maybe_uninit");
|
||||
}
|
||||
if ac.probe_rustc_version(1, 40) {
|
||||
println!("cargo:rustc-cfg=doctests");
|
||||
}
|
||||
}
|
||||
|
14
third_party/rust/memoffset/ci/miri.sh
vendored
Normal file
14
third_party/rust/memoffset/ci/miri.sh
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
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
|
28
third_party/rust/memoffset/src/lib.rs
vendored
28
third_party/rust/memoffset/src/lib.rs
vendored
@ -20,11 +20,7 @@
|
||||
|
||||
//! A crate used for calculating offsets of struct members and their spans.
|
||||
//!
|
||||
//! Some of the funcationality of the crate makes no sense when used along with structs that
|
||||
//! are not `#[repr(C, packed)]`, but it is up to the user to make sure that they are.
|
||||
//!
|
||||
//! This functionality should work for `const`s but presently doesn't work on `const fn`. Storing a
|
||||
//! value in a const and then returning it from a `const fn` should workaround most cases.
|
||||
//! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions.
|
||||
//!
|
||||
//! ## Examples
|
||||
//! ```
|
||||
@ -61,15 +57,35 @@
|
||||
//! ```
|
||||
|
||||
#![no_std]
|
||||
#![cfg_attr(
|
||||
feature = "unstable_const",
|
||||
feature(
|
||||
ptr_offset_from,
|
||||
const_fn,
|
||||
const_ptr_offset_from,
|
||||
const_maybe_uninit_as_ptr,
|
||||
const_raw_ptr_deref,
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(feature = "unstable_raw", feature(raw_ref_macros))]
|
||||
|
||||
#[macro_use]
|
||||
#[cfg(doctests)]
|
||||
#[cfg(doctest)]
|
||||
extern crate doc_comment;
|
||||
#[cfg(doctests)]
|
||||
#[cfg(doctest)]
|
||||
doctest!("../README.md");
|
||||
|
||||
// This `use` statement enables the macros to use `$crate::mem`.
|
||||
// Doing this enables this crate to function under both std and no-std crates.
|
||||
#[doc(hidden)]
|
||||
pub use core::mem;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use core::ptr;
|
||||
|
||||
#[macro_use]
|
||||
mod raw_field;
|
||||
#[macro_use]
|
||||
mod offset_of;
|
||||
#[macro_use]
|
||||
|
133
third_party/rust/memoffset/src/offset_of.rs
vendored
133
third_party/rust/memoffset/src/offset_of.rs
vendored
@ -20,41 +20,49 @@
|
||||
|
||||
/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
|
||||
/// much as is possible currently.
|
||||
#[cfg(memoffset_maybe_uninit)]
|
||||
#[cfg(maybe_uninit)]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__let_base_ptr {
|
||||
($name:ident, $type:tt) => {
|
||||
($name:ident, $type:path) => {
|
||||
// No UB here, and the pointer does not dangle, either.
|
||||
// But we have to make sure that `uninit` lives long enough,
|
||||
// so it has to be in the same scope as `$name`. That's why
|
||||
// `let_base_ptr` declares a variable (several, actually)
|
||||
// instad of returning one.
|
||||
// instead of returning one.
|
||||
let uninit = $crate::mem::MaybeUninit::<$type>::uninit();
|
||||
let $name = uninit.as_ptr();
|
||||
let $name: *const $type = uninit.as_ptr();
|
||||
};
|
||||
}
|
||||
#[cfg(not(memoffset_maybe_uninit))]
|
||||
#[cfg(not(maybe_uninit))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__let_base_ptr {
|
||||
($name:ident, $type:tt) => {
|
||||
// No UB right here, but we will later offset into a field
|
||||
// of this pointer, and that is UB when the pointer is dangling.
|
||||
let non_null = $crate::ptr::NonNull::<$type>::dangling();
|
||||
let $name = non_null.as_ptr() as *const $type;
|
||||
($name:ident, $type:path) => {
|
||||
// No UB right here, but we will later dereference this pointer to
|
||||
// offset into a field, and that is UB because the pointer is dangling.
|
||||
let $name = $crate::mem::align_of::<$type>() as *const $type;
|
||||
};
|
||||
}
|
||||
|
||||
/// Deref-coercion protection macro.
|
||||
/// Macro to compute the distance between two pointers.
|
||||
#[cfg(feature = "unstable_const")]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__field_check {
|
||||
($type:tt, $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.
|
||||
let $type { $field: _, .. };
|
||||
macro_rules! _memoffset_offset_from {
|
||||
($field:expr, $base:expr) => {
|
||||
// Compute offset, with unstable `offset_from` for const-compatibility.
|
||||
// (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.)
|
||||
unsafe { ($field as *const u8).offset_from($base as *const u8) as usize }
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "unstable_const"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset_offset_from {
|
||||
($field:expr, $base:expr) => {
|
||||
// Compute offset.
|
||||
($field as usize) - ($base as usize)
|
||||
};
|
||||
}
|
||||
|
||||
@ -79,17 +87,13 @@ macro_rules! _memoffset__field_check {
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! offset_of {
|
||||
($parent:tt, $field:tt) => {{
|
||||
_memoffset__field_check!($parent, $field);
|
||||
|
||||
// Get a base pointer.
|
||||
($parent:path, $field:tt) => {{
|
||||
// Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
|
||||
_memoffset__let_base_ptr!(base_ptr, $parent);
|
||||
// Get the field address. This is UB because we are creating a reference to
|
||||
// the uninitialized field.
|
||||
#[allow(unused_unsafe)] // for when the macro is used in an unsafe block
|
||||
let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
|
||||
let offset = (field_ptr as usize) - (base_ptr as usize);
|
||||
offset
|
||||
// Get field pointer.
|
||||
let field_ptr = raw_field!(base_ptr, $parent, $field);
|
||||
// Compute offset.
|
||||
_memoffset_offset_from!(field_ptr, base_ptr)
|
||||
}};
|
||||
}
|
||||
|
||||
@ -110,7 +114,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // this creates unaligned references
|
||||
#[cfg_attr(miri, ignore)] // this creates unaligned references
|
||||
fn offset_simple_packed() {
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
@ -132,4 +136,77 @@ mod tests {
|
||||
assert_eq!(offset_of!(Tup, 0), 0);
|
||||
assert_eq!(offset_of!(Tup, 1), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path() {
|
||||
mod sub {
|
||||
#[repr(C)]
|
||||
pub struct Foo {
|
||||
pub x: u32,
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(offset_of!(sub::Foo, x), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inside_generic_method() {
|
||||
struct Pair<T, U>(T, U);
|
||||
|
||||
fn foo<T, U>(_: Pair<T, U>) -> usize {
|
||||
offset_of!(Pair<T, U>, 1)
|
||||
}
|
||||
|
||||
assert_eq!(foo(Pair(0, 0)), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_field() {
|
||||
#[repr(C)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 2],
|
||||
c: i64,
|
||||
}
|
||||
|
||||
let f: Foo = Foo {
|
||||
a: 0,
|
||||
b: [0, 0],
|
||||
c: 0,
|
||||
};
|
||||
let f_ptr = &f as *const _;
|
||||
assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize);
|
||||
assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize);
|
||||
assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable_const")]
|
||||
#[test]
|
||||
fn const_offset() {
|
||||
#[repr(C)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 2],
|
||||
c: i64,
|
||||
}
|
||||
|
||||
assert_eq!([0; offset_of!(Foo, b)].len(), 4);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable_const")]
|
||||
#[test]
|
||||
fn const_fn_offset() {
|
||||
const fn test_fn() -> usize {
|
||||
#[repr(C)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 2],
|
||||
c: i64,
|
||||
}
|
||||
|
||||
offset_of!(Foo, b)
|
||||
}
|
||||
|
||||
assert_eq!([0; test_fn()].len(), 4);
|
||||
}
|
||||
}
|
||||
|
84
third_party/rust/memoffset/src/raw_field.rs
vendored
Normal file
84
third_party/rust/memoffset/src/raw_field.rs
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2020 Gilad Naaman, Ralf Jung
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
/// `raw_const!`, or just ref-then-cast when that is not available.
|
||||
#[cfg(feature = "unstable_raw")]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__raw_const {
|
||||
($path:expr) => {{
|
||||
$crate::ptr::raw_const!($path)
|
||||
}};
|
||||
}
|
||||
#[cfg(not(feature = "unstable_raw"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__raw_const {
|
||||
($path:expr) => {{
|
||||
// This is UB because we create an intermediate reference to uninitialized memory.
|
||||
// Nothing we can do about that without `raw_const!` though.
|
||||
&$path as *const _
|
||||
}};
|
||||
}
|
||||
|
||||
/// Deref-coercion protection macro.
|
||||
#[cfg(allow_clippy)]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__field_check {
|
||||
($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_field_pattern)]
|
||||
let $type { $field: _, .. };
|
||||
};
|
||||
}
|
||||
#[cfg(not(allow_clippy))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! _memoffset__field_check {
|
||||
($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.
|
||||
let $type { $field: _, .. };
|
||||
};
|
||||
}
|
||||
|
||||
/// Computes a const raw pointer to the given field of the given base pointer
|
||||
/// to the given parent type.
|
||||
///
|
||||
/// The `base` pointer *must not* be dangling, but it *may* point to
|
||||
/// uninitialized memory.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! raw_field {
|
||||
($base:expr, $parent:path, $field:tt) => {{
|
||||
_memoffset__field_check!($parent, $field);
|
||||
|
||||
// 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__raw_const!((*($base as *const $parent)).$field)
|
||||
}
|
||||
}};
|
||||
}
|
57
third_party/rust/memoffset/src/span_of.rs
vendored
57
third_party/rust/memoffset/src/span_of.rs
vendored
@ -93,61 +93,56 @@ macro_rules! span_of {
|
||||
(@helper $root:ident, [] ..) => {
|
||||
_memoffset__compile_error!("Expected a range, found '..'")
|
||||
};
|
||||
// Lots of UB due to taking references to uninitialized fields! But that can currently
|
||||
// not be avoided.
|
||||
// No explicit begin for range.
|
||||
(@helper $root:ident, $parent:tt, [] ..) => {{
|
||||
(@helper $root:ident, $parent:path, [] ..) => {{
|
||||
// UB due to taking references to uninitialized fields for `size_of_val`.
|
||||
($root as usize,
|
||||
$root as usize + $crate::mem::size_of_val(&(*$root)))
|
||||
}};
|
||||
(@helper $root:ident, $parent:tt, [] ..= $field:tt) => {{
|
||||
_memoffset__field_check!($parent, $field);
|
||||
(@helper $root:ident, $parent:path, [] ..= $field:tt) => {{
|
||||
// UB due to taking references to uninitialized fields for `size_of_val`.
|
||||
($root as usize,
|
||||
&(*$root).$field as *const _ as usize + $crate::mem::size_of_val(&(*$root).$field))
|
||||
raw_field!($root, $parent, $field) as usize + $crate::mem::size_of_val(&(*$root).$field))
|
||||
}};
|
||||
(@helper $root:ident, $parent:tt, [] .. $field:tt) => {{
|
||||
_memoffset__field_check!($parent, $field);
|
||||
($root as usize, &(*$root).$field as *const _ as usize)
|
||||
(@helper $root:ident, $parent:path, [] .. $field:tt) => {{
|
||||
($root as usize, raw_field!($root, $parent, $field) as usize)
|
||||
}};
|
||||
// Explicit begin and end for range.
|
||||
(@helper $root:ident, $parent:tt, # $begin:tt [] ..= $end:tt) => {{
|
||||
_memoffset__field_check!($parent, $begin);
|
||||
_memoffset__field_check!($parent, $end);
|
||||
(&(*$root).$begin as *const _ as usize,
|
||||
&(*$root).$end as *const _ as usize + $crate::mem::size_of_val(&(*$root).$end))
|
||||
(@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{
|
||||
// UB due to taking references to uninitialized fields for `size_of_val`.
|
||||
(raw_field!($root, $parent, $begin) as usize,
|
||||
raw_field!($root, $parent, $end) as usize + $crate::mem::size_of_val(&(*$root).$end))
|
||||
}};
|
||||
(@helper $root:ident, $parent:tt, # $begin:tt [] .. $end:tt) => {{
|
||||
_memoffset__field_check!($parent, $begin);
|
||||
_memoffset__field_check!($parent, $end);
|
||||
(&(*$root).$begin as *const _ as usize,
|
||||
&(*$root).$end as *const _ as usize)
|
||||
(@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{
|
||||
(raw_field!($root, $parent, $begin) as usize,
|
||||
raw_field!($root, $parent, $end) as usize)
|
||||
}};
|
||||
// No explicit end for range.
|
||||
(@helper $root:ident, $parent:tt, # $begin:tt [] ..) => {{
|
||||
_memoffset__field_check!($parent, $begin);
|
||||
(&(*$root).$begin as *const _ as usize,
|
||||
(@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{
|
||||
// UB due to taking references to uninitialized fields for `size_of_val`.
|
||||
(raw_field!($root, $parent, $begin) as usize,
|
||||
$root as usize + $crate::mem::size_of_val(&*$root))
|
||||
}};
|
||||
(@helper $root:ident, $parent:tt, # $begin:tt [] ..=) => {{
|
||||
(@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{
|
||||
_memoffset__compile_error!(
|
||||
"Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
|
||||
}};
|
||||
// Just one field.
|
||||
(@helper $root:ident, $parent:tt, # $begin:tt []) => {{
|
||||
_memoffset__field_check!($parent, $begin);
|
||||
(&(*$root).$begin as *const _ as usize,
|
||||
&(*$root).$begin as *const _ as usize + $crate::mem::size_of_val(&(*$root).$begin))
|
||||
(@helper $root:ident, $parent:path, # $begin:tt []) => {{
|
||||
// UB due to taking references to uninitialized fields for `size_of_val`.
|
||||
(raw_field!($root, $parent, $begin) as usize,
|
||||
raw_field!($root, $parent, $begin) as usize + $crate::mem::size_of_val(&(*$root).$begin))
|
||||
}};
|
||||
// Parsing.
|
||||
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
|
||||
(@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
|
||||
span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
|
||||
}};
|
||||
(@helper $root:ident, $parent:tt, [] $tt:tt $($rest:tt)*) => {{
|
||||
(@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{
|
||||
span_of!(@helper $root, $parent, #$tt [] $($rest)*)
|
||||
}};
|
||||
|
||||
// Entry point.
|
||||
($sty:tt, $($exp:tt)+) => ({
|
||||
($sty:path, $($exp:tt)+) => ({
|
||||
unsafe {
|
||||
// Get a base pointer.
|
||||
_memoffset__let_base_ptr!(root, $sty);
|
||||
@ -177,7 +172,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // this creates unaligned references
|
||||
#[cfg_attr(miri, ignore)] // this creates unaligned references
|
||||
fn span_simple_packed() {
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
|
Loading…
Reference in New Issue
Block a user