@@ -2,8 +2,9 @@ use super::poison::once::ExclusiveState;
2
2
use crate :: cell:: UnsafeCell ;
3
3
use crate :: mem:: ManuallyDrop ;
4
4
use crate :: ops:: { Deref , DerefMut } ;
5
- use crate :: panic:: { RefUnwindSafe , UnwindSafe } ;
5
+ use crate :: panic:: { self , AssertUnwindSafe , RefUnwindSafe , UnwindSafe } ;
6
6
use crate :: sync:: Once ;
7
+ use crate :: sys:: sync:: once:: ONCE_POISON_PANIC_MSG ;
7
8
use crate :: { fmt, ptr} ;
8
9
9
10
// 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> {
244
245
#[ inline]
245
246
#[ stable( feature = "lazy_cell" , since = "1.80.0" ) ]
246
247
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
+ }
254
273
255
274
// SAFETY:
256
275
// There are four possible scenarios:
257
276
// * 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 .
259
278
// * 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.
262
280
// So `value` has definitely been initialized and will not be modified again.
263
281
unsafe { & * ( * this. data . get ( ) ) . value }
264
282
}
0 commit comments