Skip to content

Commit 1724af9

Browse files
Rollup merge of #144872 - connortsui20:once-poison-docs, r=Amanieu
Document Poisoning in `LazyCell` and `LazyLock` Currently, there is no documentation of poisoning behavior in either `LazyCell` or `LazyLock`, even though both of them can be observed as poisoned by users. `LazyCell` [plagyround example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=9cf38b8dc56db100848f54085c2c697d) `LazyLock` [playground example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f1cd6f9fe16636e347ebb695a0ce30c0) # Open Questions - [x] Is it worth making the implementation of `LazyLock` more complicated to ensure that the the panic message is `"LazyLock instance has previously been poisoned"` instead of `"Once instance has previously been poisoned"`? See the `LazyLock` playground link above for more context. - [x] Does it make sense to move `LazyLock` into the `poison` module? It is certainly a poison-able type, but at the same time it is slightly different from the 4 other types currently in the `poison` module in that it is unrecoverable. I think this is more of a libs-api question. ``@rustbot`` label +T-libs-api Please let me know if these open questions deserve a separate issue / PR!
2 parents db7ac64 + 96adb7d commit 1724af9

File tree

3 files changed

+118
-5
lines changed

3 files changed

+118
-5
lines changed

library/core/src/cell/lazy.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ enum State<T, F> {
1515
///
1616
/// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html
1717
///
18+
/// # Poisoning
19+
///
20+
/// If the initialization closure passed to [`LazyCell::new`] panics, the cell will be poisoned.
21+
/// Once the cell is poisoned, any threads that attempt to access this cell (via a dereference
22+
/// or via an explicit call to [`force()`]) will panic.
23+
///
24+
/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
25+
/// difference, however, is that poisoning in `LazyCell` is _unrecoverable_. All future accesses of
26+
/// the cell from other threads will panic, whereas a type in [`std::sync::poison`] like
27+
/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
28+
///
29+
/// [`force()`]: LazyCell::force
30+
/// [`std::sync::poison`]: ../../std/sync/poison/index.html
31+
/// [`std::sync::poison::Mutex`]: ../../std/sync/poison/struct.Mutex.html
32+
/// [`PoisonError::into_inner()`]: ../../std/sync/poison/struct.PoisonError.html#method.into_inner
33+
///
1834
/// # Examples
1935
///
2036
/// ```
@@ -64,6 +80,10 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
6480
///
6581
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
6682
///
83+
/// # Panics
84+
///
85+
/// Panics if the cell is poisoned.
86+
///
6787
/// # Examples
6888
///
6989
/// ```
@@ -93,6 +113,15 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
93113
///
94114
/// This is equivalent to the `Deref` impl, but is explicit.
95115
///
116+
/// # Panics
117+
///
118+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
119+
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
120+
/// accesses of the cell (via [`force()`] or a dereference) to panic.
121+
///
122+
/// [`new()`]: LazyCell::new
123+
/// [`force()`]: LazyCell::force
124+
///
96125
/// # Examples
97126
///
98127
/// ```
@@ -123,6 +152,15 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
123152
/// Forces the evaluation of this lazy value and returns a mutable reference to
124153
/// the result.
125154
///
155+
/// # Panics
156+
///
157+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
158+
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
159+
/// accesses of the cell (via [`force()`] or a dereference) to panic.
160+
///
161+
/// [`new()`]: LazyCell::new
162+
/// [`force()`]: LazyCell::force
163+
///
126164
/// # Examples
127165
///
128166
/// ```
@@ -219,7 +257,8 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
219257
}
220258

221259
impl<T, F> LazyCell<T, F> {
222-
/// Returns a mutable reference to the value if initialized, or `None` if not.
260+
/// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
261+
/// poisoned), returns `None`.
223262
///
224263
/// # Examples
225264
///
@@ -245,7 +284,8 @@ impl<T, F> LazyCell<T, F> {
245284
}
246285
}
247286

