Skip to content

Commit fc7e6e2

Browse files
committed
Add unstable-c-unwind to block2
Improves the situation in #539.
1 parent bbf81ac commit fc7e6e2

File tree

7 files changed

+99
-33
lines changed

7 files changed

+99
-33
lines changed

crates/block2/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased - YYYY-MM-DD
88

9+
### Added
10+
* Added `unstable-c-unwind` feature flag.
11+
912

1013
## 0.5.1 - 2024-05-21
1114

crates/block2/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ unstable-winobjc = ["gnustep-1-8"]
4545
# Link to ObjFW.
4646
unstable-objfw = []
4747

48+
# Uses `extern "C-unwind"` on relevant function declarations.
49+
#
50+
# This raises MSRV to `1.71`.
51+
#
52+
# Warning: Enabling this is a breaking change for consumer crates, as it
53+
# changes the signature of functions.
54+
unstable-c-unwind = []
55+
4856
# Expose private ffi functions and statics.
4957
unstable-private = []
5058

crates/block2/src/abi.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ pub struct BlockHeader {
199199
/// If the BLOCK_USE_SRET & BLOCK_HAS_SIGNATURE flag is set, there is an
200200
/// additional hidden parameter, which is a pointer to the space on the
201201
/// stack allocated to hold the return value.
202-
pub invoke: Option<unsafe extern "C" fn()>,
202+
pub invoke: Option<crate::__c_unwind!(unsafe extern "C" fn())>,
203203
/// The block's descriptor.
204204
pub(crate) descriptor: BlockDescriptorPtr,
205205
}
@@ -257,12 +257,13 @@ pub(crate) struct BlockDescriptorCopyDispose {
257257
///
258258
/// This may be NULL since macOS 11.0.1 in Apple's runtime, but this
259259
/// should not be relied on.
260-
pub(crate) copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *const c_void)>,
260+
pub(crate) copy:
261+
Option<crate::__c_unwind!(unsafe extern "C" fn(dst: *mut c_void, src: *const c_void))>,
261262
/// Helper to destroy the block after being copied.
262263
///
263264
/// This may be NULL since macOS 11.0.1 in Apple's runtime, but this
264265
/// should not be relied on.
265-
pub(crate) dispose: Option<unsafe extern "C" fn(src: *mut c_void)>,
266+
pub(crate) dispose: Option<crate::__c_unwind!(unsafe extern "C" fn(src: *mut c_void))>,
266267
}
267268

