field_check macro; propagate parent type through span_of

This commit is contained in:
Ralf Jung
2019-07-13 17:23:47 +02:00
parent 8966c23338
commit 00429dfba5
2 changed files with 34 additions and 25 deletions
+13 -4
View File
@@ -42,6 +42,18 @@ macro_rules! let_base_ptr {
}
}
/// Deref-coercion protection macro.
#[macro_export]
#[doc(hidden)]
macro_rules! 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: _, .. };
}
}
/// Calculates the offset of the specified field from the start of the struct.
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
///
@@ -67,10 +79,7 @@ macro_rules! let_base_ptr {
#[macro_export]
macro_rules! offset_of {
($parent: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 $parent { $field: _, .. };
field_check!($parent, $field);
// Get a base pointer.
$crate::let_base_ptr!(base_ptr, $parent);
+21 -21
View File
@@ -89,46 +89,46 @@ macro_rules! span_of {
};
// Lots of UB due to taking references to uninitialized fields! But that can currently
// not be avoided.
(@helper $root:ident, [] ..= $($field:tt)+) => {
(@helper $root:ident, $parent:tt, [] ..= $($field:tt)*) => {{
($root as usize,
&(*$root).$($field)* as *const _ as usize + $crate::mem::size_of_val(&(*$root).$($field)*))
};
(@helper $root:ident, [] .. $($field:tt)+) => {
}};
(@helper $root:ident, $parent:tt, [] .. $($field:tt)+) => {{
($root as usize, &(*$root).$($field)* as *const _ as usize)
};
(@helper $root:ident, $(# $begin:tt)+ [] ..= $($end:tt)+) => {
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] ..= $($end:tt)+) => {{
(&(*$root).$($begin)* as *const _ as usize,
&(*$root).$($end)* as *const _ as usize + $crate::mem::size_of_val(&(*$root).$($end)*))
};
(@helper $root:ident, $(# $begin:tt)+ [] .. $($end:tt)+) => {
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] .. $($end:tt)+) => {{
(&(*$root).$($begin)* as *const _ as usize,
&(*$root).$($end)* as *const _ as usize)
};
(@helper $root:ident, $(# $begin:tt)+ [] ..) => {
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] ..) => {{
(&(*$root).$($begin)* as *const _ as usize,
$root as usize + $crate::mem::size_of_val(&*$root))
};
(@helper $root:ident, $(# $begin:tt)+ [] ..=) => {
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] ..=) => {{
compile_error!(
"Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
};
(@helper $root:ident, $(# $begin:tt)+ []) => {
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ []) => {{
(&(*$root).$($begin)* as *const _ as usize,
&(*$root).$($begin)* as *const _ as usize + $crate::mem::size_of_val(&(*$root).$($begin)*))
};
(@helper $root:ident, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {
span_of!(@helper $root, $(#$begin)* #$tt [] $($rest)*)
};
(@helper $root:ident, [] $tt:tt $($rest:tt)*) => {
span_of!(@helper $root, #$tt [] $($rest)*)
};
}};
(@helper $root:ident, $parent:tt, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
}};
(@helper $root:ident, $parent:tt, [] $tt:tt $($rest:tt)*) => {{
span_of!(@helper $root, $parent, #$tt [] $($rest)*)
}};
($sty:tt, $($exp:tt)+) => ({
unsafe {
// Get a base pointer.
$crate::let_base_ptr!(root, $sty);
let base = root as usize;
let (begin, end) = span_of!(@helper root, [] $($exp)*);
let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*);
begin-base..end-base
}
});