@@ -83,9 +83,15 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
8383 #[ inline]
8484 #[ unstable( feature = "lazy_cell" , issue = "109736" ) ]
8585 pub fn force ( this : & LazyCell < T , F > ) -> & T {
86+ // SAFETY:
87+ // This invalidates any mutable references to the data. The resulting
88+ // reference lives either until the end of the borrow of `this` (in the
89+ // initialized case) or is invalidates in `really_init` (in the
90+ // uninitialized case).
8691 let state = unsafe { & * this. state . get ( ) } ;
8792 match state {
8893 State :: Init ( data) => data,
94+ // SAFETY: The state is uninitialized.
8995 State :: Uninit ( _) => unsafe { LazyCell :: really_init ( this) } ,
9096 State :: Poisoned => panic ! ( "LazyCell has previously been poisoned" ) ,
9197 }
@@ -95,21 +101,30 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
95101 /// May only be called when the state is `Uninit`.
96102 #[ cold]
97103 unsafe fn really_init ( this : & LazyCell < T , F > ) -> & T {
104+ // SAFETY:
105+ // This function is only called when the state is uninitialized,
106+ // so no references to `state` can exist except for the reference
107+ // in `force`, which is invalidated here and not accessed again.
98108 let state = unsafe { & mut * this. state . get ( ) } ;
99109 // Temporarily mark the state as poisoned. This prevents reentrant
100110 // accesses and correctly poisons the cell if the closure panicked.
101111 let State :: Uninit ( f) = mem:: replace ( state, State :: Poisoned ) else { unreachable ! ( ) } ;
102112
103113 let data = f ( ) ;
104114
105- // If the closure accessed the cell, the mutable borrow will be
106- // invalidated, so create a new one here.
115+ // SAFETY:
116+ // If the closure accessed the cell through something like a reentrant
117+ // mutex, but caught the panic resulting from the state being poisoned,
118+ // the mutable borrow for `state` will be invalidated, so create a new
119+ // one here.
107120 let state = unsafe { & mut * this. state . get ( ) } ;
108121 * state = State :: Init ( data) ;
109122
110- // A reference obtained by downcasting from the mutable borrow
111- // would become stale if other references are created in `force`.
112- // Borrow the state directly instead.
123+ // SAFETY:
124+ // A reference obtained by downcasting from the mutable borrow would
125+ // become stale the next time `force` is called (since there is a conflict
126+ // between the mutable reference here and the shared reference there).
127+ // Do a new shared borrow of the state instead.
113128 let state = unsafe { & * this. state . get ( ) } ;
114129 let State :: Init ( data) = state else { unreachable ! ( ) } ;
115130 data
@@ -119,6 +134,10 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
119134impl < T , F > LazyCell < T , F > {
120135 #[ inline]
121136 fn get ( & self ) -> Option < & T > {
137+ // SAFETY:
138+ // This is sound for the same reason as in `force`: once the state is
139+ // initialized, it will not be mutably accessed again, so this reference
140+ // will stay valid for the duration of the borrow to `self`.
122141 let state = unsafe { & * self . state . get ( ) } ;
123142 match state {
124143 State :: Init ( data) => Some ( data) ,
0 commit comments