@@ -2,8 +2,9 @@ use super::poison::once::ExclusiveState;
22use crate :: cell:: UnsafeCell ;
33use crate :: mem:: ManuallyDrop ;
44use crate :: ops:: { Deref , DerefMut } ;
5- use crate :: panic:: { RefUnwindSafe , UnwindSafe } ;
5+ use crate :: panic:: { self , AssertUnwindSafe , RefUnwindSafe , UnwindSafe } ;
66use crate :: sync:: Once ;
7+ use crate :: sys:: sync:: once:: ONCE_POISON_PANIC_MSG ;
78use crate :: { fmt, ptr} ;
89
910// We use the state of a Once as discriminant value. Upon creation, the state is
@@ -244,21 +245,38 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
244245 #[ inline]
245246 #[ stable( feature = "lazy_cell" , since = "1.80.0" ) ]
246247 pub fn force ( this : & LazyLock < T , F > ) -> & T {
247- this. once . call_once ( || {
248- // SAFETY: `call_once` only runs this closure once, ever.
249- let data = unsafe { & mut * this. data . get ( ) } ;
250- let f = unsafe { ManuallyDrop :: take ( & mut data. f ) } ;
251- let value = f ( ) ;
252- data. value = ManuallyDrop :: new ( value) ;
253- } ) ;
248+ let call_once_closure = || {
249+ this. once . call_once ( || {
250+ // SAFETY: `call_once` only runs this closure once, ever.
251+ let data = unsafe { & mut * this. data . get ( ) } ;
252+ let f = unsafe { ManuallyDrop :: take ( & mut data. f ) } ;
253+ let value = f ( ) ;
254+ data. value = ManuallyDrop :: new ( value) ;
255+ } ) ;
256+ } ;
257+
258+ // If the internal `Once` is poisoned, it will panic with "Once instance has previously been
259+ // poisoned", but we want to panic with "LazyLock instance ..." instead.
260+ let result = panic:: catch_unwind ( AssertUnwindSafe ( call_once_closure) ) ;
261+
262+ if let Err ( payload) = result {
263+ // Check if this is the `Once` poison panic.
264+ if let Some ( s) = payload. downcast_ref :: < String > ( )
265+ && s == ONCE_POISON_PANIC_MSG
266+ {
267+ panic_poisoned ( ) ;
268+ } else {
269+ // This panic came from the closure `f`, so we don't need to change the message.
270+ panic:: resume_unwind ( payload) ;
271+ }
272+ }
254273
255274 // SAFETY:
256275 // There are four possible scenarios:
257276 // * the closure was called and initialized `value`.
258- // * the closure was called and panicked, so this point is never reached .
277+ // * the closure was called and panicked, which we handled above .
259278 // * the closure was not called, but a previous call initialized `value`.
260- // * the closure was not called because the Once is poisoned, so this point
261- // is never reached.
279+ // * the closure was not called because the Once is poisoned, which we handled above.
262280 // So `value` has definitely been initialized and will not be modified again.
263281 unsafe { & * ( * this. data . get ( ) ) . value }
264282 }
0 commit comments