@@ -261,6 +261,18 @@ unsafe fn try_no_ret<F: FnOnce()>(closure: F) -> Result<(), Option<Retained<Exce
261261 let context = context. cast ( ) ;
262262
263263 let mut exception = ptr:: null_mut ( ) ;
264+ // SAFETY: The function pointer and context are valid.
265+ //
266+ // The exception catching itself is sound on the Rust side, because we
267+ // correctly use `extern "C-unwind"`. Objective-C does not completely
268+ // specify how foreign unwinds are handled, though they do have the
269+ // `@catch (...)` construct intended for catching C++ exceptions, so it is
270+ // likely that they intend to support Rust panics (and it works in
271+ // practice).
272+ //
273+ // See also:
274+ // https://github.com/rust-lang/rust/pull/128321
275+ // https://github.com/rust-lang/reference/pull/1226
264276 let success = unsafe { objc2_exception_helper:: try_catch ( f, context, & mut exception) } ;
265277
266278 if success == 0 {
@@ -269,12 +281,8 @@ unsafe fn try_no_ret<F: FnOnce()>(closure: F) -> Result<(), Option<Retained<Exce
269281 // SAFETY:
270282 // The exception is always a valid object or NULL.
271283 //
272- // Since we do a retain inside `extern/exception.m`, the object has
273- // +1 retain count.
274- //
275- // Code throwing an exception know that they don't hold sole access to
276- // that object any more, so even if the type was originally mutable,
277- // it is okay to create a new `Retained` to it here.
284+ // Since we do a retain in `objc2_exception_helper/src/try_catch.m`,
285+ // the object has +1 retain count.
278286 Err ( unsafe { Retained :: from_raw ( exception. cast ( ) ) } )
279287 }
280288}
@@ -406,4 +414,14 @@ mod tests {
406414 let result = catch_unwind ( || throw ( obj) ) ;
407415 let _ = result. unwrap_err ( ) ;
408416 }
417+
418+ #[ test]
419+ #[ should_panic = "test" ]
420+ #[ cfg_attr(
421+ all( target_os = "macos" , target_arch = "x86" , panic = "unwind" ) ,
422+ ignore = "panic won't start on 32-bit / w. fragile runtime, it'll just abort, since the runtime uses setjmp/longjump unwinding"
423+ ) ]
424+ fn does_not_catch_panic ( ) {
425+ let _ = unsafe { catch ( || panic ! ( "test" ) ) } ;
426+ }
409427}
0 commit comments