Skip to content

Commit 3b8eadd

Browse files
committed
Deprecate using msg_send! without comma between arguments
1 parent 7e58561 commit 3b8eadd

File tree

9 files changed

+195
-6
lines changed

9 files changed

+195
-6
lines changed

crates/objc2/CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1515
* **BREAKING**: `AnyClass::verify_sel` now take more well-defined types
1616
`EncodeArguments` and `EncodeReturn`.
1717

18+
### Deprecated
19+
* Soft deprecated using `msg_send!` without a comma between arguments (i.e.
20+
deprecated when the `"unstable-msg-send-always-comma"` feature is enabled).
21+
22+
See the following for an example of how to upgrade:
23+
```rust
24+
// Before
25+
let _: NSInteger = msg_send![
26+
obj,
27+
addTrackingRect:rect
28+
owner:obj
29+
userData:ptr::null_mut::<c_void>()
30+
assumeInside:Bool::NO
31+
];
32+
// After
33+
let _: NSInteger = msg_send![
34+
obj,
35+
addTrackingRect: rect,
36+
owner: obj,
37+
userData: ptr::null_mut::<c_void>(),
38+
assumeInside: false,
39+
];
40+
```
41+
1842

1943
## 0.4.1 - 2023-07-31
2044

crates/objc2/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ verify = ["malloc"]
4242
# to objc2.
4343
relax-void-encoding = []
4444

45+
# Enable deprecation of using `msg_send!` without a comma between arguments.
46+
unstable-msg-send-always-comma = []
47+
4548
# Expose features that require linking to `libc::free`.
4649
#
4750
# This is not enabled by default because most users won't need it, and it

crates/objc2/src/macros/__msg_send_parse.rs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ macro_rules! __msg_send_parse {
7878
};
7979

8080
// Handle calls without comma between `selector: argument` pair.
81-
// TODO: Deprecate this
8281
{
8382
($out_macro:path)
8483
@($error_fn:ident)
@@ -87,7 +86,17 @@ macro_rules! __msg_send_parse {
8786
@()
8887
@($($selector:ident : $argument:expr)*)
8988
$($macro_args:tt)*
90-
} => {
89+
} => {{
90+
$crate::__comma_between_args!(
91+
@($(
92+
", ",
93+
stringify!($selector),
94+
": ",
95+
stringify!($argument),
96+
)+)
97+
$($macro_args)*
98+
);
99+
91100
$crate::__msg_send_parse! {
92101
($out_macro)
93102
@($error_fn)
@@ -96,5 +105,79 @@ macro_rules! __msg_send_parse {
96105
@($($selector : $argument),*)
97106
$($macro_args)*
98107
}
108+
}};
109+
}
110+
111+
#[doc(hidden)]
112+
#[macro_export]
113+
#[cfg(not(feature = "unstable-msg-send-always-comma"))]
114+
macro_rules! __comma_between_args {
115+
($($args:tt)*) => {};
116+
}
117+
118+
#[doc(hidden)]
119+
#[macro_export]
120+
#[cfg(feature = "unstable-msg-send-always-comma")]
121+
macro_rules! __comma_between_args {
122+
(
123+
@__output
124+
@($($args:tt)*)
125+
@($macro_name:literal)
126+
) => {
127+
#[deprecated = concat!(
128+
"using ", $macro_name, "! without a comma between arguments is ",
129+
"technically not valid macro syntax, and may break in a future ",
130+
"version of Rust. You should use the following instead:\n",
131+
$macro_name, "![", $($args)* "]"
132+
)]
133+
#[inline]
134+
fn __msg_send_missing_comma() {}
135+
__msg_send_missing_comma();
136+
};
137+
(
138+
@($($args:tt)*)
139+
@(__send_super_message_static)
140+
@($obj:expr)
141+
) => {
142+
$crate::__comma_between_args! {
143+
@__output
144+
@(stringify!(super($obj)), $($args)*)
145+
@("msg_send")
146+
}
147+
};
148+
(
149+
@($($args:tt)*)
150+
@(send_super_message)
151+
@($obj:expr, $superclass:expr)
152+
) => {
153+
$crate::__comma_between_args! {
154+
@__output
155+
@(stringify!(super($obj, $superclass)), $($args)*)
156+
@("msg_send")
157+
}
158+
};
159+
(
160+
@($($args:tt)*)
161+
@(send_message)
162+
@($obj:expr)
163+
) => {
164+
$crate::__comma_between_args! {
165+
@__output
166+
@(stringify!($obj), $($args)*)
167+
@("msg_send")
168+
}
169+
};
170+
// Catch-all for msg_send_id!
171+
(
172+
@($($args:tt)*)
173+
@($fn:ident)
174+
@($obj:expr)
175+
@()
176+
) => {
177+
$crate::__comma_between_args! {
178+
@__output
179+
@(stringify!($obj), $($args)*)
180+
@("msg_send_id")
181+
}
99182
};
100183
}

