@@ -180,6 +180,69 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
180180 }
181181}
182182
183+ /// Atomic combination of [`take_hook`] + [`set_hook`].
184+ ///
185+ /// [`take_hook`]: ./fn.take_hook.html
186+ /// [`set_hook`]: ./fn.set_hook.html
187+ ///
188+ /// # Panics
189+ ///
190+ /// Panics if called from a panicking thread.
191+ ///
192+ /// Panics if the provided closure calls any of the functions [`panic::take_hook`],
193+ /// [`panic::set_hook`], or [`panic::update_hook`].
194+ ///
195+ /// Note: if the provided closure panics, the panic will not be able to be handled, resulting in a
196+ /// double panic that aborts the process with a generic error message.
197+ ///
198+ /// [`panic::take_hook`]: ./fn.take_hook.html
199+ /// [`panic::set_hook`]: ./fn.set_hook.html
200+ /// [`panic::update_hook`]: ./fn.update_hook.html
201+ ///
202+ /// # Examples
203+ ///
204+ /// The following will print the custom message, and then the normal output of panic.
205+ ///
206+ /// ```should_panic
207+ /// #![feature(panic_update_hook)]
208+ /// use std::panic;
209+ ///
210+ /// panic::update_hook(|prev| {
211+ /// Box::new(move |panic_info| {
212+ /// println!("Print custom message and execute panic handler as usual");
213+ /// prev(panic_info);
214+ /// })
215+ /// });
216+ ///
217+ /// panic!("Custom and then normal");
218+ /// ```
219+ #[ unstable( feature = "panic_update_hook" , issue = "92649" ) ]
220+ pub fn update_hook < F > ( hook_fn : F )
221+ where
222+ F : FnOnce (
223+ Box < dyn Fn ( & PanicInfo < ' _ > ) + ' static + Sync + Send > ,
224+ ) -> Box < dyn Fn ( & PanicInfo < ' _ > ) + ' static + Sync + Send > ,
225+ {
226+ if thread:: panicking ( ) {
227+ panic ! ( "cannot modify the panic hook from a panicking thread" ) ;
228+ }
229+
230+ unsafe {
231+ let guard = HOOK_LOCK . write ( ) ;
232+ let old_hook = HOOK ;
233+ HOOK = Hook :: Default ;
234+
235+ let hook_for_fn = match old_hook {
236+ Hook :: Default => Box :: new ( default_hook) ,
237+ Hook :: Custom ( ptr) => Box :: from_raw ( ptr) ,
238+ } ;
239+
240+ let hook = hook_fn ( hook_for_fn) ;
241+ HOOK = Hook :: Custom ( Box :: into_raw ( hook) ) ;
242+ drop ( guard) ;
243+ }
244+ }
245+
183246fn default_hook ( info : & PanicInfo < ' _ > ) {
184247 // If this is a double panic, make sure that we print a backtrace
185248 // for this panic. Otherwise only print it if logging is enabled.
0 commit comments