@@ -71,6 +71,22 @@ impl fmt::Display for VerificationError {
71
71
72
72
impl Error for VerificationError { }
73
73
74
+ /// Relaxed version of `Encoding::equivalent_to_box` that allows
75
+ /// `*mut c_void` and `*const c_void` to be used in place of other pointers.
76
+ ///
77
+ /// Note: This is a top-level comparison; `*mut *mut c_void` or structures
78
+ /// containing `*mut c_void` are not allowed differently than usual.
79
+ fn relaxed_equivalent_to_box ( encoding : & Encoding , expected : & EncodingBox ) -> bool {
80
+ if cfg ! ( feature = "relax-void-encoding" )
81
+ && matches ! ( encoding, Encoding :: Pointer ( & Encoding :: Void ) )
82
+ && matches ! ( expected, EncodingBox :: Pointer ( _) )
83
+ {
84
+ true
85
+ } else {
86
+ encoding. equivalent_to_box ( expected)
87
+ }
88
+ }
89
+
74
90
pub ( crate ) fn verify_method_signature (
75
91
method : & Method ,
76
92
args : & [ Encoding ] ,
@@ -80,7 +96,7 @@ pub(crate) fn verify_method_signature(
80
96
81
97
// TODO: Verify stack layout
82
98
let ( expected, _stack_layout) = iter. extract_return ( ) ?;
83
- if !ret . equivalent_to_box ( & expected) {
99
+ if !relaxed_equivalent_to_box ( ret , & expected) {
84
100
return Err ( Inner :: MismatchedReturn ( expected, ret. clone ( ) ) . into ( ) ) ;
85
101
}
86
102
@@ -93,7 +109,7 @@ pub(crate) fn verify_method_signature(
93
109
if let Some ( res) = iter. next ( ) {
94
110
// TODO: Verify stack layout
95
111
let ( expected, _stack_layout) = res?;
96
- if !actual . equivalent_to_box ( & expected) {
112
+ if !relaxed_equivalent_to_box ( actual , & expected) {
97
113
return Err ( Inner :: MismatchedArgument ( i, expected, actual. clone ( ) ) . into ( ) ) ;
98
114
}
99
115
} else {
@@ -118,9 +134,10 @@ pub(crate) fn verify_method_signature(
118
134
mod tests {
119
135
use super :: * ;
120
136
use crate :: runtime:: Sel ;
121
- use crate :: sel;
122
137
use crate :: test_utils;
138
+ use crate :: { msg_send, sel} ;
123
139
use alloc:: string:: ToString ;
140
+ use core:: ffi:: c_void;
124
141
use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
125
142
126
143
#[ test]
@@ -179,20 +196,55 @@ mod tests {
179
196
#[ should_panic = "invalid message send to -[CustomObject foo]: expected return to have type code 'I', but found 'i'" ]
180
197
fn test_send_message_verified ( ) {
181
198
let obj = test_utils:: custom_object ( ) ;
182
- let _: i32 = unsafe { crate :: msg_send![ & obj, foo] } ;
199
+ let _: i32 = unsafe { msg_send ! [ & obj, foo] } ;
183
200
}
184
201
185
202
#[ test]
186
203
#[ cfg( debug_assertions) ]
187
204
#[ should_panic = "invalid message send to +[CustomObject abcDef]: method not found" ]
188
205
fn test_send_message_verified_to_class ( ) {
189
206
let cls = test_utils:: custom_class ( ) ;
190
- let _: i32 = unsafe { crate :: msg_send![ cls, abcDef] } ;
207
+ let _: i32 = unsafe { msg_send ! [ cls, abcDef] } ;
191
208
}
192
209
193
210
#[ test]
194
211
fn test_marker_traits ( ) {
195
212
fn assert_marker_traits < T : Send + Sync + UnwindSafe + RefUnwindSafe + Unpin > ( ) { }
196
213
assert_marker_traits :: < VerificationError > ( ) ;
197
214
}
215
+
216
+ #[ test]
217
+ fn test_get_reference ( ) {
218
+ let mut obj = test_utils:: custom_object ( ) ;
219
+ let _: ( ) = unsafe { msg_send ! [ & mut obj, setFoo: 42u32 ] } ;
220
+
221
+ let res: & u32 = unsafe { msg_send ! [ & obj, fooReference] } ;
222
+ assert_eq ! ( * res, 42 ) ;
223
+ let res: * const u32 = unsafe { msg_send ! [ & obj, fooReference] } ;
224
+ assert_eq ! ( unsafe { * res } , 42 ) ;
225
+ let res: * mut u32 = unsafe { msg_send ! [ & obj, fooReference] } ;
226
+ assert_eq ! ( unsafe { * res } , 42 ) ;
227
+ }
228
+
229
+ #[ test]
230
+ #[ cfg_attr(
231
+ all( debug_assertions, not( feature = "relax-void-encoding" ) ) ,
232
+ should_panic = "invalid message send to -[CustomObject fooReference]: expected return to have type code '^I', but found '^v'"
233
+ ) ]
234
+ fn test_get_reference_void ( ) {
235
+ let mut obj = test_utils:: custom_object ( ) ;
236
+ let _: ( ) = unsafe { msg_send ! [ & mut obj, setFoo: 42u32 ] } ;
237
+
238
+ let res: * mut c_void = unsafe { msg_send ! [ & obj, fooReference] } ;
239
+ let res: * mut u32 = res. cast ( ) ;
240
+ assert_eq ! ( unsafe { * res } , 42 ) ;
241
+ }
242
+
243
+ #[ test]
244
+ #[ cfg( debug_assertions) ]
245
+ #[ should_panic = "invalid message send to -[CustomObject foo]: expected return to have type code 'I', but found '^v'" ]
246
+ fn test_get_integer_void ( ) {
247
+ let obj = test_utils:: custom_object ( ) ;
248
+ let _: * mut c_void = unsafe { msg_send ! [ & obj, foo] } ;
249
+ }
198
250
}
0 commit comments