crates/objc2/src/macros/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,9 +725,11 @@ macro_rules! __class_inner {
725725
///
726726
/// # Specification
727727
///
728-
/// The syntax is similar to the message syntax in Objective-C, except with
729-
/// an (optional, though consider that deprecated) comma between arguments,
730-
/// since that works much better with rustfmt.
728+
/// The syntax is somewhat similar to the message syntax in Objective-C,
729+
/// except with a comma between arguments. Eliding the comma is possible,
730+
/// but it is soft-deprecated, and will be fully deprecated in a future
731+
/// release. The deprecation can be tried out with the
732+
/// `"unstable-msg-send-always-comma"` feature flag.
731733
///
732734
/// The first expression, know as the "receiver", can be any type that
733735
/// implements [`MessageReceiver`], like a reference or a pointer to an

crates/objc2/tests/use_macros.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub fn test_msg_send_comma_handling(obj: &MyObject, superclass: &AnyClass) {
3434
let _: () = msg_send![obj, a,];
3535
let _: () = msg_send![obj, a: 32i32];
3636
let _: () = msg_send![obj, a: 32i32,];
37+
#[cfg_attr(feature = "unstable-msg-send-always-comma", allow(deprecated))]
3738
let _: () = msg_send![obj, a: 32i32 b: 32i32];
3839
let _: () = msg_send![obj, a: 32i32, b: 32i32];
3940
let _: () = msg_send![obj, a: 32i32, b: 32i32,];
@@ -44,6 +45,7 @@ pub fn test_msg_send_comma_handling(obj: &MyObject, superclass: &AnyClass) {
4445
let _: () = msg_send![super(obj, superclass), a,];
4546
let _: () = msg_send![super(obj, superclass), a: 32i32];
4647
let _: () = msg_send![super(obj, superclass), a: 32i32,];
48+
#[cfg_attr(feature = "unstable-msg-send-always-comma", allow(deprecated))]
4749
let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32];
4850
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32];
4951
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32,];

crates/test-ui/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ default = [
2121
"icrate/Foundation_NSArray",
2222
"icrate/Foundation_NSMutableArray",
2323
"icrate/Foundation_NSValue",
24+
"objc2/unstable-msg-send-always-comma",
2425
]
2526
std = ["block2/std", "objc2/std", "icrate/std"]
2627