268269
/// Block descriptor that has an encoding / a signature.
@@ -302,12 +303,13 @@ pub(crate) struct BlockDescriptorCopyDisposeSignature {
302303
///
303304
/// This may be NULL since macOS 11.0.1 in Apple's runtime, but this
304305
/// should not be relied on.
305-
pub(crate) copy: Option<unsafe extern "C" fn(dst: *mut c_void, src: *const c_void)>,
306+
pub(crate) copy:
307+
Option<crate::__c_unwind!(unsafe extern "C" fn(dst: *mut c_void, src: *const c_void))>,
306308
/// Helper to destroy the block after being copied.
307309
///
308310
/// This may be NULL since macOS 11.0.1 in Apple's runtime, but this
309311
/// should not be relied on.
310-
pub(crate) dispose: Option<unsafe extern "C" fn(src: *mut c_void)>,
312+
pub(crate) dispose: Option<crate::__c_unwind!(unsafe extern "C" fn(src: *mut c_void))>,
311313

312314
/// Objective-C type encoding of the block.
313315
#[doc(alias = "signature")]

crates/block2/src/ffi.rs

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ use core::ffi::c_void;
55
use core::marker::{PhantomData, PhantomPinned};
66
use std::os::raw::c_int;
77

8+
#[cfg(not(feature = "unstable-c-unwind"))]
9+
#[doc(hidden)]
10+
#[macro_export]
11+
macro_rules! __c_unwind {
12+
(unsafe extern "C" $($t:tt)*) => {
13+
unsafe extern "C" $($t)*
14+
};
15+
(extern "C" $($t:tt)*) => {
16+
extern "C" $($t)*
17+
};
18+
}
19+
20+
#[cfg(feature = "unstable-c-unwind")]
21+
#[doc(hidden)]
22+
#[macro_export]
23+
macro_rules! __c_unwind {
24+
(unsafe extern "C" $($t:tt)*) => {
25+
unsafe extern "C-unwind" $($t)*
26+
};
27+
(extern "C" $($t:tt)*) => {
28+
extern "C-unwind" $($t)*
29+
};
30+
}
31+
832
/// Type for block class ISAs.
933
///
1034
/// This will likely become an extern type in the future.
@@ -31,9 +55,26 @@ pub struct Class {
3155
_opaque: UnsafeCell<PhantomData<(*const UnsafeCell<()>, PhantomPinned)>>,
3256
}
3357

34-
// TODO: Use `extern "C-unwind"` when in MSRV (because the runtime functions
35-
// may call external routines).
36-
extern "C" {
58+
#[cfg(not(feature = "unstable-c-unwind"))]
59+
macro_rules! extern_c_unwind {
60+
($($t:tt)*) => {
61+
extern "C" {
62+
$($t)*
63+
}
64+
};
65+
}
66+
67+
#[cfg(feature = "unstable-c-unwind")]
68+
macro_rules! extern_c_unwind {
69+
($($t:tt)*) => {
70+
extern "C-unwind" {
71+
$($t)*
72+
}
73+
};
74+
}
75+
76+
// Use `extern "C-unwind"`, runtime functions may call external routines.
77+
extern_c_unwind! {
3778
/// Class ISA used for global blocks.
3879
pub static _NSConcreteGlobalBlock: Class;
3980

@@ -85,7 +126,7 @@ pub mod private {
85126
#[cfg(any(doc, target_vendor = "apple", feature = "compiler-rt"))]
86127
use std::os::raw::c_ulong;
87128

88-
extern "C" {
129+
extern_c_unwind! {
89130
pub static _NSConcreteMallocBlock: Class;
90131
#[cfg(any(doc, target_vendor = "apple", feature = "compiler-rt"))]
91132
pub static _NSConcreteAutoBlock: Class;
@@ -160,12 +201,21 @@ mod tests {
160201
println!("{:?}", unsafe {
161202
ptr::addr_of!(private::_NSConcreteMallocBlock)
162203
});
163-
println!("{:p}", _Block_copy as unsafe extern "C" fn(_) -> _);
164204
println!(
165205
"{:p}",
166-
_Block_object_assign as unsafe extern "C" fn(_, _, _)
206+
_Block_copy as __c_unwind!(unsafe extern "C" fn(_) -> _)
207+
);
208+
println!(
209+
"{:p}",
210+
_Block_object_assign as __c_unwind!(unsafe extern "C" fn(_, _, _))
211+
);
212+
println!(
213+
"{:p}",
214+
_Block_object_dispose as __c_unwind!(unsafe extern "C" fn(_, _))
215+
);
216+
println!(
217+
"{:p}",
218+
_Block_release as __c_unwind!(unsafe extern "C" fn(_))
167219
);
168-
println!("{:p}", _Block_object_dispose as unsafe extern "C" fn(_, _));
169-
println!("{:p}", _Block_release as unsafe extern "C" fn(_));
170220
}
171221
}

crates/block2/src/global.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,17 @@ macro_rules! global_block {
186186
let mut header = $crate::GlobalBlock::<dyn Fn($($t),*) $(-> $r)? + 'static>::__DEFAULT_HEADER;
187187
header.isa = ::core::ptr::addr_of!($crate::ffi::_NSConcreteGlobalBlock);
188188
header.invoke = ::core::option::Option::Some({
189-
unsafe extern "C" fn inner(_: *mut $crate::GlobalBlock<dyn Fn($($t),*) $(-> $r)? + 'static>, $($a: $t),*) $(-> $r)? {
189+
$crate::__c_unwind!(unsafe extern "C" fn inner(
190+
_: *mut $crate::GlobalBlock<dyn Fn($($t),*) $(-> $r)? + 'static>,
191+
$($a: $t),*
192+
) $(-> $r)? {
190193
$body
191-
}
194+
});
192195

193196
// TODO: SAFETY
194197
::core::mem::transmute::<
195-
unsafe extern "C" fn(*mut $crate::GlobalBlock<dyn Fn($($t),*) $(-> $r)? + 'static>, $($a: $t),*) $(-> $r)?,
196-
unsafe extern "C" fn(),
198+
$crate::__c_unwind!(unsafe extern "C" fn(*mut $crate::GlobalBlock<dyn Fn($($t),*) $(-> $r)? + 'static>, $($a: $t),*) $(-> $r)?),
199+
$crate::__c_unwind!(unsafe extern "C" fn()),
197200
>(inner)
198201
});
199202
$crate::GlobalBlock::from_header(header)

crates/block2/src/stack.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ impl<'f, A, R, Closure> StackBlock<'f, A, R, Closure> {
7676
/// the heap in `_Block_copy` operations.
7777
const SIZE: c_ulong = mem::size_of::<Self>() as _;
7878

79-
/// Drop the closure that this block contains.
80-
unsafe extern "C" fn drop_closure(block: *mut c_void) {
79+
// Drop the closure that this block contains.
80+
crate::__c_unwind! {unsafe extern "C" fn drop_closure(block: *mut c_void) {
8181
let block: *mut Self = block.cast();
8282
// When this function is called, the block no longer lives on the
8383
// stack, it has been moved to the heap as part of some `_Block_copy`
@@ -97,7 +97,7 @@ impl<'f, A, R, Closure> StackBlock<'f, A, R, Closure> {
9797
// part of some `_Block_copy` operation, and as such it is valid to
9898
// drop here.
9999
unsafe { ptr::drop_in_place(closure) };
100-
}
100+
}}
101101

102102
const DESCRIPTOR_BASIC: BlockDescriptor = BlockDescriptor {
103103
reserved: 0,
@@ -107,8 +107,8 @@ impl<'f, A, R, Closure> StackBlock<'f, A, R, Closure> {
107107

108108
// `StackBlock::new`
109109
impl<'f, A, R, Closure: Clone> StackBlock<'f, A, R, Closure> {
110-
/// Clone the closure from one block to another.
111-
unsafe extern "C" fn clone_closure(dst: *mut c_void, src: *const c_void) {
110+
// Clone the closure from one block to another.
111+
crate::__c_unwind! {unsafe extern "C" fn clone_closure(dst: *mut c_void, src: *const c_void) {
112112
let dst: *mut Self = dst.cast();
113113
let src: *const Self = src.cast();
114114
// When this function is called as part of some `_Block_copy`
@@ -132,7 +132,7 @@ impl<'f, A, R, Closure: Clone> StackBlock<'f, A, R, Closure> {
132132
// already `memmove`d data once more, which is unnecessary for closure
133133
// captures that implement `Copy`.
134134
unsafe { ptr::write(dst_closure, src_closure.clone()) };
135-
}
135+
}}
136136

137137
const DESCRIPTOR_WITH_CLONE: BlockDescriptorCopyDispose = BlockDescriptorCopyDispose {
138138
reserved: 0,
@@ -182,10 +182,10 @@ impl<'f, A, R, Closure> StackBlock<'f, A, R, Closure> {
182182

183183
// `RcBlock::new`
184184
impl<'f, A, R, Closure> StackBlock<'f, A, R, Closure> {
185-
unsafe extern "C" fn empty_clone_closure(_dst: *mut c_void, _src: *const c_void) {
185+
crate::__c_unwind! {unsafe extern "C" fn empty_clone_closure(_dst: *mut c_void, _src: *const c_void) {
186186
// We do nothing, the closure has been `memmove`'d already, and
187187
// ownership will be passed in `RcBlock::new`.
188-
}
188+
}}
189189

190190
const DESCRIPTOR_WITH_DROP: BlockDescriptorCopyDispose = BlockDescriptorCopyDispose {
191191
reserved: 0,

crates/block2/src/traits.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub unsafe trait BlockFn: private::Sealed<Self::Args, Self::Output> {
3434
/// Calls the given invoke function with the block and arguments.
3535
#[doc(hidden)]
3636
unsafe fn __call_block(
37-
invoke: unsafe extern "C" fn(),
37+
invoke: crate::__c_unwind!(unsafe extern "C" fn()),
3838
block: *mut Block<Self>,
3939
args: Self::Args,
4040
) -> Self::Output;
@@ -60,7 +60,7 @@ where
6060
type Dyn: ?Sized + BlockFn<Args = A, Output = R>;
6161

6262
#[doc(hidden)]
63-
fn __get_invoke_stack_block() -> unsafe extern "C" fn();
63+
fn __get_invoke_stack_block() -> crate::__c_unwind!(unsafe extern "C" fn());
6464
}
6565

6666
macro_rules! impl_traits {
@@ -77,7 +77,7 @@ macro_rules! impl_traits {
7777

7878
#[inline]
7979
unsafe fn __call_block(
80-
invoke: unsafe extern "C" fn(),
80+
invoke: crate::__c_unwind!(unsafe extern "C" fn()),
8181
block: *mut Block<Self>,
8282
($($a,)*): Self::Args,
8383
) -> Self::Output {
@@ -99,8 +99,8 @@ macro_rules! impl_traits {
9999
type Dyn = dyn Fn($($t),*) -> R + 'f;
100100

101101
#[inline]
102-
fn __get_invoke_stack_block() -> unsafe extern "C" fn() {
103-
unsafe extern "C" fn invoke<'f, $($t,)* R, Closure>(
102+
fn __get_invoke_stack_block() -> crate::__c_unwind!(unsafe extern "C" fn()) {
103+
crate::__c_unwind!(unsafe extern "C" fn invoke<'f, $($t,)* R, Closure>(
104104
block: *mut StackBlock<'f, ($($t,)*), R, Closure>,
105105
$($a: $t,)*
106106
) -> R
@@ -109,12 +109,12 @@ macro_rules! impl_traits {
109109
{
110110
let closure = unsafe { &*ptr::addr_of!((*block).closure) };
111111
(closure)($($a),*)
112-
}
112+
});
113113

114114
unsafe {
115115
mem::transmute::<
116-
unsafe extern "C" fn(*mut StackBlock<'f, ($($t,)*), R, Closure>, $($t,)*) -> R,
117-
unsafe extern "C" fn(),
116+
crate::__c_unwind!(unsafe extern "C" fn(*mut StackBlock<'f, ($($t,)*), R, Closure>, $($t,)*) -> R),
117+
crate::__c_unwind!(unsafe extern "C" fn()),
118118
>(invoke)
119119
}
120120
}

0 commit comments

Comments
 (0)