Skip to content

Commit bdb7202

Browse files
committed
Require users of msg_send! to specify the return type
This is a breaking change, to prevent misuses such as SSheldon#62
1 parent 39a6d52 commit bdb7202

File tree

12 files changed

+77
-60
lines changed

12 files changed

+77
-60
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
## 0.3.0
2+
3+
### Changed
4+
5+
* Require users of `msg_send!` to specify the return type.
6+
7+
Previously, the return type was inferred based on context, and
8+
`let () = msg_send![…];` was documented as the correct use when there is no return value.
9+
However `msg_send![…];` compiled fine and was equivalent as of Rust 1.38,
10+
even though it happened to rely on an unspecified part of the language
11+
(type inference fallback for diverging expressions)
12+
13+
When Rust first tried to change fallback from `()` (the unit type) to `!` (the never type),
14+
this cause such uses of `msg_send!` to have Undefined Behavior
15+
beacause a function was returning `Result<!, SomeError>::Ok`, which should be impossible:
16+
<https://github.com/SSheldon/rust-objc/issues/62>
17+
18+
With this change, both `let () = msg_send![…];` and `msg_send![…];` become `msg_send![… => ()];`.
19+
120
## 0.2.6
221

322
### Fixed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "objc"
3-
version = "0.2.6"
3+
version = "0.3.0"
44
authors = ["Steven Sheldon"]
55
edition = "2018"
66

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ Objective-C objects can be messaged using the `msg_send!` macro:
99

1010
``` rust
1111
let cls = class!(NSObject);
12-
let obj: *mut Object = msg_send![cls, new];
13-
let hash: usize = msg_send![obj, hash];
14-
let is_kind: BOOL = msg_send![obj, isKindOfClass:cls];
12+
let obj = msg_send![cls, new => *mut Object];
13+
let hash = msg_send![obj, hash => usize];
14+
let is_kind = msg_send![obj, isKindOfClass:cls => BOOL];
1515
// Even void methods must have their return type annotated
16-
let _: () = msg_send![obj, release];
16+
msg_send![obj, release => ()];
1717
```
1818

1919
## Reference counting
@@ -27,7 +27,7 @@ and safely fails if the object has been deallocated.
2727
``` rust
2828
// StrongPtr will release the object when dropped
2929
let obj = unsafe {
30-
StrongPtr::new(msg_send![class!(NSObject), new])
30+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
3131
};
3232

3333
// Cloning retains the object an additional time

examples/example.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ fn main() {
1818

1919
// Allocate an instance
2020
let obj = unsafe {
21-
let obj: *mut Object = msg_send![cls, alloc];
22-
let obj: *mut Object = msg_send![obj, init];
21+
let obj = msg_send![cls, alloc => *mut Object];
22+
let obj = msg_send![obj, init => *mut Object];
2323
StrongPtr::new(obj)
2424
};
2525
println!("NSObject address: {:p}", obj);
@@ -38,8 +38,8 @@ fn main() {
3838
assert!(*hash_return == usize::ENCODING);
3939

4040
// Invoke a method on the object
41-
let hash: usize = unsafe {
42-
msg_send![*obj, hash]
41+
let hash = unsafe {
42+
msg_send![*obj, hash => usize]
4343
};
4444
println!("NSObject hash: {}", hash);
4545
}

src/declare.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,18 +322,16 @@ mod tests {
322322
// Registering the custom class is in test_utils
323323
let obj = test_utils::custom_object();
324324
unsafe {
325-
let _: () = msg_send![obj, setFoo:13u32];
326-
let result: u32 = msg_send![obj, foo];
327-
assert!(result == 13);
325+
msg_send![obj, setFoo:13u32 => ()];
326+
assert!(msg_send![obj, foo => u32] == 13);
328327
}
329328
}
330329

331330
#[test]
332331
fn test_class_method() {
333332
let cls = test_utils::custom_class();
334333
unsafe {
335-
let result: u32 = msg_send![cls, classFoo];
336-
assert!(result == 7);
334+
assert!(msg_send![cls, classFoo => u32] == 7);
337335
}
338336
}
339337
}

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ Objective-C objects can be messaged using the [`msg_send!`](macro.msg_send!.html
1111
# fn main() {
1212
# unsafe {
1313
let cls = class!(NSObject);
14-
let obj: *mut Object = msg_send![cls, new];
15-
let hash: usize = msg_send![obj, hash];
16-
let is_kind: BOOL = msg_send![obj, isKindOfClass:cls];
14+
let obj = msg_send![cls, new => *mut Object];
15+
let hash = msg_send![obj, hash => usize];
16+
let is_kind = msg_send![obj, isKindOfClass:cls => BOOL];
1717
// Even void methods must have their return type annotated
18-
let _: () = msg_send![obj, release];
18+
msg_send![obj, release => ()];
1919
# }
2020
# }
2121
```

