diff --git a/objc2-foundation/examples/custom_class.rs b/objc2-foundation/examples/custom_class.rs index 2029ec105..eaede8547 100644 --- a/objc2-foundation/examples/custom_class.rs +++ b/objc2-foundation/examples/custom_class.rs @@ -70,12 +70,12 @@ fn main() { obj.set_number(7); println!("Number: {}", unsafe { - let number: u32 = msg_send![obj, number]; + let number: u32 = msg_send![&obj, number]; number }); unsafe { - let _: () = msg_send![obj, setNumber: 12u32]; + let _: () = msg_send![&mut obj, setNumber: 12u32]; } println!("Number: {}", obj.number()); } diff --git a/objc2-foundation/src/array.rs b/objc2-foundation/src/array.rs index e9d31187a..5f79e3f6a 100644 --- a/objc2-foundation/src/array.rs +++ b/objc2-foundation/src/array.rs @@ -274,13 +274,14 @@ impl NSMutableArray { #[doc(alias = "removeLastObject")] pub fn pop(&mut self) -> Option> { - self.last().map(|obj| { - let obj = unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() }; - unsafe { - let _: () = msg_send![self, removeLastObject]; - } - obj - }) + self.last() + .map(|obj| unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() }) + .map(|obj| { + unsafe { + let _: () = msg_send![self, removeLastObject]; + } + obj + }) } #[doc(alias = "removeAllObjects")] diff --git a/objc2-foundation/src/data.rs b/objc2-foundation/src/data.rs index f072ac87b..c3829a800 100644 --- a/objc2-foundation/src/data.rs +++ b/objc2-foundation/src/data.rs @@ -156,7 +156,8 @@ impl NSMutableData { impl NSMutableData { #[doc(alias = "mutableBytes")] pub fn bytes_mut(&mut self) -> &mut [u8] { - let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] }; + let this = &mut *self; // Reborrow + let ptr: *mut c_void = unsafe { msg_send![this, mutableBytes] }; // The bytes pointer may be null for length zero if ptr.is_null() { &mut [] diff --git a/objc2-foundation/src/dictionary.rs b/objc2-foundation/src/dictionary.rs index 072b3190c..69fde1907 100644 --- a/objc2-foundation/src/dictionary.rs +++ b/objc2-foundation/src/dictionary.rs @@ -129,7 +129,7 @@ impl NSDictionary { pub fn into_values_array(dict: Id) -> Id, Shared> { unsafe { - let vals = msg_send![dict, allValues]; + let vals = msg_send![&dict, allValues]; Id::retain_autoreleased(vals).unwrap() } } diff --git a/objc2-foundation/src/enumerator.rs b/objc2-foundation/src/enumerator.rs index 305f4c094..35f2b3776 100644 --- a/objc2-foundation/src/enumerator.rs +++ b/objc2-foundation/src/enumerator.rs @@ -33,7 +33,7 @@ impl<'a, T: Message> Iterator for NSEnumerator<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - unsafe { msg_send![self.id, nextObject] } + unsafe { msg_send![&mut self.id, nextObject] } } } diff --git a/objc2-foundation/src/value.rs b/objc2-foundation/src/value.rs index 206a5a2ca..2a5c7da6f 100644 --- a/objc2-foundation/src/value.rs +++ b/objc2-foundation/src/value.rs @@ -177,7 +177,7 @@ mod tests { fn test_value_nsrange() { let val = NSValue::new(NSRange::from(1..2)); assert!(NSRange::ENCODING.equivalent_to_str(val.encoding().unwrap())); - let range: NSRange = unsafe { objc2::msg_send![val, rangeValue] }; + let range: NSRange = unsafe { objc2::msg_send![&val, rangeValue] }; assert_eq!(range, NSRange::from(1..2)); // NSValue -getValue is broken on GNUStep for some types #[cfg(not(feature = "gnustep-1-7"))] diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index 1ac1ca7ad..a01897653 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -38,6 +38,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). `ClassBuilder::add_method`. * Renamed `ClassDecl` and `ProtocolDecl` to `ClassBuilder` and `ProtocolBuilder`. The old names are kept as deprecated aliases. +* **BREAKING**: Changed how `msg_send!` works wrt. capturing its arguments. + + This will require changes to your code wherever you used `Id`, for example: + ```rust + // Before + let obj: Id = ...; + let p: i32 = unsafe { msg_send![obj, parameter] }; + let _: () = unsafe { msg_send![obj, setParameter: p + 1] }; + // After + let mut obj: Id = ...; + let p: i32 = unsafe { msg_send![&obj, parameter] }; + let _: () = unsafe { msg_send![&mut obj, setParameter: p + 1] }; + ``` + + Notice that we now clearly pass `obj` by reference, and therein also + communicate the mutability of the object (in the first case, immutable, and + in the second, mutable). + + If you previously used `*mut Object` or `&Object` as the receiver, message + sending should work exactly as before. ### Fixed * Properly sealed the `MessageArguments` trait (it already had a hidden diff --git a/objc2/examples/introspection.rs b/objc2/examples/introspection.rs index 51d7a31d0..cfe126b15 100644 --- a/objc2/examples/introspection.rs +++ b/objc2/examples/introspection.rs @@ -42,6 +42,6 @@ fn main() { } // Invoke a method on the object - let hash: usize = unsafe { msg_send![obj, hash] }; + let hash: usize = unsafe { msg_send![&obj, hash] }; println!("NSObject hash: {}", hash); } diff --git a/objc2/examples/talk_to_me.rs b/objc2/examples/talk_to_me.rs index ba1418256..1ab776884 100644 --- a/objc2/examples/talk_to_me.rs +++ b/objc2/examples/talk_to_me.rs @@ -31,9 +31,9 @@ fn main() { let utterance: *mut Object = unsafe { msg_send![utterance, initWithString: &*string] }; let utterance: Id = unsafe { Id::new(utterance).unwrap() }; - // let _: () = unsafe { msg_send![utterance, setVolume: 90.0f32 }; - // let _: () = unsafe { msg_send![utterance, setRate: 0.50f32 }; - // let _: () = unsafe { msg_send![utterance, setPitchMultiplier: 0.80f32 }; + // let _: () = unsafe { msg_send![&utterance, setVolume: 90.0f32 }; + // let _: () = unsafe { msg_send![&utterance, setRate: 0.50f32 }; + // let _: () = unsafe { msg_send![&utterance, setPitchMultiplier: 0.80f32 }; - let _: () = unsafe { msg_send![synthesizer, speakUtterance: &*utterance] }; + let _: () = unsafe { msg_send![&synthesizer, speakUtterance: &*utterance] }; } diff --git a/objc2/src/declare.rs b/objc2/src/declare.rs index c1e22184e..49aa62fea 100644 --- a/objc2/src/declare.rs +++ b/objc2/src/declare.rs @@ -415,9 +415,9 @@ mod tests { #[test] fn test_custom_class() { // Registering the custom class is in test_utils - let obj = test_utils::custom_object(); - let _: () = unsafe { msg_send![obj, setFoo: 13u32] }; - let result: u32 = unsafe { msg_send![obj, foo] }; + let mut obj = test_utils::custom_object(); + let _: () = unsafe { msg_send![&mut obj, setFoo: 13u32] }; + let result: u32 = unsafe { msg_send![&obj, foo] }; assert_eq!(result, 13); } diff --git a/objc2/src/lib.rs b/objc2/src/lib.rs index 577524d13..83f654b2e 100644 --- a/objc2/src/lib.rs +++ b/objc2/src/lib.rs @@ -42,8 +42,8 @@ //! }; //! //! // Usage -//! let hash: NSUInteger = unsafe { msg_send![obj, hash] }; -//! let is_kind = unsafe { msg_send_bool![obj, isKindOfClass: cls] }; +//! let hash: NSUInteger = unsafe { msg_send![&obj, hash] }; +//! let is_kind = unsafe { msg_send_bool![&obj, isKindOfClass: cls] }; //! assert!(is_kind); //! ``` //! diff --git a/objc2/src/macros.rs b/objc2/src/macros.rs index 6d9ea7356..227cfb4b2 100644 --- a/objc2/src/macros.rs +++ b/objc2/src/macros.rs @@ -54,22 +54,32 @@ macro_rules! sel { /// Sends a message to an object or class. /// -/// The first argument can be any type that implements [`MessageReceiver`], -/// like a reference, a pointer, or an [`rc::Id`] to an object (where the -/// object implements [`Message`]). -/// -/// In general this is wildly `unsafe`, even more so than sending messages in +/// This is wildly `unsafe`, even more so than sending messages in /// Objective-C, because this macro doesn't know the expected types and /// because Rust has more safety invariants to uphold. Make sure to review the -/// safety section below. +/// safety section below! +/// +/// # General information +/// +/// The syntax is similar to the message syntax in Objective-C, except we +/// allow an optional comma between arguments (works better with rustfmt). /// -/// The syntax is similar to the message syntax in Objective-C. +/// The first argument (know as the "receiver") can be any type that +/// implements [`MessageReceiver`], like a reference or a pointer to an +/// object, or even a reference to an [`rc::Id`] containing an object. +/// Each subsequent argument must implement [`Encode`]. +/// +/// Behind the scenes this translates into a call to [`sel!`], and afterwards +/// a fully qualified call to [`MessageReceiver::send_message`] (note that +/// this means that auto-dereferencing of the receiver is not supported, +/// making the ergonomics when using this slightly worse). /// /// Variadic arguments are not currently supported. /// /// [`MessageReceiver`]: crate::MessageReceiver -/// [`Message`]: crate::Message /// [`rc::Id`]: crate::rc::Id +/// [`Encode`]: crate::Encode +/// [`MessageReceiver::send_message`]: crate::MessageReceiver::send_message /// /// # Panics /// @@ -83,13 +93,12 @@ macro_rules! sel { /// /// # Safety /// -/// The user must ensure that the selector is a valid method and is available -/// on the given receiver. +/// This macro can't inspect header files to see the expected types, so it is +/// your responsibility that the selector exists on the receiver, and that the +/// argument types and return type are what the receiver excepts for this +/// selector - similar to defining an external function in FFI. /// -/// Since this macro can't inspect header files to see the expected types, it -/// is the users responsibility that the argument types and return type are -/// what the receiver excepts for this selector. A way of doing this is by -/// defining a wrapper function: +/// The recommended way of doing this is by defining a wrapper function: /// ``` /// # use std::os::raw::{c_int, c_char}; /// # use objc2::msg_send; @@ -99,19 +108,35 @@ macro_rules! sel { /// } /// ``` /// -/// The user must also uphold any safety requirements (explicit and implicit) -/// that the method has (e.g. methods that take pointers as an argument -/// usually require that the pointer is valid and often non-null). +/// This way we are clearly communicating to Rust that this method takes an +/// immutable object, a C-integer, and returns a pointer to (probably) a +/// C-compatible string. Afterwards, it becomes fairly trivial to make a safe +/// abstraction around this. +/// +/// In particular, you must uphold the following requirements: +/// +/// 1. The selector is a valid method that is available on the given receiver. +/// +/// 2. The types of the receiver and arguments must match what is expected on +/// the Objective-C side. +/// +/// 3. The call must not violate Rust's mutability rules, e.g. if passing an +/// `&T`, the Objective-C method must not mutate the variable (this is true +/// for receivers as well). +/// +/// 4. If the receiver is a raw pointer the user must ensure that it is valid +/// (aligned, dereferenceable, initialized and so on). Messages to `null` +/// pointers are allowed (though heavily discouraged), but only if the +/// return type itself is a pointer. /// -/// Additionally, the call must not violate Rust's mutability rules, e.g. if -/// passing an `&T` the Objective-C method must not mutate the variable. +/// 5. The method must not (yet, see [RFC-2945]) throw an exception. /// -/// If the receiver is a raw pointer the user must ensure that it is valid -/// (aligned, dereferenceable, initialized and so on). Messages to `null` -/// pointers are allowed (though discouraged), but only if the return type -/// itself is a pointer. +/// 6. You must uphold any additional safety requirements (explicit and +/// implicit) that the method has (for example, methods that take pointers +/// usually require that the pointer is valid, and sometimes non-null. +/// Another example, some methods may only be called on the main thread). /// -/// Finally, the method must not (yet, see [RFC-2945]) throw an exception. +/// 7. TODO: Maybe more? /// /// # Examples /// @@ -132,7 +157,7 @@ macro_rules! msg_send { [super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({ let sel = $crate::sel!($selector); let result; - match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ()) { + match $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ()) { Err(s) => panic!("{}", s), Ok(r) => result = r, } @@ -141,7 +166,7 @@ macro_rules! msg_send { [super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr $(,)?)+] => ({ let sel = $crate::sel!($($selector :)+); let result; - match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($argument,)+)) { + match $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ($($argument,)+)) { Err(s) => panic!("{}", s), Ok(r) => result = r, } @@ -150,7 +175,7 @@ macro_rules! msg_send { [$obj:expr, $selector:ident $(,)?] => ({ let sel = $crate::sel!($selector); let result; - match $crate::MessageReceiver::send_message(&$obj, sel, ()) { + match $crate::MessageReceiver::send_message($obj, sel, ()) { Err(s) => panic!("{}", s), Ok(r) => result = r, } @@ -159,7 +184,7 @@ macro_rules! msg_send { [$obj:expr, $($selector:ident : $argument:expr $(,)?)+] => ({ let sel = $crate::sel!($($selector :)+); let result; - match $crate::MessageReceiver::send_message(&$obj, sel, ($($argument,)+)) { + match $crate::MessageReceiver::send_message($obj, sel, ($($argument,)+)) { Err(s) => panic!("{}", s), Ok(r) => result = r, } diff --git a/objc2/src/message/mod.rs b/objc2/src/message/mod.rs index 3a29772ec..1371029d3 100644 --- a/objc2/src/message/mod.rs +++ b/objc2/src/message/mod.rs @@ -5,7 +5,7 @@ use core::mem::ManuallyDrop; use core::ptr::NonNull; use std::error::Error; -use crate::rc::{Id, Ownership}; +use crate::rc::{Id, Owned, Ownership}; use crate::runtime::{Class, Imp, Object, Sel}; use crate::{Encode, EncodeArguments, RefEncode}; @@ -69,19 +69,22 @@ unsafe impl Message for Class {} // TODO: Make this fully private pub(crate) mod private { - use super::{Id, ManuallyDrop, Message, MessageReceiver, NonNull, Ownership}; + use super::*; pub trait Sealed {} impl Sealed for *const T {} impl Sealed for *mut T {} + impl Sealed for NonNull {} impl<'a, T: Message + ?Sized> Sealed for &'a T {} impl<'a, T: Message + ?Sized> Sealed for &'a mut T {} - impl Sealed for NonNull {} - impl Sealed for Id {} - impl Sealed for ManuallyDrop {} + 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> {} } /// Types that can directly be used as the receiver of Objective-C messages. @@ -96,9 +99,9 @@ pub(crate) mod private { /// # Safety /// /// [`Self::as_raw_receiver`] must be implemented correctly. -pub unsafe trait MessageReceiver: private::Sealed { +pub unsafe trait MessageReceiver: private::Sealed + Sized { /// Get a raw pointer to the receiver of the message. - fn as_raw_receiver(&self) -> *mut Object; + fn as_raw_receiver(self) -> *mut Object; /// Sends a message to self with the given selector and arguments. /// @@ -118,7 +121,7 @@ pub unsafe trait MessageReceiver: private::Sealed { /// The added invariant is that the selector must take the same number of /// arguments as is given. #[cfg_attr(not(feature = "verify_message"), inline(always))] - unsafe fn send_message(&self, sel: Sel, args: A) -> Result + unsafe fn send_message(self, sel: Sel, args: A) -> Result where A: MessageArguments, R: Encode, @@ -161,7 +164,7 @@ pub unsafe trait MessageReceiver: private::Sealed { /// arguments as is given. #[cfg_attr(not(feature = "verify_message"), inline(always))] unsafe fn send_super_message( - &self, + self, superclass: &Class, sel: Sel, args: A, @@ -202,7 +205,7 @@ pub unsafe trait MessageReceiver: private::Sealed { /// assert!(result.is_ok()); /// ``` #[cfg(feature = "malloc")] - fn verify_message(&self, sel: Sel) -> Result<(), MessageError> + fn verify_message(self, sel: Sel) -> Result<(), MessageError> where A: EncodeArguments, R: Encode, @@ -217,50 +220,64 @@ pub unsafe trait MessageReceiver: private::Sealed { unsafe impl MessageReceiver for *const T { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - *self as *mut T as *mut Object + fn as_raw_receiver(self) -> *mut Object { + self as *mut T as *mut Object } } unsafe impl MessageReceiver for *mut T { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - *self as *mut Object + fn as_raw_receiver(self) -> *mut Object { + self as *mut Object + } +} + +unsafe impl MessageReceiver for NonNull { + #[inline] + fn as_raw_receiver(self) -> *mut Object { + self.as_ptr() as *mut Object } } unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a T { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - *self as *const T as *mut T as *mut Object + fn as_raw_receiver(self) -> *mut Object { + self as *const T as *mut T as *mut Object } } unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut T { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - *self as *const T as *mut T as *mut Object + fn as_raw_receiver(self) -> *mut Object { + self as *const T as *mut T as *mut Object } } -unsafe impl MessageReceiver for NonNull { +unsafe impl<'a, T: Message + ?Sized, O: Ownership> MessageReceiver for &'a Id { #[inline] - fn as_raw_receiver(&self) -> *mut Object { + fn as_raw_receiver(self) -> *mut Object { self.as_ptr() as *mut Object } } -unsafe impl MessageReceiver for Id { +unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut Id { #[inline] - fn as_raw_receiver(&self) -> *mut Object { + fn as_raw_receiver(self) -> *mut Object { self.as_ptr() as *mut Object } } -unsafe impl MessageReceiver for ManuallyDrop { +unsafe impl<'a, T: Message + ?Sized, O: Ownership> MessageReceiver for &'a ManuallyDrop> { + #[inline] + fn as_raw_receiver(self) -> *mut Object { + (**self).as_ptr() as *mut Object + } +} + +unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut ManuallyDrop> { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - (**self).as_raw_receiver() + fn as_raw_receiver(self) -> *mut Object { + (**self).as_ptr() as *mut Object } } @@ -382,10 +399,10 @@ mod tests { #[test] fn test_send_message() { - let obj = test_utils::custom_object(); + let mut obj = test_utils::custom_object(); let result: u32 = unsafe { - let _: () = msg_send![obj, setFoo: 4u32]; - msg_send![obj, foo] + let _: () = msg_send![&mut obj, setFoo: 4u32]; + msg_send![&obj, foo] }; assert_eq!(result, 4); } @@ -393,7 +410,7 @@ mod tests { #[test] fn test_send_message_stret() { let obj = test_utils::custom_object(); - let result: test_utils::CustomStruct = unsafe { msg_send![obj, customStruct] }; + let result: test_utils::CustomStruct = unsafe { msg_send![&obj, customStruct] }; let expected = test_utils::CustomStruct { a: 1, b: 2, @@ -431,15 +448,15 @@ mod tests { #[test] fn test_send_message_super() { - let obj = test_utils::custom_subclass_object(); + let mut obj = test_utils::custom_subclass_object(); let superclass = test_utils::custom_class(); unsafe { - let _: () = msg_send![obj, setFoo: 4u32]; - let foo: u32 = msg_send![super(obj, superclass), foo]; + let _: () = msg_send![&mut obj, setFoo: 4u32]; + let foo: u32 = msg_send![super(&obj, superclass), foo]; assert_eq!(foo, 4); // The subclass is overriden to return foo + 2 - let foo: u32 = msg_send![obj, foo]; + let foo: u32 = msg_send![&obj, foo]; assert_eq!(foo, 6); } } @@ -447,10 +464,10 @@ mod tests { #[test] fn test_send_message_manuallydrop() { let obj = test_utils::custom_object(); - let obj = ManuallyDrop::new(obj); + let mut obj = ManuallyDrop::new(obj); let result: u32 = unsafe { - let _: () = msg_send![obj, setFoo: 4u32]; - msg_send![obj, foo] + let _: () = msg_send![&mut obj, setFoo: 4u32]; + msg_send![&obj, foo] }; assert_eq!(result, 4); diff --git a/objc2/src/test_utils.rs b/objc2/src/test_utils.rs index 440d88955..2f2ce4c13 100644 --- a/objc2/src/test_utils.rs +++ b/objc2/src/test_utils.rs @@ -1,3 +1,4 @@ +use core::mem::ManuallyDrop; use core::ops::{Deref, DerefMut}; use std::os::raw::c_char; use std::sync::Once; @@ -20,12 +21,36 @@ impl CustomObject { } // TODO: Remove the need for this hack -impl crate::message::private::Sealed for CustomObject {} +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 {} -unsafe impl MessageReceiver for CustomObject { +unsafe impl MessageReceiver for &CustomObject { #[inline] - fn as_raw_receiver(&self) -> *mut Object { - self.obj + fn as_raw_receiver(self) -> *mut Object { + (&**self).as_raw_receiver() + } +} + +unsafe impl MessageReceiver for &mut CustomObject { + #[inline] + fn as_raw_receiver(self) -> *mut Object { + (&**self).as_raw_receiver() + } +} + +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() } } diff --git a/tests/assembly/test_msg_send_zero_cost/lib.rs b/tests/assembly/test_msg_send_zero_cost/lib.rs index 9a29a4af4..faf37d5cb 100644 --- a/tests/assembly/test_msg_send_zero_cost/lib.rs +++ b/tests/assembly/test_msg_send_zero_cost/lib.rs @@ -5,5 +5,5 @@ use objc2::MessageReceiver; #[no_mangle] pub fn handle(obj: &Object, sel: Sel) -> *mut Object { - unsafe { MessageReceiver::send_message(&obj, sel, ()).unwrap() } + unsafe { MessageReceiver::send_message(obj, sel, ()).unwrap() } } diff --git a/tests/assembly/test_retain_autoreleased/lib.rs b/tests/assembly/test_retain_autoreleased/lib.rs index 9a722262c..ca1de6623 100644 --- a/tests/assembly/test_retain_autoreleased/lib.rs +++ b/tests/assembly/test_retain_autoreleased/lib.rs @@ -6,6 +6,6 @@ use objc2::MessageReceiver; #[no_mangle] pub fn handle(obj: &Object, sel: Sel) -> Option> { - let ptr: *mut Object = unsafe { MessageReceiver::send_message(&obj, sel, ()).unwrap() }; + let ptr: *mut Object = unsafe { MessageReceiver::send_message(obj, sel, ()).unwrap() }; unsafe { Id::retain_autoreleased(ptr) } } diff --git a/tests/ui/msg_send_only_message.stderr b/tests/ui/msg_send_only_message.stderr index 9dddfbff9..b3a2b28e2 100644 --- a/tests/ui/msg_send_only_message.stderr +++ b/tests/ui/msg_send_only_message.stderr @@ -5,11 +5,13 @@ error[E0277]: the trait bound `{integer}: MessageReceiver` is not satisfied | ^^^^^^^^^^^^^^^^^ the trait `MessageReceiver` is not implemented for `{integer}` | = 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 - Id - ManuallyDrop NonNull = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)