crates/test-ui/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Use as:
44
//! ```
5-
//! TRYBUILD=overwrite cargo +nightly run --features=run --bin test-ui
5+
//! TRYBUILD=overwrite RUSTFLAGS="--deny=warnings" cargo +nightly run --features=run --bin test-ui
66
//! ```
77
//!
88
//! These are not part of the normal test suite, because trybuild doesn't pass
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! Test msg_send! syntax with missing commas.
2+
use icrate::Foundation::NSString;
3+
use objc2::rc::Id;
4+
use objc2::{msg_send, msg_send_bool, msg_send_id, ClassType};
5+
6+
fn main() {
7+
let obj: &NSString = &NSString::new();
8+
9+
let _: () = unsafe { msg_send![super(obj), a:obj b:obj] };
10+
let _: () = unsafe { msg_send![super(obj, NSString::class()), a:obj b:obj] };
11+
let _: () = unsafe { msg_send![obj, a:obj b:obj] };
12+
13+
unsafe { msg_send_bool![obj, c:obj d:obj] };
14+
15+
let _: Id<NSString> = unsafe { msg_send_id![obj, e:obj f:obj] };
16+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error: use of deprecated macro `msg_send_bool`: use a normal msg_send! instead, it will perform the conversion for you
2+
--> ui/msg_send_missing_comma.rs
3+
|
4+
| unsafe { msg_send_bool![obj, c:obj d:obj] };
5+
| ^^^^^^^^^^^^^
6+
|
7+
= note: `-D deprecated` implied by `-D warnings`
8+
9+
error: use of deprecated macro `objc2::msg_send_bool`: use a normal msg_send! instead, it will perform the conversion for you
10+
--> ui/msg_send_missing_comma.rs
11+
|
12+
| use objc2::{msg_send, msg_send_bool, msg_send_id, ClassType};
13+
| ^^^^^^^^^^^^^
14+
15+
error: use of deprecated function `main::__msg_send_missing_comma`: using msg_send! without a comma between arguments is technically not valid macro syntax, and may break in a future version of Rust. You should use the following instead:
16+
msg_send![super(obj), a: obj, b: obj]
17+
--> ui/msg_send_missing_comma.rs
18+
|
19+
| let _: () = unsafe { msg_send![super(obj), a:obj b:obj] };
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
|
22+
= note: this error originates in the macro `$crate::__comma_between_args` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
23+
24+
error: use of deprecated function `main::__msg_send_missing_comma`: using msg_send! without a comma between arguments is technically not valid macro syntax, and may break in a future version of Rust. You should use the following instead:
25+
msg_send![super(obj, NSString::class()), a: obj, b: obj]
26+
--> ui/msg_send_missing_comma.rs
27+
|
28+
| let _: () = unsafe { msg_send![super(obj, NSString::class()), a:obj b:obj] };
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
|
31+
= note: this error originates in the macro `$crate::__comma_between_args` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
32+
33+
error: use of deprecated function `main::__msg_send_missing_comma`: using msg_send! without a comma between arguments is technically not valid macro syntax, and may break in a future version of Rust. You should use the following instead:
34+
msg_send![obj, a: obj, b: obj]
35+
--> ui/msg_send_missing_comma.rs
36+
|
37+
| let _: () = unsafe { msg_send![obj, a:obj b:obj] };
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
|
40+
= note: this error originates in the macro `$crate::__comma_between_args` which comes from the expansion of the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
41+
42+
error: use of deprecated function `main::__msg_send_missing_comma`: using msg_send! without a comma between arguments is technically not valid macro syntax, and may break in a future version of Rust. You should use the following instead:
43+
msg_send![obj, c: obj, d: obj]
44+
--> ui/msg_send_missing_comma.rs
45+
|
46+
| unsafe { msg_send_bool![obj, c:obj d:obj] };
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
|
49+
= note: this error originates in the macro `$crate::__comma_between_args` which comes from the expansion of the macro `msg_send_bool` (in Nightly builds, run with -Z macro-backtrace for more info)
50+
51+
error: use of deprecated function `main::__msg_send_missing_comma`: using msg_send_id! without a comma between arguments is technically not valid macro syntax, and may break in a future version of Rust. You should use the following instead:
52+
msg_send_id![obj, e: obj, f: obj]
53+
--> ui/msg_send_missing_comma.rs
54+
|
55+
| let _: Id<NSString> = unsafe { msg_send_id![obj, e:obj f:obj] };
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57+
|
58+
= note: this error originates in the macro `$crate::__comma_between_args` which comes from the expansion of the macro `msg_send_id` (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)