11use std:: hash:: Hash ;
2- use std:: mem;
2+ use std:: mem:: ManuallyDrop ;
33
44use rustc_data_structures:: hash_table:: { Entry , HashTable } ;
55use rustc_data_structures:: stack:: ensure_sufficient_stack;
@@ -26,17 +26,6 @@ fn equivalent_key<K: Eq, V>(k: K) -> impl Fn(&(K, V)) -> bool {
2626 move |x| x. 0 == k
2727}
2828
29- /// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
30- /// was poisoned by a panic.
31- fn expect_job < ' tcx > ( status : ActiveKeyStatus < ' tcx > ) -> QueryJob < ' tcx > {
32- match status {
33- ActiveKeyStatus :: Started ( job) => job,
34- ActiveKeyStatus :: Poisoned => {
35- panic ! ( "job for query failed to start and was poisoned" )
36- }
37- }
38- }
39-
4029pub ( crate ) fn all_inactive < ' tcx , K > ( state : & QueryState < ' tcx , K > ) -> bool {
4130 state. active . lock_shards ( ) . all ( |shard| shard. is_empty ( ) )
4231}
@@ -154,33 +143,45 @@ where
154143{
155144 /// Completes the query by updating the query cache with the `result`,
156145 /// signals the waiter, and forgets the guard so it won't poison the query.
157- fn complete < C > ( self , cache : & C , result : C :: Value , dep_node_index : DepNodeIndex )
146+ fn complete < C > ( self , cache : & C , value : C :: Value , dep_node_index : DepNodeIndex )
158147 where
159148 C : QueryCache < Key = K > ,
160149 {
161- // Forget ourself so our destructor won't poison the query.
162- // (Extract fields by value first to make sure we don't leak anything.)
163- let Self { state, key, key_hash } : Self = self ;
164- mem:: forget ( self ) ;
165-
166150 // Mark as complete before we remove the job from the active state
167151 // so no other thread can re-execute this query.
168- cache. complete ( key, result, dep_node_index) ;
169-
170- let job = {
171- // don't keep the lock during the `unwrap()` of the retrieved value, or we taint the
172- // underlying shard.
173- // since unwinding also wants to look at this map, this can also prevent a double
174- // panic.
175- let mut shard = state. active . lock_shard_by_hash ( key_hash) ;
176- match shard. find_entry ( key_hash, equivalent_key ( key) ) {
177- Err ( _) => None ,
178- Ok ( occupied) => Some ( occupied. remove ( ) . 0 . 1 ) ,
152+ cache. complete ( self . key , value, dep_node_index) ;
153+
154+ let mut this = ManuallyDrop :: new ( self ) ;
155+
156+ // Drop everything without poisoning the query.
157+ this. drop_and_maybe_poison ( /* poison */ false ) ;
158+ }
159+
160+ fn drop_and_maybe_poison ( & mut self , poison : bool ) {
161+ let status = {
162+ let mut shard = self . state . active . lock_shard_by_hash ( self . key_hash ) ;
163+ match shard. find_entry ( self . key_hash , equivalent_key ( self . key ) ) {
164+ Err ( _) => {
165+ // Note: we must not panic while holding the lock, because unwinding also looks
166+ // at this map, which can result in a double panic. So drop it first.
167+ drop ( shard) ;
168+ panic ! ( ) ;
169+ }
170+ Ok ( occupied) => {
171+ let ( ( key, status) , vacant) = occupied. remove ( ) ;
172+ if poison {
173+ vacant. insert ( ( key, ActiveKeyStatus :: Poisoned ) ) ;
174+ }
175+ status
176+ }
179177 }
180178 } ;
181- let job = expect_job ( job. expect ( "active query job entry" ) ) ;
182179
183- job. signal_complete ( ) ;
180+ // Also signal the completion of the job, so waiters will continue execution.
181+ match status {
182+ ActiveKeyStatus :: Started ( job) => job. signal_complete ( ) ,
183+ ActiveKeyStatus :: Poisoned => panic ! ( ) ,
184+ }
184185 }
185186}
186187
@@ -192,21 +193,7 @@ where
192193 #[ cold]
193194 fn drop ( & mut self ) {
194195 // Poison the query so jobs waiting on it panic.
195- let Self { state, key, key_hash } = * self ;
196- let job = {
197- let mut shard = state. active . lock_shard_by_hash ( key_hash) ;
198- match shard. find_entry ( key_hash, equivalent_key ( key) ) {
199- Err ( _) => panic ! ( ) ,
200- Ok ( occupied) => {
201- let ( ( key, value) , vacant) = occupied. remove ( ) ;
202- vacant. insert ( ( key, ActiveKeyStatus :: Poisoned ) ) ;
203- expect_job ( value)
204- }
205- }
206- } ;
207- // Also signal the completion of the job, so waiters
208- // will continue execution.
209- job. signal_complete ( ) ;
196+ self . drop_and_maybe_poison ( /* poison */ true ) ;
210197 }
211198}
212199
0 commit comments