From 519cc088eeaf8c63e1e5865441dd4601446e001e Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sun, 29 Jan 2023 04:55:16 +0100 Subject: [PATCH 1/5] Simplify EncodeConvert internals a bit --- crates/objc2/src/encode.rs | 18 ++---------------- crates/objc2/src/runtime/bool.rs | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/crates/objc2/src/encode.rs b/crates/objc2/src/encode.rs index 89d44fcea..2374e5dce 100644 --- a/crates/objc2/src/encode.rs +++ b/crates/objc2/src/encode.rs @@ -658,11 +658,7 @@ encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K); encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L); mod convert_private { - use super::*; - pub trait Sealed {} - impl Sealed for T {} - impl Sealed for bool {} } /// Represents types that can easily be converted to/from an [`Encode`] type. @@ -679,10 +675,6 @@ pub trait EncodeConvert: convert_private::Sealed { #[doc(hidden)] type __Inner: Encode; - /// The actual encoding this type has. - #[doc(hidden)] - const __ENCODING: Encoding; - #[doc(hidden)] fn __from_inner(inner: Self::__Inner) -> Self; @@ -690,9 +682,9 @@ pub trait EncodeConvert: convert_private::Sealed { fn __into_inner(self) -> Self::__Inner; } +impl convert_private::Sealed for T {} impl EncodeConvert for T { type __Inner = Self; - const __ENCODING: Encoding = Self::ENCODING; #[inline] fn __from_inner(inner: Self::__Inner) -> Self { @@ -705,9 +697,9 @@ impl EncodeConvert for T { } } +impl convert_private::Sealed for bool {} impl EncodeConvert for bool { type __Inner = Bool; - const __ENCODING: Encoding = Encoding::Bool; #[inline] fn __from_inner(inner: Self::__Inner) -> Self { @@ -934,12 +926,6 @@ mod tests { assert!(!false.__into_inner().as_bool()); assert!(true.__into_inner().as_bool()); - assert_eq!(bool::__ENCODING, Encoding::Bool); - - assert_eq!( - ::__Inner::__ENCODING, - ::__Inner::ENCODING - ); #[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))] assert_eq!(::__Inner::ENCODING, Encoding::Char); diff --git a/crates/objc2/src/runtime/bool.rs b/crates/objc2/src/runtime/bool.rs index b2aa92f45..a1ca8d6db 100644 --- a/crates/objc2/src/runtime/bool.rs +++ b/crates/objc2/src/runtime/bool.rs @@ -1,6 +1,6 @@ use core::fmt; -use crate::encode::{Encode, EncodeConvert, Encoding, RefEncode}; +use crate::encode::{Encode, Encoding, RefEncode}; use crate::ffi; /// The Objective-C `BOOL` type. @@ -99,6 +99,18 @@ impl fmt::Debug for Bool { } } +trait Helper { + const __ENCODING: Encoding; +} + +impl Helper for T { + const __ENCODING: Encoding = T::ENCODING; +} + +impl Helper for bool { + const __ENCODING: Encoding = Encoding::Bool; +} + // SAFETY: `Bool` is `repr(transparent)`. unsafe impl Encode for Bool { // i8::__ENCODING == Encoding::Char @@ -125,6 +137,7 @@ unsafe impl RefEncode for Bool { #[cfg(test)] mod tests { use super::*; + use crate::encode::EncodeConvert; use alloc::format; #[test] @@ -157,6 +170,16 @@ mod tests { assert_eq!(b.as_raw() as usize, 0); } + #[test] + fn test_encode() { + assert_eq!(bool::__ENCODING, Encoding::Bool); + + assert_eq!( + ::__Inner::__ENCODING, + ::__Inner::ENCODING + ); + } + #[test] fn test_impls() { let b: Bool = Default::default(); From 29f8790cf7ff0b4f4a4369b70ccec86b0ecb9e0e Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 30 Jan 2023 02:10:46 +0100 Subject: [PATCH 2/5] Test things that should not be `encode` with UI tests UI-test brittleness is solved by pinning nightly version --- crates/objc2/src/encode.rs | 22 ----- crates/test-ui/ui/not_encode.rs | 21 +++++ crates/test-ui/ui/not_encode.stderr | 133 ++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 22 deletions(-) create mode 100644 crates/test-ui/ui/not_encode.rs create mode 100644 crates/test-ui/ui/not_encode.stderr diff --git a/crates/objc2/src/encode.rs b/crates/objc2/src/encode.rs index 2374e5dce..cb34b8a14 100644 --- a/crates/objc2/src/encode.rs +++ b/crates/objc2/src/encode.rs @@ -309,28 +309,6 @@ unsafe impl Encode for () { const ENCODING: Encoding = Encoding::Void; } -// UI tests of this is too brittle. -#[cfg(doctest)] -/// ``` -/// use objc2::encode::Encode; -/// <()>::ENCODING; // TODO: Make this fail as well -/// ``` -/// ```should_fail -/// use core::ffi::c_void; -/// use objc2::encode::Encode; -/// ::ENCODING; -/// ``` -/// ```should_fail -/// use objc2::encode::Encode; -/// <*const ()>::ENCODING; -/// ``` -/// ```should_fail -/// use core::ffi::c_void; -/// use objc2::encode::Encode; -/// <&c_void>::ENCODING; -/// ``` -extern "C" {} - macro_rules! encode_impls_size { ($($t:ty => ($t16:ty, $t32:ty, $t64:ty),)*) => ($( #[doc = concat!("The encoding of [`", stringify!($t), "`] varies based on the target pointer width.")] diff --git a/crates/test-ui/ui/not_encode.rs b/crates/test-ui/ui/not_encode.rs new file mode 100644 index 000000000..921336e26 --- /dev/null +++ b/crates/test-ui/ui/not_encode.rs @@ -0,0 +1,21 @@ +//! Verify that certain things we don't want to be encode aren't. +use core::ffi::c_void; + +use objc2::encode::Encode; +use objc2::runtime::Sel; + +fn is_encode() {} + +fn main() { + is_encode::>(); + + is_encode::<()>(); // TODO: Make this fail as well + is_encode::<&()>(); + is_encode::<*const ()>(); + is_encode::(); + is_encode::<&c_void>(); + + is_encode:: &'static ()>(); + + is_encode::<&Sel>(); +} diff --git a/crates/test-ui/ui/not_encode.stderr b/crates/test-ui/ui/not_encode.stderr new file mode 100644 index 000000000..06830f3e1 --- /dev/null +++ b/crates/test-ui/ui/not_encode.stderr @@ -0,0 +1,133 @@ +error[E0277]: the trait bound `Vec: Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::>(); + | ^^^^^^^^ the trait `Encode` is not implemented for `Vec` + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + () + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + and $N others +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `(): RefEncode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<&()>(); + | ^^^ the trait `RefEncode` is not implemented for `()` + | + = note: required for `&()` to implement `Encode` +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` +help: consider removing the leading `&`-reference + | +13 - is_encode::<&()>(); +13 + is_encode::<()>(); + | + +error[E0277]: the trait bound `(): RefEncode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<*const ()>(); + | ^^^^^^^^^ the trait `RefEncode` is not implemented for `()` + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `*const ()` to implement `Encode` +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `c_void: Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::(); + | ^^^^^^ the trait `Encode` is not implemented for `c_void` + | + = help: the following other types implement trait `Encode`: + *const c_void + *mut c_void +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `c_void: RefEncode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<&c_void>(); + | ^^^^^^^ the trait `RefEncode` is not implemented for `c_void` + | + = help: the following other types implement trait `RefEncode`: + *const c_void + *mut c_void + = note: required for `&c_void` to implement `Encode` +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `fn() -> &'static (): Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode:: &'static ()>(); + | ^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `fn() -> &'static ()` + | + = help: the following other types implement trait `Encode`: + extern "C" fn() -> Ret + extern "C" fn(A) -> Ret + extern "C" fn(A, ...) -> Ret + extern "C" fn(A, B) -> Ret + extern "C" fn(A, B, ...) -> Ret + extern "C" fn(A, B, C) -> Ret + extern "C" fn(A, B, C, ...) -> Ret + extern "C" fn(A, B, C, D) -> Ret + and $N others +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `objc2::runtime::Sel: RefEncode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<&Sel>(); + | ^^^^ the trait `RefEncode` is not implemented for `objc2::runtime::Sel` + | + = note: required for `&objc2::runtime::Sel` to implement `Encode` +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` +help: consider removing the leading `&`-reference + | +20 - is_encode::<&Sel>(); +20 + is_encode::(); + | From 3458c9a2dd2425b015ab22f8bf625561f59f461e Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 1 Feb 2023 01:18:31 +0100 Subject: [PATCH 3/5] Redo encoding helpers to disallow `()` in argument position --- crates/block2/src/block.rs | 17 +- crates/block2/src/concrete_block.rs | 11 +- crates/block2/src/global.rs | 12 +- crates/objc2/CHANGELOG.md | 6 +- crates/objc2/src/declare.rs | 25 +- crates/objc2/src/declare/ivar_bool.rs | 6 +- crates/objc2/src/encode.rs | 187 +------------ crates/objc2/src/encode/__unstable.rs | 246 ++++++++++++++++++ crates/objc2/src/lib.rs | 4 +- crates/objc2/src/macros/declare_class.rs | 14 +- crates/objc2/src/message/apple/arm.rs | 9 +- crates/objc2/src/message/apple/arm64.rs | 4 +- crates/objc2/src/message/apple/mod.rs | 10 +- crates/objc2/src/message/apple/x86.rs | 7 +- crates/objc2/src/message/apple/x86_64.rs | 9 +- crates/objc2/src/message/gnustep.rs | 6 +- crates/objc2/src/message/mod.rs | 27 +- crates/objc2/src/runtime.rs | 7 +- crates/objc2/src/runtime/bool.rs | 10 +- crates/test-ui/ui/add_method_no_bool.stderr | 5 +- .../ui/declare_class_invalid_type.stderr | 44 ++-- .../test-ui/ui/declare_class_invalid_type3.rs | 18 ++ .../ui/declare_class_invalid_type3.stderr | 29 +++ .../ui/extern_methods_invalid_type.stderr | 18 +- .../test-ui/ui/global_block_not_encode.stderr | 2 +- crates/test-ui/ui/msg_send_not_encode.rs | 2 + crates/test-ui/ui/msg_send_not_encode.stderr | 41 ++- crates/test-ui/ui/not_encode.rs | 6 +- crates/test-ui/ui/not_encode.stderr | 112 +++++++- 29 files changed, 583 insertions(+), 311 deletions(-) create mode 100644 crates/objc2/src/encode/__unstable.rs create mode 100644 crates/test-ui/ui/declare_class_invalid_type3.rs create mode 100644 crates/test-ui/ui/declare_class_invalid_type3.stderr diff --git a/crates/block2/src/block.rs b/crates/block2/src/block.rs index ca1f9644c..2b43d77af 100644 --- a/crates/block2/src/block.rs +++ b/crates/block2/src/block.rs @@ -1,7 +1,8 @@ use core::marker::PhantomData; use core::mem; -use objc2::encode::{Encode, EncodeArguments, Encoding, RefEncode}; +use objc2::encode::__unstable::EncodeReturn; +use objc2::encode::{Encode, Encoding, RefEncode}; use crate::ffi; @@ -15,10 +16,10 @@ use crate::ffi; /// /// This is a sealed trait, and should not need to be implemented. Open an /// issue if you know a use-case where this restrition should be lifted! -pub unsafe trait BlockArguments: EncodeArguments + Sized { +pub unsafe trait BlockArguments: Sized { /// Calls the given method the block and arguments. #[doc(hidden)] - unsafe fn __call_block( + unsafe fn __call_block( invoke: unsafe extern "C" fn(), block: *mut Block, args: Self, @@ -29,7 +30,11 @@ macro_rules! block_args_impl { ($($a:ident: $t:ident),*) => ( unsafe impl<$($t: Encode),*> BlockArguments for ($($t,)*) { #[inline] - unsafe fn __call_block(invoke: unsafe extern "C" fn(), block: *mut Block, ($($a,)*): Self) -> R { + unsafe fn __call_block( + invoke: unsafe extern "C" fn(), + block: *mut Block, + ($($a,)*): Self, + ) -> R { // Very similar to `MessageArguments::__invoke` let invoke: unsafe extern "C" fn(*mut Block $(, $t)*) -> R = unsafe { mem::transmute(invoke) @@ -93,11 +98,11 @@ pub struct Block { _p: PhantomData R>, } -unsafe impl RefEncode for Block { +unsafe impl RefEncode for Block { const ENCODING_REF: Encoding = Encoding::Block; } -impl Block { +impl Block { /// Call self with the given arguments. /// /// # Safety diff --git a/crates/block2/src/concrete_block.rs b/crates/block2/src/concrete_block.rs index fa39fd77b..88f566205 100644 --- a/crates/block2/src/concrete_block.rs +++ b/crates/block2/src/concrete_block.rs @@ -5,6 +5,7 @@ use core::ops::Deref; use core::ptr; use std::os::raw::c_ulong; +use objc2::encode::__unstable::EncodeReturn; use objc2::encode::{Encode, Encoding, RefEncode}; use crate::{ffi, Block, BlockArguments, RcBlock}; @@ -25,7 +26,7 @@ mod private { /// issue if you know a use-case where this restrition should be lifted! pub unsafe trait IntoConcreteBlock: private::Sealed + Sized { /// The return type of the resulting `ConcreteBlock`. - type Output: Encode; + type Output: EncodeReturn; #[doc(hidden)] fn __into_concrete_block(self) -> ConcreteBlock; @@ -36,12 +37,12 @@ macro_rules! concrete_block_impl { concrete_block_impl!($f,); ); ($f:ident, $($a:ident : $t:ident),*) => ( - impl<$($t: Encode,)* R: Encode, X> private::Sealed<($($t,)*)> for X + impl<$($t: Encode,)* R: EncodeReturn, X> private::Sealed<($($t,)*)> for X where X: Fn($($t,)*) -> R, {} - unsafe impl<$($t: Encode,)* R: Encode, X> IntoConcreteBlock<($($t,)*)> for X + unsafe impl<$($t: Encode,)* R: EncodeReturn, X> IntoConcreteBlock<($($t,)*)> for X where X: Fn($($t,)*) -> R, { @@ -166,14 +167,14 @@ pub struct ConcreteBlock { pub(crate) closure: F, } -unsafe impl RefEncode for ConcreteBlock { +unsafe impl RefEncode for ConcreteBlock { const ENCODING_REF: Encoding = Encoding::Block; } impl ConcreteBlock where A: BlockArguments, - R: Encode, + R: EncodeReturn, F: IntoConcreteBlock, { /// Constructs a `ConcreteBlock` with the given closure. diff --git a/crates/block2/src/global.rs b/crates/block2/src/global.rs index fb58b69f3..57e885111 100644 --- a/crates/block2/src/global.rs +++ b/crates/block2/src/global.rs @@ -5,7 +5,7 @@ use core::ops::Deref; use core::ptr; use std::os::raw::c_ulong; -use objc2::encode::Encode; +use objc2::encode::__unstable::EncodeReturn; use super::{ffi, Block}; use crate::BlockArguments; @@ -35,13 +35,13 @@ pub struct GlobalBlock { unsafe impl Sync for GlobalBlock where A: BlockArguments, - R: Encode, + R: EncodeReturn, { } unsafe impl Send for GlobalBlock where A: BlockArguments, - R: Encode, + R: EncodeReturn, { } @@ -78,7 +78,7 @@ impl GlobalBlock { impl Deref for GlobalBlock where A: BlockArguments, - R: Encode, + R: EncodeReturn, { type Target = Block; @@ -94,7 +94,7 @@ where /// /// The syntax is similar to a static closure (except that all types have to /// be specified). Note that the block cannot capture its environment, and -/// its argument types and return type must be [`Encode`]. +/// its argument types and return type must be [`EncodeReturn`]. /// /// # Examples /// @@ -130,7 +130,7 @@ where /// assert_eq!(x, 47); /// ``` /// -/// The following does not compile because [`Box`] is not [`Encode`]: +/// The following does not compile because [`Box`] is not [`EncodeReturn`]: /// /// ```compile_fail /// use block2::global_block; diff --git a/crates/objc2/CHANGELOG.md b/crates/objc2/CHANGELOG.md index fff553cc8..e6c5b1018 100644 --- a/crates/objc2/CHANGELOG.md +++ b/crates/objc2/CHANGELOG.md @@ -17,8 +17,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). `Debug`, `Hash`, `PartialEq` and `Eq`. * Support running `Drop` impls on `dealloc` in `declare_class!`. * Added `declare::IvarEncode` and `declare::IvarBool` types. -* Moved the `objc2_encode` traits to `objc2::encode` (API surface is - unchanged, since they were already exposed from that). +* **BREAKING**: Moved the `objc2_encode` traits to `objc2::encode`. + + This includes removing the `EncodeConvert` and `EncodeArguments` traits. ### Changed * **BREAKING**: Using the automatic `NSError**`-to-`Result` functionality in @@ -113,6 +114,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Allow empty structs in `declare_class!` macro. * Allow using `extern_methods!` without the `ClassType` trait in scope. * Fixed a few small issues with `declare_class!`. +* Fixed `()` being possible in argument position in `msg_send!`. ## 0.3.0-beta.4 - 2022-12-24 diff --git a/crates/objc2/src/declare.rs b/crates/objc2/src/declare.rs index cce301fc6..ffb35d484 100644 --- a/crates/objc2/src/declare.rs +++ b/crates/objc2/src/declare.rs @@ -124,7 +124,8 @@ use core::ptr; use core::ptr::NonNull; use std::ffi::CString; -use crate::encode::{Encode, EncodeArguments, Encoding, RefEncode}; +use crate::encode::__unstable::{EncodeArguments, EncodeReturn}; +use crate::encode::{Encode, Encoding, RefEncode}; use crate::ffi; use crate::rc::Allocated; use crate::runtime::{Bool, Class, Imp, Object, Protocol, Sel}; @@ -148,7 +149,7 @@ pub trait MethodImplementation: private::Sealed { /// The callee type of the method. type Callee: RefEncode + ?Sized; /// The return type of the method. - type Ret: Encode; + type Ret: EncodeReturn; /// The argument types of the method. type Args: EncodeArguments; @@ -161,14 +162,14 @@ macro_rules! method_decl_impl { impl<$($l,)* T, $r, $($t),*> private::Sealed for $f where T: Message + ?Sized, - $r: Encode, + $r: EncodeReturn, $($t: Encode,)* {} impl<$($l,)* T, $r, $($t),*> MethodImplementation for $f where T: Message + ?Sized, - $r: Encode, + $r: EncodeReturn, $($t: Encode,)* { type Callee = T; @@ -183,13 +184,13 @@ macro_rules! method_decl_impl { (@<$($l:lifetime),*> Class, $r:ident, $f:ty, $($t:ident),*) => { impl<$($l,)* $r, $($t),*> private::Sealed for $f where - $r: Encode, + $r: EncodeReturn, $($t: Encode,)* {} impl<$($l,)* $r, $($t),*> MethodImplementation for $f where - $r: Encode, + $r: EncodeReturn, $($t: Encode,)* { type Callee = Class; @@ -408,7 +409,7 @@ impl ClassBuilder { F: MethodImplementation, { let enc_args = F::Args::ENCODINGS; - let enc_ret = F::Ret::ENCODING; + let enc_ret = F::Ret::ENCODING_RETURN; let sel_args = sel.number_of_arguments(); assert_eq!( @@ -465,7 +466,7 @@ impl ClassBuilder { F: MethodImplementation, { let enc_args = F::Args::ENCODINGS; - let enc_ret = F::Ret::ENCODING; + let enc_ret = F::Ret::ENCODING_RETURN; let sel_args = sel.number_of_arguments(); assert_eq!( @@ -629,7 +630,7 @@ impl ProtocolBuilder { is_instance_method: bool, ) where Args: EncodeArguments, - Ret: Encode, + Ret: EncodeReturn, { let encs = Args::ENCODINGS; let sel_args = sel.number_of_arguments(); @@ -641,7 +642,7 @@ impl ProtocolBuilder { sel_args, encs.len(), ); - let types = method_type_encoding(&Ret::ENCODING, encs); + let types = method_type_encoding(&Ret::ENCODING_RETURN, encs); unsafe { ffi::protocol_addMethodDescription( self.as_mut_ptr(), @@ -657,7 +658,7 @@ impl ProtocolBuilder { pub fn add_method_description(&mut self, sel: Sel, is_required: bool) where Args: EncodeArguments, - Ret: Encode, + Ret: EncodeReturn, { self.add_method_description_common::(sel, is_required, true) } @@ -666,7 +667,7 @@ impl ProtocolBuilder { pub fn add_class_method_description(&mut self, sel: Sel, is_required: bool) where Args: EncodeArguments, - Ret: Encode, + Ret: EncodeReturn, { self.add_method_description_common::(sel, is_required, false) } diff --git a/crates/objc2/src/declare/ivar_bool.rs b/crates/objc2/src/declare/ivar_bool.rs index 8c8451892..00a7da968 100644 --- a/crates/objc2/src/declare/ivar_bool.rs +++ b/crates/objc2/src/declare/ivar_bool.rs @@ -4,15 +4,11 @@ use super::InnerIvarType; /// Ivar of [`bool`]. /// -/// This is used to work around the fact that `bool` is not [`Encode`], only -/// [`EncodeConvert`] (and that is only usable when we can do a conversion -/// step, which we can't here). +/// This is used to work around the fact that `bool` is not [`Encode`]. /// /// If you want to access this instance variable to Objective-C, you must do /// so using C99 `_Bool`; if you want to use `BOOL` in Objective-C, you should /// use `IvarEncode`. -/// -/// [`EncodeConvert`]: crate::encode::EncodeConvert #[repr(transparent)] pub struct IvarBool(bool); diff --git a/crates/objc2/src/encode.rs b/crates/objc2/src/encode.rs index cb34b8a14..8ba69adad 100644 --- a/crates/objc2/src/encode.rs +++ b/crates/objc2/src/encode.rs @@ -68,7 +68,8 @@ use core::num::{ use core::ptr::NonNull; use core::sync::atomic; -use crate::runtime::Bool; +// Intentionally not `#[doc(hidden)]` +pub mod __unstable; #[doc(inline)] pub use objc2_encode::{Encoding, EncodingBox, ParseError}; @@ -216,8 +217,8 @@ pub unsafe trait RefEncode { /// See [the nomicon][nomicon-nullable] for details on which types uphold this /// promise. /// -/// This is used to work around, which would normally prevent from -/// implementing [`Encode`]/[`RefEncode`] for `Option`. +/// This is used to work around the orphan rule, which would normally prevent +/// you from implementing [`Encode`]/[`RefEncode`] for `Option`. /// /// [nomicon-nullable]: https://doc.rust-lang.org/nightly/nomicon/ffi.html#the-nullable-pointer-optimization /// @@ -300,15 +301,6 @@ encode_impls!( // TODO: Structs in core::arch? -/// To allow usage as the return type of generic functions. -/// -/// You should not rely on this encoding to exist for any other purpose (since -/// `()` is not FFI-safe)! -// TODO: Figure out a way to remove this - maybe with a `EncodeReturn` trait? -unsafe impl Encode for () { - const ENCODING: Encoding = Encoding::Void; -} - macro_rules! encode_impls_size { ($($t:ty => ($t16:ty, $t32:ty, $t64:ty),)*) => ($( #[doc = concat!("The encoding of [`", stringify!($t), "`] varies based on the target pointer width.")] @@ -584,22 +576,22 @@ unsafe impl OptionEncode for NonNull {} /// pointers that are higher-ranked over lifetimes don't get implemented. /// /// We could fix it by adding those impls and allowing `coherence_leak_check`, -/// but it would have to be done for _all_ references, `Option<&T>` and such as -/// well. So trying to do it quickly requires generating a polynomial amount of -/// implementations, which IMO is overkill for such a small issue. +/// but it would have to be done for _all_ references, `Option<&T>` and such +/// as well. So trying to do it quickly requires generating a polynomial +/// amount of implementations, which IMO is overkill for such a small issue. /// /// Using `?Sized` is probably not safe here because C functions can only take /// and return items with a known size. macro_rules! encode_fn_pointer_impl { (@ $FnTy: ty, $($Arg: ident),*) => { - unsafe impl Encode for $FnTy { + unsafe impl Encode for $FnTy { const ENCODING: Encoding = Encoding::Pointer(&Encoding::Unknown); } - unsafe impl RefEncode for $FnTy { + unsafe impl RefEncode for $FnTy { const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); } // SAFETY: Function pointers have a NULL niche - unsafe impl OptionEncode for $FnTy {} + unsafe impl OptionEncode for $FnTy {} }; (# $abi:literal; $($Arg: ident),+) => { // Normal functions @@ -635,126 +627,10 @@ encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J); encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K); encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L); -mod convert_private { - pub trait Sealed {} -} - -/// Represents types that can easily be converted to/from an [`Encode`] type. -/// -/// This is implemented specially for [`bool`] to allow using that as -/// Objective-C `BOOL`, where it would otherwise not be allowed (since they -/// are not ABI compatible). -/// -/// This is mostly an implementation detail, and hence the trait is sealed. -/// Open an issue if you know a use-case where this restrition should be -/// lifted! -pub trait EncodeConvert: convert_private::Sealed { - /// The inner type that this can be converted to and from. - #[doc(hidden)] - type __Inner: Encode; - - #[doc(hidden)] - fn __from_inner(inner: Self::__Inner) -> Self; - - #[doc(hidden)] - fn __into_inner(self) -> Self::__Inner; -} - -impl convert_private::Sealed for T {} -impl EncodeConvert for T { - type __Inner = Self; - - #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { - inner - } - - #[inline] - fn __into_inner(self) -> Self::__Inner { - self - } -} - -impl convert_private::Sealed for bool {} -impl EncodeConvert for bool { - type __Inner = Bool; - - #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { - inner.as_bool() - } - - #[inline] - fn __into_inner(self) -> Self::__Inner { - Bool::new(self) - } -} - -mod args_private { - pub trait Sealed {} -} - -/// Types that represent an ordered group of function arguments, where each -/// argument has an Objective-C type-encoding, or can be converted from one. -/// -/// This is implemented for tuples of up to 16 arguments, where each argument -/// implements [`EncodeConvert`]. It is primarily used to make generic code -/// a bit easier. -/// -/// Note that tuples themselves don't implement [`Encode`] directly, because -/// they're not FFI-safe! -/// -/// This is a sealed trait, and should not need to be implemented. Open an -/// issue if you know a use-case where this restrition should be lifted! -/// -/// -/// # Safety -/// -/// You cannot rely on this trait for ensuring that the arguments all -/// are [`Encode`], since they may only implement [`EncodeConvert`]. Use your -/// own trait and add [`Encode`] bounds on that. -pub unsafe trait EncodeArguments: args_private::Sealed { - /// The encodings for the arguments. - const ENCODINGS: &'static [Encoding]; -} - -macro_rules! encode_args_impl { - ($($Arg: ident),*) => { - impl<$($Arg: EncodeConvert),*> args_private::Sealed for ($($Arg,)*) {} - - unsafe impl<$($Arg: EncodeConvert),*> EncodeArguments for ($($Arg,)*) { - const ENCODINGS: &'static [Encoding] = &[ - // T::__Inner::ENCODING => T::ENCODING - // bool::__Inner::ENCODING => Bool::ENCODING - $($Arg::__Inner::ENCODING),* - ]; - } - }; -} - -encode_args_impl!(); -encode_args_impl!(A); -encode_args_impl!(A, B); -encode_args_impl!(A, B, C); -encode_args_impl!(A, B, C, D); -encode_args_impl!(A, B, C, D, E); -encode_args_impl!(A, B, C, D, E, F); -encode_args_impl!(A, B, C, D, E, F, G); -encode_args_impl!(A, B, C, D, E, F, G, H); -encode_args_impl!(A, B, C, D, E, F, G, H, I); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); -encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); - #[cfg(test)] mod tests { use super::*; - use core::any::TypeId; use core::sync::atomic::*; #[test] @@ -809,8 +685,6 @@ mod tests { #[test] fn test_void() { - // TODO: Remove this - assert_eq!(<()>::ENCODING, Encoding::Void); assert_eq!( <*const c_void>::ENCODING, Encoding::Pointer(&Encoding::Void) @@ -844,7 +718,7 @@ mod tests { Encoding::Pointer(&Encoding::Unknown) ); assert_eq!( - ()>::ENCODING, + u32>::ENCODING, Encoding::Pointer(&Encoding::Unknown) ); assert_eq!( @@ -876,43 +750,4 @@ mod tests { impls_encode(my_fn3 as extern "C" fn(_) -> _); impls_encode(my_fn4 as extern "C" fn(_, _) -> _); } - - #[test] - fn convert_normally_noop() { - assert_eq!( - TypeId::of::<::__Inner>(), - TypeId::of::() - ); - assert_eq!(::__from_inner(42), 42); - assert_eq!(42i32.__into_inner(), 42); - } - - #[test] - fn convert_i8() { - assert_eq!( - TypeId::of::<::__Inner>(), - TypeId::of::() - ); - assert_eq!(::__from_inner(-3), -3); - assert_eq!((-3i32).__into_inner(), -3); - } - - #[test] - fn convert_bool() { - assert!(!::__from_inner(Bool::NO)); - assert!(::__from_inner(Bool::YES)); - - assert!(!false.__into_inner().as_bool()); - assert!(true.__into_inner().as_bool()); - - #[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))] - assert_eq!(::__Inner::ENCODING, Encoding::Char); - } - - #[test] - fn test_encode_arguments() { - assert!(<()>::ENCODINGS.is_empty()); - assert_eq!(<(i8,)>::ENCODINGS, &[i8::ENCODING]); - assert_eq!(<(i8, u32)>::ENCODINGS, &[i8::ENCODING, u32::ENCODING]); - } } diff --git a/crates/objc2/src/encode/__unstable.rs b/crates/objc2/src/encode/__unstable.rs new file mode 100644 index 000000000..620430e0a --- /dev/null +++ b/crates/objc2/src/encode/__unstable.rs @@ -0,0 +1,246 @@ +//! # Unstable encoding traits. +//! +//! The traits in this module are unstable, meaning that they are **outside +//! the usual SemVer guarantee**, and may freely change or be removed in patch +//! versions. +//! +//! They are provided here mostly for documentation purposes (e.g. you can +//! check [`EncodeReturn`] to see which types are possible as the return value +//! of a function pointer). +//! +//! If you would like to use some of these, please [open an issue], then we +//! can discuss making them stable. +//! +//! [open an issue]: https://github.com/madsmtm/objc2/issues/new +#![cfg_attr( + feature = "unstable-docsrs", + doc(cfg(feature = "unstable-encode-internals")) +)] + +use crate::encode::{Encode, Encoding}; +use crate::runtime::Bool; + +mod return_private { + pub trait Sealed {} +} + +/// Types that are safe as the return value from Objective-C. +/// +/// We currently don't need a similar `EncodeArgument` trait, but we might in +/// the future. +pub unsafe trait EncodeReturn: return_private::Sealed { + /// The Objective-C type-encoding for this type. + const ENCODING_RETURN: Encoding; +} + +impl return_private::Sealed for () {} +unsafe impl EncodeReturn for () { + const ENCODING_RETURN: Encoding = Encoding::Void; +} + +impl return_private::Sealed for T {} +unsafe impl EncodeReturn for T { + const ENCODING_RETURN: Encoding = T::ENCODING; +} + +mod convert_private { + pub trait Sealed {} +} + +impl convert_private::Sealed for T {} +impl convert_private::Sealed for bool {} + +/// Represents types that can easily be converted to/from an [`Encode`] type. +/// +/// This is implemented specially for [`bool`] to allow using that as +/// Objective-C `BOOL`, where it would otherwise not be allowed (since they +/// are not ABI compatible). +pub trait EncodeConvertArgument: convert_private::Sealed { + /// The inner type that this can be converted to and from. + #[doc(hidden)] + type __Inner: Encode; + + #[doc(hidden)] + fn __from_inner(inner: Self::__Inner) -> Self; + + #[doc(hidden)] + fn __into_inner(self) -> Self::__Inner; +} + +impl EncodeConvertArgument for T { + type __Inner = Self; + + #[inline] + fn __from_inner(inner: Self::__Inner) -> Self { + inner + } + + #[inline] + fn __into_inner(self) -> Self::__Inner { + self + } +} + +impl EncodeConvertArgument for bool { + type __Inner = Bool; + + #[inline] + fn __from_inner(inner: Self::__Inner) -> Self { + inner.as_bool() + } + + #[inline] + fn __into_inner(self) -> Self::__Inner { + Bool::new(self) + } +} + +/// Same as [`EncodeConvertArgument`], but for return types. +pub trait EncodeConvertReturn: convert_private::Sealed { + /// The inner type that this can be converted to and from. + #[doc(hidden)] + type __Inner: EncodeReturn; + + #[doc(hidden)] + fn __from_inner(inner: Self::__Inner) -> Self; + + #[doc(hidden)] + fn __into_inner(self) -> Self::__Inner; +} + +impl EncodeConvertReturn for T { + type __Inner = Self; + + #[inline] + fn __from_inner(inner: Self::__Inner) -> Self { + inner + } + + #[inline] + fn __into_inner(self) -> Self::__Inner { + self + } +} + +impl EncodeConvertReturn for bool { + type __Inner = Bool; + + #[inline] + fn __from_inner(inner: Self::__Inner) -> Self { + inner.as_bool() + } + + #[inline] + fn __into_inner(self) -> Self::__Inner { + Bool::new(self) + } +} + +mod args_private { + pub trait Sealed {} +} + +/// Types that represent an ordered group of function arguments, where each +/// argument has an Objective-C type-encoding, or can be converted from one. +/// +/// This is implemented for tuples of up to 16 arguments, where each argument +/// implements [`EncodeConvertArgument`]. It is primarily used to make generic +/// code a bit easier. +/// +/// Note that tuples themselves don't implement [`Encode`] directly, because +/// they're not FFI-safe! +pub unsafe trait EncodeArguments: args_private::Sealed { + /// The encodings for the arguments. + const ENCODINGS: &'static [Encoding]; +} + +macro_rules! encode_args_impl { + ($($Arg: ident),*) => { + impl<$($Arg: EncodeConvertArgument),*> args_private::Sealed for ($($Arg,)*) {} + + unsafe impl<$($Arg: EncodeConvertArgument),*> EncodeArguments for ($($Arg,)*) { + const ENCODINGS: &'static [Encoding] = &[ + // T::__Inner::ENCODING => T::ENCODING + // bool::__Inner::ENCODING => Bool::ENCODING + $($Arg::__Inner::ENCODING),* + ]; + } + }; +} + +encode_args_impl!(); +encode_args_impl!(A); +encode_args_impl!(A, B); +encode_args_impl!(A, B, C); +encode_args_impl!(A, B, C, D); +encode_args_impl!(A, B, C, D, E); +encode_args_impl!(A, B, C, D, E, F); +encode_args_impl!(A, B, C, D, E, F, G); +encode_args_impl!(A, B, C, D, E, F, G, H); +encode_args_impl!(A, B, C, D, E, F, G, H, I); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); + +#[cfg(test)] +mod tests { + use super::*; + + use core::any::TypeId; + + #[test] + fn test_return() { + assert_eq!(::ENCODING_RETURN, ::ENCODING); + assert_eq!(<()>::ENCODING_RETURN, Encoding::Void); + } + + #[test] + fn convert_normally_noop() { + assert_eq!( + TypeId::of::<::__Inner>(), + TypeId::of::() + ); + assert_eq!(::__from_inner(42), 42); + assert_eq!(EncodeConvertArgument::__into_inner(42i32), 42); + } + + #[test] + fn convert_i8() { + assert_eq!( + TypeId::of::<::__Inner>(), + TypeId::of::() + ); + assert_eq!(::__from_inner(-3), -3); + assert_eq!(EncodeConvertArgument::__into_inner(-3i32), -3); + } + + #[test] + fn convert_bool() { + assert!(!::__from_inner(Bool::NO)); + assert!(::__from_inner(Bool::YES)); + assert!(!::__from_inner(Bool::NO)); + assert!(::__from_inner(Bool::YES)); + + assert!(!EncodeConvertArgument::__into_inner(false).as_bool()); + assert!(EncodeConvertArgument::__into_inner(true).as_bool()); + assert!(!EncodeConvertReturn::__into_inner(false).as_bool()); + assert!(EncodeConvertReturn::__into_inner(true).as_bool()); + + #[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))] + assert_eq!( + ::__Inner::ENCODING, + Encoding::Char + ); + } + + #[test] + fn test_encode_arguments() { + assert!(<()>::ENCODINGS.is_empty()); + assert_eq!(<(i8,)>::ENCODINGS, &[i8::ENCODING]); + assert_eq!(<(i8, u32)>::ENCODINGS, &[i8::ENCODING, u32::ENCODING]); + } +} diff --git a/crates/objc2/src/lib.rs b/crates/objc2/src/lib.rs index b96859937..116f770df 100644 --- a/crates/objc2/src/lib.rs +++ b/crates/objc2/src/lib.rs @@ -160,7 +160,7 @@ feature(negative_impls, auto_traits) )] #![cfg_attr(feature = "unstable-c-unwind", feature(c_unwind))] -#![cfg_attr(feature = "unstable-docsrs", feature(doc_auto_cfg))] +#![cfg_attr(feature = "unstable-docsrs", feature(doc_cfg, doc_auto_cfg))] #![warn(elided_lifetimes_in_paths)] #![warn(missing_docs)] #![deny(non_ascii_idents)] @@ -189,7 +189,7 @@ pub use objc_sys as ffi; pub use self::class_type::ClassType; #[doc(no_inline)] -pub use self::encode::{Encode, EncodeArguments, Encoding, RefEncode}; +pub use self::encode::{Encode, Encoding, RefEncode}; pub use self::message::{Message, MessageArguments, MessageReceiver}; pub use self::protocol::{ImplementedBy, ProtocolObject, ProtocolType}; pub use self::verify::VerificationError; diff --git a/crates/objc2/src/macros/declare_class.rs b/crates/objc2/src/macros/declare_class.rs index 6d7a3168e..b74b258b9 100644 --- a/crates/objc2/src/macros/declare_class.rs +++ b/crates/objc2/src/macros/declare_class.rs @@ -879,7 +879,7 @@ macro_rules! __declare_class_rewrite_args { } => { $crate::__declare_class_rewrite_args! { ($($($rest_args)*)?) - ($($args_converted)* _ : <$param_ty as $crate::encode::EncodeConvert>::__Inner,) + ($($args_converted)* _ : <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__Inner,) ($($body_prefix)*) ($out_macro) @@ -897,10 +897,10 @@ macro_rules! __declare_class_rewrite_args { } => { $crate::__declare_class_rewrite_args! { ($($($rest_args)*)?) - ($($args_converted)* $param : <$param_ty as $crate::encode::EncodeConvert>::__Inner,) + ($($args_converted)* $param : <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__Inner,) ( $($body_prefix)* - let mut $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param); + let mut $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_inner($param); ) ($out_macro) @@ -918,10 +918,10 @@ macro_rules! __declare_class_rewrite_args { } => { $crate::__declare_class_rewrite_args! { ($($($rest_args)*)?) - ($($args_converted)* $param : <$param_ty as $crate::encode::EncodeConvert>::__Inner,) + ($($args_converted)* $param : <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__Inner,) ( $($body_prefix)* - let $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param); + let $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_inner($param); ) ($out_macro) @@ -972,7 +972,7 @@ macro_rules! __declare_class_method_out_inner { $($qualifiers)* extern "C" fn $name( $($args_prefix)* $($args_converted)* - ) $(-> <$ret as $crate::encode::EncodeConvert>::__Inner)? { + ) $(-> <$ret as $crate::encode::__unstable::EncodeConvertReturn>::__Inner)? { $($body_prefix)* $crate::__convert_result! { $body $(; $ret)? @@ -1057,7 +1057,7 @@ macro_rules! __convert_result { ($body:block; $ret:ty) => { let __objc2_result = $body; #[allow(unreachable_code)] - <$ret as $crate::encode::EncodeConvert>::__into_inner(__objc2_result) + <$ret as $crate::encode::__unstable::EncodeConvertReturn>::__into_inner(__objc2_result) }; } diff --git a/crates/objc2/src/message/apple/arm.rs b/crates/objc2/src/message/apple/arm.rs index a04ae048c..4c4aa4e4a 100644 --- a/crates/objc2/src/message/apple/arm.rs +++ b/crates/objc2/src/message/apple/arm.rs @@ -1,18 +1,19 @@ use core::mem; use super::MsgSendFn; +use crate::encode::Encoding; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::Imp; -use crate::{Encode, Encoding}; /// Double-word sized fundamental data types don't use stret, but any /// composite type larger than 4 bytes does. /// /// /// -unsafe impl MsgSendFn for T { +unsafe impl MsgSendFn for T { const MSG_SEND: Imp = { - if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING { + if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING_RETURN { ffi::objc_msgSend } else if mem::size_of::() <= 4 { ffi::objc_msgSend @@ -21,7 +22,7 @@ unsafe impl MsgSendFn for T { } }; const MSG_SEND_SUPER: Imp = { - if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING { + if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING_RETURN { ffi::objc_msgSendSuper } else if mem::size_of::() <= 4 { ffi::objc_msgSendSuper diff --git a/crates/objc2/src/message/apple/arm64.rs b/crates/objc2/src/message/apple/arm64.rs index 37b09505c..9366d631d 100644 --- a/crates/objc2/src/message/apple/arm64.rs +++ b/crates/objc2/src/message/apple/arm64.rs @@ -1,12 +1,12 @@ use super::MsgSendFn; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::Imp; -use crate::Encode; /// `objc_msgSend_stret` is not even available in arm64. /// /// -unsafe impl MsgSendFn for T { +unsafe impl MsgSendFn for T { const MSG_SEND: Imp = ffi::objc_msgSend; const MSG_SEND_SUPER: Imp = ffi::objc_msgSendSuper; } diff --git a/crates/objc2/src/message/apple/mod.rs b/crates/objc2/src/message/apple/mod.rs index 66a0c73f5..8fb13129c 100644 --- a/crates/objc2/src/message/apple/mod.rs +++ b/crates/objc2/src/message/apple/mod.rs @@ -1,4 +1,4 @@ -use crate::encode::Encode; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::{Class, Imp, Object, Sel}; use crate::MessageArguments; @@ -17,9 +17,9 @@ mod arch; mod arch; /// On the above architectures we can statically find the correct method to -/// call from the return type, by looking at its `Encode` implementation. +/// call from the return type, by looking at its `EncodeReturn` impl. #[allow(clippy::missing_safety_doc)] -unsafe trait MsgSendFn: Encode { +unsafe trait MsgSendFn: EncodeReturn { const MSG_SEND: Imp; const MSG_SEND_SUPER: Imp; } @@ -29,7 +29,7 @@ unsafe trait MsgSendFn: Encode { pub(crate) unsafe fn send_unverified(receiver: *mut Object, sel: Sel, args: A) -> R where A: MessageArguments, - R: Encode, + R: EncodeReturn, { let msg_send_fn = R::MSG_SEND; unsafe { conditional_try!(|| A::__invoke(msg_send_fn, receiver, sel, args)) } @@ -45,7 +45,7 @@ pub(crate) unsafe fn send_super_unverified( ) -> R where A: MessageArguments, - R: Encode, + R: EncodeReturn, { let superclass: *const Class = superclass; let mut sup = ffi::objc_super { diff --git a/crates/objc2/src/message/apple/x86.rs b/crates/objc2/src/message/apple/x86.rs index 3d67cad9a..ef5497413 100644 --- a/crates/objc2/src/message/apple/x86.rs +++ b/crates/objc2/src/message/apple/x86.rs @@ -1,19 +1,20 @@ use core::mem; use super::MsgSendFn; +use crate::encode::Encoding; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::Imp; -use crate::{Encode, Encoding}; /// Structures 1 or 2 bytes in size are placed in EAX. /// Structures 4 or 8 bytes in size are placed in: EAX and EDX. /// Structures of other sizes are placed at the address supplied by the caller. /// /// -unsafe impl MsgSendFn for T { +unsafe impl MsgSendFn for T { const MSG_SEND: Imp = { // See https://github.com/apple-oss-distributions/objc4/blob/objc4-818.2/runtime/message.h#L156-L172 - if let Encoding::Float | Encoding::Double | Encoding::LongDouble = T::ENCODING { + if let Encoding::Float | Encoding::Double | Encoding::LongDouble = T::ENCODING_RETURN { ffi::objc_msgSend_fpret } else if let 0 | 1 | 2 | 4 | 8 = mem::size_of::() { ffi::objc_msgSend diff --git a/crates/objc2/src/message/apple/x86_64.rs b/crates/objc2/src/message/apple/x86_64.rs index 4e2f153fd..5d4fb0d02 100644 --- a/crates/objc2/src/message/apple/x86_64.rs +++ b/crates/objc2/src/message/apple/x86_64.rs @@ -1,21 +1,22 @@ use core::mem; use super::MsgSendFn; +use crate::encode::Encoding; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::Imp; -use crate::{Encode, Encoding}; /// If the size of an object is larger than two eightbytes, it has class /// MEMORY. If the type has class MEMORY, then the caller provides space for /// the return value and passes the address of this storage. /// /// -unsafe impl MsgSendFn for T { +unsafe impl MsgSendFn for T { const MSG_SEND: Imp = { // See https://github.com/apple-oss-distributions/objc4/blob/objc4-818.2/runtime/message.h#L156-L172 - if let Encoding::LongDouble = T::ENCODING { + if let Encoding::LongDouble = T::ENCODING_RETURN { ffi::objc_msgSend_fpret - } else if let Encoding::LongDoubleComplex = T::ENCODING { + } else if let Encoding::LongDoubleComplex = T::ENCODING_RETURN { ffi::objc_msgSend_fp2ret } else if mem::size_of::() <= 16 { ffi::objc_msgSend diff --git a/crates/objc2/src/message/gnustep.rs b/crates/objc2/src/message/gnustep.rs index a73b85720..bbf65e4d9 100644 --- a/crates/objc2/src/message/gnustep.rs +++ b/crates/objc2/src/message/gnustep.rs @@ -1,7 +1,7 @@ use core::hint; use core::mem; -use crate::encode::Encode; +use crate::encode::__unstable::EncodeReturn; use crate::ffi; use crate::runtime::{Class, Imp, Object, Sel}; use crate::MessageArguments; @@ -24,7 +24,7 @@ fn unwrap_msg_send_fn(msg_send_fn: Option) -> Imp { pub(crate) unsafe fn send_unverified(receiver: *mut Object, sel: Sel, args: A) -> R where A: MessageArguments, - R: Encode, + R: EncodeReturn, { // If `receiver` is NULL, objc_msg_lookup will return a standard C-method // taking two arguments, the receiver and the selector. Transmuting and @@ -50,7 +50,7 @@ pub(crate) unsafe fn send_super_unverified( ) -> R where A: MessageArguments, - R: Encode, + R: EncodeReturn, { if receiver.is_null() { // SAFETY: Same as in `send_unverified`. diff --git a/crates/objc2/src/message/mod.rs b/crates/objc2/src/message/mod.rs index f057ea6f9..0c55cee4e 100644 --- a/crates/objc2/src/message/mod.rs +++ b/crates/objc2/src/message/mod.rs @@ -2,7 +2,10 @@ use core::mem; use core::mem::ManuallyDrop; use core::ptr::{self, NonNull}; -use crate::encode::{Encode, EncodeArguments, EncodeConvert, RefEncode}; +use crate::encode::__unstable::{ + EncodeArguments, EncodeConvertArgument, EncodeConvertReturn, EncodeReturn, +}; +use crate::encode::{Encode, RefEncode}; use crate::rc::{Id, Owned, Ownership, Shared}; use crate::runtime::{Class, Imp, Object, Sel}; use crate::ClassType; @@ -217,16 +220,16 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { unsafe fn send_message(self, sel: Sel, args: A) -> R where A: MessageArguments, - R: EncodeConvert, + R: EncodeConvertReturn, { let this = self.__as_raw_receiver(); #[cfg(debug_assertions)] { // SAFETY: Caller ensures only valid or NULL pointers. let obj = unsafe { this.as_ref() }; - msg_send_check(obj, sel, A::ENCODINGS, &R::__Inner::ENCODING); + msg_send_check(obj, sel, A::ENCODINGS, &R::__Inner::ENCODING_RETURN); } - unsafe { EncodeConvert::__from_inner(send_unverified(this, sel, args)) } + unsafe { EncodeConvertReturn::__from_inner(send_unverified(this, sel, args)) } } /// Sends a message to a specific superclass with the given selector and @@ -256,7 +259,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { unsafe fn send_super_message(self, superclass: &Class, sel: Sel, args: A) -> R where A: MessageArguments, - R: EncodeConvert, + R: EncodeConvertReturn, { let this = self.__as_raw_receiver(); #[cfg(debug_assertions)] @@ -268,7 +271,9 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { panic_verify(superclass, sel, err); } } - unsafe { EncodeConvert::__from_inner(send_super_unverified(this, superclass, sel, args)) } + unsafe { + EncodeConvertReturn::__from_inner(send_super_unverified(this, superclass, sel, args)) + } } #[inline] @@ -279,7 +284,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { Self::__Inner: ClassType, ::Super: ClassType, A: MessageArguments, - R: EncodeConvert, + R: EncodeConvertReturn, { unsafe { self.send_super_message(::Super::class(), sel, args) } } @@ -482,7 +487,7 @@ pub unsafe trait MessageArguments: EncodeArguments { /// be called directly; instead, use the `msg_send!` macro or, in cases /// with a dynamic selector, the [`MessageReceiver::send_message`] method. #[doc(hidden)] - unsafe fn __invoke(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R; + unsafe fn __invoke(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R; } pub trait __TupleExtender { @@ -494,9 +499,9 @@ pub trait __TupleExtender { macro_rules! message_args_impl { ($($a:ident: $t:ident),*) => ( - unsafe impl<$($t: EncodeConvert),*> MessageArguments for ($($t,)*) { + unsafe impl<$($t: EncodeConvertArgument),*> MessageArguments for ($($t,)*) { #[inline] - unsafe fn __invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R { + unsafe fn __invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R { // The imp must be cast to the appropriate function pointer // type before being called; the msgSend functions are not // parametric, but instead "trampolines" to the actual @@ -512,7 +517,7 @@ macro_rules! message_args_impl { // TODO: On x86_64 it would be more efficient to use a GOT // entry here (e.g. adding `nonlazybind` in LLVM). // Same can be said of e.g. `objc_retain` and `objc_release`. - unsafe { imp(obj, sel $(, EncodeConvert::__into_inner($a))*) } + unsafe { imp(obj, sel $(, EncodeConvertArgument::__into_inner($a))*) } } } diff --git a/crates/objc2/src/runtime.rs b/crates/objc2/src/runtime.rs index 4e1d77744..802fe5db3 100644 --- a/crates/objc2/src/runtime.rs +++ b/crates/objc2/src/runtime.rs @@ -27,7 +27,8 @@ mod nsobject; mod nszone; pub(crate) use self::method_encoding_iter::{EncodingParseError, MethodEncodingIter}; -use crate::encode::{Encode, EncodeArguments, EncodeConvert, Encoding, OptionEncode, RefEncode}; +use crate::encode::__unstable::{EncodeArguments, EncodeConvertReturn, EncodeReturn}; +use crate::encode::{Encode, Encoding, OptionEncode, RefEncode}; use crate::ffi; use crate::verify::{verify_method_signature, Inner, VerificationError}; @@ -624,10 +625,10 @@ impl Class { pub fn verify_sel(&self, sel: Sel) -> Result<(), VerificationError> where A: EncodeArguments, - R: EncodeConvert, + R: EncodeConvertReturn, { let method = self.instance_method(sel).ok_or(Inner::MethodNotFound)?; - verify_method_signature(method, A::ENCODINGS, &R::__Inner::ENCODING) + verify_method_signature(method, A::ENCODINGS, &R::__Inner::ENCODING_RETURN) } } diff --git a/crates/objc2/src/runtime/bool.rs b/crates/objc2/src/runtime/bool.rs index a1ca8d6db..c649168ea 100644 --- a/crates/objc2/src/runtime/bool.rs +++ b/crates/objc2/src/runtime/bool.rs @@ -137,7 +137,7 @@ unsafe impl RefEncode for Bool { #[cfg(test)] mod tests { use super::*; - use crate::encode::EncodeConvert; + use crate::encode::__unstable::{EncodeConvertArgument, EncodeConvertReturn}; use alloc::format; #[test] @@ -175,8 +175,12 @@ mod tests { assert_eq!(bool::__ENCODING, Encoding::Bool); assert_eq!( - ::__Inner::__ENCODING, - ::__Inner::ENCODING + ::__Inner::__ENCODING, + ::__Inner::ENCODING + ); + assert_eq!( + ::__Inner::__ENCODING, + ::__Inner::ENCODING ); } diff --git a/crates/test-ui/ui/add_method_no_bool.stderr b/crates/test-ui/ui/add_method_no_bool.stderr index 3fa1f8492..613ef457d 100644 --- a/crates/test-ui/ui/add_method_no_bool.stderr +++ b/crates/test-ui/ui/add_method_no_bool.stderr @@ -9,12 +9,12 @@ error[E0277]: the trait bound `bool: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others = note: required for `unsafe extern "C" fn(&objc2::runtime::Object, objc2::runtime::Sel, bool)` to implement `MethodImplementation` note: required by a bound in `ClassBuilder::add_method` @@ -34,13 +34,14 @@ error[E0277]: the trait bound `bool: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others + = note: required for `bool` to implement `EncodeReturn` = note: required for `unsafe extern "C" fn(&objc2::runtime::Object, objc2::runtime::Sel) -> bool` to implement `MethodImplementation` note: required by a bound in `ClassBuilder::add_method` --> $WORKSPACE/crates/objc2/src/declare.rs diff --git a/crates/test-ui/ui/declare_class_invalid_type.stderr b/crates/test-ui/ui/declare_class_invalid_type.stderr index 5b4898669..d5c5efdf5 100644 --- a/crates/test-ui/ui/declare_class_invalid_type.stderr +++ b/crates/test-ui/ui/declare_class_invalid_type.stderr @@ -13,19 +13,20 @@ error[E0277]: the trait bound `Id: Encode` is not satisfie = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Id` to implement `encode::convert_private::Sealed` -note: required by a bound in `EncodeConvert` - --> $WORKSPACE/crates/objc2/src/encode.rs + = note: required for `Id` to implement `EncodeReturn` + = note: required for `Id` to implement `__unstable::convert_private::Sealed` +note: required by a bound in `EncodeConvertReturn` + --> $WORKSPACE/crates/objc2/src/encode/__unstable.rs | - | pub trait EncodeConvert: convert_private::Sealed { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvert` + | pub trait EncodeConvertReturn: convert_private::Sealed { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvertReturn` = note: this error originates in the macro `$crate::__declare_class_method_out_inner` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Vec<()>: Encode` is not satisfied @@ -43,19 +44,20 @@ error[E0277]: the trait bound `Vec<()>: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Vec<()>` to implement `encode::convert_private::Sealed` -note: required by a bound in `EncodeConvert` - --> $WORKSPACE/crates/objc2/src/encode.rs + = note: required for `Vec<()>` to implement `EncodeReturn` + = note: required for `Vec<()>` to implement `__unstable::convert_private::Sealed` +note: required by a bound in `EncodeConvertReturn` + --> $WORKSPACE/crates/objc2/src/encode/__unstable.rs | - | pub trait EncodeConvert: convert_private::Sealed { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvert` + | pub trait EncodeConvertReturn: convert_private::Sealed { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvertReturn` = note: this error originates in the macro `$crate::__declare_class_method_out_inner` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Box: Encode` is not satisfied @@ -73,19 +75,14 @@ error[E0277]: the trait bound `Box: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Box` to implement `encode::convert_private::Sealed` -note: required by a bound in `EncodeConvert` - --> $WORKSPACE/crates/objc2/src/encode.rs - | - | pub trait EncodeConvert: convert_private::Sealed { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvert` + = note: required for `Box` to implement `EncodeConvertArgument` = note: this error originates in the macro `$crate::__declare_class_rewrite_args` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `CustomObject: Encode` is not satisfied @@ -103,17 +100,12 @@ error[E0277]: the trait bound `CustomObject: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `CustomObject` to implement `encode::convert_private::Sealed` -note: required by a bound in `EncodeConvert` - --> $WORKSPACE/crates/objc2/src/encode.rs - | - | pub trait EncodeConvert: convert_private::Sealed { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EncodeConvert` + = note: required for `CustomObject` to implement `EncodeConvertArgument` = note: this error originates in the macro `$crate::__declare_class_rewrite_args` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/test-ui/ui/declare_class_invalid_type3.rs b/crates/test-ui/ui/declare_class_invalid_type3.rs new file mode 100644 index 000000000..643cb9002 --- /dev/null +++ b/crates/test-ui/ui/declare_class_invalid_type3.rs @@ -0,0 +1,18 @@ +use objc2::declare::IvarEncode; +use objc2::runtime::NSObject; +use objc2::{declare_class, ClassType}; + +declare_class!( + struct CustomObject { + field: IvarEncode<(), "_field">, + } + + mod ivars; + + unsafe impl ClassType for CustomObject { + type Super = NSObject; + const NAME: &'static str = "CustomObject"; + } +); + +fn main() {} diff --git a/crates/test-ui/ui/declare_class_invalid_type3.stderr b/crates/test-ui/ui/declare_class_invalid_type3.stderr new file mode 100644 index 000000000..a92956472 --- /dev/null +++ b/crates/test-ui/ui/declare_class_invalid_type3.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `(): Encode` is not satisfied + --> ui/declare_class_invalid_type3.rs + | + | / declare_class!( + | | struct CustomObject { + | | field: IvarEncode<(), "_field">, + | | } +... | + | | } + | | ); + | |_^ the trait `Encode` is not implemented for `()` + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `objc2::declare::IvarEncode<()>` to implement `InnerIvarType` +note: required by a bound in `objc2::declare::IvarType::Type` + --> $WORKSPACE/crates/objc2/src/declare/ivar.rs + | + | type Type: InnerIvarType; + | ^^^^^^^^^^^^^ required by this bound in `IvarType::Type` + = note: this error originates in the macro `$crate::__parse_fields` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/test-ui/ui/extern_methods_invalid_type.stderr b/crates/test-ui/ui/extern_methods_invalid_type.stderr index 705b330ff..c9385dd95 100644 --- a/crates/test-ui/ui/extern_methods_invalid_type.stderr +++ b/crates/test-ui/ui/extern_methods_invalid_type.stderr @@ -12,19 +12,20 @@ error[E0277]: the trait bound `Id: Encode` is not sa = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Id` to implement `EncodeConvert` + = note: required for `Id` to implement `EncodeReturn` + = note: required for `Id` to implement `EncodeConvertReturn` note: required by a bound in `send_message` --> $WORKSPACE/crates/objc2/src/message/mod.rs | - | R: EncodeConvert, - | ^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + | R: EncodeConvertReturn, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `i32: MaybeUnwrap` is not satisfied @@ -87,19 +88,20 @@ error[E0277]: the trait bound `Result<(), Id>: Encode` is not = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Result<(), Id>` to implement `EncodeConvert` + = note: required for `Result<(), Id>` to implement `EncodeReturn` + = note: required for `Result<(), Id>` to implement `EncodeConvertReturn` note: required by a bound in `send_message` --> $WORKSPACE/crates/objc2/src/message/mod.rs | - | R: EncodeConvert, - | ^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + | R: EncodeConvertReturn, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Result, Id>: MaybeUnwrap` is not satisfied diff --git a/crates/test-ui/ui/global_block_not_encode.stderr b/crates/test-ui/ui/global_block_not_encode.stderr index 624e0beb6..9784e83d6 100644 --- a/crates/test-ui/ui/global_block_not_encode.stderr +++ b/crates/test-ui/ui/global_block_not_encode.stderr @@ -9,12 +9,12 @@ error[E0277]: the trait bound `Box: objc2::encode::Encode` is not satisfied = help: the following other types implement trait `objc2::encode::Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others = note: required for `(Box,)` to implement `BlockArguments` = note: required for `GlobalBlock<(Box,)>` to implement `Sync` diff --git a/crates/test-ui/ui/msg_send_not_encode.rs b/crates/test-ui/ui/msg_send_not_encode.rs index 33587a7ac..d7500d3f9 100644 --- a/crates/test-ui/ui/msg_send_not_encode.rs +++ b/crates/test-ui/ui/msg_send_not_encode.rs @@ -8,5 +8,7 @@ fn main() { let x: Vec; let _: () = msg_send![cls, newWith: x]; + + let _: () = msg_send![cls, unitAsArgument: ()]; } } diff --git a/crates/test-ui/ui/msg_send_not_encode.stderr b/crates/test-ui/ui/msg_send_not_encode.stderr index 917bb2d87..9516455e0 100644 --- a/crates/test-ui/ui/msg_send_not_encode.stderr +++ b/crates/test-ui/ui/msg_send_not_encode.stderr @@ -7,19 +7,20 @@ error[E0277]: the trait bound `Vec: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Vec` to implement `EncodeConvert` + = note: required for `Vec` to implement `EncodeReturn` + = note: required for `Vec` to implement `EncodeConvertReturn` note: required by a bound in `send_message` --> $WORKSPACE/crates/objc2/src/message/mod.rs | - | R: EncodeConvert, - | ^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + | R: EncodeConvertReturn, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Vec: Encode` is not satisfied @@ -34,14 +35,14 @@ error[E0277]: the trait bound `Vec: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 and $N others - = note: required for `Vec` to implement `EncodeConvert` + = note: required for `Vec` to implement `EncodeConvertArgument` = note: required for `(Vec,)` to implement `MessageArguments` note: required by a bound in `send_message` --> $WORKSPACE/crates/objc2/src/message/mod.rs @@ -49,3 +50,31 @@ note: required by a bound in `send_message` | A: MessageArguments, | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `(): Encode` is not satisfied + --> ui/msg_send_not_encode.rs + | + | let _: () = msg_send![cls, unitAsArgument: ()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `Encode` is not implemented for `()` + | required by a bound introduced by this call + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `()` to implement `EncodeConvertArgument` + = note: required for `((),)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/test-ui/ui/not_encode.rs b/crates/test-ui/ui/not_encode.rs index 921336e26..8f745340d 100644 --- a/crates/test-ui/ui/not_encode.rs +++ b/crates/test-ui/ui/not_encode.rs @@ -3,19 +3,23 @@ use core::ffi::c_void; use objc2::encode::Encode; use objc2::runtime::Sel; +use block2::Block; fn is_encode() {} fn main() { is_encode::>(); - is_encode::<()>(); // TODO: Make this fail as well + is_encode::<()>(); is_encode::<&()>(); is_encode::<*const ()>(); is_encode::(); is_encode::<&c_void>(); + is_encode::<&Block<((), i32), ()>>(); is_encode:: &'static ()>(); + is_encode::(); + is_encode::(); is_encode::<&Sel>(); } diff --git a/crates/test-ui/ui/not_encode.stderr b/crates/test-ui/ui/not_encode.stderr index 06830f3e1..c5a4e860c 100644 --- a/crates/test-ui/ui/not_encode.stderr +++ b/crates/test-ui/ui/not_encode.stderr @@ -7,12 +7,34 @@ error[E0277]: the trait bound `Vec: Encode` is not satisfied = help: the following other types implement trait `Encode`: &'a T &'a mut T - () *const T *const c_void *mut T *mut c_void AtomicI16 + AtomicI32 + and $N others +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `(): Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<()>(); + | ^^ the trait `Encode` is not implemented for `()` + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 and $N others note: required by a bound in `is_encode` --> ui/not_encode.rs @@ -26,17 +48,22 @@ error[E0277]: the trait bound `(): RefEncode` is not satisfied | is_encode::<&()>(); | ^^^ the trait `RefEncode` is not implemented for `()` | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others = note: required for `&()` to implement `Encode` note: required by a bound in `is_encode` --> ui/not_encode.rs | | fn is_encode() {} | ^^^^^^ required by this bound in `is_encode` -help: consider removing the leading `&`-reference - | -13 - is_encode::<&()>(); -13 + is_encode::<()>(); - | error[E0277]: the trait bound `(): RefEncode` is not satisfied --> ui/not_encode.rs @@ -92,6 +119,31 @@ note: required by a bound in `is_encode` | fn is_encode() {} | ^^^^^^ required by this bound in `is_encode` +error[E0277]: the trait bound `(): Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::<&Block<((), i32), ()>>(); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `()` + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `((), i32)` to implement `BlockArguments` + = note: required for `block2::Block<((), i32), ()>` to implement `RefEncode` + = note: required for `&block2::Block<((), i32), ()>` to implement `Encode` +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + error[E0277]: the trait bound `fn() -> &'static (): Encode` is not satisfied --> ui/not_encode.rs | @@ -114,6 +166,50 @@ note: required by a bound in `is_encode` | fn is_encode() {} | ^^^^^^ required by this bound in `is_encode` +error[E0277]: the trait bound `fn(()): Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::(); + | ^^^^^^ the trait `Encode` is not implemented for `fn(())` + | + = help: the following other types implement trait `Encode`: + extern "C" fn() -> Ret + extern "C" fn(A) -> Ret + extern "C" fn(A, ...) -> Ret + extern "C" fn(A, B) -> Ret + extern "C" fn(A, B, ...) -> Ret + extern "C" fn(A, B, C) -> Ret + extern "C" fn(A, B, C, ...) -> Ret + extern "C" fn(A, B, C, D) -> Ret + and $N others +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + +error[E0277]: the trait bound `fn(i32, ()): Encode` is not satisfied + --> ui/not_encode.rs + | + | is_encode::(); + | ^^^^^^^^^^^ the trait `Encode` is not implemented for `fn(i32, ())` + | + = help: the following other types implement trait `Encode`: + extern "C" fn() -> Ret + extern "C" fn(A) -> Ret + extern "C" fn(A, ...) -> Ret + extern "C" fn(A, B) -> Ret + extern "C" fn(A, B, ...) -> Ret + extern "C" fn(A, B, C) -> Ret + extern "C" fn(A, B, C, ...) -> Ret + extern "C" fn(A, B, C, D) -> Ret + and $N others +note: required by a bound in `is_encode` + --> ui/not_encode.rs + | + | fn is_encode() {} + | ^^^^^^ required by this bound in `is_encode` + error[E0277]: the trait bound `objc2::runtime::Sel: RefEncode` is not satisfied --> ui/not_encode.rs | @@ -128,6 +224,6 @@ note: required by a bound in `is_encode` | ^^^^^^ required by this bound in `is_encode` help: consider removing the leading `&`-reference | -20 - is_encode::<&Sel>(); -20 + is_encode::(); +24 - is_encode::<&Sel>(); +24 + is_encode::(); | From 21b2952f66e8c0f032c68c460fd24b6c2ae01948 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 1 Feb 2023 00:59:13 +0100 Subject: [PATCH 4/5] Add support for out parameters like `&mut Id<_, _>` in `msg_send!` Supported types: - `&mut Id<_, _>` - `&mut Option>` - `Option<&mut Id<_, _>>` - `Option<&mut Option>>` --- Cargo.lock | 14 + Cargo.toml | 3 + crates/objc2/CHANGELOG.md | 2 + crates/objc2/src/__macro_helpers.rs | 10 +- .../objc2/src/declare/declare_class_tests.rs | 68 +++ crates/objc2/src/encode/__unstable.rs | 131 +++-- crates/objc2/src/macros.rs | 88 ++- crates/objc2/src/macros/declare_class.rs | 11 +- crates/objc2/src/message/mod.rs | 19 +- crates/objc2/src/rc/id.rs | 2 +- crates/objc2/src/rc/mod.rs | 1 + crates/objc2/src/rc/test_object.rs | 7 + crates/objc2/src/rc/writeback.rs | 343 +++++++++++ .../crates/test_msg_send_error/Cargo.toml | 25 + .../expected/apple-aarch64.s | 257 ++++++++ .../expected/apple-armv7.s | 262 +++++++++ .../expected/apple-armv7s.s | 262 +++++++++ .../test_msg_send_error/expected/apple-x86.s | 338 +++++++++++ .../expected/apple-x86_64.s | 238 ++++++++ .../expected/gnustep-x86.s | 435 ++++++++++++++ .../expected/gnustep-x86_64.s | 336 +++++++++++ .../crates/test_msg_send_error/lib.rs | 37 ++ .../test_msg_send_id/expected/apple-aarch64.s | 24 + .../test_msg_send_id/expected/apple-armv7.s | 21 + .../test_msg_send_id/expected/apple-armv7s.s | 21 + .../test_msg_send_id/expected/apple-x86.s | 37 ++ .../test_msg_send_id/expected/apple-x86_64.s | 31 + .../test_msg_send_id/expected/gnustep-x86.s | 44 ++ .../expected/gnustep-x86_64.s | 34 ++ .../crates/test_msg_send_id/lib.rs | 10 + .../crates/test_out_parameters/Cargo.toml | 25 + .../expected/apple-aarch64.s | 246 ++++++++ .../expected/apple-armv7.s | 227 ++++++++ .../expected/apple-armv7s.s | 235 ++++++++ .../test_out_parameters/expected/apple-x86.s | 386 ++++++++++++ .../expected/apple-x86_64.s | 287 +++++++++ .../expected/gnustep-x86.s | 551 ++++++++++++++++++ .../expected/gnustep-x86_64.s | 416 +++++++++++++ .../crates/test_out_parameters/lib.rs | 87 +++ crates/test-assembly/src/lib.rs | 7 +- crates/test-ui/ui/not_writeback.rs | 26 + crates/test-ui/ui/not_writeback.stderr | 172 ++++++ 42 files changed, 5696 insertions(+), 80 deletions(-) create mode 100644 crates/objc2/src/rc/writeback.rs create mode 100644 crates/test-assembly/crates/test_msg_send_error/Cargo.toml create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/apple-aarch64.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7s.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/apple-x86.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/apple-x86_64.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86_64.s create mode 100644 crates/test-assembly/crates/test_msg_send_error/lib.rs create mode 100644 crates/test-assembly/crates/test_out_parameters/Cargo.toml create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s create mode 100644 crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s create mode 100644 crates/test-assembly/crates/test_out_parameters/lib.rs create mode 100644 crates/test-ui/ui/not_writeback.rs create mode 100644 crates/test-ui/ui/not_writeback.stderr diff --git a/Cargo.lock b/Cargo.lock index 8a21c7dae..19542280e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -438,6 +438,13 @@ dependencies = [ "objc2", ] +[[package]] +name = "test_msg_send_error" +version = "0.1.0" +dependencies = [ + "objc2", +] + [[package]] name = "test_msg_send_id" version = "0.1.0" @@ -466,6 +473,13 @@ dependencies = [ "icrate", ] +[[package]] +name = "test_out_parameters" +version = "0.1.0" +dependencies = [ + "objc2", +] + [[package]] name = "test_retain_autoreleased" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 795c2fd0b..06d745801 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ resolver = "2" inherits = "release" # Enable LTO to allow testing the `unstable-static-sel-inlined` feature lto = true +# Don't emit unwind info; while important to get right, the control flow is +# very hard to glean from assembly output. +panic = "abort" diff --git a/crates/objc2/CHANGELOG.md b/crates/objc2/CHANGELOG.md index e6c5b1018..5e21d523f 100644 --- a/crates/objc2/CHANGELOG.md +++ b/crates/objc2/CHANGELOG.md @@ -20,6 +20,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * **BREAKING**: Moved the `objc2_encode` traits to `objc2::encode`. This includes removing the `EncodeConvert` and `EncodeArguments` traits. +* Added support for out-parameters like `&mut Id<_, _>` in `msg_send!`, + `msg_send_id!` and `extern_methods!`. ### Changed * **BREAKING**: Using the automatic `NSError**`-to-`Result` functionality in diff --git a/crates/objc2/src/__macro_helpers.rs b/crates/objc2/src/__macro_helpers.rs index 1c6fb3911..0b9119012 100644 --- a/crates/objc2/src/__macro_helpers.rs +++ b/crates/objc2/src/__macro_helpers.rs @@ -138,15 +138,15 @@ pub trait MsgSendId { if let Some(res) = res { // In this case, the error is likely not created. If it is, it is // autoreleased anyhow, so it would be a waste to retain and - // release it. + // release it here. Ok(res) } else { // In this case, the error has very likely been created, but has - // been autoreleased (as is common for "out parameters"). Hence we - // need to retain it if we want it to live across autorelease - // pools. + // been autoreleased (as is common for "out parameters", see + // `src/rc/writeback.rs`). Hence we need to retain it if we want + // it to live across autorelease pools. // - // SAFETY: The closure `f` is guaranteed to populate the error + // SAFETY: The message send is guaranteed to populate the error // object, or leave it as NULL. The error is shared, and all // holders of the error know this, so is safe to retain. Err(unsafe { encountered_error(err) }) diff --git a/crates/objc2/src/declare/declare_class_tests.rs b/crates/objc2/src/declare/declare_class_tests.rs index 5ee050ebf..c075a9b47 100644 --- a/crates/objc2/src/declare/declare_class_tests.rs +++ b/crates/objc2/src/declare/declare_class_tests.rs @@ -443,3 +443,71 @@ fn test_subclass_duplicate_ivar() { let ivar_dynamically = unsafe { obj.ivar::("ivar") }; assert_eq!(*ivar_dynamically, 3); } + +declare_class!( + struct OutParam; + + unsafe impl ClassType for OutParam { + type Super = NSObject; + const NAME: &'static str = "OutParam"; + } + + unsafe impl OutParam { + #[method(unsupported1:)] + fn _unsupported1(_param: &mut Id) {} + + #[method(unsupported2:)] + fn _unsupported2(_param: Option<&mut Id>) {} + + #[method(unsupported3:)] + fn _unsupported3(_param: &mut Option>) {} + + #[method(unsupported4:)] + fn _unsupported4(_param: Option<&mut Option>>) {} + } +); + +extern_methods!( + unsafe impl OutParam { + #[method_id(new)] + fn new() -> Id; + + #[method(unsupported1:)] + fn unsupported1(_param: &mut Id); + + #[method(unsupported2:)] + fn unsupported2(_param: Option<&mut Id>); + + #[method(unsupported3:)] + fn unsupported3(_param: &mut Option>); + + #[method(unsupported4:)] + fn unsupported4(_param: Option<&mut Option>>); + } +); + +#[test] +#[should_panic = "`&mut Id<_, _>` is not supported in `declare_class!` yet"] +fn out_param1() { + let mut param = OutParam::new(); + OutParam::unsupported1(&mut param); +} + +#[test] +#[should_panic = "`Option<&mut Id<_, _>>` is not supported in `declare_class!` yet"] +fn out_param2() { + OutParam::unsupported2(None); +} + +#[test] +#[should_panic = "`&mut Option>` is not supported in `declare_class!` yet"] +fn out_param3() { + let mut param = Some(OutParam::new()); + OutParam::unsupported3(&mut param); +} + +#[test] +#[should_panic = "`Option<&mut Option>>` is not supported in `declare_class!` yet"] +fn out_param4() { + OutParam::unsupported4(None); +} diff --git a/crates/objc2/src/encode/__unstable.rs b/crates/objc2/src/encode/__unstable.rs index 620430e0a..9244806cb 100644 --- a/crates/objc2/src/encode/__unstable.rs +++ b/crates/objc2/src/encode/__unstable.rs @@ -18,7 +18,9 @@ )] use crate::encode::{Encode, Encoding}; +use crate::rc::{Id, Ownership}; use crate::runtime::Bool; +use crate::Message; mod return_private { pub trait Sealed {} @@ -28,18 +30,18 @@ mod return_private { /// /// We currently don't need a similar `EncodeArgument` trait, but we might in /// the future. -pub unsafe trait EncodeReturn: return_private::Sealed { +pub trait EncodeReturn: return_private::Sealed { /// The Objective-C type-encoding for this type. const ENCODING_RETURN: Encoding; } impl return_private::Sealed for () {} -unsafe impl EncodeReturn for () { +impl EncodeReturn for () { const ENCODING_RETURN: Encoding = Encoding::Void; } impl return_private::Sealed for T {} -unsafe impl EncodeReturn for T { +impl EncodeReturn for T { const ENCODING_RETURN: Encoding = T::ENCODING; } @@ -50,75 +52,95 @@ mod convert_private { impl convert_private::Sealed for T {} impl convert_private::Sealed for bool {} +// Implemented in rc/writeback.rs +impl convert_private::Sealed for &mut Id {} +impl convert_private::Sealed for Option<&mut Id> {} +impl convert_private::Sealed for &mut Option> {} +impl convert_private::Sealed for Option<&mut Option>> {} + /// Represents types that can easily be converted to/from an [`Encode`] type. /// /// This is implemented specially for [`bool`] to allow using that as /// Objective-C `BOOL`, where it would otherwise not be allowed (since they /// are not ABI compatible). +/// +/// This is also done specially for `&mut Id<_, _>`-like arguments, to allow +/// using those as "out" parameters. pub trait EncodeConvertArgument: convert_private::Sealed { /// The inner type that this can be converted to and from. #[doc(hidden)] type __Inner: Encode; + /// A helper type for out parameters. + #[doc(hidden)] + type __StoredBeforeMessage: Sized; + #[doc(hidden)] - fn __from_inner(inner: Self::__Inner) -> Self; + fn __from_declared_param(inner: Self::__Inner) -> Self; #[doc(hidden)] - fn __into_inner(self) -> Self::__Inner; + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage); + + #[doc(hidden)] + unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage) {} +} + +/// Same as [`EncodeConvertArgument`], but for return types. +pub trait EncodeConvertReturn: convert_private::Sealed { + /// The inner type that this can be converted to and from. + #[doc(hidden)] + type __Inner: EncodeReturn; + + #[doc(hidden)] + fn __into_declared_return(self) -> Self::__Inner; + + #[doc(hidden)] + fn __from_return(inner: Self::__Inner) -> Self; } impl EncodeConvertArgument for T { type __Inner = Self; + type __StoredBeforeMessage = (); + #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { + fn __from_declared_param(inner: Self::__Inner) -> Self { inner } #[inline] - fn __into_inner(self) -> Self::__Inner { - self + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + (self, ()) } } -impl EncodeConvertArgument for bool { - type __Inner = Bool; +impl EncodeConvertReturn for T { + type __Inner = Self; #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { - inner.as_bool() + fn __into_declared_return(self) -> Self::__Inner { + self } #[inline] - fn __into_inner(self) -> Self::__Inner { - Bool::new(self) + fn __from_return(inner: Self::__Inner) -> Self { + inner } } -/// Same as [`EncodeConvertArgument`], but for return types. -pub trait EncodeConvertReturn: convert_private::Sealed { - /// The inner type that this can be converted to and from. - #[doc(hidden)] - type __Inner: EncodeReturn; - - #[doc(hidden)] - fn __from_inner(inner: Self::__Inner) -> Self; - - #[doc(hidden)] - fn __into_inner(self) -> Self::__Inner; -} +impl EncodeConvertArgument for bool { + type __Inner = Bool; -impl EncodeConvertReturn for T { - type __Inner = Self; + type __StoredBeforeMessage = (); #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { - inner + fn __from_declared_param(inner: Self::__Inner) -> Self { + inner.as_bool() } #[inline] - fn __into_inner(self) -> Self::__Inner { - self + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + (Bool::new(self), ()) } } @@ -126,13 +148,13 @@ impl EncodeConvertReturn for bool { type __Inner = Bool; #[inline] - fn __from_inner(inner: Self::__Inner) -> Self { - inner.as_bool() + fn __into_declared_return(self) -> Self::__Inner { + Bool::new(self) } #[inline] - fn __into_inner(self) -> Self::__Inner { - Bool::new(self) + fn __from_return(inner: Self::__Inner) -> Self { + inner.as_bool() } } @@ -149,7 +171,7 @@ mod args_private { /// /// Note that tuples themselves don't implement [`Encode`] directly, because /// they're not FFI-safe! -pub unsafe trait EncodeArguments: args_private::Sealed { +pub trait EncodeArguments: args_private::Sealed { /// The encodings for the arguments. const ENCODINGS: &'static [Encoding]; } @@ -158,7 +180,7 @@ macro_rules! encode_args_impl { ($($Arg: ident),*) => { impl<$($Arg: EncodeConvertArgument),*> args_private::Sealed for ($($Arg,)*) {} - unsafe impl<$($Arg: EncodeConvertArgument),*> EncodeArguments for ($($Arg,)*) { + impl<$($Arg: EncodeConvertArgument),*> EncodeArguments for ($($Arg,)*) { const ENCODINGS: &'static [Encoding] = &[ // T::__Inner::ENCODING => T::ENCODING // bool::__Inner::ENCODING => Bool::ENCODING @@ -204,8 +226,11 @@ mod tests { TypeId::of::<::__Inner>(), TypeId::of::() ); - assert_eq!(::__from_inner(42), 42); - assert_eq!(EncodeConvertArgument::__into_inner(42i32), 42); + assert_eq!( + ::__from_declared_param(42), + 42 + ); + assert_eq!(EncodeConvertArgument::__into_argument(42i32).0, 42); } #[test] @@ -214,21 +239,25 @@ mod tests { TypeId::of::<::__Inner>(), TypeId::of::() ); - assert_eq!(::__from_inner(-3), -3); - assert_eq!(EncodeConvertArgument::__into_inner(-3i32), -3); + assert_eq!(::__from_declared_param(-3), -3); + assert_eq!(EncodeConvertArgument::__into_argument(-3i32).0, -3); } #[test] fn convert_bool() { - assert!(!::__from_inner(Bool::NO)); - assert!(::__from_inner(Bool::YES)); - assert!(!::__from_inner(Bool::NO)); - assert!(::__from_inner(Bool::YES)); - - assert!(!EncodeConvertArgument::__into_inner(false).as_bool()); - assert!(EncodeConvertArgument::__into_inner(true).as_bool()); - assert!(!EncodeConvertReturn::__into_inner(false).as_bool()); - assert!(EncodeConvertReturn::__into_inner(true).as_bool()); + assert!(!::__from_declared_param( + Bool::NO + )); + assert!(::__from_declared_param( + Bool::YES + )); + assert!(!::__from_return(Bool::NO)); + assert!(::__from_return(Bool::YES)); + + assert!(!EncodeConvertArgument::__into_argument(false).0.as_bool()); + assert!(EncodeConvertArgument::__into_argument(true).0.as_bool()); + assert!(!EncodeConvertReturn::__into_declared_return(false).as_bool()); + assert!(EncodeConvertReturn::__into_declared_return(true).as_bool()); #[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))] assert_eq!( diff --git a/crates/objc2/src/macros.rs b/crates/objc2/src/macros.rs index f94b148f7..69a7b12b9 100644 --- a/crates/objc2/src/macros.rs +++ b/crates/objc2/src/macros.rs @@ -761,24 +761,46 @@ macro_rules! __class_inner { /// [`runtime::Bool`]: crate::runtime::Bool /// /// +/// # Out-parameters +/// +/// Parameters like `NSString**` in Objective-C are passed by "writeback", +/// which essentially just means that the callee autoreleases any value that +/// they may write into the parameter. +/// +/// This macro has support for passing such parameters using the following +/// types: +/// - `&mut Id<_, _>` +/// - `Option<&mut Id<_, _>>` +/// - `&mut Option>`, +/// - `Option<&mut Option>>` +/// +/// Beware with the first two, since they will cause undefined behaviour if +/// the method overwrites the value with `nil`. +/// +/// See [clang's documentation][clang-out-params] for more details. +/// +/// [clang-out-params]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#passing-to-an-out-parameter-by-writeback +/// +/// /// # Errors /// -/// Many methods take an `NSError**` as their last parameter, which is used to -/// communicate errors to the caller, see [Error Handling Programming Guide -/// For Cocoa][cocoa-error]. +/// The most common place you'll see out-parameters is as `NSError**` the last +/// parameter, which is used to communicate errors to the caller, see [Error +/// Handling Programming Guide For Cocoa][cocoa-error]. /// /// Similar to Swift's [importing of error parameters][swift-error], this -/// macro supports transforming methods whose last parameter is `NSError**` -/// and returns `BOOL`, into the Rust equivalent, the [`Result`] type. +/// macro supports an even more convenient version than the out-parameter +/// support, which transforms methods whose last parameter is `NSError**` and +/// returns `BOOL`, into the Rust equivalent, the [`Result`] type. /// -/// In particular, you can make the last argument the special marker `_`, and -/// then the macro will return a `Result<(), Id>` (where you must +/// In particular, if you make the last argument the special marker `_`, then +/// the macro will return a `Result<(), Id>` (where you must /// specify `E` yourself, usually you'd use `icrate::Foundation::NSError`). /// -/// At runtime, a temporary error variable is created on the stack and sent as -/// the last parameter. If the message send then returns `NO`/`false` (or in -/// the case of `msg_send_id!`, `NULL`), the error variable is loaded and -/// returned in [`Err`]. +/// At runtime, we create the temporary error variable for you on the stack +/// and send it as the out-parameter to the method. If the method then returns +/// `NO`/`false` (or in the case of `msg_send_id!`, `NULL`), the error +/// variable is loaded and returned in [`Err`]. /// /// Do beware that this is only valid on methods that return `BOOL`, see /// [`msg_send_id!`] for methods that return instance types. @@ -834,7 +856,11 @@ macro_rules! __class_inner { /// may not be valid outside of an [`autoreleasepool`] ([`msg_send_id!`] /// can greatly help with that). /// -/// 8. TODO: Maybe more? +/// 8. Each out-parameter must have the correct nullability, and the method +/// must not have any attributes that changes the how it handles memory +/// management for these. +/// +/// 9. TODO: Maybe more? /// /// [`autoreleasepool`]: crate::rc::autoreleasepool /// [`msg_send_id!`]: crate::msg_send_id @@ -898,16 +924,46 @@ macro_rules! __class_inner { /// /// ```no_run /// use objc2::msg_send; -/// use objc2::runtime::Object; /// use objc2::rc::{Id, Shared}; /// -/// let obj: *mut Object; // Let's assume an instance of `NSBundle` -/// # obj = 0 as *mut Object; +/// # type NSBundle = objc2::runtime::Object; +/// # type NSError = objc2::runtime::Object; +/// let obj: &NSBundle; +/// # obj = todo!(); /// // The `_` tells the macro that the return type should be `Result`. -/// let res: Result<(), Id> = unsafe { +/// let res: Result<(), Id> = unsafe { /// msg_send![obj, preflightAndReturnError: _] /// }; /// ``` +/// +/// Sending a message with an out parameter _and_ automatic error handling. +/// +/// ```no_run +/// use objc2::msg_send; +/// use objc2::rc::{Id, Shared}; +/// +/// # type NSFileManager = objc2::runtime::Object; +/// # type NSURL = objc2::runtime::Object; +/// # type NSError = objc2::runtime::Object; +/// let obj: &NSFileManager; +/// # obj = todo!(); +/// let url: &NSURL; +/// # url = todo!(); +/// let mut result_url: Option> = None; +/// unsafe { +/// msg_send![ +/// obj, +/// trashItemAtURL: url, +/// resultingItemURL: Some(&mut result_url), +/// error: _ +/// ]? +/// // ^ is possible on error-returning methods, if the return type is specified +/// }; +/// +/// // Use `result_url` here +/// +/// # Ok::<(), Id>(()) +/// ``` #[macro_export] macro_rules! msg_send { [super($obj:expr), $($selector_and_arguments:tt)+] => { diff --git a/crates/objc2/src/macros/declare_class.rs b/crates/objc2/src/macros/declare_class.rs index b74b258b9..bdd50d264 100644 --- a/crates/objc2/src/macros/declare_class.rs +++ b/crates/objc2/src/macros/declare_class.rs @@ -84,6 +84,9 @@ /// make it behave similarly to the Objective-C `BOOL`. Use [`runtime::Bool`] /// if you want to control this manually. /// +/// Note that `&mut Id<_, _>` and other such out parameters are not yet +/// supported, and may generate a panic at runtime. +/// /// ["associated functions"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods /// ["methods"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods /// [`extern_methods!`]: crate::extern_methods @@ -900,7 +903,7 @@ macro_rules! __declare_class_rewrite_args { ($($args_converted)* $param : <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__Inner,) ( $($body_prefix)* - let mut $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_inner($param); + let mut $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_declared_param($param); ) ($out_macro) @@ -921,7 +924,7 @@ macro_rules! __declare_class_rewrite_args { ($($args_converted)* $param : <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__Inner,) ( $($body_prefix)* - let $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_inner($param); + let $param = <$param_ty as $crate::encode::__unstable::EncodeConvertArgument>::__from_declared_param($param); ) ($out_macro) @@ -1057,7 +1060,9 @@ macro_rules! __convert_result { ($body:block; $ret:ty) => { let __objc2_result = $body; #[allow(unreachable_code)] - <$ret as $crate::encode::__unstable::EncodeConvertReturn>::__into_inner(__objc2_result) + <$ret as $crate::encode::__unstable::EncodeConvertReturn>::__into_declared_return( + __objc2_result, + ) }; } diff --git a/crates/objc2/src/message/mod.rs b/crates/objc2/src/message/mod.rs index 0c55cee4e..b38442967 100644 --- a/crates/objc2/src/message/mod.rs +++ b/crates/objc2/src/message/mod.rs @@ -229,7 +229,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { let obj = unsafe { this.as_ref() }; msg_send_check(obj, sel, A::ENCODINGS, &R::__Inner::ENCODING_RETURN); } - unsafe { EncodeConvertReturn::__from_inner(send_unverified(this, sel, args)) } + unsafe { EncodeConvertReturn::__from_return(send_unverified(this, sel, args)) } } /// Sends a message to a specific superclass with the given selector and @@ -272,7 +272,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized { } } unsafe { - EncodeConvertReturn::__from_inner(send_super_unverified(this, superclass, sel, args)) + EncodeConvertReturn::__from_return(send_super_unverified(this, superclass, sel, args)) } } @@ -502,6 +502,8 @@ macro_rules! message_args_impl { unsafe impl<$($t: EncodeConvertArgument),*> MessageArguments for ($($t,)*) { #[inline] unsafe fn __invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R { + $(let $a = EncodeConvertArgument::__into_argument($a);)* + // The imp must be cast to the appropriate function pointer // type before being called; the msgSend functions are not // parametric, but instead "trampolines" to the actual @@ -517,7 +519,18 @@ macro_rules! message_args_impl { // TODO: On x86_64 it would be more efficient to use a GOT // entry here (e.g. adding `nonlazybind` in LLVM). // Same can be said of e.g. `objc_retain` and `objc_release`. - unsafe { imp(obj, sel $(, EncodeConvertArgument::__into_inner($a))*) } + let result = unsafe { imp(obj, sel $(, $a.0)*) }; + + // TODO: If we want `objc_retainAutoreleasedReturnValue` to + // work, we must not do any work before it has been run; so + // somehow, we should've done that before this call! + $( + // SAFETY: The argument was passed to the message sending + // function, and the stored values are only processed this + // once. See `src/rc/writeback.rs` for details. + unsafe { <$t as EncodeConvertArgument>::__process_after_message_send($a.1) }; + )* + result } } diff --git a/crates/objc2/src/rc/id.rs b/crates/objc2/src/rc/id.rs index 99c5578a4..47f76cb53 100644 --- a/crates/objc2/src/rc/id.rs +++ b/crates/objc2/src/rc/id.rs @@ -125,7 +125,7 @@ pub struct Id { impl Id { #[inline] - unsafe fn new_nonnull(ptr: NonNull) -> Self { + pub(crate) unsafe fn new_nonnull(ptr: NonNull) -> Self { Self { ptr, item: PhantomData, diff --git a/crates/objc2/src/rc/mod.rs b/crates/objc2/src/rc/mod.rs index 49191bba3..91df64a73 100644 --- a/crates/objc2/src/rc/mod.rs +++ b/crates/objc2/src/rc/mod.rs @@ -63,6 +63,7 @@ mod id_traits; mod ownership; mod test_object; mod weak_id; +mod writeback; pub use self::allocated::Allocated; pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe}; diff --git a/crates/objc2/src/rc/test_object.rs b/crates/objc2/src/rc/test_object.rs index 5f3de0c2e..705cb4f2f 100644 --- a/crates/objc2/src/rc/test_object.rs +++ b/crates/objc2/src/rc/test_object.rs @@ -264,6 +264,13 @@ declare_class!( unsafe { msg_send_id![Some(this), init] } } } + + #[method(outParamNull:)] + fn out_param_null(param: Option<&mut *mut __RcTestObject>) { + if let Some(param) = param { + *param = ptr::null_mut(); + } + } } ); diff --git a/crates/objc2/src/rc/writeback.rs b/crates/objc2/src/rc/writeback.rs new file mode 100644 index 000000000..ae329b325 --- /dev/null +++ b/crates/objc2/src/rc/writeback.rs @@ -0,0 +1,343 @@ +//! Support for passing "out"-parameters to `msg_send!` and family. +//! +//! See clang's documentation: +//! +//! +//! Note: We differ from that in that we do not create a temporary, whoose +//! address we then work on; instead, we just directly reuse the pointer that +//! the user provides (since, if it's a mutable pointer, we know that it's not +//! shared elsewhere in the program, and hence it is safe to modify directly). +use core::mem::ManuallyDrop; +use core::ptr::NonNull; + +use crate::encode::__unstable::EncodeConvertArgument; +use crate::rc::{Id, Ownership}; +use crate::Message; + +// Note the `'static` bound here - this may not be necessary, but I'm unsure +// of the exact requirements, so we better just keep it for now. +impl EncodeConvertArgument for &mut Id { + // We use `*mut T` as the inner value instead of `NonNull`, since we + // want to do debug checking that the value hasn't unexpectedly been + // overwritten to contain NULL (which is clear UB, but the user might have + // made a mistake). + type __Inner = NonNull<*mut T>; + + type __StoredBeforeMessage = ( + // A copy of the argument, so that we can retain it after the message + // send. Ideally, we'd just work with e.g. `&mut *mut T`, but we can't + // do that inside the generic context of `MessageArguments::__invoke`. + Self::__Inner, + // A pointer to the old value stored in the `Id`, so that we can + // release if after the message send. + NonNull, + ); + + #[inline] + fn __from_declared_param(_inner: Self::__Inner) -> Self { + todo!("`&mut Id<_, _>` is not supported in `declare_class!` yet") + } + + #[inline] + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + let ptr: NonNull> = NonNull::from(self); + // `Id` is `#[repr(transparent)]` over `NonNull`. + let ptr: NonNull> = ptr.cast(); + + // SAFETY: The value came from `&mut _`, and we only read a pointer. + let old: NonNull = unsafe { *ptr.as_ptr() }; + + // `NonNull` has the same layout as `*mut T`. + let ptr: NonNull<*mut T> = ptr.cast(); + + (ptr, (ptr, old)) + } + + #[inline] + unsafe fn __process_after_message_send((ptr, old): Self::__StoredBeforeMessage) { + // In terms of provenance, we roughly just want to do the following: + // ``` + // fn do(value: &mut Id) { + // let old = value.clone(); + // msg_send![... value ...]; + // let _ = value.clone(); + // drop(old); + // } + // ``` + // + // Which is definitly valid under stacked borrows! See also this + // playground link for testing something equivalent in Miri: + // + // + // + // + // In Objective-C terms, we want to retain the new value and release + // the old, and importantly, in that order (such that we don't dealloc + // the value if it didn't change). So something like this: + // ``` + // fn do(value: &mut Id) { + // let old = *value; + // msg_send![... value ...]; + // objc_retain(*value); + // objc_release(old); + // } + // ``` + // + // Note that using `Id` is perfectly sound, since we may + // only intermittently have a retain count of 2 to the value, but + // after the function returns we're guaranteed to be back to 1. + + // SAFETY: Caller ensures that the pointer is either left as-is, or is + // safe to retain at this point. + let new: Option> = unsafe { Id::retain(*ptr.as_ptr()) }; + // We ignore the result of `retain`, since it always returns the same + // value as was given (and it would just be unnecessary work to write + // that value back into `ptr` again). + let _new = ManuallyDrop::new(new); + #[cfg(debug_assertions)] + if _new.is_none() { + panic!("found that NULL was written to `&mut Id<_, _>`, which is UB! You should handle this with `&mut Option>` instead"); + } + + // SAFETY: The old pointer was valid when it was constructed. + // + // If the message send modified `ptr`, they would have left a +1 + // retain count on the old pointer; so either we have +1 from that, or + // the message send didn't modify the pointer and we instead have +1 + // retain count from the `retain` above. + let _: Id = unsafe { Id::new_nonnull(old) }; + } +} + +impl EncodeConvertArgument for &mut Option> { + type __Inner = NonNull<*mut T>; + + type __StoredBeforeMessage = (Self::__Inner, *mut T); + + #[inline] + fn __from_declared_param(_inner: Self::__Inner) -> Self { + todo!("`&mut Option>` is not supported in `declare_class!` yet") + } + + #[inline] + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + let ptr: NonNull>> = NonNull::from(self); + // `Option>` has the same memory layout as `*mut T`. + let ptr: NonNull<*mut T> = ptr.cast(); + // SAFETY: Same as for `&mut Id` + let old: *mut T = unsafe { *ptr.as_ptr() }; + + (ptr, (ptr, old)) + } + + #[inline] + unsafe fn __process_after_message_send((ptr, old): Self::__StoredBeforeMessage) { + // SAFETY: Same as for `&mut Id` + let new: Option> = unsafe { Id::retain(*ptr.as_ptr()) }; + let _ = ManuallyDrop::new(new); + + // SAFETY: Same as for `&mut Id` + // + // Note: We explicitly keep the `if old == nil { objc_release(old) }` + // check, since we expect that the user would often do: + // + // ``` + // let mut value = None + // do(&mut value); + // ``` + // + // And in that case, we can elide the `objc_release`! + let _: Option> = unsafe { Id::new(old) }; + } +} + +// Note: For `Option<&mut ...>` we explicitly want to do the `if Some` checks +// before anything else, since whether `None` or `Some` was passed is often +// known at compile-time, and for the `None` case it would be detrimental to +// have extra `retain/release` calls here. + +impl EncodeConvertArgument for Option<&mut Id> { + type __Inner = Option>; + + type __StoredBeforeMessage = Option<(NonNull<*mut T>, NonNull)>; + + #[inline] + fn __from_declared_param(_inner: Self::__Inner) -> Self { + todo!("`Option<&mut Id<_, _>>` is not supported in `declare_class!` yet") + } + + #[inline] + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + if let Some(this) = self { + let (ptr, stored) = this.__into_argument(); + (Some(ptr), Some(stored)) + } else { + (None, None) + } + } + + #[inline] + unsafe fn __process_after_message_send(stored: Self::__StoredBeforeMessage) { + if let Some(stored) = stored { + // SAFETY: Checked by caller + unsafe { <&mut Id>::__process_after_message_send(stored) }; + } + } +} + +impl EncodeConvertArgument for Option<&mut Option>> { + type __Inner = Option>; + + type __StoredBeforeMessage = Option<(NonNull<*mut T>, *mut T)>; + + #[inline] + fn __from_declared_param(_inner: Self::__Inner) -> Self { + todo!("`Option<&mut Option>>` is not supported in `declare_class!` yet") + } + + #[inline] + fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) { + if let Some(this) = self { + let (ptr, stored) = this.__into_argument(); + (Some(ptr), Some(stored)) + } else { + (None, None) + } + } + + #[inline] + unsafe fn __process_after_message_send(stored: Self::__StoredBeforeMessage) { + if let Some(stored) = stored { + // SAFETY: Checked by caller + unsafe { <&mut Option>>::__process_after_message_send(stored) }; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::rc::{Owned, __RcTestObject, __ThreadTestData, autoreleasepool}; + use crate::{msg_send, msg_send_id, ClassType}; + + #[test] + fn test_bool_error() { + let mut expected = __ThreadTestData::current(); + + fn bool_error(should_error: bool, error: Option<&mut Option>>) { + let cls = __RcTestObject::class(); + let did_succeed: bool = + unsafe { msg_send![cls, boolAndShouldError: should_error, error: error] }; + assert_ne!(should_error, did_succeed); + } + + bool_error(false, None); + bool_error(true, None); + expected.assert_current(); + + fn helper( + expected: &mut __ThreadTestData, + should_error: bool, + mut error: Option>, + ) { + std::dbg!(should_error, &error); + autoreleasepool(|_| { + bool_error(should_error, Some(&mut error)); + if should_error { + expected.alloc += 1; + expected.init += 1; + expected.autorelease += 1; + } + expected.assert_current(); + }); + + if should_error { + expected.release += 1; + } + expected.assert_current(); + + if error.is_some() { + expected.release += 1; + expected.dealloc += 1; + } + drop(error); + expected.assert_current(); + } + + helper(&mut expected, false, None); + + expected.retain += 1; + helper(&mut expected, true, None); + + expected.alloc += 1; + expected.init += 1; + expected.retain += 1; + expected.release += 1; + helper(&mut expected, false, Some(__RcTestObject::new())); + + expected.alloc += 1; + expected.init += 1; + expected.retain += 1; + expected.release += 1; + expected.dealloc += 1; + helper(&mut expected, true, Some(__RcTestObject::new())); + } + + #[test] + #[cfg_attr( + not(debug_assertions), + ignore = "invokes UB which is only caught with debug_assertions" + )] + #[should_panic = "found that NULL was written to `&mut Id<_, _>`, which is UB! You should handle this with `&mut Option>` instead"] + fn test_debug_check_ub() { + let cls = __RcTestObject::class(); + let mut param: Id<_, _> = __RcTestObject::new(); + let _: () = unsafe { msg_send![cls, outParamNull: &mut param] }; + } + + // TODO: Fix this in release mode with Apple's runtime + const AUTORELEASE_SKIPPED: bool = cfg!(feature = "gnustep-1-7"); + + #[test] + fn test_id_interaction() { + let mut expected = __ThreadTestData::current(); + let cls = __RcTestObject::class(); + + let mut err: Id<__RcTestObject, Owned> = __RcTestObject::new(); + expected.alloc += 1; + expected.init += 1; + expected.assert_current(); + + autoreleasepool(|_| { + let obj: Option> = + unsafe { msg_send_id![cls, idAndShouldError: false, error: &mut err] }; + expected.alloc += 1; + expected.init += 1; + if !AUTORELEASE_SKIPPED { + expected.autorelease += 1; + expected.retain += 1; + } + + expected.retain += 1; + expected.release += 1; + expected.assert_current(); + + drop(obj); + expected.release += 1; + if AUTORELEASE_SKIPPED { + expected.dealloc += 1; + } + expected.assert_current(); + }); + if !AUTORELEASE_SKIPPED { + expected.release += 1; + expected.dealloc += 1; + } + expected.assert_current(); + + drop(err); + expected.release += 1; + expected.dealloc += 1; + expected.assert_current(); + } +} diff --git a/crates/test-assembly/crates/test_msg_send_error/Cargo.toml b/crates/test-assembly/crates/test_msg_send_error/Cargo.toml new file mode 100644 index 000000000..9da571e57 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "test_msg_send_error" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +objc2 = { path = "../../../objc2", default-features = false } + +[features] +default = ["apple", "std"] +std = ["objc2/std"] +# Runtime +apple = ["objc2/apple"] +gnustep-1-7 = ["objc2/gnustep-1-7"] +gnustep-1-8 = ["gnustep-1-7", "objc2/gnustep-1-8"] +gnustep-1-9 = ["gnustep-1-8", "objc2/gnustep-1-9"] +gnustep-2-0 = ["gnustep-1-9", "objc2/gnustep-2-0"] +gnustep-2-1 = ["gnustep-2-0", "objc2/gnustep-2-1"] + +# Hack +assembly-features = [] diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/apple-aarch64.s b/crates/test-assembly/crates/test_msg_send_error/expected/apple-aarch64.s new file mode 100644 index 000000000..1cde3f2d7 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/apple-aarch64.s @@ -0,0 +1,257 @@ + .section __TEXT,__text,regular,pure_instructions + .p2align 2 +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + stp x20, x19, [sp, #-32]! + stp x29, x30, [sp, #16] + add x29, sp, #16 + mov x19, x1 + bl _objc_retain + cbz x0, LBB0_2 + ldp x29, x30, [sp, #16] + ldp x20, x19, [sp], #32 + ret +LBB0_2: +Lloh0: + adrp x0, l_anon.[ID].0@PAGE +Lloh1: + add x0, x0, l_anon.[ID].0@PAGEOFF + mov w1, #56 + mov x2, x19 + bl SYM(core::option::expect_failed::GENERATED_ID, 0) + .loh AdrpAdd Lloh0, Lloh1 + + .p2align 2 +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + stp x29, x30, [sp, #-16]! + mov x29, sp + bl _objc_retain + cbz x0, LBB1_2 + ldp x29, x30, [sp], #16 + ret +LBB1_2: +Lloh2: + adrp x0, l_anon.[ID].1@PAGE +Lloh3: + add x0, x0, l_anon.[ID].1@PAGEOFF +Lloh4: + adrp x2, l_anon.[ID].3@PAGE +Lloh5: + add x2, x2, l_anon.[ID].3@PAGEOFF + mov w1, #54 + bl SYM(core::option::expect_failed::GENERATED_ID, 0) + .loh AdrpAdd Lloh4, Lloh5 + .loh AdrpAdd Lloh2, Lloh3 + + .globl _error_bool + .p2align 2 +_error_bool: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x3, sp, #8 + bl _objc_msgSend + mov x8, x0 + mov x0, #0 + tbz w8, #0, LBB2_2 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB2_2: + ldr x0, [sp, #8] + bl SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + + .globl _error_new + .p2align 2 +_error_new: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + cbz x0, LBB3_2 + mov x1, x0 + mov x0, #0 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB3_2: + ldr x0, [sp, #8] +Lloh6: + adrp x1, l_anon.[ID].4@PAGE +Lloh7: + add x1, x1, l_anon.[ID].4@PAGEOFF + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov x1, x0 + mov w0, #1 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + .loh AdrpAdd Lloh6, Lloh7 + + .globl _error_alloc + .p2align 2 +_error_alloc: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + cbz x0, LBB4_2 + mov x1, x0 + mov x0, #0 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB4_2: + ldr x0, [sp, #8] +Lloh8: + adrp x1, l_anon.[ID].5@PAGE +Lloh9: + add x1, x1, l_anon.[ID].5@PAGEOFF + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov x1, x0 + mov w0, #1 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + .loh AdrpAdd Lloh8, Lloh9 + + .globl _error_init + .p2align 2 +_error_init: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + cbz x0, LBB5_2 + mov x1, x0 + mov x0, #0 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB5_2: + ldr x0, [sp, #8] +Lloh10: + adrp x1, l_anon.[ID].6@PAGE +Lloh11: + add x1, x1, l_anon.[ID].6@PAGEOFF + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov x1, x0 + mov w0, #1 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + .loh AdrpAdd Lloh10, Lloh11 + + .globl _error_copy + .p2align 2 +_error_copy: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + cbz x0, LBB6_2 + mov x1, x0 + mov x0, #0 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB6_2: + ldr x0, [sp, #8] +Lloh12: + adrp x1, l_anon.[ID].7@PAGE +Lloh13: + add x1, x1, l_anon.[ID].7@PAGEOFF + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov x1, x0 + mov w0, #1 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + .loh AdrpAdd Lloh12, Lloh13 + + .globl _error_autoreleased + .p2align 2 +_error_autoreleased: + sub sp, sp, #32 + stp x29, x30, [sp, #16] + add x29, sp, #16 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + ; InlineAsm Start + mov x29, x29 + ; InlineAsm End + bl _objc_retainAutoreleasedReturnValue + cbz x0, LBB7_2 + mov x1, x0 + mov x0, #0 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret +LBB7_2: + ldr x0, [sp, #8] +Lloh14: + adrp x1, l_anon.[ID].8@PAGE +Lloh15: + add x1, x1, l_anon.[ID].8@PAGEOFF + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov x1, x0 + mov w0, #1 + ldp x29, x30, [sp, #16] + add sp, sp, #32 + ret + .loh AdrpAdd Lloh14, Lloh15 + + .section __TEXT,__const +l_anon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + +l_anon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + +l_anon.[ID].2: + .ascii "crates/$DIR/lib.rs" + + .section __DATA,__const + .p2align 3 +l_anon.[ID].3: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\013\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].4: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\020\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].5: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\025\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].6: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\032\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].7: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\037\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].8: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000$\000\000\000\005\000\000" + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7.s b/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7.s new file mode 100644 index 000000000..bc8b301b2 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7.s @@ -0,0 +1,262 @@ + .section __TEXT,__text,regular,pure_instructions + .syntax unified + .p2align 2 + .code 32 +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push {r4, r7, lr} + add r7, sp, #4 + mov r4, r1 + bl _objc_retain + cmp r0, #0 + popne {r4, r7, pc} +LBB0_1: + movw r0, :lower16:(l_anon.[ID].0-(LPC0_0+8)) + mov r1, #56 + movt r0, :upper16:(l_anon.[ID].0-(LPC0_0+8)) + mov r2, r4 +LPC0_0: + add r0, pc, r0 + mov lr, pc + b SYM(core::option::expect_failed::GENERATED_ID, 0) + + .p2align 2 + .code 32 +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push {r7, lr} + mov r7, sp + bl _objc_retain + cmp r0, #0 + popne {r7, pc} +LBB1_1: + movw r0, :lower16:(l_anon.[ID].1-(LPC1_0+8)) + mov r1, #54 + movt r0, :upper16:(l_anon.[ID].1-(LPC1_0+8)) + movw r2, :lower16:(l_anon.[ID].3-(LPC1_1+8)) + movt r2, :upper16:(l_anon.[ID].3-(LPC1_1+8)) +LPC1_0: + add r0, pc, r0 +LPC1_1: + add r2, pc, r2 + mov lr, pc + b SYM(core::option::expect_failed::GENERATED_ID, 0) + + .globl _error_bool + .p2align 2 + .code 32 +_error_bool: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r3, sp + str r4, [sp] + bl _objc_msgSend + cmp r0, #0 + beq LBB2_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB2_2: + ldr r0, [sp] + bl SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + mov r4, r0 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_new + .p2align 2 + .code 32 +_error_new: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB3_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB3_2: + ldr r0, [sp] + movw r1, :lower16:(l_anon.[ID].4-(LPC3_0+8)) + movt r1, :upper16:(l_anon.[ID].4-(LPC3_0+8)) +LPC3_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_alloc + .p2align 2 + .code 32 +_error_alloc: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB4_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB4_2: + ldr r0, [sp] + movw r1, :lower16:(l_anon.[ID].5-(LPC4_0+8)) + movt r1, :upper16:(l_anon.[ID].5-(LPC4_0+8)) +LPC4_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_init + .p2align 2 + .code 32 +_error_init: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB5_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB5_2: + ldr r0, [sp] + movw r1, :lower16:(l_anon.[ID].6-(LPC5_0+8)) + movt r1, :upper16:(l_anon.[ID].6-(LPC5_0+8)) +LPC5_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_copy + .p2align 2 + .code 32 +_error_copy: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB6_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB6_2: + ldr r0, [sp] + movw r1, :lower16:(l_anon.[ID].7-(LPC6_0+8)) + movt r1, :upper16:(l_anon.[ID].7-(LPC6_0+8)) +LPC6_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_autoreleased + .p2align 2 + .code 32 +_error_autoreleased: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + @ InlineAsm Start + mov r7, r7 + @ InlineAsm End + bl _objc_retainAutoreleasedReturnValue + mov r1, r0 + cmp r0, #0 + beq LBB7_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB7_2: + ldr r0, [sp] + movw r1, :lower16:(l_anon.[ID].8-(LPC7_0+8)) + movt r1, :upper16:(l_anon.[ID].8-(LPC7_0+8)) +LPC7_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .section __TEXT,__const +l_anon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + +l_anon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + +l_anon.[ID].2: + .ascii "crates/$DIR/lib.rs" + + .section __DATA,__const + .p2align 2 +l_anon.[ID].3: + .long l_anon.[ID].2 + .asciz "6\000\000\000\013\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].4: + .long l_anon.[ID].2 + .asciz "6\000\000\000\020\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].5: + .long l_anon.[ID].2 + .asciz "6\000\000\000\025\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].6: + .long l_anon.[ID].2 + .asciz "6\000\000\000\032\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].7: + .long l_anon.[ID].2 + .asciz "6\000\000\000\037\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].8: + .long l_anon.[ID].2 + .asciz "6\000\000\000$\000\000\000\005\000\000" + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7s.s b/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7s.s new file mode 100644 index 000000000..671898c1d --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/apple-armv7s.s @@ -0,0 +1,262 @@ + .section __TEXT,__text,regular,pure_instructions + .syntax unified + .p2align 2 + .code 32 +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push {r4, r7, lr} + add r7, sp, #4 + mov r4, r1 + bl _objc_retain + cmp r0, #0 + popne {r4, r7, pc} +LBB0_1: + movw r0, :lower16:(l_anon.[ID].0-(LPC0_0+8)) + mov r1, #56 + movt r0, :upper16:(l_anon.[ID].0-(LPC0_0+8)) + mov r2, r4 +LPC0_0: + add r0, pc, r0 + mov lr, pc + b SYM(core::option::expect_failed::GENERATED_ID, 0) + + .p2align 2 + .code 32 +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push {r7, lr} + mov r7, sp + bl _objc_retain + cmp r0, #0 + popne {r7, pc} +LBB1_1: + movw r0, :lower16:(l_anon.[ID].1-(LPC1_0+8)) + mov r1, #54 + movt r0, :upper16:(l_anon.[ID].1-(LPC1_0+8)) + movw r2, :lower16:(l_anon.[ID].3-(LPC1_1+8)) + movt r2, :upper16:(l_anon.[ID].3-(LPC1_1+8)) +LPC1_0: + add r0, pc, r0 +LPC1_1: + add r2, pc, r2 + mov lr, pc + b SYM(core::option::expect_failed::GENERATED_ID, 0) + + .globl _error_bool + .p2align 2 + .code 32 +_error_bool: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r3, sp + str r4, [sp] + bl _objc_msgSend + cmp r0, #0 + beq LBB2_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB2_2: + ldr r0, [sp] + bl SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + mov r4, r0 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_new + .p2align 2 + .code 32 +_error_new: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB3_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB3_2: + movw r1, :lower16:(l_anon.[ID].4-(LPC3_0+8)) + movt r1, :upper16:(l_anon.[ID].4-(LPC3_0+8)) + ldr r0, [sp] +LPC3_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_alloc + .p2align 2 + .code 32 +_error_alloc: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB4_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB4_2: + movw r1, :lower16:(l_anon.[ID].5-(LPC4_0+8)) + movt r1, :upper16:(l_anon.[ID].5-(LPC4_0+8)) + ldr r0, [sp] +LPC4_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_init + .p2align 2 + .code 32 +_error_init: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB5_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB5_2: + movw r1, :lower16:(l_anon.[ID].6-(LPC5_0+8)) + movt r1, :upper16:(l_anon.[ID].6-(LPC5_0+8)) + ldr r0, [sp] +LPC5_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_copy + .p2align 2 + .code 32 +_error_copy: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + mov r1, r0 + cmp r0, #0 + beq LBB6_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB6_2: + movw r1, :lower16:(l_anon.[ID].7-(LPC6_0+8)) + movt r1, :upper16:(l_anon.[ID].7-(LPC6_0+8)) + ldr r0, [sp] +LPC6_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _error_autoreleased + .p2align 2 + .code 32 +_error_autoreleased: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r4, #0 + mov r2, sp + str r4, [sp] + bl _objc_msgSend + @ InlineAsm Start + mov r7, r7 + @ InlineAsm End + bl _objc_retainAutoreleasedReturnValue + mov r1, r0 + cmp r0, #0 + beq LBB7_2 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} +LBB7_2: + movw r1, :lower16:(l_anon.[ID].8-(LPC7_0+8)) + movt r1, :upper16:(l_anon.[ID].8-(LPC7_0+8)) + ldr r0, [sp] +LPC7_0: + add r1, pc, r1 + bl SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov r1, r0 + mov r4, #1 + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .section __TEXT,__const +l_anon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + +l_anon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + +l_anon.[ID].2: + .ascii "crates/$DIR/lib.rs" + + .section __DATA,__const + .p2align 2 +l_anon.[ID].3: + .long l_anon.[ID].2 + .asciz "6\000\000\000\013\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].4: + .long l_anon.[ID].2 + .asciz "6\000\000\000\020\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].5: + .long l_anon.[ID].2 + .asciz "6\000\000\000\025\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].6: + .long l_anon.[ID].2 + .asciz "6\000\000\000\032\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].7: + .long l_anon.[ID].2 + .asciz "6\000\000\000\037\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].8: + .long l_anon.[ID].2 + .asciz "6\000\000\000$\000\000\000\005\000\000" + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86.s b/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86.s new file mode 100644 index 000000000..ec38e7705 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86.s @@ -0,0 +1,338 @@ + .section __TEXT,__text,regular,pure_instructions + .intel_syntax noprefix + .p2align 4, 0x90 +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push ebp + mov ebp, esp + push edi + push esi + mov esi, edx + call L0$pb +L0$pb: + pop edi + sub esp, 12 + push ecx + call _objc_retain + add esp, 16 + test eax, eax + je LBB0_2 + pop esi + pop edi + pop ebp + ret +LBB0_2: + sub esp, 4 + lea eax, [edi + l_anon.[ID].0-L0$pb] + push esi + push 56 + push eax + call SYM(core::option::expect_failed::GENERATED_ID, 0) + + .p2align 4, 0x90 +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push ebp + mov ebp, esp + push esi + push eax + call L1$pb +L1$pb: + pop esi + sub esp, 12 + push ecx + call _objc_retain + add esp, 16 + test eax, eax + je LBB1_2 + add esp, 4 + pop esi + pop ebp + ret +LBB1_2: + sub esp, 4 + lea eax, [esi + l_anon.[ID].3-L1$pb] + lea ecx, [esi + l_anon.[ID].1-L1$pb] + push eax + push 54 + push ecx + call SYM(core::option::expect_failed::GENERATED_ID, 0) + + .globl _error_bool + .p2align 4, 0x90 +_error_bool: + push ebp + mov ebp, esp + push esi + push eax + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov edx, dword ptr [ebp + 16] + mov dword ptr [ebp - 8], 0 + lea esi, [ebp - 8] + push esi + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + mov ecx, eax + xor eax, eax + test cl, cl + je LBB2_1 + add esp, 4 + pop esi + pop ebp + ret +LBB2_1: + mov ecx, dword ptr [ebp - 8] + call SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + add esp, 4 + pop esi + pop ebp + ret + + .globl _error_new + .p2align 4, 0x90 +_error_new: + push ebp + mov ebp, esp + push esi + push eax + call L3$pb +L3$pb: + pop esi + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + test eax, eax + je LBB3_2 + mov edx, eax + xor eax, eax + add esp, 4 + pop esi + pop ebp + ret +LBB3_2: + mov ecx, dword ptr [ebp - 8] + lea edx, [esi + l_anon.[ID].4-L3$pb] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + add esp, 4 + pop esi + pop ebp + ret + + .globl _error_alloc + .p2align 4, 0x90 +_error_alloc: + push ebp + mov ebp, esp + push esi + push eax + call L4$pb +L4$pb: + pop esi + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + test eax, eax + je LBB4_2 + mov edx, eax + xor eax, eax + add esp, 4 + pop esi + pop ebp + ret +LBB4_2: + mov ecx, dword ptr [ebp - 8] + lea edx, [esi + l_anon.[ID].5-L4$pb] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + add esp, 4 + pop esi + pop ebp + ret + + .globl _error_init + .p2align 4, 0x90 +_error_init: + push ebp + mov ebp, esp + push esi + push eax + call L5$pb +L5$pb: + pop esi + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + test eax, eax + je LBB5_2 + mov edx, eax + xor eax, eax + add esp, 4 + pop esi + pop ebp + ret +LBB5_2: + mov ecx, dword ptr [ebp - 8] + lea edx, [esi + l_anon.[ID].6-L5$pb] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + add esp, 4 + pop esi + pop ebp + ret + + .globl _error_copy + .p2align 4, 0x90 +_error_copy: + push ebp + mov ebp, esp + push esi + push eax + call L6$pb +L6$pb: + pop esi + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + test eax, eax + je LBB6_2 + mov edx, eax + xor eax, eax + add esp, 4 + pop esi + pop ebp + ret +LBB6_2: + mov ecx, dword ptr [ebp - 8] + lea edx, [esi + l_anon.[ID].7-L6$pb] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + add esp, 4 + pop esi + pop ebp + ret + + .globl _error_autoreleased + .p2align 4, 0x90 +_error_autoreleased: + push ebp + mov ebp, esp + push esi + push eax + call L7$pb +L7$pb: + pop esi + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + ## InlineAsm Start + + mov ebp, ebp + + ## InlineAsm End + sub esp, 12 + push eax + call _objc_retainAutoreleasedReturnValue + add esp, 16 + test eax, eax + je LBB7_2 + mov edx, eax + xor eax, eax + add esp, 4 + pop esi + pop ebp + ret +LBB7_2: + mov ecx, dword ptr [ebp - 8] + lea edx, [esi + l_anon.[ID].8-L7$pb] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + add esp, 4 + pop esi + pop ebp + ret + + .section __TEXT,__const +l_anon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + +l_anon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + +l_anon.[ID].2: + .ascii "crates/$DIR/lib.rs" + + .section __DATA,__const + .p2align 2 +l_anon.[ID].3: + .long l_anon.[ID].2 + .asciz "6\000\000\000\013\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].4: + .long l_anon.[ID].2 + .asciz "6\000\000\000\020\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].5: + .long l_anon.[ID].2 + .asciz "6\000\000\000\025\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].6: + .long l_anon.[ID].2 + .asciz "6\000\000\000\032\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].7: + .long l_anon.[ID].2 + .asciz "6\000\000\000\037\000\000\000\005\000\000" + + .p2align 2 +l_anon.[ID].8: + .long l_anon.[ID].2 + .asciz "6\000\000\000$\000\000\000\005\000\000" + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86_64.s b/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86_64.s new file mode 100644 index 000000000..81fe2f788 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/apple-x86_64.s @@ -0,0 +1,238 @@ + .section __TEXT,__text,regular,pure_instructions + .intel_syntax noprefix + .p2align 4, 0x90 +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push rbp + mov rbp, rsp + push rbx + push rax + mov rbx, rsi + call _objc_retain + test rax, rax + je LBB0_2 + add rsp, 8 + pop rbx + pop rbp + ret +LBB0_2: + lea rdi, [rip + l_anon.[ID].0] + mov esi, 56 + mov rdx, rbx + call SYM(core::option::expect_failed::GENERATED_ID, 0) + + .p2align 4, 0x90 +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push rbp + mov rbp, rsp + call _objc_retain + test rax, rax + je LBB1_2 + pop rbp + ret +LBB1_2: + lea rdi, [rip + l_anon.[ID].1] + lea rdx, [rip + l_anon.[ID].3] + mov esi, 54 + call SYM(core::option::expect_failed::GENERATED_ID, 0) + + .globl _error_bool + .p2align 4, 0x90 +_error_bool: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rcx, [rbp - 8] + call _objc_msgSend + test al, al + je LBB2_2 + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB2_2: + mov rdi, qword ptr [rbp - 8] + call SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + add rsp, 16 + pop rbp + ret + + .globl _error_new + .p2align 4, 0x90 +_error_new: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rdx, [rbp - 8] + call _objc_msgSend + test rax, rax + je LBB3_2 + mov rdx, rax + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB3_2: + mov rdi, qword ptr [rbp - 8] + lea rsi, [rip + l_anon.[ID].4] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 16 + pop rbp + ret + + .globl _error_alloc + .p2align 4, 0x90 +_error_alloc: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rdx, [rbp - 8] + call _objc_msgSend + test rax, rax + je LBB4_2 + mov rdx, rax + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB4_2: + mov rdi, qword ptr [rbp - 8] + lea rsi, [rip + l_anon.[ID].5] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 16 + pop rbp + ret + + .globl _error_init + .p2align 4, 0x90 +_error_init: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rdx, [rbp - 8] + call _objc_msgSend + test rax, rax + je LBB5_2 + mov rdx, rax + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB5_2: + mov rdi, qword ptr [rbp - 8] + lea rsi, [rip + l_anon.[ID].6] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 16 + pop rbp + ret + + .globl _error_copy + .p2align 4, 0x90 +_error_copy: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rdx, [rbp - 8] + call _objc_msgSend + test rax, rax + je LBB6_2 + mov rdx, rax + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB6_2: + mov rdi, qword ptr [rbp - 8] + lea rsi, [rip + l_anon.[ID].7] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 16 + pop rbp + ret + + .globl _error_autoreleased + .p2align 4, 0x90 +_error_autoreleased: + push rbp + mov rbp, rsp + sub rsp, 16 + mov qword ptr [rbp - 8], 0 + lea rdx, [rbp - 8] + call _objc_msgSend + mov rdi, rax + call _objc_retainAutoreleasedReturnValue + ## InlineAsm Start + + nop + + ## InlineAsm End + test rax, rax + je LBB7_2 + mov rdx, rax + xor eax, eax + add rsp, 16 + pop rbp + ret +LBB7_2: + mov rdi, qword ptr [rbp - 8] + lea rsi, [rip + l_anon.[ID].8] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 16 + pop rbp + ret + + .section __TEXT,__const +l_anon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + +l_anon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + +l_anon.[ID].2: + .ascii "crates/$DIR/lib.rs" + + .section __DATA,__const + .p2align 3 +l_anon.[ID].3: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\013\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].4: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\020\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].5: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\025\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].6: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\032\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].7: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\037\000\000\000\005\000\000" + + .p2align 3 +l_anon.[ID].8: + .quad l_anon.[ID].2 + .asciz "6\000\000\000\000\000\000\000$\000\000\000\005\000\000" + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86.s b/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86.s new file mode 100644 index 000000000..96790d294 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86.s @@ -0,0 +1,435 @@ + .text + .intel_syntax noprefix + .section .text.unlikely.SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0),"ax",@progbits + .p2align 4, 0x90 + .type SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0),@function +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push ebx + push esi + push eax + call .L0$pb +.L0$pb: + pop ebx + mov esi, edx +.Ltmp0: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb) + sub esp, 12 + push ecx + call objc_retain@PLT + add esp, 16 + test eax, eax + je .LBB0_1 + add esp, 4 + pop esi + pop ebx + ret +.LBB0_1: + sub esp, 4 + lea eax, [ebx + .Lanon.[ID].0@GOTOFF] + push esi + push 56 + push eax + call SYM(core::option::expect_failed::GENERATED_ID, 0)@PLT + add esp, 16 + ud2 +.Lfunc_end0: + .size SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0), .Lfunc_end0-SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + + .section .text.unlikely.SYM(objc2[CRATE_ID]::message::encountered_error::, 0),"ax",@progbits + .p2align 4, 0x90 + .type SYM(objc2[CRATE_ID]::message::encountered_error::, 0),@function +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push ebx + sub esp, 8 + call .L1$pb +.L1$pb: + pop ebx +.Ltmp1: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp1-.L1$pb) + sub esp, 12 + push ecx + call objc_retain@PLT + add esp, 16 + test eax, eax + je .LBB1_1 + add esp, 8 + pop ebx + ret +.LBB1_1: + sub esp, 4 + lea eax, [ebx + .Lanon.[ID].3@GOTOFF] + lea ecx, [ebx + .Lanon.[ID].1@GOTOFF] + push eax + push 54 + push ecx + call SYM(core::option::expect_failed::GENERATED_ID, 0)@PLT + add esp, 16 + ud2 +.Lfunc_end1: + .size SYM(objc2[CRATE_ID]::message::encountered_error::, 0), .Lfunc_end1-SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + + .section .text.error_bool,"ax",@progbits + .globl error_bool + .p2align 4, 0x90 + .type error_bool,@function +error_bool: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov edi, dword ptr [esp + 40] + mov esi, dword ptr [esp + 32] + mov ebp, dword ptr [esp + 36] + call .L2$pb +.L2$pb: + pop ebx + mov dword ptr [esp + 8], 0 +.Ltmp2: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp2-.L2$pb) + sub esp, 8 + push ebp + push esi + call objc_msg_lookup@PLT + add esp, 16 + lea ecx, [esp + 8] + push ecx + push edi + push ebp + push esi + call eax + add esp, 16 + mov ecx, eax + xor eax, eax + test cl, cl + je .LBB2_1 +.LBB2_2: + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret +.LBB2_1: + mov ecx, dword ptr [esp + 8] + call SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + jmp .LBB2_2 +.Lfunc_end2: + .size error_bool, .Lfunc_end2-error_bool + + .section .text.error_new,"ax",@progbits + .globl error_new + .p2align 4, 0x90 + .type error_new,@function +error_new: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L3$pb +.L3$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp3: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp3-.L3$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + test eax, eax + je .LBB3_2 + mov edx, eax + xor eax, eax +.LBB3_3: + add esp, 16 + pop esi + pop edi + pop ebx + ret +.LBB3_2: + mov ecx, dword ptr [esp + 12] + lea edx, [ebx + .Lanon.[ID].4@GOTOFF] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + jmp .LBB3_3 +.Lfunc_end3: + .size error_new, .Lfunc_end3-error_new + + .section .text.error_alloc,"ax",@progbits + .globl error_alloc + .p2align 4, 0x90 + .type error_alloc,@function +error_alloc: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L4$pb +.L4$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp4: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp4-.L4$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + test eax, eax + je .LBB4_2 + mov edx, eax + xor eax, eax +.LBB4_3: + add esp, 16 + pop esi + pop edi + pop ebx + ret +.LBB4_2: + mov ecx, dword ptr [esp + 12] + lea edx, [ebx + .Lanon.[ID].5@GOTOFF] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + jmp .LBB4_3 +.Lfunc_end4: + .size error_alloc, .Lfunc_end4-error_alloc + + .section .text.error_init,"ax",@progbits + .globl error_init + .p2align 4, 0x90 + .type error_init,@function +error_init: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + call .L5$pb +.L5$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp5: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp5-.L5$pb) + test esi, esi + je .LBB5_1 + mov edi, dword ptr [esp + 36] + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + test eax, eax + je .LBB5_4 + mov edx, eax + xor eax, eax +.LBB5_6: + add esp, 16 + pop esi + pop edi + pop ebx + ret +.LBB5_1: + xor ecx, ecx + jmp .LBB5_5 +.LBB5_4: + mov ecx, dword ptr [esp + 12] +.LBB5_5: + lea edx, [ebx + .Lanon.[ID].6@GOTOFF] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + jmp .LBB5_6 +.Lfunc_end5: + .size error_init, .Lfunc_end5-error_init + + .section .text.error_copy,"ax",@progbits + .globl error_copy + .p2align 4, 0x90 + .type error_copy,@function +error_copy: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L6$pb +.L6$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp6: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp6-.L6$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + test eax, eax + je .LBB6_2 + mov edx, eax + xor eax, eax +.LBB6_3: + add esp, 16 + pop esi + pop edi + pop ebx + ret +.LBB6_2: + mov ecx, dword ptr [esp + 12] + lea edx, [ebx + .Lanon.[ID].7@GOTOFF] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + jmp .LBB6_3 +.Lfunc_end6: + .size error_copy, .Lfunc_end6-error_copy + + .section .text.error_autoreleased,"ax",@progbits + .globl error_autoreleased + .p2align 4, 0x90 + .type error_autoreleased,@function +error_autoreleased: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L7$pb +.L7$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp7: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp7-.L7$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 4 + push eax + call objc_retainAutoreleasedReturnValue@PLT + add esp, 16 + test eax, eax + je .LBB7_2 + mov edx, eax + xor eax, eax +.LBB7_3: + add esp, 16 + pop esi + pop edi + pop ebx + ret +.LBB7_2: + mov ecx, dword ptr [esp + 12] + lea edx, [ebx + .Lanon.[ID].8@GOTOFF] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov edx, eax + mov eax, 1 + jmp .LBB7_3 +.Lfunc_end7: + .size error_autoreleased, .Lfunc_end7-error_autoreleased + + .type .Lanon.[ID].0,@object + .section .rodata..Lanon.[ID].0,"a",@progbits +.Lanon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + .size .Lanon.[ID].0, 56 + + .type .Lanon.[ID].1,@object + .section .rodata..Lanon.[ID].1,"a",@progbits +.Lanon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + .size .Lanon.[ID].1, 54 + + .type .Lanon.[ID].2,@object + .section .rodata..Lanon.[ID].2,"a",@progbits +.Lanon.[ID].2: + .ascii "crates/$DIR/lib.rs" + .size .Lanon.[ID].2, 54 + + .type .Lanon.[ID].3,@object + .section .data.rel.ro..Lanon.[ID].3,"aw",@progbits + .p2align 2 +.Lanon.[ID].3: + .long .Lanon.[ID].2 + .asciz "6\000\000\000\013\000\000\000\005\000\000" + .size .Lanon.[ID].3, 16 + + .type .Lanon.[ID].4,@object + .section .data.rel.ro..Lanon.[ID].4,"aw",@progbits + .p2align 2 +.Lanon.[ID].4: + .long .Lanon.[ID].2 + .asciz "6\000\000\000\020\000\000\000\005\000\000" + .size .Lanon.[ID].4, 16 + + .type .Lanon.[ID].5,@object + .section .data.rel.ro..Lanon.[ID].5,"aw",@progbits + .p2align 2 +.Lanon.[ID].5: + .long .Lanon.[ID].2 + .asciz "6\000\000\000\025\000\000\000\005\000\000" + .size .Lanon.[ID].5, 16 + + .type .Lanon.[ID].6,@object + .section .data.rel.ro..Lanon.[ID].6,"aw",@progbits + .p2align 2 +.Lanon.[ID].6: + .long .Lanon.[ID].2 + .asciz "6\000\000\000\032\000\000\000\005\000\000" + .size .Lanon.[ID].6, 16 + + .type .Lanon.[ID].7,@object + .section .data.rel.ro..Lanon.[ID].7,"aw",@progbits + .p2align 2 +.Lanon.[ID].7: + .long .Lanon.[ID].2 + .asciz "6\000\000\000\037\000\000\000\005\000\000" + .size .Lanon.[ID].7, 16 + + .type .Lanon.[ID].8,@object + .section .data.rel.ro..Lanon.[ID].8,"aw",@progbits + .p2align 2 +.Lanon.[ID].8: + .long .Lanon.[ID].2 + .asciz "6\000\000\000$\000\000\000\005\000\000" + .size .Lanon.[ID].8, 16 + + .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86_64.s b/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86_64.s new file mode 100644 index 000000000..7020cf029 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/expected/gnustep-x86_64.s @@ -0,0 +1,336 @@ + .text + .intel_syntax noprefix + .section .text.unlikely.SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0),"ax",@progbits + .p2align 4, 0x90 + .type SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0),@function +SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0): + push rbx + mov rbx, rsi + call qword ptr [rip + objc_retain@GOTPCREL] + test rax, rax + je .LBB0_1 + pop rbx + ret +.LBB0_1: + lea rdi, [rip + .Lanon.[ID].0] + mov esi, 56 + mov rdx, rbx + call qword ptr [rip + SYM(core::option::expect_failed::GENERATED_ID, 0)@GOTPCREL] + ud2 +.Lfunc_end0: + .size SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0), .Lfunc_end0-SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + + .section .text.unlikely.SYM(objc2[CRATE_ID]::message::encountered_error::, 0),"ax",@progbits + .p2align 4, 0x90 + .type SYM(objc2[CRATE_ID]::message::encountered_error::, 0),@function +SYM(objc2[CRATE_ID]::message::encountered_error::, 0): + push rax + call qword ptr [rip + objc_retain@GOTPCREL] + test rax, rax + je .LBB1_1 + pop rcx + ret +.LBB1_1: + lea rdi, [rip + .Lanon.[ID].1] + lea rdx, [rip + .Lanon.[ID].3] + mov esi, 54 + call qword ptr [rip + SYM(core::option::expect_failed::GENERATED_ID, 0)@GOTPCREL] + ud2 +.Lfunc_end1: + .size SYM(objc2[CRATE_ID]::message::encountered_error::, 0), .Lfunc_end1-SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + + .section .text.error_bool,"ax",@progbits + .globl error_bool + .p2align 4, 0x90 + .type error_bool,@function +error_bool: + push rbp + push r14 + push rbx + sub rsp, 16 + mov r14d, edx + mov rbx, rsi + mov rbp, rdi + mov qword ptr [rsp + 8], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + lea rcx, [rsp + 8] + mov rdi, rbp + mov rsi, rbx + mov edx, r14d + call rax + test al, al + je .LBB2_2 + xor eax, eax +.LBB2_3: + add rsp, 16 + pop rbx + pop r14 + pop rbp + ret +.LBB2_2: + mov rdi, qword ptr [rsp + 8] + call SYM(objc2[CRATE_ID]::message::encountered_error::, 0) + jmp .LBB2_3 +.Lfunc_end2: + .size error_bool, .Lfunc_end2-error_bool + + .section .text.error_new,"ax",@progbits + .globl error_new + .p2align 4, 0x90 + .type error_new,@function +error_new: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + test rax, rax + je .LBB3_2 + mov rdx, rax + xor eax, eax + add rsp, 8 + pop rbx + pop r14 + ret +.LBB3_2: + mov rdi, qword ptr [rsp] + lea rsi, [rip + .Lanon.[ID].4] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end3: + .size error_new, .Lfunc_end3-error_new + + .section .text.error_alloc,"ax",@progbits + .globl error_alloc + .p2align 4, 0x90 + .type error_alloc,@function +error_alloc: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + test rax, rax + je .LBB4_2 + mov rdx, rax + xor eax, eax + add rsp, 8 + pop rbx + pop r14 + ret +.LBB4_2: + mov rdi, qword ptr [rsp] + lea rsi, [rip + .Lanon.[ID].5] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end4: + .size error_alloc, .Lfunc_end4-error_alloc + + .section .text.error_init,"ax",@progbits + .globl error_init + .p2align 4, 0x90 + .type error_init,@function +error_init: + push r14 + push rbx + push rax + mov qword ptr [rsp], 0 + test rdi, rdi + je .LBB5_1 + mov r14, rsi + mov rbx, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + test rax, rax + je .LBB5_4 + mov rdx, rax + xor eax, eax + add rsp, 8 + pop rbx + pop r14 + ret +.LBB5_1: + xor edi, edi + jmp .LBB5_5 +.LBB5_4: + mov rdi, qword ptr [rsp] +.LBB5_5: + lea rsi, [rip + .Lanon.[ID].6] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end5: + .size error_init, .Lfunc_end5-error_init + + .section .text.error_copy,"ax",@progbits + .globl error_copy + .p2align 4, 0x90 + .type error_copy,@function +error_copy: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + test rax, rax + je .LBB6_2 + mov rdx, rax + xor eax, eax + add rsp, 8 + pop rbx + pop r14 + ret +.LBB6_2: + mov rdi, qword ptr [rsp] + lea rsi, [rip + .Lanon.[ID].7] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end6: + .size error_copy, .Lfunc_end6-error_copy + + .section .text.error_autoreleased,"ax",@progbits + .globl error_autoreleased + .p2align 4, 0x90 + .type error_autoreleased,@function +error_autoreleased: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + mov rdi, rax + call qword ptr [rip + objc_retainAutoreleasedReturnValue@GOTPCREL] + test rax, rax + je .LBB7_2 + mov rdx, rax + xor eax, eax + add rsp, 8 + pop rbx + pop r14 + ret +.LBB7_2: + mov rdi, qword ptr [rsp] + lea rsi, [rip + .Lanon.[ID].8] + call SYM(objc2[CRATE_ID]::__macro_helpers::encountered_error::, 0) + mov rdx, rax + mov eax, 1 + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end7: + .size error_autoreleased, .Lfunc_end7-error_autoreleased + + .type .Lanon.[ID].0,@object + .section .rodata..Lanon.[ID].0,"a",@progbits +.Lanon.[ID].0: + .ascii "error parameter should be set if the method returns NULL" + .size .Lanon.[ID].0, 56 + + .type .Lanon.[ID].1,@object + .section .rodata..Lanon.[ID].1,"a",@progbits +.Lanon.[ID].1: + .ascii "error parameter should be set if the method returns NO" + .size .Lanon.[ID].1, 54 + + .type .Lanon.[ID].2,@object + .section .rodata..Lanon.[ID].2,"a",@progbits +.Lanon.[ID].2: + .ascii "crates/$DIR/lib.rs" + .size .Lanon.[ID].2, 54 + + .type .Lanon.[ID].3,@object + .section .data.rel.ro..Lanon.[ID].3,"aw",@progbits + .p2align 3 +.Lanon.[ID].3: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\013\000\000\000\005\000\000" + .size .Lanon.[ID].3, 24 + + .type .Lanon.[ID].4,@object + .section .data.rel.ro..Lanon.[ID].4,"aw",@progbits + .p2align 3 +.Lanon.[ID].4: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\020\000\000\000\005\000\000" + .size .Lanon.[ID].4, 24 + + .type .Lanon.[ID].5,@object + .section .data.rel.ro..Lanon.[ID].5,"aw",@progbits + .p2align 3 +.Lanon.[ID].5: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\025\000\000\000\005\000\000" + .size .Lanon.[ID].5, 24 + + .type .Lanon.[ID].6,@object + .section .data.rel.ro..Lanon.[ID].6,"aw",@progbits + .p2align 3 +.Lanon.[ID].6: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\032\000\000\000\005\000\000" + .size .Lanon.[ID].6, 24 + + .type .Lanon.[ID].7,@object + .section .data.rel.ro..Lanon.[ID].7,"aw",@progbits + .p2align 3 +.Lanon.[ID].7: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000\037\000\000\000\005\000\000" + .size .Lanon.[ID].7, 24 + + .type .Lanon.[ID].8,@object + .section .data.rel.ro..Lanon.[ID].8,"aw",@progbits + .p2align 3 +.Lanon.[ID].8: + .quad .Lanon.[ID].2 + .asciz "6\000\000\000\000\000\000\000$\000\000\000\005\000\000" + .size .Lanon.[ID].8, 24 + + .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_msg_send_error/lib.rs b/crates/test-assembly/crates/test_msg_send_error/lib.rs new file mode 100644 index 000000000..ea2b2ddc7 --- /dev/null +++ b/crates/test-assembly/crates/test_msg_send_error/lib.rs @@ -0,0 +1,37 @@ +//! Test that error parameters are handled correctly. +use objc2::rc::{Allocated, Id, Shared}; +use objc2::runtime::{Class, Object, Sel}; +use objc2::MessageReceiver; +use objc2::__macro_helpers::{Alloc, CopyOrMutCopy, Init, MsgSendId, New, Other}; + +type Result = std::result::Result>; + +#[no_mangle] +unsafe fn error_bool(obj: &Object, sel: Sel, param: u32) -> Result<()> { + MessageReceiver::__send_message_error(obj, sel, (param,)) +} + +#[no_mangle] +unsafe fn error_new(cls: &Class, sel: Sel) -> Result> { + New::send_message_id_error(cls, sel, ()) +} + +#[no_mangle] +unsafe fn error_alloc(cls: &Class, sel: Sel) -> Result> { + Alloc::send_message_id_error(cls, sel, ()) +} + +#[no_mangle] +unsafe fn error_init(obj: Option>, sel: Sel) -> Result> { + Init::send_message_id_error(obj, sel, ()) +} + +#[no_mangle] +unsafe fn error_copy(obj: &Object, sel: Sel) -> Result> { + CopyOrMutCopy::send_message_id_error(obj, sel, ()) +} + +#[no_mangle] +unsafe fn error_autoreleased(obj: &Object, sel: Sel) -> Result> { + Other::send_message_id_error(obj, sel, ()) +} diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/apple-aarch64.s b/crates/test-assembly/crates/test_msg_send_id/expected/apple-aarch64.s index 42676bf19..717b37422 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/apple-aarch64.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/apple-aarch64.s @@ -180,6 +180,30 @@ Lloh9: bl SYM( as objc2::__macro_helpers::MsgSendIdFailed>::failed::GENERATED_ID, 0) .loh AdrpAdd Lloh8, Lloh9 + .globl _handle_with_out_param + .p2align 2 +_handle_with_out_param: + stp x22, x21, [sp, #-48]! + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + ldr x20, [x2] + bl _objc_msgSend + mov x21, x0 + ldr x0, [x19] + bl _objc_retain + mov x0, x20 + bl _objc_release + ; InlineAsm Start + mov x29, x29 + ; InlineAsm End + mov x0, x21 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + ldp x22, x21, [sp], #48 + b _objc_retainAutoreleasedReturnValue + .section __TEXT,__const l_anon.[ID].0: .ascii "crates/$DIR/lib.rs" diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7.s b/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7.s index 118aadc01..3fbc72e73 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7.s @@ -177,6 +177,27 @@ LPC12_0: mov lr, pc b SYM( as objc2::__macro_helpers::MsgSendIdFailed>::failed::GENERATED_ID, 0) + .globl _handle_with_out_param + .p2align 2 + .code 32 +_handle_with_out_param: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r4, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r6, r0 + ldr r0, [r4] + bl _objc_retain + mov r0, r5 + bl _objc_release + @ InlineAsm Start + mov r7, r7 + @ InlineAsm End + mov r0, r6 + pop {r4, r5, r6, r7, lr} + b _objc_retainAutoreleasedReturnValue + .section __TEXT,__const l_anon.[ID].0: .ascii "crates/$DIR/lib.rs" diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7s.s b/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7s.s index f41ecb417..c8a8dcc5e 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7s.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/apple-armv7s.s @@ -189,6 +189,27 @@ LPC12_0: mov lr, pc b SYM( as objc2::__macro_helpers::MsgSendIdFailed>::failed::GENERATED_ID, 0) + .globl _handle_with_out_param + .p2align 2 + .code 32 +_handle_with_out_param: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r4, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r6, r0 + ldr r0, [r4] + bl _objc_retain + mov r0, r5 + bl _objc_release + mov r0, r6 + @ InlineAsm Start + mov r7, r7 + @ InlineAsm End + bl _objc_retainAutoreleasedReturnValue + pop {r4, r5, r6, r7, pc} + .section __TEXT,__const l_anon.[ID].0: .ascii "crates/$DIR/lib.rs" diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86.s b/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86.s index 9f2d91a5c..a00dc4db1 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86.s @@ -290,6 +290,43 @@ LBB12_2: push esi call SYM( as objc2::__macro_helpers::MsgSendIdFailed>::failed::GENERATED_ID, 0) + .globl _handle_with_out_param + .p2align 4, 0x90 +_handle_with_out_param: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov ebx, dword ptr [ebp + 16] + mov edi, dword ptr [ebx] + mov dword ptr [esp + 8], ebx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebx] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + ## InlineAsm Start + + mov ebp, ebp + + ## InlineAsm End + mov dword ptr [esp], esi + call _objc_retainAutoreleasedReturnValue + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret + .section __TEXT,__const l_anon.[ID].0: .ascii "crates/$DIR/lib.rs" diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86_64.s b/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86_64.s index b09d8fc2f..e20a21975 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86_64.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/apple-x86_64.s @@ -201,6 +201,37 @@ LBB12_2: mov rsi, r14 call SYM( as objc2::__macro_helpers::MsgSendIdFailed>::failed::GENERATED_ID, 0) + .globl _handle_with_out_param + .p2align 4, 0x90 +_handle_with_out_param: + push rbp + mov rbp, rsp + push r15 + push r14 + push rbx + push rax + mov rbx, rdx + mov r14, qword ptr [rdx] + call _objc_msgSend + mov r15, rax + mov rdi, qword ptr [rbx] + call _objc_retain + mov rdi, r14 + call _objc_release + mov rdi, r15 + call _objc_retainAutoreleasedReturnValue + ## InlineAsm Start + + nop + + ## InlineAsm End + add rsp, 8 + pop rbx + pop r14 + pop r15 + pop rbp + ret + .section __TEXT,__const l_anon.[ID].0: .ascii "crates/$DIR/lib.rs" diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86.s b/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86.s index 6014c6284..cd8c827b3 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86.s @@ -502,6 +502,50 @@ handle_autoreleased_fallible: .Lfunc_end12: .size handle_autoreleased_fallible, .Lfunc_end12-handle_autoreleased_fallible + .section .text.handle_with_out_param,"ax",@progbits + .globl handle_with_out_param + .p2align 4, 0x90 + .type handle_with_out_param,@function +handle_with_out_param: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [esp + 32] + mov esi, dword ptr [esp + 36] + mov edi, dword ptr [esp + 40] + call .L13$pb +.L13$pb: + pop ebx +.Ltmp13: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp13-.L13$pb) + mov dword ptr [esp + 4], esi + mov dword ptr [esp], eax + call objc_msg_lookup@PLT + mov ecx, dword ptr [esp + 32] + mov ebp, dword ptr [edi] + mov dword ptr [esp + 8], edi + mov dword ptr [esp + 4], esi + mov dword ptr [esp], ecx + call eax + mov esi, eax + mov eax, dword ptr [edi] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], ebp + call objc_release@PLT + mov dword ptr [esp], esi + call objc_retainAutoreleasedReturnValue@PLT + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end13: + .size handle_with_out_param, .Lfunc_end13-handle_with_out_param + .type .Lanon.[ID].0,@object .section .rodata..Lanon.[ID].0,"a",@progbits .Lanon.[ID].0: diff --git a/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86_64.s b/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86_64.s index 8b0e91e1c..7b85147dc 100644 --- a/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86_64.s +++ b/crates/test-assembly/crates/test_msg_send_id/expected/gnustep-x86_64.s @@ -352,6 +352,40 @@ handle_autoreleased_fallible: .Lfunc_end12: .size handle_autoreleased_fallible, .Lfunc_end12-handle_autoreleased_fallible + .section .text.handle_with_out_param,"ax",@progbits + .globl handle_with_out_param + .p2align 4, 0x90 + .type handle_with_out_param,@function +handle_with_out_param: + push r15 + push r14 + push r12 + push rbx + push rax + mov rbx, rdx + mov r14, rsi + mov r15, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov r12, qword ptr [rbx] + mov rdi, r15 + mov rsi, r14 + mov rdx, rbx + call rax + mov r14, rax + mov rdi, qword ptr [rbx] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r12 + call qword ptr [rip + objc_release@GOTPCREL] + mov rdi, r14 + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + jmp qword ptr [rip + objc_retainAutoreleasedReturnValue@GOTPCREL] +.Lfunc_end13: + .size handle_with_out_param, .Lfunc_end13-handle_with_out_param + .type .Lanon.[ID].0,@object .section .rodata..Lanon.[ID].0,"a",@progbits .Lanon.[ID].0: diff --git a/crates/test-assembly/crates/test_msg_send_id/lib.rs b/crates/test-assembly/crates/test_msg_send_id/lib.rs index 929218caf..5d2db7497 100644 --- a/crates/test-assembly/crates/test_msg_send_id/lib.rs +++ b/crates/test-assembly/crates/test_msg_send_id/lib.rs @@ -71,3 +71,13 @@ unsafe fn handle_autoreleased(obj: &Object, sel: Sel) -> Option Id { Other::send_message_id(obj, sel, ()) } + +// TODO: The optimization does not happen here, fix this! +#[no_mangle] +unsafe fn handle_with_out_param( + obj: &Object, + sel: Sel, + param: &mut Id, +) -> Option> { + Other::send_message_id(obj, sel, (param,)) +} diff --git a/crates/test-assembly/crates/test_out_parameters/Cargo.toml b/crates/test-assembly/crates/test_out_parameters/Cargo.toml new file mode 100644 index 000000000..73dda7dcb --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "test_out_parameters" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +objc2 = { path = "../../../objc2", default-features = false } + +[features] +default = ["apple", "std"] +std = ["objc2/std"] +# Runtime +apple = ["objc2/apple"] +gnustep-1-7 = ["objc2/gnustep-1-7"] +gnustep-1-8 = ["gnustep-1-7", "objc2/gnustep-1-8"] +gnustep-1-9 = ["gnustep-1-8", "objc2/gnustep-1-9"] +gnustep-2-0 = ["gnustep-1-9", "objc2/gnustep-2-0"] +gnustep-2-1 = ["gnustep-2-0", "objc2/gnustep-2-1"] + +# Hack +assembly-features = [] diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s new file mode 100644 index 000000000..0b77cf062 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/apple-aarch64.s @@ -0,0 +1,246 @@ + .section __TEXT,__text,regular,pure_instructions + .globl _nonnull_nonnull + .p2align 2 +_nonnull_nonnull: + stp x22, x21, [sp, #-48]! + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + ldr x20, [x2] + bl _objc_msgSend + mov x21, x0 + ldr x0, [x19] + bl _objc_retain + mov x0, x20 + bl _objc_release + mov x0, x21 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + ldp x22, x21, [sp], #48 + ret + + .globl _null_nonnull + .p2align 2 +_null_nonnull: + cbz x2, LBB1_2 + stp x22, x21, [sp, #-48]! + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + ldr x20, [x2] + bl _objc_msgSend + mov x21, x0 + ldr x0, [x19] + bl _objc_retain + mov x0, x20 + bl _objc_release + mov x0, x21 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + ldp x22, x21, [sp], #48 + ret +LBB1_2: + b _objc_msgSend + + .globl _nonnull_null + .p2align 2 +_nonnull_null: + stp x22, x21, [sp, #-48]! + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x21, x2 + ldr x19, [x2] + bl _objc_msgSend + mov x20, x0 + ldr x0, [x21] + bl _objc_retain + cbz x19, LBB2_2 + mov x0, x19 + bl _objc_release +LBB2_2: + mov x0, x20 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + ldp x22, x21, [sp], #48 + ret + + .globl _null_null + .p2align 2 +_null_null: + cbz x2, LBB3_4 + stp x22, x21, [sp, #-48]! + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x21, x2 + ldr x19, [x2] + bl _objc_msgSend + mov x20, x0 + ldr x0, [x21] + bl _objc_retain + cbz x19, LBB3_3 + mov x0, x19 + bl _objc_release +LBB3_3: + mov x0, x20 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + ldp x22, x21, [sp], #48 + ret +LBB3_4: + b _objc_msgSend + + .globl _two_nonnull_nonnull + .p2align 2 +_two_nonnull_nonnull: + stp x24, x23, [sp, #-64]! + stp x22, x21, [sp, #16] + stp x20, x19, [sp, #32] + stp x29, x30, [sp, #48] + add x29, sp, #48 + mov x19, x3 + mov x20, x2 + ldr x21, [x2] + ldr x22, [x3] + bl _objc_msgSend + mov x23, x0 + ldr x0, [x20] + bl _objc_retain + mov x0, x21 + bl _objc_release + ldr x0, [x19] + bl _objc_retain + mov x0, x22 + bl _objc_release + mov x0, x23 + ldp x29, x30, [sp, #48] + ldp x20, x19, [sp, #32] + ldp x22, x21, [sp, #16] + ldp x24, x23, [sp], #64 + ret + + .globl _call_with_none1 + .p2align 2 +_call_with_none1: + mov x2, #0 + b _objc_msgSend + + .globl _call_with_none2 + .p2align 2 +_call_with_none2: + mov x2, #0 + b _objc_msgSend + + .globl _call_with_none3 + .p2align 2 +_call_with_none3: + sub sp, sp, #48 + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + mov x19, x0 + ldr x0, [sp, #8] + bl _objc_retain + ldr x1, [sp, #8] + mov x0, x19 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + add sp, sp, #48 + ret + + .globl _call_with_none4 + .p2align 2 +_call_with_none4: + sub sp, sp, #48 + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + str xzr, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + mov x19, x0 + ldr x0, [sp, #8] + bl _objc_retain + ldr x1, [sp, #8] + mov x0, x19 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + add sp, sp, #48 + ret + + .globl _call_with_some1 + .p2align 2 +_call_with_some1: + sub sp, sp, #48 + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + str x2, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + mov x20, x0 + ldr x0, [sp, #8] + bl _objc_retain + mov x0, x19 + bl _objc_release + ldr x1, [sp, #8] + mov x0, x20 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + add sp, sp, #48 + ret + + .globl _call_with_some2 + .p2align 2 +_call_with_some2: + sub sp, sp, #48 + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + str x2, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + mov x20, x0 + ldr x0, [sp, #8] + bl _objc_retain + mov x0, x19 + bl _objc_release + ldr x1, [sp, #8] + mov x0, x20 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + add sp, sp, #48 + ret + + .globl _call_with_some3 + .p2align 2 +_call_with_some3: + sub sp, sp, #48 + stp x20, x19, [sp, #16] + stp x29, x30, [sp, #32] + add x29, sp, #32 + mov x19, x2 + str x2, [sp, #8] + add x2, sp, #8 + bl _objc_msgSend + mov x20, x0 + ldr x0, [sp, #8] + bl _objc_retain + mov x0, x19 + bl _objc_release + ldr x1, [sp, #8] + mov x0, x20 + ldp x29, x30, [sp, #32] + ldp x20, x19, [sp, #16] + add sp, sp, #48 + ret + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s new file mode 100644 index 000000000..4388893c3 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7.s @@ -0,0 +1,227 @@ + .section __TEXT,__text,regular,pure_instructions + .syntax unified + .globl _nonnull_nonnull + .p2align 2 + .code 32 +_nonnull_nonnull: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r4, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r6, r0 + ldr r0, [r4] + bl _objc_retain + mov r0, r5 + bl _objc_release + mov r0, r6 + pop {r4, r5, r6, r7, pc} + + .globl _null_nonnull + .p2align 2 + .code 32 +_null_nonnull: + cmp r2, #0 + beq LBB1_2 + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r4, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r6, r0 + ldr r0, [r4] + bl _objc_retain + mov r0, r5 + bl _objc_release + mov r0, r6 + pop {r4, r5, r6, r7, pc} +LBB1_2: + mov r2, #0 + b _objc_msgSend + + .globl _nonnull_null + .p2align 2 + .code 32 +_nonnull_null: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r6, r2 + ldr r4, [r2] + bl _objc_msgSend + mov r5, r0 + ldr r0, [r6] + bl _objc_retain + cmp r4, #0 + beq LBB2_2 + mov r0, r4 + bl _objc_release +LBB2_2: + mov r0, r5 + pop {r4, r5, r6, r7, pc} + + .globl _null_null + .p2align 2 + .code 32 +_null_null: + cmp r2, #0 + beq LBB3_4 + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r6, r2 + ldr r4, [r2] + bl _objc_msgSend + mov r5, r0 + ldr r0, [r6] + bl _objc_retain + cmp r4, #0 + beq LBB3_3 + mov r0, r4 + bl _objc_release +LBB3_3: + mov r0, r5 + pop {r4, r5, r6, r7, pc} +LBB3_4: + mov r2, #0 + b _objc_msgSend + + .globl _two_nonnull_nonnull + .p2align 2 + .code 32 +_two_nonnull_nonnull: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + push {r8, r10} + mov r4, r3 + mov r5, r2 + ldr r8, [r3] + ldr r6, [r2] + bl _objc_msgSend + mov r10, r0 + ldr r0, [r5] + bl _objc_retain + mov r0, r6 + bl _objc_release + ldr r0, [r4] + bl _objc_retain + mov r0, r8 + bl _objc_release + mov r0, r10 + pop {r8, r10} + pop {r4, r5, r6, r7, pc} + + .globl _call_with_none1 + .p2align 2 + .code 32 +_call_with_none1: + mov r2, #0 + b _objc_msgSend + + .globl _call_with_none2 + .p2align 2 + .code 32 +_call_with_none2: + mov r2, #0 + b _objc_msgSend + + .globl _call_with_none3 + .p2align 2 + .code 32 +_call_with_none3: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r2, #0 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r4, r0 + ldr r0, [sp] + bl _objc_retain + ldr r1, [sp] + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _call_with_none4 + .p2align 2 + .code 32 +_call_with_none4: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r2, #0 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r4, r0 + ldr r0, [sp] + bl _objc_retain + ldr r1, [sp] + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _call_with_some1 + .p2align 2 + .code 32 +_call_with_some1: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + + .globl _call_with_some2 + .p2align 2 + .code 32 +_call_with_some2: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + + .globl _call_with_some3 + .p2align 2 + .code 32 +_call_with_some3: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s new file mode 100644 index 000000000..684e06419 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/apple-armv7s.s @@ -0,0 +1,235 @@ + .section __TEXT,__text,regular,pure_instructions + .syntax unified + .globl _nonnull_nonnull + .p2align 2 + .code 32 +_nonnull_nonnull: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r4, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r6, r0 + ldr r0, [r4] + bl _objc_retain + mov r0, r5 + bl _objc_release + mov r0, r6 + pop {r4, r5, r6, r7, pc} + + .globl _null_nonnull + .p2align 2 + .code 32 +_null_nonnull: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + cmp r2, #0 + beq LBB1_2 + mov r5, r2 + ldr r6, [r2] + bl _objc_msgSend + mov r4, r0 + ldr r0, [r5] + bl _objc_retain + mov r0, r6 + bl _objc_release + mov r0, r4 + pop {r4, r5, r6, r7, pc} +LBB1_2: + mov r2, #0 + bl _objc_msgSend + pop {r4, r5, r6, r7, pc} + + .globl _nonnull_null + .p2align 2 + .code 32 +_nonnull_null: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + mov r6, r2 + ldr r4, [r2] + bl _objc_msgSend + mov r5, r0 + ldr r0, [r6] + bl _objc_retain + cmp r4, #0 + beq LBB2_2 + mov r0, r4 + bl _objc_release +LBB2_2: + mov r0, r5 + pop {r4, r5, r6, r7, pc} + + .globl _null_null + .p2align 2 + .code 32 +_null_null: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + cmp r2, #0 + beq LBB3_4 + mov r6, r2 + ldr r5, [r2] + bl _objc_msgSend + mov r4, r0 + ldr r0, [r6] + bl _objc_retain + cmp r5, #0 + beq LBB3_3 + mov r0, r5 + bl _objc_release +LBB3_3: + mov r0, r4 + pop {r4, r5, r6, r7, pc} +LBB3_4: + mov r2, #0 + bl _objc_msgSend + pop {r4, r5, r6, r7, pc} + + .globl _two_nonnull_nonnull + .p2align 2 + .code 32 +_two_nonnull_nonnull: + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + push {r8, r10} + mov r4, r3 + mov r5, r2 + ldr r8, [r3] + ldr r6, [r2] + bl _objc_msgSend + mov r10, r0 + ldr r0, [r5] + bl _objc_retain + mov r0, r6 + bl _objc_release + ldr r0, [r4] + bl _objc_retain + mov r0, r8 + bl _objc_release + mov r0, r10 + pop {r8, r10} + pop {r4, r5, r6, r7, pc} + + .globl _call_with_none1 + .p2align 2 + .code 32 +_call_with_none1: + push {r7, lr} + mov r7, sp + mov r2, #0 + bl _objc_msgSend + pop {r7, pc} + + .globl _call_with_none2 + .p2align 2 + .code 32 +_call_with_none2: + push {r7, lr} + mov r7, sp + mov r2, #0 + bl _objc_msgSend + pop {r7, pc} + + .globl _call_with_none3 + .p2align 2 + .code 32 +_call_with_none3: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r2, #0 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r4, r0 + ldr r0, [sp] + bl _objc_retain + ldr r1, [sp] + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _call_with_none4 + .p2align 2 + .code 32 +_call_with_none4: + push {r4, r7, lr} + add r7, sp, #4 + sub sp, sp, #4 + mov r2, #0 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r4, r0 + ldr r0, [sp] + bl _objc_retain + ldr r1, [sp] + mov r0, r4 + sub sp, r7, #4 + pop {r4, r7, pc} + + .globl _call_with_some1 + .p2align 2 + .code 32 +_call_with_some1: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + + .globl _call_with_some2 + .p2align 2 + .code 32 +_call_with_some2: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + + .globl _call_with_some3 + .p2align 2 + .code 32 +_call_with_some3: + push {r4, r5, r7, lr} + add r7, sp, #8 + sub sp, sp, #4 + mov r4, r2 + str r2, [sp] + mov r2, sp + bl _objc_msgSend + mov r5, r0 + ldr r0, [sp] + bl _objc_retain + mov r0, r4 + bl _objc_release + ldr r1, [sp] + mov r0, r5 + sub sp, r7, #8 + pop {r4, r5, r7, pc} + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s new file mode 100644 index 000000000..5b060aa7a --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86.s @@ -0,0 +1,386 @@ + .section __TEXT,__text,regular,pure_instructions + .intel_syntax noprefix + .globl _nonnull_nonnull + .p2align 4, 0x90 +_nonnull_nonnull: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov ebx, dword ptr [ebp + 16] + mov edi, dword ptr [ebx] + mov dword ptr [esp + 8], ebx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebx] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + mov eax, esi + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret + + .globl _null_nonnull + .p2align 4, 0x90 +_null_nonnull: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 12 + mov edi, dword ptr [ebp + 16] + mov ecx, dword ptr [ebp + 12] + mov eax, dword ptr [ebp + 8] + test edi, edi + je LBB1_1 + mov ebx, dword ptr [edi] + sub esp, 4 + push edi + push ecx + push eax + call _objc_msgSend + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [edi] + call _objc_retain + add esp, 4 + push ebx + call _objc_release + add esp, 16 + mov eax, esi + add esp, 12 + jmp LBB1_2 +LBB1_1: + sub esp, 4 + push 0 + push ecx + push eax + call _objc_msgSend + add esp, 28 +LBB1_2: + pop esi + pop edi + pop ebx + pop ebp + ret + + .globl _nonnull_null + .p2align 4, 0x90 +_nonnull_null: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov ebx, dword ptr [ebp + 16] + mov edi, dword ptr [ebx] + mov dword ptr [esp + 8], ebx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebx] + mov dword ptr [esp], eax + call _objc_retain + test edi, edi + je LBB2_2 + mov dword ptr [esp], edi + call _objc_release +LBB2_2: + mov eax, esi + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret + + .globl _null_null + .p2align 4, 0x90 +_null_null: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 12 + mov ebx, dword ptr [ebp + 16] + mov ecx, dword ptr [ebp + 12] + mov eax, dword ptr [ebp + 8] + test ebx, ebx + je LBB3_1 + mov edi, dword ptr [ebx] + sub esp, 4 + push ebx + push ecx + push eax + call _objc_msgSend + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [ebx] + call _objc_retain + add esp, 16 + test edi, edi + je LBB3_4 + sub esp, 12 + push edi + call _objc_release + add esp, 16 +LBB3_4: + mov eax, esi + add esp, 12 + jmp LBB3_5 +LBB3_1: + sub esp, 4 + push 0 + push ecx + push eax + call _objc_msgSend + add esp, 28 +LBB3_5: + pop esi + pop edi + pop ebx + pop ebp + ret + + .globl _two_nonnull_nonnull + .p2align 4, 0x90 +_two_nonnull_nonnull: + push ebp + mov ebp, esp + push ebx + push edi + push esi + sub esp, 28 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov esi, dword ptr [ebp + 20] + mov ebx, dword ptr [ebp + 16] + mov edi, dword ptr [ebx] + mov edx, dword ptr [esi] + mov dword ptr [ebp - 16], edx + mov dword ptr [esp + 12], esi + mov dword ptr [esp + 8], ebx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebx] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + mov eax, dword ptr [ebp + 20] + mov eax, dword ptr [eax] + mov dword ptr [esp], eax + call _objc_retain + mov eax, dword ptr [ebp - 16] + mov dword ptr [esp], eax + call _objc_release + mov eax, esi + add esp, 28 + pop esi + pop edi + pop ebx + pop ebp + ret + + .globl _call_with_none1 + .p2align 4, 0x90 +_call_with_none1: + push ebp + mov ebp, esp + sub esp, 8 + sub esp, 4 + push 0 + push dword ptr [ebp + 12] + push dword ptr [ebp + 8] + call _objc_msgSend + add esp, 24 + pop ebp + ret + + .globl _call_with_none2 + .p2align 4, 0x90 +_call_with_none2: + push ebp + mov ebp, esp + sub esp, 8 + sub esp, 4 + push 0 + push dword ptr [ebp + 12] + push dword ptr [ebp + 8] + call _objc_msgSend + add esp, 24 + pop ebp + ret + + .globl _call_with_none3 + .p2align 4, 0x90 +_call_with_none3: + push ebp + mov ebp, esp + push esi + push eax + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [ebp - 8] + call _objc_retain + add esp, 16 + mov edx, dword ptr [ebp - 8] + mov eax, esi + add esp, 4 + pop esi + pop ebp + ret + + .globl _call_with_none4 + .p2align 4, 0x90 +_call_with_none4: + push ebp + mov ebp, esp + push esi + push eax + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov dword ptr [ebp - 8], 0 + sub esp, 4 + lea edx, [ebp - 8] + push edx + push ecx + push eax + call _objc_msgSend + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [ebp - 8] + call _objc_retain + add esp, 16 + mov edx, dword ptr [ebp - 8] + mov eax, esi + add esp, 4 + pop esi + pop ebp + ret + + .globl _call_with_some1 + .p2align 4, 0x90 +_call_with_some1: + push ebp + mov ebp, esp + push edi + push esi + sub esp, 16 + mov edi, dword ptr [ebp + 16] + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + lea edx, [ebp + 16] + mov dword ptr [esp + 8], edx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebp + 16] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + mov edx, dword ptr [ebp + 16] + mov eax, esi + add esp, 16 + pop esi + pop edi + pop ebp + ret + + .globl _call_with_some2 + .p2align 4, 0x90 +_call_with_some2: + push ebp + mov ebp, esp + push edi + push esi + sub esp, 16 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov edi, dword ptr [ebp + 16] + mov dword ptr [ebp - 12], edi + lea edx, [ebp - 12] + mov dword ptr [esp + 8], edx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebp - 12] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + mov edx, dword ptr [ebp - 12] + mov eax, esi + add esp, 16 + pop esi + pop edi + pop ebp + ret + + .globl _call_with_some3 + .p2align 4, 0x90 +_call_with_some3: + push ebp + mov ebp, esp + push edi + push esi + sub esp, 16 + mov eax, dword ptr [ebp + 8] + mov ecx, dword ptr [ebp + 12] + mov edi, dword ptr [ebp + 16] + mov dword ptr [ebp - 12], edi + lea edx, [ebp - 12] + mov dword ptr [esp + 8], edx + mov dword ptr [esp + 4], ecx + mov dword ptr [esp], eax + call _objc_msgSend + mov esi, eax + mov eax, dword ptr [ebp - 12] + mov dword ptr [esp], eax + call _objc_retain + mov dword ptr [esp], edi + call _objc_release + mov edx, dword ptr [ebp - 12] + mov eax, esi + add esp, 16 + pop esi + pop edi + pop ebp + ret + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s new file mode 100644 index 000000000..11fcf2390 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/apple-x86_64.s @@ -0,0 +1,287 @@ + .section __TEXT,__text,regular,pure_instructions + .intel_syntax noprefix + .globl _nonnull_nonnull + .p2align 4, 0x90 +_nonnull_nonnull: + push rbp + mov rbp, rsp + push r15 + push r14 + push rbx + push rax + mov rbx, rdx + mov r14, qword ptr [rdx] + call _objc_msgSend + mov r15, rax + mov rdi, qword ptr [rbx] + call _objc_retain + mov rdi, r14 + call _objc_release + mov rax, r15 + add rsp, 8 + pop rbx + pop r14 + pop r15 + pop rbp + ret + + .globl _null_nonnull + .p2align 4, 0x90 +_null_nonnull: + test rdx, rdx + je LBB1_2 + push rbp + mov rbp, rsp + push r15 + push r14 + push rbx + push rax + mov rbx, rdx + mov r14, qword ptr [rdx] + call _objc_msgSend + mov r15, rax + mov rdi, qword ptr [rbx] + call _objc_retain + mov rdi, r14 + call _objc_release + mov rax, r15 + add rsp, 8 + pop rbx + pop r14 + pop r15 + pop rbp + ret +LBB1_2: + xor edx, edx + jmp _objc_msgSend + + .globl _nonnull_null + .p2align 4, 0x90 +_nonnull_null: + push rbp + mov rbp, rsp + push r15 + push r14 + push rbx + push rax + mov rbx, rdx + mov r15, qword ptr [rdx] + call _objc_msgSend + mov r14, rax + mov rdi, qword ptr [rbx] + call _objc_retain + test r15, r15 + je LBB2_2 + mov rdi, r15 + call _objc_release +LBB2_2: + mov rax, r14 + add rsp, 8 + pop rbx + pop r14 + pop r15 + pop rbp + ret + + .globl _null_null + .p2align 4, 0x90 +_null_null: + test rdx, rdx + je LBB3_4 + push rbp + mov rbp, rsp + push r15 + push r14 + push rbx + push rax + mov rbx, rdx + mov r15, qword ptr [rdx] + call _objc_msgSend + mov r14, rax + mov rdi, qword ptr [rbx] + call _objc_retain + test r15, r15 + je LBB3_3 + mov rdi, r15 + call _objc_release +LBB3_3: + mov rax, r14 + add rsp, 8 + pop rbx + pop r14 + pop r15 + pop rbp + ret +LBB3_4: + xor edx, edx + jmp _objc_msgSend + + .globl _two_nonnull_nonnull + .p2align 4, 0x90 +_two_nonnull_nonnull: + push rbp + mov rbp, rsp + push r15 + push r14 + push r13 + push r12 + push rbx + push rax + mov r14, rcx + mov rbx, rdx + mov r15, qword ptr [rdx] + mov r12, qword ptr [rcx] + call _objc_msgSend + mov r13, rax + mov rdi, qword ptr [rbx] + call _objc_retain + mov rdi, r15 + call _objc_release + mov rdi, qword ptr [r14] + call _objc_retain + mov rdi, r12 + call _objc_release + mov rax, r13 + add rsp, 8 + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp + ret + + .globl _call_with_none1 + .p2align 4, 0x90 +_call_with_none1: + push rbp + mov rbp, rsp + xor edx, edx + pop rbp + jmp _objc_msgSend + + .globl _call_with_none2 + .p2align 4, 0x90 +_call_with_none2: + push rbp + mov rbp, rsp + xor edx, edx + pop rbp + jmp _objc_msgSend + + .globl _call_with_none3 + .p2align 4, 0x90 +_call_with_none3: + push rbp + mov rbp, rsp + push rbx + push rax + mov qword ptr [rbp - 16], 0 + lea rdx, [rbp - 16] + call _objc_msgSend + mov rbx, rax + mov rdi, qword ptr [rbp - 16] + call _objc_retain + mov rdx, qword ptr [rbp - 16] + mov rax, rbx + add rsp, 8 + pop rbx + pop rbp + ret + + .globl _call_with_none4 + .p2align 4, 0x90 +_call_with_none4: + push rbp + mov rbp, rsp + push rbx + push rax + mov qword ptr [rbp - 16], 0 + lea rdx, [rbp - 16] + call _objc_msgSend + mov rbx, rax + mov rdi, qword ptr [rbp - 16] + call _objc_retain + mov rdx, qword ptr [rbp - 16] + mov rax, rbx + add rsp, 8 + pop rbx + pop rbp + ret + + .globl _call_with_some1 + .p2align 4, 0x90 +_call_with_some1: + push rbp + mov rbp, rsp + push r14 + push rbx + sub rsp, 16 + mov rbx, rdx + mov qword ptr [rbp - 24], rdx + lea rdx, [rbp - 24] + call _objc_msgSend + mov r14, rax + mov rdi, qword ptr [rbp - 24] + call _objc_retain + mov rdi, rbx + call _objc_release + mov rdx, qword ptr [rbp - 24] + mov rax, r14 + add rsp, 16 + pop rbx + pop r14 + pop rbp + ret + + .globl _call_with_some2 + .p2align 4, 0x90 +_call_with_some2: + push rbp + mov rbp, rsp + push r14 + push rbx + sub rsp, 16 + mov rbx, rdx + mov qword ptr [rbp - 24], rdx + lea rdx, [rbp - 24] + call _objc_msgSend + mov r14, rax + mov rdi, qword ptr [rbp - 24] + call _objc_retain + mov rdi, rbx + call _objc_release + mov rdx, qword ptr [rbp - 24] + mov rax, r14 + add rsp, 16 + pop rbx + pop r14 + pop rbp + ret + + .globl _call_with_some3 + .p2align 4, 0x90 +_call_with_some3: + push rbp + mov rbp, rsp + push r14 + push rbx + sub rsp, 16 + mov rbx, rdx + mov qword ptr [rbp - 24], rdx + lea rdx, [rbp - 24] + call _objc_msgSend + mov r14, rax + mov rdi, qword ptr [rbp - 24] + call _objc_retain + mov rdi, rbx + call _objc_release + mov rdx, qword ptr [rbp - 24] + mov rax, r14 + add rsp, 16 + pop rbx + pop r14 + pop rbp + ret + +.subsections_via_symbols diff --git a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s new file mode 100644 index 000000000..8444e9cc4 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86.s @@ -0,0 +1,551 @@ + .text + .intel_syntax noprefix + .section .text.nonnull_nonnull,"ax",@progbits + .globl nonnull_nonnull + .p2align 4, 0x90 + .type nonnull_nonnull,@function +nonnull_nonnull: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [esp + 32] + mov esi, dword ptr [esp + 36] + mov edi, dword ptr [esp + 40] + call .L0$pb +.L0$pb: + pop ebx +.Ltmp0: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb) + mov dword ptr [esp + 4], esi + mov dword ptr [esp], eax + call objc_msg_lookup@PLT + mov ecx, dword ptr [esp + 32] + mov ebp, dword ptr [edi] + mov dword ptr [esp + 8], edi + mov dword ptr [esp + 4], esi + mov dword ptr [esp], ecx + call eax + mov esi, eax + mov eax, dword ptr [edi] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], ebp + call objc_release@PLT + mov eax, esi + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end0: + .size nonnull_nonnull, .Lfunc_end0-nonnull_nonnull + + .section .text.null_nonnull,"ax",@progbits + .globl null_nonnull + .p2align 4, 0x90 + .type null_nonnull,@function +null_nonnull: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov edi, dword ptr [esp + 40] + mov ebp, dword ptr [esp + 36] + mov esi, dword ptr [esp + 32] + call .L1$pb +.L1$pb: + pop ebx +.Ltmp1: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp1-.L1$pb) + sub esp, 8 + push ebp + push esi + call objc_msg_lookup@PLT + add esp, 16 + test edi, edi + je .LBB1_1 + mov ecx, dword ptr [edi] + mov dword ptr [esp + 8], ecx + sub esp, 4 + push edi + push ebp + push esi + call eax + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [edi] + call objc_retain@PLT + add esp, 4 + push dword ptr [esp + 20] + call objc_release@PLT + add esp, 16 + mov eax, esi + add esp, 12 + jmp .LBB1_2 +.LBB1_1: + sub esp, 4 + push 0 + push ebp + push esi + call eax + add esp, 28 +.LBB1_2: + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end1: + .size null_nonnull, .Lfunc_end1-null_nonnull + + .section .text.nonnull_null,"ax",@progbits + .globl nonnull_null + .p2align 4, 0x90 + .type nonnull_null,@function +nonnull_null: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov eax, dword ptr [esp + 32] + mov esi, dword ptr [esp + 36] + mov ebp, dword ptr [esp + 40] + call .L2$pb +.L2$pb: + pop ebx +.Ltmp2: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp2-.L2$pb) + mov dword ptr [esp + 4], esi + mov dword ptr [esp], eax + call objc_msg_lookup@PLT + mov ecx, dword ptr [esp + 32] + mov edi, dword ptr [ebp] + mov dword ptr [esp + 8], ebp + mov dword ptr [esp + 4], esi + mov dword ptr [esp], ecx + call eax + mov esi, eax + mov eax, dword ptr [ebp] + mov dword ptr [esp], eax + call objc_retain@PLT + test edi, edi + je .LBB2_2 + mov dword ptr [esp], edi + call objc_release@PLT +.LBB2_2: + mov eax, esi + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end2: + .size nonnull_null, .Lfunc_end2-nonnull_null + + .section .text.null_null,"ax",@progbits + .globl null_null + .p2align 4, 0x90 + .type null_null,@function +null_null: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov edi, dword ptr [esp + 40] + mov ebp, dword ptr [esp + 36] + mov esi, dword ptr [esp + 32] + call .L3$pb +.L3$pb: + pop ebx +.Ltmp3: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp3-.L3$pb) + sub esp, 8 + push ebp + push esi + call objc_msg_lookup@PLT + add esp, 16 + test edi, edi + je .LBB3_1 + mov ecx, esi + mov esi, dword ptr [edi] + sub esp, 4 + push edi + push ebp + push ecx + call eax + add esp, 16 + mov ebp, eax + sub esp, 12 + push dword ptr [edi] + call objc_retain@PLT + add esp, 16 + test esi, esi + je .LBB3_4 + sub esp, 12 + push esi + call objc_release@PLT + add esp, 16 +.LBB3_4: + mov eax, ebp + add esp, 12 + jmp .LBB3_5 +.LBB3_1: + sub esp, 4 + push 0 + push ebp + push esi + call eax + add esp, 28 +.LBB3_5: + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end3: + .size null_null, .Lfunc_end3-null_null + + .section .text.two_nonnull_nonnull,"ax",@progbits + .globl two_nonnull_nonnull + .p2align 4, 0x90 + .type two_nonnull_nonnull,@function +two_nonnull_nonnull: + push ebp + push ebx + push edi + push esi + sub esp, 28 + mov eax, dword ptr [esp + 48] + mov esi, dword ptr [esp + 52] + mov edi, dword ptr [esp + 56] + call .L4$pb +.L4$pb: + pop ebx +.Ltmp4: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp4-.L4$pb) + mov dword ptr [esp + 4], esi + mov dword ptr [esp], eax + call objc_msg_lookup@PLT + mov ecx, dword ptr [esp + 60] + mov ebp, dword ptr [edi] + mov dword ptr [esp + 8], edi + mov dword ptr [esp + 4], esi + mov edx, dword ptr [ecx] + mov dword ptr [esp + 12], ecx + mov ecx, dword ptr [esp + 48] + mov dword ptr [esp + 24], edx + mov dword ptr [esp], ecx + call eax + mov esi, eax + mov eax, dword ptr [edi] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], ebp + call objc_release@PLT + mov eax, dword ptr [esp + 60] + mov eax, dword ptr [eax] + mov dword ptr [esp], eax + call objc_retain@PLT + mov eax, dword ptr [esp + 24] + mov dword ptr [esp], eax + call objc_release@PLT + mov eax, esi + add esp, 28 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end4: + .size two_nonnull_nonnull, .Lfunc_end4-two_nonnull_nonnull + + .section .text.call_with_none1,"ax",@progbits + .globl call_with_none1 + .p2align 4, 0x90 + .type call_with_none1,@function +call_with_none1: + push ebx + push edi + push esi + mov esi, dword ptr [esp + 16] + mov edi, dword ptr [esp + 20] + call .L5$pb +.L5$pb: + pop ebx +.Ltmp5: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp5-.L5$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + push 0 + push edi + push esi + call eax + add esp, 16 + pop esi + pop edi + pop ebx + ret +.Lfunc_end5: + .size call_with_none1, .Lfunc_end5-call_with_none1 + + .section .text.call_with_none2,"ax",@progbits + .globl call_with_none2 + .p2align 4, 0x90 + .type call_with_none2,@function +call_with_none2: + push ebx + push edi + push esi + mov esi, dword ptr [esp + 16] + mov edi, dword ptr [esp + 20] + call .L6$pb +.L6$pb: + pop ebx +.Ltmp6: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp6-.L6$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + push 0 + push edi + push esi + call eax + add esp, 16 + pop esi + pop edi + pop ebx + ret +.Lfunc_end6: + .size call_with_none2, .Lfunc_end6-call_with_none2 + + .section .text.call_with_none3,"ax",@progbits + .globl call_with_none3 + .p2align 4, 0x90 + .type call_with_none3,@function +call_with_none3: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L7$pb +.L7$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp7: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp7-.L7$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [esp + 24] + call objc_retain@PLT + add esp, 16 + mov edx, dword ptr [esp + 12] + mov eax, esi + add esp, 16 + pop esi + pop edi + pop ebx + ret +.Lfunc_end7: + .size call_with_none3, .Lfunc_end7-call_with_none3 + + .section .text.call_with_none4,"ax",@progbits + .globl call_with_none4 + .p2align 4, 0x90 + .type call_with_none4,@function +call_with_none4: + push ebx + push edi + push esi + sub esp, 16 + mov esi, dword ptr [esp + 32] + mov edi, dword ptr [esp + 36] + call .L8$pb +.L8$pb: + pop ebx + mov dword ptr [esp + 12], 0 +.Ltmp8: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp8-.L8$pb) + sub esp, 8 + push edi + push esi + call objc_msg_lookup@PLT + add esp, 12 + lea ecx, [esp + 16] + push ecx + push edi + push esi + call eax + add esp, 16 + mov esi, eax + sub esp, 12 + push dword ptr [esp + 24] + call objc_retain@PLT + add esp, 16 + mov edx, dword ptr [esp + 12] + mov eax, esi + add esp, 16 + pop esi + pop edi + pop ebx + ret +.Lfunc_end8: + .size call_with_none4, .Lfunc_end8-call_with_none4 + + .section .text.call_with_some1,"ax",@progbits + .globl call_with_some1 + .p2align 4, 0x90 + .type call_with_some1,@function +call_with_some1: + push ebp + push ebx + push edi + push esi + sub esp, 12 + mov esi, dword ptr [esp + 32] + mov ebp, dword ptr [esp + 36] + mov edi, dword ptr [esp + 40] + call .L9$pb +.L9$pb: + pop ebx +.Ltmp9: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp9-.L9$pb) + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + call objc_msg_lookup@PLT + lea ecx, [esp + 40] + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + mov dword ptr [esp + 8], ecx + call eax + mov esi, eax + mov eax, dword ptr [esp + 40] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], edi + call objc_release@PLT + mov edx, dword ptr [esp + 40] + mov eax, esi + add esp, 12 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end9: + .size call_with_some1, .Lfunc_end9-call_with_some1 + + .section .text.call_with_some2,"ax",@progbits + .globl call_with_some2 + .p2align 4, 0x90 + .type call_with_some2,@function +call_with_some2: + push ebp + push ebx + push edi + push esi + sub esp, 28 + mov esi, dword ptr [esp + 48] + mov ebp, dword ptr [esp + 52] + mov edi, dword ptr [esp + 56] + call .L10$pb +.L10$pb: + pop ebx +.Ltmp10: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp10-.L10$pb) + mov dword ptr [esp + 24], edi + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + call objc_msg_lookup@PLT + lea ecx, [esp + 24] + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + mov dword ptr [esp + 8], ecx + call eax + mov esi, eax + mov eax, dword ptr [esp + 24] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], edi + call objc_release@PLT + mov edx, dword ptr [esp + 24] + mov eax, esi + add esp, 28 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end10: + .size call_with_some2, .Lfunc_end10-call_with_some2 + + .section .text.call_with_some3,"ax",@progbits + .globl call_with_some3 + .p2align 4, 0x90 + .type call_with_some3,@function +call_with_some3: + push ebp + push ebx + push edi + push esi + sub esp, 28 + mov esi, dword ptr [esp + 48] + mov ebp, dword ptr [esp + 52] + mov edi, dword ptr [esp + 56] + call .L11$pb +.L11$pb: + pop ebx +.Ltmp11: + add ebx, offset _GLOBAL_OFFSET_TABLE_+(.Ltmp11-.L11$pb) + mov dword ptr [esp + 24], edi + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + call objc_msg_lookup@PLT + lea ecx, [esp + 24] + mov dword ptr [esp + 4], ebp + mov dword ptr [esp], esi + mov dword ptr [esp + 8], ecx + call eax + mov esi, eax + mov eax, dword ptr [esp + 24] + mov dword ptr [esp], eax + call objc_retain@PLT + mov dword ptr [esp], edi + call objc_release@PLT + mov edx, dword ptr [esp + 24] + mov eax, esi + add esp, 28 + pop esi + pop edi + pop ebx + pop ebp + ret +.Lfunc_end11: + .size call_with_some3, .Lfunc_end11-call_with_some3 + + .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s new file mode 100644 index 000000000..7a11089cb --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/expected/gnustep-x86_64.s @@ -0,0 +1,416 @@ + .text + .intel_syntax noprefix + .section .text.nonnull_nonnull,"ax",@progbits + .globl nonnull_nonnull + .p2align 4, 0x90 + .type nonnull_nonnull,@function +nonnull_nonnull: + push r15 + push r14 + push r12 + push rbx + push rax + mov rbx, rdx + mov r14, rsi + mov r15, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov r12, qword ptr [rbx] + mov rdi, r15 + mov rsi, r14 + mov rdx, rbx + call rax + mov r14, rax + mov rdi, qword ptr [rbx] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r12 + call qword ptr [rip + objc_release@GOTPCREL] + mov rax, r14 + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + ret +.Lfunc_end0: + .size nonnull_nonnull, .Lfunc_end0-nonnull_nonnull + + .section .text.null_nonnull,"ax",@progbits + .globl null_nonnull + .p2align 4, 0x90 + .type null_nonnull,@function +null_nonnull: + push r15 + push r14 + push r12 + push rbx + push rax + mov rbx, rdx + mov r14, rsi + mov r15, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rcx, rax + test rbx, rbx + je .LBB1_2 + mov r12, qword ptr [rbx] + mov rdi, r15 + mov rsi, r14 + mov rdx, rbx + call rcx + mov r14, rax + mov rdi, qword ptr [rbx] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r12 + call qword ptr [rip + objc_release@GOTPCREL] + mov rax, r14 + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + ret +.LBB1_2: + mov rdi, r15 + mov rsi, r14 + xor edx, edx + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + jmp rcx +.Lfunc_end1: + .size null_nonnull, .Lfunc_end1-null_nonnull + + .section .text.nonnull_null,"ax",@progbits + .globl nonnull_null + .p2align 4, 0x90 + .type nonnull_null,@function +nonnull_null: + push r15 + push r14 + push r12 + push rbx + push rax + mov rbx, rdx + mov r14, rsi + mov r12, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov r15, qword ptr [rbx] + mov rdi, r12 + mov rsi, r14 + mov rdx, rbx + call rax + mov r14, rax + mov rdi, qword ptr [rbx] + call qword ptr [rip + objc_retain@GOTPCREL] + test r15, r15 + je .LBB2_2 + mov rdi, r15 + call qword ptr [rip + objc_release@GOTPCREL] +.LBB2_2: + mov rax, r14 + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + ret +.Lfunc_end2: + .size nonnull_null, .Lfunc_end2-nonnull_null + + .section .text.null_null,"ax",@progbits + .globl null_null + .p2align 4, 0x90 + .type null_null,@function +null_null: + push r15 + push r14 + push r12 + push rbx + push rax + mov rbx, rdx + mov r14, rsi + mov r12, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rcx, rax + test rbx, rbx + je .LBB3_4 + mov r15, qword ptr [rbx] + mov rdi, r12 + mov rsi, r14 + mov rdx, rbx + call rcx + mov r14, rax + mov rdi, qword ptr [rbx] + call qword ptr [rip + objc_retain@GOTPCREL] + test r15, r15 + je .LBB3_3 + mov rdi, r15 + call qword ptr [rip + objc_release@GOTPCREL] +.LBB3_3: + mov rax, r14 + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + ret +.LBB3_4: + mov rdi, r12 + mov rsi, r14 + xor edx, edx + add rsp, 8 + pop rbx + pop r12 + pop r14 + pop r15 + jmp rcx +.Lfunc_end3: + .size null_null, .Lfunc_end3-null_null + + .section .text.two_nonnull_nonnull,"ax",@progbits + .globl two_nonnull_nonnull + .p2align 4, 0x90 + .type two_nonnull_nonnull,@function +two_nonnull_nonnull: + push rbp + push r15 + push r14 + push r13 + push r12 + push rbx + push rax + mov r14, rcx + mov rbx, rdx + mov r15, rsi + mov r12, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov r13, qword ptr [rbx] + mov rcx, qword ptr [r14] + mov qword ptr [rsp], rcx + mov rdi, r12 + mov rsi, r15 + mov rdx, rbx + mov rcx, r14 + call rax + mov rbp, rax + mov rdi, qword ptr [rbx] + mov r15, qword ptr [rip + objc_retain@GOTPCREL] + call r15 + mov rbx, qword ptr [rip + objc_release@GOTPCREL] + mov rdi, r13 + call rbx + mov rdi, qword ptr [r14] + call r15 + mov rdi, qword ptr [rsp] + call rbx + mov rax, rbp + add rsp, 8 + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp + ret +.Lfunc_end4: + .size two_nonnull_nonnull, .Lfunc_end4-two_nonnull_nonnull + + .section .text.call_with_none1,"ax",@progbits + .globl call_with_none1 + .p2align 4, 0x90 + .type call_with_none1,@function +call_with_none1: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdi, rbx + mov rsi, r14 + xor edx, edx + add rsp, 8 + pop rbx + pop r14 + jmp rax +.Lfunc_end5: + .size call_with_none1, .Lfunc_end5-call_with_none1 + + .section .text.call_with_none2,"ax",@progbits + .globl call_with_none2 + .p2align 4, 0x90 + .type call_with_none2,@function +call_with_none2: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdi, rbx + mov rsi, r14 + xor edx, edx + add rsp, 8 + pop rbx + pop r14 + jmp rax +.Lfunc_end6: + .size call_with_none2, .Lfunc_end6-call_with_none2 + + .section .text.call_with_none3,"ax",@progbits + .globl call_with_none3 + .p2align 4, 0x90 + .type call_with_none3,@function +call_with_none3: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + mov rbx, rax + mov rdi, qword ptr [rsp] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdx, qword ptr [rsp] + mov rax, rbx + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end7: + .size call_with_none3, .Lfunc_end7-call_with_none3 + + .section .text.call_with_none4,"ax",@progbits + .globl call_with_none4 + .p2align 4, 0x90 + .type call_with_none4,@function +call_with_none4: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov qword ptr [rsp], 0 + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + mov rdx, rsp + mov rdi, rbx + mov rsi, r14 + call rax + mov rbx, rax + mov rdi, qword ptr [rsp] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdx, qword ptr [rsp] + mov rax, rbx + add rsp, 8 + pop rbx + pop r14 + ret +.Lfunc_end8: + .size call_with_none4, .Lfunc_end8-call_with_none4 + + .section .text.call_with_some1,"ax",@progbits + .globl call_with_some1 + .p2align 4, 0x90 + .type call_with_some1,@function +call_with_some1: + push r15 + push r14 + push rbx + sub rsp, 16 + mov r14, rdx + mov r15, rsi + mov rbx, rdi + mov qword ptr [rsp + 8], rdx + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + lea rdx, [rsp + 8] + mov rdi, rbx + mov rsi, r15 + call rax + mov rbx, rax + mov rdi, qword ptr [rsp + 8] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r14 + call qword ptr [rip + objc_release@GOTPCREL] + mov rdx, qword ptr [rsp + 8] + mov rax, rbx + add rsp, 16 + pop rbx + pop r14 + pop r15 + ret +.Lfunc_end9: + .size call_with_some1, .Lfunc_end9-call_with_some1 + + .section .text.call_with_some2,"ax",@progbits + .globl call_with_some2 + .p2align 4, 0x90 + .type call_with_some2,@function +call_with_some2: + push r15 + push r14 + push rbx + sub rsp, 16 + mov r14, rdx + mov r15, rsi + mov rbx, rdi + mov qword ptr [rsp + 8], rdx + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + lea rdx, [rsp + 8] + mov rdi, rbx + mov rsi, r15 + call rax + mov rbx, rax + mov rdi, qword ptr [rsp + 8] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r14 + call qword ptr [rip + objc_release@GOTPCREL] + mov rdx, qword ptr [rsp + 8] + mov rax, rbx + add rsp, 16 + pop rbx + pop r14 + pop r15 + ret +.Lfunc_end10: + .size call_with_some2, .Lfunc_end10-call_with_some2 + + .section .text.call_with_some3,"ax",@progbits + .globl call_with_some3 + .p2align 4, 0x90 + .type call_with_some3,@function +call_with_some3: + push r15 + push r14 + push rbx + sub rsp, 16 + mov r14, rdx + mov r15, rsi + mov rbx, rdi + mov qword ptr [rsp + 8], rdx + call qword ptr [rip + objc_msg_lookup@GOTPCREL] + lea rdx, [rsp + 8] + mov rdi, rbx + mov rsi, r15 + call rax + mov rbx, rax + mov rdi, qword ptr [rsp + 8] + call qword ptr [rip + objc_retain@GOTPCREL] + mov rdi, r14 + call qword ptr [rip + objc_release@GOTPCREL] + mov rdx, qword ptr [rsp + 8] + mov rax, rbx + add rsp, 16 + pop rbx + pop r14 + pop r15 + ret +.Lfunc_end11: + .size call_with_some3, .Lfunc_end11-call_with_some3 + + .section ".note.GNU-stack","",@progbits diff --git a/crates/test-assembly/crates/test_out_parameters/lib.rs b/crates/test-assembly/crates/test_out_parameters/lib.rs new file mode 100644 index 000000000..c2cf19cd2 --- /dev/null +++ b/crates/test-assembly/crates/test_out_parameters/lib.rs @@ -0,0 +1,87 @@ +//! Test that out parameters are handled correctly. +use objc2::rc::{Id, Owned}; +use objc2::runtime::{Object, Sel}; +use objc2::MessageReceiver; + +#[no_mangle] +unsafe fn nonnull_nonnull(obj: &Object, sel: Sel, param: &mut Id) -> usize { + MessageReceiver::send_message(obj, sel, (param,)) +} + +#[no_mangle] +unsafe fn null_nonnull(obj: &Object, sel: Sel, param: Option<&mut Id>) -> usize { + MessageReceiver::send_message(obj, sel, (param,)) +} + +#[no_mangle] +unsafe fn nonnull_null(obj: &Object, sel: Sel, param: &mut Option>) -> usize { + MessageReceiver::send_message(obj, sel, (param,)) +} + +#[no_mangle] +unsafe fn null_null( + obj: &Object, + sel: Sel, + param: Option<&mut Option>>, +) -> usize { + MessageReceiver::send_message(obj, sel, (param,)) +} + +#[no_mangle] +unsafe fn two_nonnull_nonnull( + obj: &Object, + sel: Sel, + param1: &mut Id, + param2: &mut Id, +) -> usize { + MessageReceiver::send_message(obj, sel, (param1, param2)) +} + +// +// Calling in specific ways that the optimizer should be able to recognize +// + +// These should fully avoid any extra `retain/release` +#[no_mangle] +unsafe fn call_with_none1(obj: &Object, sel: Sel) -> usize { + null_nonnull(obj, sel, None) +} +#[no_mangle] +unsafe fn call_with_none2(obj: &Object, sel: Sel) -> usize { + null_null(obj, sel, None) +} + +type Res = (usize, Option>); + +// These should only need a `retain` +#[no_mangle] +unsafe fn call_with_none3(obj: &Object, sel: Sel) -> Res { + let mut param = None; + let res = nonnull_null(obj, sel, &mut param); + (res, param) +} +#[no_mangle] +unsafe fn call_with_none4(obj: &Object, sel: Sel) -> Res { + let mut param = None; + let res = null_null(obj, sel, Some(&mut param)); + (res, param) +} + +// These should need `retain/release`, but not have any branches +#[no_mangle] +unsafe fn call_with_some1(obj: &Object, sel: Sel, mut param: Id) -> Res { + let res = null_nonnull(obj, sel, Some(&mut param)); + (res, Some(param)) +} +#[no_mangle] +unsafe fn call_with_some2(obj: &Object, sel: Sel, param: Id) -> Res { + let mut param = Some(param); + let res = nonnull_null(obj, sel, &mut param); + (res, param) +} +#[no_mangle] +unsafe fn call_with_some3(obj: &Object, sel: Sel, param: Id) -> Res { + let mut param = Some(param); + let res = null_null(obj, sel, Some(&mut param)); + (res, param) +} diff --git a/crates/test-assembly/src/lib.rs b/crates/test-assembly/src/lib.rs index 174ae3d1d..a74b2fa6d 100644 --- a/crates/test-assembly/src/lib.rs +++ b/crates/test-assembly/src/lib.rs @@ -137,7 +137,7 @@ fn demangle_assembly(assembly: &str) -> String { // // Example: test_msg_send_static_sel[f7bb0e08e35403f3]::handle_with_sel::NAME_DATA // Becomes: test_msg_send_static_sel[CRATE_ID]::handle_with_sel::NAME_DATA - static ref RE_CRATE_ID: Regex = Regex::new(r"\[.*\]").unwrap(); + static ref RE_CRATE_ID: Regex = Regex::new(r"\[.*?\]").unwrap(); // Replace last part of symbol if it looks to be autogenerated // @@ -328,5 +328,10 @@ l_anon.[ID].0: "#; let output = demangle_assembly(before); assert_eq!(output, after, "Got {output}"); + + let before = r#"__RINvNtCshB9ITk7tvJd_4core3ptr13drop_in_placeINtNtB4_6option6OptionINtNtNtCsaWDm3USgSkM_5objc22rc2id2IdNtNtB19_7runtime6ObjectNtNtB17_9ownership6SharedEEECs8tAMaYSsbuV_19test_out_parameters:"#; + let after = r#"SYM(core[CRATE_ID]::ptr::drop_in_place::>>, 0):"#; + let output = demangle_assembly(before); + assert_eq!(output, after, "Got {output}"); } } diff --git a/crates/test-ui/ui/not_writeback.rs b/crates/test-ui/ui/not_writeback.rs new file mode 100644 index 000000000..cecbaaea1 --- /dev/null +++ b/crates/test-ui/ui/not_writeback.rs @@ -0,0 +1,26 @@ +use objc2::rc::{Id, Shared, Owned}; +use objc2::runtime::NSObject; +use objc2::msg_send; + +fn main() { + let obj = &NSObject::new(); + + let _: &mut Id = unsafe { msg_send![obj, a] }; + + let param: Id = NSObject::new(); + let _: () = unsafe { msg_send![obj, a: param] }; + + let param: Id = NSObject::new(); + let _: () = unsafe { msg_send![obj, a: ¶m] }; + + let param: Id = NSObject::new(); + let _: () = unsafe { msg_send![obj, a: Some(¶m)] }; + + let param: *mut Id = std::ptr::null_mut(); + let _: () = unsafe { msg_send![obj, a: param] }; + + let mut param = NSObject::new(); + let mut param = &mut param; + let param: &mut &mut Id = &mut param; + let _: () = unsafe { msg_send![obj, a: param] }; +} diff --git a/crates/test-ui/ui/not_writeback.stderr b/crates/test-ui/ui/not_writeback.stderr new file mode 100644 index 000000000..667de20d5 --- /dev/null +++ b/crates/test-ui/ui/not_writeback.stderr @@ -0,0 +1,172 @@ +error[E0277]: the trait bound `Id: RefEncode` is not satisfied + --> ui/not_writeback.rs + | + | let _: &mut Id = unsafe { msg_send![obj, a] }; + | ^^^^^^^^^^^^^^^^^ the trait `RefEncode` is not implemented for `Id` + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `&mut Id` to implement `Encode` + = note: required for `&mut Id` to implement `EncodeReturn` + = note: required for `&mut Id` to implement `EncodeConvertReturn` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | R: EncodeConvertReturn, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Id: Encode` is not satisfied + --> ui/not_writeback.rs + | + | let _: () = unsafe { msg_send![obj, a: param] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `Encode` is not implemented for `Id` + | required by a bound introduced by this call + | + = help: the following other types implement trait `Encode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `Id` to implement `EncodeConvertArgument` + = note: required for `(Id,)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Id: RefEncode` is not satisfied + --> ui/not_writeback.rs + | + | let _: () = unsafe { msg_send![obj, a: ¶m] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `RefEncode` is not implemented for `Id` + | required by a bound introduced by this call + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `&Id` to implement `Encode` + = note: required for `&Id` to implement `EncodeConvertArgument` + = note: required for `(&Id,)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Id: RefEncode` is not satisfied + --> ui/not_writeback.rs + | + | let _: () = unsafe { msg_send![obj, a: Some(¶m)] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `RefEncode` is not implemented for `Id` + | required by a bound introduced by this call + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `&Id` to implement `Encode` + = note: 1 redundant requirement hidden + = note: required for `Option<&Id>` to implement `Encode` + = note: required for `Option<&Id>` to implement `EncodeConvertArgument` + = note: required for `(Option<&Id>,)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Id: RefEncode` is not satisfied + --> ui/not_writeback.rs + | + | let _: () = unsafe { msg_send![obj, a: param] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `RefEncode` is not implemented for `Id` + | required by a bound introduced by this call + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `*mut Id` to implement `Encode` + = note: required for `*mut Id` to implement `EncodeConvertArgument` + = note: required for `(*mut Id,)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Id: RefEncode` is not satisfied + --> ui/not_writeback.rs + | + | let _: () = unsafe { msg_send![obj, a: param] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `RefEncode` is not implemented for `Id` + | required by a bound introduced by this call + | + = help: the following other types implement trait `RefEncode`: + &'a T + &'a mut T + *const T + *const c_void + *mut T + *mut c_void + AtomicI16 + AtomicI32 + and $N others + = note: required for `&mut Id` to implement `RefEncode` + = note: required for `&mut &mut Id` to implement `Encode` + = note: required for `&mut &mut Id` to implement `EncodeConvertArgument` + = note: required for `(&mut &mut Id,)` to implement `MessageArguments` +note: required by a bound in `send_message` + --> $WORKSPACE/crates/objc2/src/message/mod.rs + | + | A: MessageArguments, + | ^^^^^^^^^^^^^^^^ required by this bound in `MessageReceiver::send_message` + = note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) From 284ade9b88436b8531e4f6c999fc6d80ef09993a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 1 Feb 2023 00:52:43 +0100 Subject: [PATCH 5/5] icrate: Re-add out-parameters --- crates/header-translator/src/rust_type.rs | 42 +++++++++++------------ crates/icrate/CHANGELOG.md | 1 + crates/icrate/src/generated | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/crates/header-translator/src/rust_type.rs b/crates/header-translator/src/rust_type.rs index 9a3281a70..d9d52b965 100644 --- a/crates/header-translator/src/rust_type.rs +++ b/crates/header-translator/src/rust_type.rs @@ -1722,27 +1722,27 @@ impl fmt::Display for Ty { is_const: false, pointee, } => match &**pointee { - // TODO: Re-enable once we can support it - // Inner::Id { - // ty, - // is_const: false, - // lifetime: Lifetime::Autoreleasing, - // nullability: inner_nullability, - // } if self.kind == TyKind::MethodArgument => { - // let tokens = if *inner_nullability == Nullability::NonNull { - // format!("Id<{ty}, Shared>") - // } else { - // format!("Option>") - // }; - // if *nullability == Nullability::NonNull { - // write!(f, "&mut {tokens}") - // } else { - // write!(f, "Option<&mut {tokens}>") - // } - // } - // Inner::Id { .. } => { - // unreachable!("there should be no id with other values: {self:?}") - // } + Inner::Id { + ty, + // Don't care about the const-ness of the id. + is_const: _, + lifetime: Lifetime::Autoreleasing, + nullability: inner_nullability, + } if self.kind == TyKind::MethodArgument => { + let tokens = if *inner_nullability == Nullability::NonNull { + format!("Id<{ty}, Shared>") + } else { + format!("Option>") + }; + if *nullability == Nullability::NonNull { + write!(f, "&mut {tokens}") + } else { + write!(f, "Option<&mut {tokens}>") + } + } + Inner::Id { .. } if self.kind == TyKind::MethodArgument => { + unreachable!("invalid out-pointer id {self:?}") + } block @ Inner::Block { .. } => { if *nullability == Nullability::NonNull { write!(f, "&{block}") diff --git a/crates/icrate/CHANGELOG.md b/crates/icrate/CHANGELOG.md index ecfcbb035..f2eaad139 100644 --- a/crates/icrate/CHANGELOG.md +++ b/crates/icrate/CHANGELOG.md @@ -88,6 +88,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Removed a few instances of `TodoProtocols`. * Fixed type-encoding of a few `struct`s. * Fixed `NSProxy` trait methods. +* **BREAKING**: Fixed type in methods that worked with out-parameters. ## icrate 0.0.1 - 2022-12-24 diff --git a/crates/icrate/src/generated b/crates/icrate/src/generated index 975605f98..d59e0a6b8 160000 --- a/crates/icrate/src/generated +++ b/crates/icrate/src/generated @@ -1 +1 @@ -Subproject commit 975605f9801e4441425a86c3e525ac8717dc50ff +Subproject commit d59e0a6b88addce7aa0997b2f389b1d10e657449