src/macros.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,39 +69,39 @@ Variadic arguments are not currently supported.
6969
# fn main() {
7070
# unsafe {
7171
let obj: *mut Object;
72-
# let obj: *mut Object = 0 as *mut Object;
73-
let description: *const Object = msg_send![obj, description];
74-
let _: () = msg_send![obj, setArg1:1 arg2:2];
72+
# let obj = 0 as *mut Object;
73+
let description = msg_send![obj, description => *mut Object];
74+
msg_send![obj, setArg1:1 arg2:2 => ()];
7575
# }
7676
# }
7777
```
7878
*/
7979
#[macro_export]
8080
macro_rules! msg_send {
81-
(super($obj:expr, $superclass:expr), $name:ident) => ({
81+
(super($obj:expr, $superclass:expr), $name:ident => $ret:ty) => ({
8282
let sel = $crate::sel!($name);
83-
match $crate::__send_super_message(&*$obj, $superclass, sel, ()) {
83+
match $crate::__send_super_message::<_, _, $ret>(&*$obj, $superclass, sel, ()) {
8484
Err(s) => panic!("{}", s),
8585
Ok(r) => r,
8686
}
8787
});
88-
(super($obj:expr, $superclass:expr), $($name:ident : $arg:expr)+) => ({
88+
(super($obj:expr, $superclass:expr), $($name:ident : $arg:expr)+ => $ret:ty) => ({
8989
let sel = $crate::sel!($($name:)+);
90-
match $crate::__send_super_message(&*$obj, $superclass, sel, ($($arg,)*)) {
90+
match $crate::__send_super_message::<_, _, $ret>(&*$obj, $superclass, sel, ($($arg,)*)) {
9191
Err(s) => panic!("{}", s),
9292
Ok(r) => r,
9393
}
9494
});
95-
($obj:expr, $name:ident) => ({
95+
($obj:expr, $name:ident => $ret:ty) => ({
9696
let sel = $crate::sel!($name);
97-
match $crate::__send_message(&*$obj, sel, ()) {
97+
match $crate::__send_message::<_, _, $ret>(&*$obj, sel, ()) {
9898
Err(s) => panic!("{}", s),
9999
Ok(r) => r,
100100
}
101101
});
102-
($obj:expr, $($name:ident : $arg:expr)+) => ({
102+
($obj:expr, $($name:ident : $arg:expr)+ => $ret:ty) => ({
103103
let sel = $crate::sel!($($name:)+);
104-
match $crate::__send_message(&*$obj, sel, ($($arg,)*)) {
104+
match $crate::__send_message::<_, _, $ret>(&*$obj, sel, ($($arg,)*)) {
105105
Err(s) => panic!("{}", s),
106106
Ok(r) => r,
107107
}

src/message/mod.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub unsafe trait Message {
8888
# use objc::Message;
8989
# fn main() {
9090
let obj: &Object;
91-
# obj = unsafe { msg_send![class!(NSObject), new] };
91+
# obj = unsafe { msg_send![class!(NSObject), new => &Object] };
9292
let sel = sel!(isKindOfClass:);
9393
// Verify isKindOfClass: takes one Class and returns a BOOL
9494
let result = obj.verify_message::<(&Class,), BOOL>(sel);
@@ -230,18 +230,18 @@ mod tests {
230230
#[test]
231231
fn test_send_message() {
232232
let obj = test_utils::custom_object();
233-
let result: u32 = unsafe {
234-
let _: () = msg_send![obj, setFoo:4u32];
235-
msg_send![obj, foo]
233+
let result = unsafe {
234+
msg_send![obj, setFoo:4u32 => ()];
235+
msg_send![obj, foo => u32]
236236
};
237237
assert!(result == 4);
238238
}
239239

240240
#[test]
241241
fn test_send_message_stret() {
242242
let obj = test_utils::custom_object();
243-
let result: test_utils::CustomStruct = unsafe {
244-
msg_send![obj, customStruct]
243+
let result = unsafe {
244+
msg_send![obj, customStruct => test_utils::CustomStruct]
245245
};
246246
let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
247247
assert!(result == expected);
@@ -251,18 +251,18 @@ mod tests {
251251
#[test]
252252
fn test_send_message_nil() {
253253
let nil: *mut Object = ::std::ptr::null_mut();
254-
let result: usize = unsafe {
255-
msg_send![nil, hash]
254+
let result = unsafe {
255+
msg_send![nil, hash => usize]
256256
};
257257
assert!(result == 0);
258258

259-
let result: *mut Object = unsafe {
260-
msg_send![nil, description]
259+
let result = unsafe {
260+
msg_send![nil, description => *mut Object]
261261
};
262262
assert!(result.is_null());
263263

264-
let result: f64 = unsafe {
265-
msg_send![nil, doubleValue]
264+
let result = unsafe {
265+
msg_send![nil, doubleValue => f64]
266266
};
267267
assert!(result == 0.0);
268268
}
@@ -272,13 +272,12 @@ mod tests {
272272
let obj = test_utils::custom_subclass_object();
273273
let superclass = test_utils::custom_class();
274274
unsafe {
275-
let _: () = msg_send![obj, setFoo:4u32];
276-
let foo: u32 = msg_send![super(obj, superclass), foo];
275+
msg_send![obj, setFoo:4u32 => ()];
276+
let foo = msg_send![super(obj, superclass), foo => u32];
277277
assert!(foo == 4);
278278

279279
// The subclass is overriden to return foo + 2
280-
let foo: u32 = msg_send![obj, foo];
281-
assert!(foo == 6);
280+
assert!(msg_send![obj, foo => u32] == 6);
282281
}
283282
}
284283

src/rc/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ For more information on Objective-C's reference counting, see Apple's documentat
1818
``` no_run
1919
# #[macro_use] extern crate objc;
2020
# use objc::rc::{autoreleasepool, StrongPtr};
21+
# use objc::runtime::Object;
2122
# fn main() {
2223
// StrongPtr will release the object when dropped
2324
let obj = unsafe {
24-
StrongPtr::new(msg_send![class!(NSObject), new])
25+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
2526
};
2627
2728
// Cloning retains the object an additional time
@@ -58,11 +59,11 @@ mod tests {
5859
#[test]
5960
fn test_strong_clone() {
6061
fn retain_count(obj: *mut Object) -> usize {
61-
unsafe { msg_send![obj, retainCount] }
62+
unsafe { msg_send![obj, retainCount => usize] }
6263
}
6364

6465
let obj = unsafe {
65-
StrongPtr::new(msg_send![class!(NSObject), new])
66+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
6667
};
6768
assert!(retain_count(*obj) == 1);
6869

@@ -77,7 +78,7 @@ mod tests {
7778
#[test]
7879
fn test_weak() {
7980
let obj = unsafe {
80-
StrongPtr::new(msg_send![class!(NSObject), new])
81+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
8182
};
8283
let weak = obj.weak();
8384

@@ -92,7 +93,7 @@ mod tests {
9293
#[test]
9394
fn test_weak_copy() {
9495
let obj = unsafe {
95-
StrongPtr::new(msg_send![class!(NSObject), new])
96+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
9697
};
9798
let weak = obj.weak();
9899

@@ -104,11 +105,11 @@ mod tests {
104105
#[test]
105106
fn test_autorelease() {
106107
let obj = unsafe {
107-
StrongPtr::new(msg_send![class!(NSObject), new])
108+
StrongPtr::new(msg_send![class!(NSObject), new => *mut Object])
108109
};
109110

110111
fn retain_count(obj: *mut Object) -> usize {
111-
unsafe { msg_send![obj, retainCount] }
112+
unsafe { msg_send![obj, retainCount => usize] }
112113
}
113114
let cloned = obj.clone();
114115

src/runtime.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,8 @@ mod tests {
593593
#[test]
594594
fn test_protocol_method() {
595595
let class = test_utils::custom_class();
596-
let result: i32 = unsafe {
597-
msg_send![class, addNumber:1 toNumber:2]
596+
let result = unsafe {
597+
msg_send![class, addNumber:1 toNumber:2 => i32]
598598
};
599599
assert_eq!(result, 3);
600600
}

src/test_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ pub fn custom_subclass() -> &'static Class {
157157
let mut decl = ClassDecl::new("CustomSubclassObject", superclass).unwrap();
158158

159159
extern fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 {
160-
let foo: u32 = unsafe {
161-
msg_send![super(this, custom_class()), foo]
160+
let foo = unsafe {
161+
msg_send![super(this, custom_class()), foo => u32]
162162
};
163163
foo + 2
164164
}

tests/use_macros.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use objc::runtime::Object;
99
fn use_class_and_msg_send() {
1010
unsafe {
1111
let cls = class!(NSObject);
12-
let obj: *mut Object = msg_send![cls, new];
13-
let _hash: usize = msg_send![obj, hash];
14-
let _: () = msg_send![obj, release];
12+
let obj = msg_send![cls, new => *mut Object];
13+
let _hash = msg_send![obj, hash => usize];
14+
msg_send![obj, release => ()];
1515
}
1616
}
1717

0 commit comments

Comments
 (0)