@@ -94,6 +94,8 @@ extern crate alloc;
9494/// }
9595/// };
9696/// ```
97+ ///
98+ /// This does NOT accept closures, since, as of Rust 1.91.0, closures cannot be `unsafe`.
9799#[ macro_export]
98100macro_rules! unsafe_fn {
99101 ( $fn: expr $( , $arg: expr) + ) => {
@@ -184,108 +186,53 @@ macro_rules! unsafe_fn_internal_access_tuple_tree_field {
184186}
185187//-------------
186188
187- // No need to seal this trait, as it's implemented for all types.
188- /// Trait to accept/"normalize" a given receiver `self` from `T` to `&T`, or from `T` to `&mut T`.
189- /// See [AsRefOrMut::prudent_normalize_value_self_as_ref].
190- ///
191- /// Blanket implemented for all types.
192- pub trait AsRefOrMut {
193- /// Serves to accept/"normalize" a given receiver `self` that is of type `T`, `&T` or `&mut T`, so that
194- /// the result is always of type `&T`. That way we can store its result in a local variable,
195- /// even if `self` was passed in by value (rather than by reference) without moving it.
196- ///
197- /// We call this method with the standard dot notation, and that's why it has such a long name,
198- /// so it doesn't conflict with user-defined inherent methods or with other traits. We do NOT
199- /// call this as `AsRefOrMutOrValue::prudent_normalize_value_self_as_ref(...)`, as that would
200- /// require the receiver expression to be a reference (rather than allowing a value), and that's
201- /// a restriction we want to prevent.
202- ///
203- /// Used by [unsafe_method_ref].
204- fn prudent_normalize_value_self_as_ref ( & self ) -> & Self {
205- self
206- }
207-
208- /// Like [AsRefOrMut::prudent_normalize_value_self_as_ref], but this "normalizes" the given
209- /// receiver to a mutable reference.
210- ///
211- /// Used by [unsafe_method_mut].
212- fn prudent_normalize_value_self_as_mut ( & mut self ) -> & mut Self {
213- self
214- }
215- }
216- impl < T > AsRefOrMut for T { }
217-
218- /// Invoke an unsafe method that has a shared reference as a receiver: `&self`.
219- ///
220- /// Like [unsafe_fn], but
221- /// - This accepts a receiver `&self`, `&mut self` and `self` (which is then referenced, so it's
222- /// **not** moved/copied).
223- /// - This stores `self` in a variable outside of the generated `unsafe {...}`.
224- /// - $fn can **NOT** be an expression or a path (which doesn't work in standard methods calls), but
225- /// only an identifier.
226- #[ macro_export]
227- macro_rules! unsafe_method_ref {
228- ( $self: expr, $fn: ident $( , $arg: expr) * ) => {
229- //$crate::unsafe_method_internal_normalize!{ $self, () (.prudent_normalize_value_self_as_ref()) $fn $(, $arg)* }
230-
231- // const-friendly; if it creates a double reference &&, because the given expression already
232- // yields a reference, that's OK. Rust will dereference it 2x.
233- $crate:: unsafe_method_internal_normalize!{ $self, ( & ) ( ) $fn $( , $arg) * }
234- }
235- }
236-
237- /// Like [unsafe_method_ref], but for methods whose receiver is a mutable reference: `&mut self`.
238- #[ macro_export]
239- macro_rules! unsafe_method_mut {
240- ( $self: expr, $fn: ident $( , $arg: expr) * ) => {
241- // @TODO normal. prefix: &mut
242- $crate:: unsafe_method_internal_normalize!{ $self, ( ) ( . prudent_normalize_value_self_as_mut( ) ) $fn $( , $arg) * }
243- }
244- }
245-
246- /// Like [unsafe_method_ref], but for methods whose receiver is passed by value: `self` (that is,
247- /// copied if it's [core::marker::Copy], or moved otherwise).
248- #[ macro_export]
249- macro_rules! unsafe_method_val {
250- ( $self: expr, $fn: ident $( , $arg: expr) * ) => {
251- $crate:: unsafe_method_internal_normalize!{ $self, ( ) ( ) $fn $( , $arg) * }
252- }
253- }
254-
255- #[ doc( hidden) ]
189+ /// Invoke an `unsafe`` method. Like [unsafe_fn], but
190+ /// - This accepts a receiver `&self`, `&mut self` and `self`. TODO Box/Rc/Arc, dyn?
191+ /// - This treats `self` as if in an `unsafe {...}` block.
192+ /// - $fn can **NOT** be an expression or a qualified path (which doesn't work in standard methods
193+ /// calls anyways), but only an identifier.
256194#[ macro_export]
257- /// - `$( $normalizer_suffix_part:tt )*` - an expression suffix that gets appended to $self (including any
258- /// leading dot, if needed). For `unsafe_method_ref` and `unsafe_method`_it "normalizes" the given
259- /// `$self`` to the type expected (shared reference `&self` or mutable reference `&mut`). For
260- /// unsafe_method_val it's empty.
261- macro_rules! unsafe_method_internal_normalize {
262- ( $self: expr, ( $( $normalizer_prefix_part: tt ) * ) ( $( $normalizer_suffix_part: tt ) * ) $fn: ident $( , $arg: expr) + ) => {
263- // Enclosed in a block, so that
264- // 1. the result can be used as a value in an outer expression,and
265- // 2. local variables don't conflict with the outer scope
195+ macro_rules! unsafe_method {
196+ ( $self: expr, $fn: ident $( , $arg: expr) + ) => {
197+ // Enclosed in a block, so that the result can be used as a value in an outer expression
198+ // without upsetting operator precedence.
266199 {
267- use $crate:: AsRefOrMut as _;
268- let ( tuple_tree, receiver) = (
269- $crate:: unsafe_fn_internal_build_tuple_tree!{ $( $arg) ,+ } ,
270- $( $normalizer_prefix_part ) * ( $self ) $( $normalizer_suffix_part ) *
271- ) ;
272- $crate:: unsafe_method_internal! {
273- receiver,
274- $fn,
275- tuple_tree,
276- ( $( $arg ) ,* ) ,
277- ( 0 )
200+ if false {
201+ let ( tuple_tree, mut receiver) = (
202+ $crate:: unsafe_fn_internal_build_tuple_tree!{ $( $arg) ,+ } ,
203+ $self
204+ ) ;
205+ // Assign the result, in case the method is `#[must_use]`
206+ let _ = $crate:: unsafe_method_internal! {
207+ receiver,
208+ $fn,
209+ tuple_tree,
210+ ( $( $arg ) ,* ) ,
211+ ( 0 )
212+ } ;
213+ unreachable!( )
214+ } else {
215+ unsafe { $self. $fn ( $( $arg ) ,* ) }
278216 }
279217 }
280218 } ;
281219
282- ( $self: expr, ( $( $normalizer_prefix_part: tt ) * ) ( $( $normalizer_suffix_part: tt ) * ) $fn: ident ) => {
220+ ( $self: expr, $fn: ident ) => {
221+ // Enclosed in a block, so that the result can be used as a value in an outer expression
222+ // without upsetting operator precedence.
283223 {
284- use $crate:: AsRefOrMut as _;
285- let receiver = $( $normalizer_prefix_part ) * ( $self ) $( $normalizer_suffix_part ) * ;
286- #[ allow( unsafe_code) ]
287- unsafe {
288- receiver. $fn( )
224+ if false {
225+ let mut receiver = $self;
226+ // Assign the result, in case the method is `#[must_use]`
227+ let _ = {
228+ #[ allow( unsafe_code) ]
229+ unsafe {
230+ receiver. $fn( )
231+ }
232+ } ;
233+ unreachable!( )
234+ } else {
235+ $self. $fn ( )
289236 }
290237 }
291238 } ;
@@ -318,12 +265,17 @@ macro_rules! unsafe_method_internal {
318265 )
319266 ) ,*
320267 ) => {
321- #[ allow( unsafe_code) ]
322- unsafe {
323- $self. $fn( $(
324- $crate:: unsafe_fn_internal_access_tuple_tree_field!{ $tuple_tree, $( $accessor_part) ,+ }
325- ) ,*
326- )
268+ // Extra block needed, in case the result is assigned to a variable. Otherwise surprise:
269+ // "attributes on expressions are experimental"
270+ // https://github.com/rust-lang/rust/issues/15701
271+ {
272+ #[ allow( unsafe_code) ]
273+ unsafe {
274+ $self. $fn( $(
275+ $crate:: unsafe_fn_internal_access_tuple_tree_field!{ $tuple_tree, $( $accessor_part) ,+ }
276+ ) ,*
277+ )
278+ }
327279 }
328280 } ;
329281}
@@ -476,4 +428,3 @@ macro_rules! unsafe_set {
476428//
477429// #![feature(stmt_expr_attributes)]
478430//
479- // (#[deny(unsafe_code)] s ).prudent_normalize_value_self_as_mut();
0 commit comments