44
55use crate :: any:: Any ;
66use crate :: collections;
7+ use crate :: mem;
78use crate :: panicking;
89use crate :: sync:: { Mutex , RwLock } ;
910use crate :: thread:: Result ;
@@ -106,6 +107,11 @@ where
106107/// aborting the process as well. This function *only* catches unwinding panics,
107108/// not those that abort the process.
108109///
110+ /// This function returns the payload that the closure panicked with. Because the payload
111+ /// is allowed to be any type, it is possible for it to be a type that itself panics when
112+ /// dropped. To make sure that badly-behaved panic payloads like these do not cause bugs,
113+ /// use [`drop_unwind`] instead.
114+ ///
109115/// Also note that unwinding into Rust code with a foreign exception (e.g.
110116/// an exception thrown from C++ code) is undefined behavior.
111117///
@@ -129,6 +135,66 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
129135 unsafe { panicking:: r#try ( f) }
130136}
131137
138+ /// Invokes a closure, dropping the cause of an unwinding panic if one occurs.
139+ ///
140+ /// Unlike [`catch_unwind`], this function does not return the payload that the
141+ /// closure panicked with if it panics. Instead, the payload is dropped in such
142+ /// a way that avoids propagating panics the payload causes when it is dropped.
143+ /// As such, unlike [`catch_unwind`], you can safely ignore and drop the result
144+ /// of this function without potentially causing the outer function to unwind.
145+ ///
146+ /// It is currently undefined behavior to unwind from Rust code into foreign
147+ /// code, so this function is particularly useful when Rust is called from
148+ /// another language (normally C). This can run arbitrary Rust code, capturing a
149+ /// panic and allowing a graceful handling of the error.
150+ ///
151+ /// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
152+ /// that all captured variables are safe to cross this boundary. The purpose of
153+ /// this bound is to encode the concept of [exception safety][rfc] in the type
154+ /// system. Most usage of this function should not need to worry about this
155+ /// bound as programs are naturally unwind safe without `unsafe` code. If it
156+ /// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
157+ /// assert that the usage here is indeed unwind safe.
158+ ///
159+ /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
160+ ///
161+ /// # Notes
162+ ///
163+ /// Note that this function **may not catch all panics** in Rust. A panic in
164+ /// Rust is not always implemented via unwinding, but can be implemented by
165+ /// aborting the process as well. This function *only* catches unwinding panics,
166+ /// not those that abort the process.
167+ ///
168+ /// Also note that unwinding into Rust code with a foreign exception (e.g.
169+ /// an exception thrown from C++ code) is undefined behavior.
170+ ///
171+ /// # Examples
172+ ///
173+ /// ```
174+ /// #![feature(drop_unwind)]
175+ ///
176+ /// use std::panic;
177+ ///
178+ /// let _ = panic::drop_unwind(|| {
179+ /// panic!("oh no!");
180+ /// });
181+ /// println!("hello!");
182+ /// ```
183+ #[ unstable( feature = "drop_unwind" , issue = "none" ) ]
184+ pub fn drop_unwind < F : FnOnce ( ) -> R + UnwindSafe , R > ( f : F ) -> core:: result:: Result < R , ( ) > {
185+ struct AbortOnDrop ;
186+ impl Drop for AbortOnDrop {
187+ fn drop ( & mut self ) {
188+ crate :: process:: abort ( ) ;
189+ }
190+ }
191+
192+ let abort_on_drop = AbortOnDrop ;
193+ let res = catch_unwind ( f) . map_err ( drop) ;
194+ mem:: forget ( abort_on_drop) ;
195+ res
196+ }
197+
132198/// Triggers a panic without invoking the panic hook.
133199///
134200/// This is designed to be used in conjunction with [`catch_unwind`] to, for
0 commit comments