1 // Copyright (c) 2020 Gilad Naaman, Ralf Jung 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in all 11 // copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 // SOFTWARE. 20 21 /// `addr_of!`, or just ref-then-cast when that is not available. 22 #[cfg(raw_ref_macros)] 23 #[macro_export] 24 #[doc(hidden)] 25 macro_rules! _memoffset__addr_of { 26 ($path:expr) => {{ 27 $crate::__priv::ptr::addr_of!($path) 28 }}; 29 } 30 #[cfg(not(raw_ref_macros))] 31 #[macro_export] 32 #[doc(hidden)] 33 macro_rules! _memoffset__addr_of { 34 ($path:expr) => {{ 35 // This is UB because we create an intermediate reference to uninitialized memory. 36 // Nothing we can do about that without `addr_of!` though. 37 &$path as *const _ 38 }}; 39 } 40 41 /// Deref-coercion protection macro. 42 #[cfg(allow_clippy)] 43 #[macro_export] 44 #[doc(hidden)] 45 macro_rules! _memoffset__field_check { 46 ($type:path, $field:tt) => { 47 // Make sure the field actually exists. This line ensures that a 48 // compile-time error is generated if $field is accessed through a 49 // Deref impl. 50 #[allow(clippy::unneeded_field_pattern)] 51 let $type { $field: _, .. }; 52 }; 53 } 54 #[cfg(not(allow_clippy))] 55 #[macro_export] 56 #[doc(hidden)] 57 macro_rules! _memoffset__field_check { 58 ($type:path, $field:tt) => { 59 // Make sure the field actually exists. This line ensures that a 60 // compile-time error is generated if $field is accessed through a 61 // Deref impl. 62 let $type { $field: _, .. }; 63 }; 64 } 65 66 /// Deref-coercion protection macro. 67 #[macro_export] 68 #[doc(hidden)] 69 macro_rules! _memoffset__field_check_tuple { 70 ($type:ty, $field:tt) => { 71 // Make sure the type argument is a tuple 72 let (_, ..): $type; 73 }; 74 } 75 76 /// Computes a const raw pointer to the given field of the given base pointer 77 /// to the given parent type. 78 /// 79 /// The `base` pointer *must not* be dangling, but it *may* point to 80 /// uninitialized memory. 81 #[macro_export(local_inner_macros)] 82 macro_rules! raw_field { 83 ($base:expr, $parent:path, $field:tt) => {{ 84 _memoffset__field_check!($parent, $field); 85 let base = $base; // evaluate $base outside the `unsafe` block 86 87 // Get the field address. 88 // Crucially, we know that this will not trigger a deref coercion because 89 // of the field check we did above. 90 #[allow(unused_unsafe)] // for when the macro is used in an unsafe block 91 unsafe { 92 _memoffset__addr_of!((*(base as *const $parent)).$field) 93 } 94 }}; 95 } 96 97 /// Computes a const raw pointer to the given field of the given base pointer 98 /// to the given parent tuple typle. 99 /// 100 /// The `base` pointer *must not* be dangling, but it *may* point to 101 /// uninitialized memory. 102 #[cfg(tuple_ty)] 103 #[macro_export(local_inner_macros)] 104 macro_rules! raw_field_tuple { 105 ($base:expr, $parent:ty, $field:tt) => {{ 106 _memoffset__field_check_tuple!($parent, $field); 107 let base = $base; // evaluate $base outside the `unsafe` block 108 109 // Get the field address. 110 // Crucially, we know that this will not trigger a deref coercion because 111 // of the field check we did above. 112 #[allow(unused_unsafe)] // for when the macro is used in an unsafe block 113 unsafe { 114 _memoffset__addr_of!((*(base as *const $parent)).$field) 115 } 116 }}; 117 } 118