From 7ba94f9cc892c5299c34b47578db5182c46d16c0 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 Jun 2022 18:48:21 +0200 Subject: [PATCH] Consume `ManuallyDrop>` in `msg_send!` If you do not want to consume it, the possibility of doing `msg_send![&*obj]` exists, but most of the time that is indeed what you want (I mean, why else would you wrap it in `ManuallyDrop`?) --- objc2/src/message/mod.rs | 28 +++++++------------------- objc2/src/rc/id.rs | 4 ++++ objc2/src/test_utils.rs | 29 +++++++++++++++------------ tests/ui/msg_send_only_message.stderr | 3 +-- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/objc2/src/message/mod.rs b/objc2/src/message/mod.rs index 3ea1c390d..a1aebc473 100644 --- a/objc2/src/message/mod.rs +++ b/objc2/src/message/mod.rs @@ -83,8 +83,7 @@ pub(crate) mod private { impl<'a, T: Message + ?Sized, O: Ownership> Sealed for &'a Id {} impl<'a, T: Message + ?Sized> Sealed for &'a mut Id {} - impl<'a, T: Message + ?Sized, O: Ownership> Sealed for &'a ManuallyDrop> {} - impl<'a, T: Message + ?Sized> Sealed for &'a mut ManuallyDrop> {} + impl Sealed for ManuallyDrop> {} } /// Types that can directly be used as the receiver of Objective-C messages. @@ -267,17 +266,10 @@ unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut Id { } } -unsafe impl<'a, T: Message + ?Sized, O: Ownership> MessageReceiver for &'a ManuallyDrop> { +unsafe impl MessageReceiver for ManuallyDrop> { #[inline] fn as_raw_receiver(self) -> *mut Object { - Id::as_ptr(&**self) as *mut Object - } -} - -unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut ManuallyDrop> { - #[inline] - fn as_raw_receiver(self) -> *mut Object { - Id::as_mut_ptr(&mut **self) as *mut Object + Id::consume_as_ptr(self) as *mut Object } } @@ -481,17 +473,11 @@ mod tests { #[test] fn test_send_message_manuallydrop() { - let obj = test_utils::custom_object(); - let mut obj = ManuallyDrop::new(obj); - let result: u32 = unsafe { - let _: () = msg_send![&mut obj, setFoo: 4u32]; - msg_send![&obj, foo] + let obj = ManuallyDrop::new(test_utils::custom_object()); + unsafe { + let _: () = msg_send![obj, release]; }; - assert_eq!(result, 4); - - let obj: *const ManuallyDrop = obj.as_ptr().cast(); - let result: u32 = unsafe { msg_send![obj, foo] }; - assert_eq!(result, 4); + // `obj` is consumed, can't use here } #[test] diff --git a/objc2/src/rc/id.rs b/objc2/src/rc/id.rs index dbf3bb7ad..2bf24ef1e 100644 --- a/objc2/src/rc/id.rs +++ b/objc2/src/rc/id.rs @@ -199,6 +199,10 @@ impl Id { pub fn as_ptr(this: &Id) -> *const T { this.ptr.as_ptr() } + + pub(crate) fn consume_as_ptr(this: ManuallyDrop) -> *mut T { + this.ptr.as_ptr() + } } impl Id { diff --git a/objc2/src/test_utils.rs b/objc2/src/test_utils.rs index 2f2ce4c13..e6aaca6a5 100644 --- a/objc2/src/test_utils.rs +++ b/objc2/src/test_utils.rs @@ -23,34 +23,26 @@ impl CustomObject { // TODO: Remove the need for this hack impl crate::message::private::Sealed for &CustomObject {} impl crate::message::private::Sealed for &mut CustomObject {} -impl crate::message::private::Sealed for &ManuallyDrop {} -impl crate::message::private::Sealed for &mut ManuallyDrop {} +impl crate::message::private::Sealed for ManuallyDrop {} unsafe impl MessageReceiver for &CustomObject { #[inline] fn as_raw_receiver(self) -> *mut Object { - (&**self).as_raw_receiver() + self.obj } } unsafe impl MessageReceiver for &mut CustomObject { #[inline] fn as_raw_receiver(self) -> *mut Object { - (&**self).as_raw_receiver() + self.obj } } -unsafe impl MessageReceiver for &ManuallyDrop { +unsafe impl MessageReceiver for ManuallyDrop { #[inline] fn as_raw_receiver(self) -> *mut Object { - (&**self).as_raw_receiver() - } -} - -unsafe impl MessageReceiver for &mut ManuallyDrop { - #[inline] - fn as_raw_receiver(self) -> *mut Object { - (&**self).as_raw_receiver() + self.obj } } @@ -106,6 +98,14 @@ pub(crate) fn custom_class() -> &'static Class { builder.add_protocol(proto); builder.add_ivar::("_foo"); + unsafe extern "C" fn custom_obj_release( + this: *mut Object, + _cmd: Sel, + ) { + // Drop the value + let _ = CustomObject { obj: this }; + } + extern "C" fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) { unsafe { this.set_ivar::("_foo", foo); @@ -145,6 +145,9 @@ pub(crate) fn custom_class() -> &'static Class { } unsafe { + let release: unsafe extern "C" fn(*mut Object, Sel) = custom_obj_release; + builder.add_method(sel!(release), release); + let set_foo: extern "C" fn(&mut Object, Sel, u32) = custom_obj_set_foo; builder.add_method(sel!(setFoo:), set_foo); let get_foo: extern "C" fn(&Object, Sel) -> u32 = custom_obj_get_foo; diff --git a/tests/ui/msg_send_only_message.stderr b/tests/ui/msg_send_only_message.stderr index b3a2b28e2..912dcf9bb 100644 --- a/tests/ui/msg_send_only_message.stderr +++ b/tests/ui/msg_send_only_message.stderr @@ -6,12 +6,11 @@ error[E0277]: the trait bound `{integer}: MessageReceiver` is not satisfied | = help: the following other types implement trait `MessageReceiver`: &'a Id - &'a ManuallyDrop> &'a T &'a mut Id - &'a mut ManuallyDrop> &'a mut T *const T *mut T + ManuallyDrop> NonNull = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)