248-
/// Returns a reference to the value if initialized, or `None` if not.
287+
/// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
288+
/// returns `None`.
249289
///
250290
/// # Examples
251291
///
@@ -278,6 +318,15 @@ impl<T, F> LazyCell<T, F> {
278318
#[stable(feature = "lazy_cell", since = "1.80.0")]
279319
impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
280320
type Target = T;
321+
322+
/// # Panics
323+
///
324+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
325+
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
326+
/// accesses of the cell (via [`force()`] or a dereference) to panic.
327+
///
328+
/// [`new()`]: LazyCell::new
329+
/// [`force()`]: LazyCell::force
281330
#[inline]
282331
fn deref(&self) -> &T {
283332
LazyCell::force(self)
@@ -286,6 +335,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
286335

287336
#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
288337
impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {
338+
/// # Panics
339+
///
340+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
341+
/// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
342+
/// accesses of the cell (via [`force()`] or a dereference) to panic.
343+
///
344+
/// [`new()`]: LazyCell::new
345+
/// [`force()`]: LazyCell::force
289346
#[inline]
290347
fn deref_mut(&mut self) -> &mut T {
291348
LazyCell::force_mut(self)

library/std/src/sync/lazy_lock.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ union Data<T, F> {
2525
///
2626
/// [`LazyCell`]: crate::cell::LazyCell
2727
///
28+
/// # Poisoning
29+
///
30+
/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
31+
/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
32+
/// or via an explicit call to [`force()`]) will panic.
33+
///
34+
/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
35+
/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
36+
/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
37+
/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
38+
///
39+
/// [`force()`]: LazyLock::force
40+
/// [`std::sync::poison`]: crate::sync::poison
41+
/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
42+
/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
43+
///
2844
/// # Examples
2945
///
3046
/// Initialize static variables with `LazyLock`.
@@ -102,6 +118,10 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
102118
///
103119
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
104120
///
121+
/// # Panics
122+
///
123+
/// Panics if the lock is poisoned.
124+
///
105125
/// # Examples
106126
///
107127
/// ```
@@ -136,6 +156,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
136156
/// Forces the evaluation of this lazy value and returns a mutable reference to
137157
/// the result.
138158
///
159+
/// # Panics
160+
///
161+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
162+
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
163+
/// accesses of the lock (via [`force()`] or a dereference) to panic.
164+
///
165+
/// [`new()`]: LazyLock::new
166+
/// [`force()`]: LazyLock::force
167+
///
139168
/// # Examples
140169
///
141170
/// ```
@@ -193,6 +222,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
193222
/// This method will block the calling thread if another initialization
194223
/// routine is currently running.
195224
///
225+
/// # Panics
226+
///
227+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
228+
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
229+
/// accesses of the lock (via [`force()`] or a dereference) to panic.
230+
///
231+
/// [`new()`]: LazyLock::new
232+
/// [`force()`]: LazyLock::force
233+
///
196234
/// # Examples
197235
///
198236
/// ```
@@ -227,7 +265,8 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
227265
}
228266

229267
impl<T, F> LazyLock<T, F> {
230-
/// Returns a mutable reference to the value if initialized, or `None` if not.
268+
/// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
269+
/// poisoned), returns `None`.
231270
///
232271
/// # Examples
233272
///
@@ -256,7 +295,8 @@ impl<T, F> LazyLock<T, F> {
256295
}
257296
}
258297

259-
/// Returns a reference to the value if initialized, or `None` if not.
298+
/// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
299+
/// returns `None`.
260300
///
261301
/// # Examples
262302
///
@@ -307,6 +347,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
307347
/// This method will block the calling thread if another initialization
308348
/// routine is currently running.
309349
///
350+
/// # Panics
351+
///
352+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
353+
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
354+
/// accesses of the lock (via [`force()`] or a dereference) to panic.
355+
///
356+
/// [`new()`]: LazyLock::new
357+
/// [`force()`]: LazyLock::force
310358
#[inline]
311359
fn deref(&self) -> &T {
312360
LazyLock::force(self)
@@ -315,6 +363,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
315363

316364
#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
317365
impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
366+
/// # Panics
367+
///
368+
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
369+
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
370+
/// accesses of the lock (via [`force()`] or a dereference) to panic.
371+
///
372+
/// [`new()`]: LazyLock::new
373+
/// [`force()`]: LazyLock::force
318374
#[inline]
319375
fn deref_mut(&mut self) -> &mut T {
320376
LazyLock::force_mut(self)

library/std/src/sync/poison.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//!
1212
//! The specifics of how this "poisoned" state affects other threads and whether
1313
//! the panics are recognized reliably or on a best-effort basis depend on the
14-
//! primitive. See [#Overview] below.
14+
//! primitive. See [Overview](#overview) below.
1515
//!
1616
//! For the alternative implementations that do not employ poisoning,
1717
//! see [`std::sync::nonpoison`].

0 commit comments

Comments
 (0)