1- //! The implementation of the query system itself. This defines the macros that
2- //! generate the actual methods on tcx which find and execute the provider,
3- //! manage the caches, and so forth.
4-
5- use std:: cell:: Cell ;
6- use std:: fmt:: Debug ;
71use std:: hash:: Hash ;
82use std:: mem;
93
10- use rustc_data_structures:: fingerprint:: Fingerprint ;
11- use rustc_data_structures:: hash_table:: { self , Entry , HashTable } ;
12- use rustc_data_structures:: sharded:: { self , Sharded } ;
4+ use rustc_data_structures:: hash_table:: { Entry , HashTable } ;
135use rustc_data_structures:: stack:: ensure_sufficient_stack;
14- use rustc_data_structures:: { outline, sync} ;
6+ use rustc_data_structures:: { outline, sharded , sync} ;
157use rustc_errors:: { Diag , FatalError , StashKey } ;
8+ use rustc_query_system:: dep_graph:: { DepGraphData , DepNodeKey , HasDepContext } ;
9+ use rustc_query_system:: query:: {
10+ ActiveKeyStatus , CycleError , CycleErrorHandling , QueryCache , QueryContext , QueryDispatcher ,
11+ QueryJob , QueryJobId , QueryJobInfo , QueryLatch , QueryMap , QueryMode , QueryStackDeferred ,
12+ QueryStackFrame , QueryState , incremental_verify_ich, report_cycle,
13+ } ;
1614use rustc_span:: { DUMMY_SP , Span } ;
17- use tracing:: instrument;
1815
19- use super :: { QueryDispatcher , QueryStackDeferred , QueryStackFrameExtra } ;
20- use crate :: dep_graph:: {
21- DepContext , DepGraphData , DepNode , DepNodeIndex , DepNodeKey , HasDepContext ,
22- } ;
23- use crate :: ich:: StableHashingContext ;
24- use crate :: query:: caches:: QueryCache ;
25- use crate :: query:: job:: { QueryInfo , QueryJob , QueryJobId , QueryJobInfo , QueryLatch , report_cycle} ;
26- use crate :: query:: {
27- CycleErrorHandling , QueryContext , QueryMap , QueryStackFrame , SerializedDepNodeIndex ,
28- } ;
16+ use crate :: dep_graph:: { DepContext , DepNode , DepNodeIndex } ;
2917
3018#[ inline]
3119fn equivalent_key < K : Eq , V > ( k : & K ) -> impl Fn ( & ( K , V ) ) -> bool + ' _ {
3220 move |x| x. 0 == * k
3321}
3422
35- /// For a particular query, keeps track of "active" keys, i.e. keys whose
36- /// evaluation has started but has not yet finished successfully.
37- ///
38- /// (Successful query evaluation for a key is represented by an entry in the
39- /// query's in-memory cache.)
40- pub struct QueryState < ' tcx , K > {
41- active : Sharded < hash_table:: HashTable < ( K , ActiveKeyStatus < ' tcx > ) > > ,
42- }
43-
44- /// For a particular query and key, tracks the status of a query evaluation
45- /// that has started, but has not yet finished successfully.
46- ///
47- /// (Successful query evaluation for a key is represented by an entry in the
48- /// query's in-memory cache.)
49- enum ActiveKeyStatus < ' tcx > {
50- /// Some thread is already evaluating the query for this key.
51- ///
52- /// The enclosed [`QueryJob`] can be used to wait for it to finish.
53- Started ( QueryJob < ' tcx > ) ,
54-
55- /// The query panicked. Queries trying to wait on this will raise a fatal error which will
56- /// silently panic.
57- Poisoned ,
58- }
59-
60- impl < ' tcx > ActiveKeyStatus < ' tcx > {
61- /// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
62- /// was poisoned by a panic.
63- fn expect_job ( self ) -> QueryJob < ' tcx > {
64- match self {
65- Self :: Started ( job) => job,
66- Self :: Poisoned => {
67- panic ! ( "job for query failed to start and was poisoned" )
68- }
23+ /// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
24+ /// was poisoned by a panic.
25+ fn expect_job < ' tcx > ( status : ActiveKeyStatus < ' tcx > ) -> QueryJob < ' tcx > {
26+ match status {
27+ ActiveKeyStatus :: Started ( job) => job,
28+ ActiveKeyStatus :: Poisoned => {
29+ panic ! ( "job for query failed to start and was poisoned" )
6930 }
7031 }
7132}
7233
73- impl < ' tcx , K > QueryState < ' tcx , K >
74- where
75- K : Eq + Hash + Copy + Debug ,
76- {
77- pub fn all_inactive ( & self ) -> bool {
78- self . active . lock_shards ( ) . all ( |shard| shard. is_empty ( ) )
79- }
80-
81- /// Internal plumbing for collecting the set of active jobs for this query.
82- ///
83- /// Should only be called from `gather_active_jobs`.
84- pub fn gather_active_jobs_inner < Qcx : Copy > (
85- & self ,
86- qcx : Qcx ,
87- make_frame : fn ( Qcx , K ) -> QueryStackFrame < QueryStackDeferred < ' tcx > > ,
88- jobs : & mut QueryMap < ' tcx > ,
89- require_complete : bool ,
90- ) -> Option < ( ) > {
91- let mut active = Vec :: new ( ) ;
92-
93- // Helper to gather active jobs from a single shard.
94- let mut gather_shard_jobs = |shard : & HashTable < ( K , ActiveKeyStatus < ' tcx > ) > | {
95- for ( k, v) in shard. iter ( ) {
96- if let ActiveKeyStatus :: Started ( ref job) = * v {
97- active. push ( ( * k, job. clone ( ) ) ) ;
98- }
99- }
100- } ;
34+ pub ( crate ) fn all_inactive < ' tcx , K > ( state : & QueryState < ' tcx , K > ) -> bool {
35+ state. active . lock_shards ( ) . all ( |shard| shard. is_empty ( ) )
36+ }
10137
102- // Lock shards and gather jobs from each shard.
103- if require_complete {
104- for shard in self . active . lock_shards ( ) {
105- gather_shard_jobs ( & shard) ;
106- }
107- } else {
108- // We use try_lock_shards here since we are called from the
109- // deadlock handler, and this shouldn't be locked.
110- for shard in self . active . try_lock_shards ( ) {
111- let shard = shard?;
112- gather_shard_jobs ( & shard) ;
38+ /// Internal plumbing for collecting the set of active jobs for this query.
39+ ///
40+ /// Should only be called from `gather_active_jobs`.
41+ pub ( crate ) fn gather_active_jobs_inner < ' tcx , Qcx : Copy , K : Copy > (
42+ state : & QueryState < ' tcx , K > ,
43+ qcx : Qcx ,
44+ make_frame : fn ( Qcx , K ) -> QueryStackFrame < QueryStackDeferred < ' tcx > > ,
45+ jobs : & mut QueryMap < ' tcx > ,
46+ require_complete : bool ,
47+ ) -> Option < ( ) > {
48+ let mut active = Vec :: new ( ) ;
49+
50+ // Helper to gather active jobs from a single shard.
51+ let mut gather_shard_jobs = |shard : & HashTable < ( K , ActiveKeyStatus < ' tcx > ) > | {
52+ for ( k, v) in shard. iter ( ) {
53+ if let ActiveKeyStatus :: Started ( ref job) = * v {
54+ active. push ( ( * k, job. clone ( ) ) ) ;
11355 }
11456 }
57+ } ;
11558
116- // Call `make_frame` while we're not holding a `self.active` lock as `make_frame` may call
117- // queries leading to a deadlock.
118- for ( key, job) in active {
119- let frame = make_frame ( qcx, key) ;
120- jobs. insert ( job. id , QueryJobInfo { frame, job } ) ;
59+ // Lock shards and gather jobs from each shard.
60+ if require_complete {
61+ for shard in state. active . lock_shards ( ) {
62+ gather_shard_jobs ( & shard) ;
63+ }
64+ } else {
65+ // We use try_lock_shards here since we are called from the
66+ // deadlock handler, and this shouldn't be locked.
67+ for shard in state. active . try_lock_shards ( ) {
68+ let shard = shard?;
69+ gather_shard_jobs ( & shard) ;
12170 }
122-
123- Some ( ( ) )
12471 }
125- }
12672
127- impl < ' tcx , K > Default for QueryState < ' tcx , K > {
128- fn default ( ) -> QueryState < ' tcx , K > {
129- QueryState { active : Default :: default ( ) }
73+ // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
74+ // queries leading to a deadlock.
75+ for ( key, job) in active {
76+ let frame = make_frame ( qcx, key) ;
77+ jobs. insert ( job. id , QueryJobInfo { frame, job } ) ;
13078 }
79+
80+ Some ( ( ) )
13181}
13282
13383/// A type representing the responsibility to execute the job in the `job` field.
@@ -217,7 +167,7 @@ where
217167 Ok ( occupied) => Some ( occupied. remove ( ) . 0 . 1 ) ,
218168 }
219169 } ;
220- let job = job. expect ( "active query job entry" ) . expect_job ( ) ;
170+ let job = expect_job ( job. expect ( "active query job entry" ) ) ;
221171
222172 job. signal_complete ( ) ;
223173 }
@@ -240,7 +190,7 @@ where
240190 Ok ( occupied) => {
241191 let ( ( key, value) , vacant) = occupied. remove ( ) ;
242192 vacant. insert ( ( key, ActiveKeyStatus :: Poisoned ) ) ;
243- value . expect_job ( )
193+ expect_job ( value )
244194 }
245195 }
246196 } ;
@@ -250,22 +200,6 @@ where
250200 }
251201}
252202
253- #[ derive( Clone , Debug ) ]
254- pub struct CycleError < I = QueryStackFrameExtra > {
255- /// The query and related span that uses the cycle.
256- pub usage : Option < ( Span , QueryStackFrame < I > ) > ,
257- pub cycle : Vec < QueryInfo < I > > ,
258- }
259-
260- impl < ' tcx > CycleError < QueryStackDeferred < ' tcx > > {
261- fn lift ( & self ) -> CycleError < QueryStackFrameExtra > {
262- CycleError {
263- usage : self . usage . as_ref ( ) . map ( |( span, frame) | ( * span, frame. lift ( ) ) ) ,
264- cycle : self . cycle . iter ( ) . map ( |info| info. lift ( ) ) . collect ( ) ,
265- }
266- }
267- }
268-
269203#[ cold]
270204#[ inline( never) ]
271205fn cycle_error < ' tcx , Q > (
@@ -664,89 +598,6 @@ where
664598 Some ( ( result, dep_node_index) )
665599}
666600
667- #[ inline]
668- #[ instrument( skip( tcx, dep_graph_data, result, hash_result, format_value) , level = "debug" ) ]
669- pub ( crate ) fn incremental_verify_ich < Tcx , V > (
670- tcx : Tcx ,
671- dep_graph_data : & DepGraphData < Tcx :: Deps > ,
672- result : & V ,
673- prev_index : SerializedDepNodeIndex ,
674- hash_result : Option < fn ( & mut StableHashingContext < ' _ > , & V ) -> Fingerprint > ,
675- format_value : fn ( & V ) -> String ,
676- ) where
677- Tcx : DepContext ,
678- {
679- if !dep_graph_data. is_index_green ( prev_index) {
680- incremental_verify_ich_not_green ( tcx, prev_index)
681- }
682-
683- let new_hash = hash_result. map_or ( Fingerprint :: ZERO , |f| {
684- tcx. with_stable_hashing_context ( |mut hcx| f ( & mut hcx, result) )
685- } ) ;
686-
687- let old_hash = dep_graph_data. prev_fingerprint_of ( prev_index) ;
688-
689- if new_hash != old_hash {
690- incremental_verify_ich_failed ( tcx, prev_index, & || format_value ( result) ) ;
691- }
692- }
693-
694- #[ cold]
695- #[ inline( never) ]
696- fn incremental_verify_ich_not_green < Tcx > ( tcx : Tcx , prev_index : SerializedDepNodeIndex )
697- where
698- Tcx : DepContext ,
699- {
700- panic ! (
701- "fingerprint for green query instance not loaded from cache: {:?}" ,
702- tcx. dep_graph( ) . data( ) . unwrap( ) . prev_node_of( prev_index)
703- )
704- }
705-
706- // Note that this is marked #[cold] and intentionally takes `dyn Debug` for `result`,
707- // as we want to avoid generating a bunch of different implementations for LLVM to
708- // chew on (and filling up the final binary, too).
709- #[ cold]
710- #[ inline( never) ]
711- fn incremental_verify_ich_failed < Tcx > (
712- tcx : Tcx ,
713- prev_index : SerializedDepNodeIndex ,
714- result : & dyn Fn ( ) -> String ,
715- ) where
716- Tcx : DepContext ,
717- {
718- // When we emit an error message and panic, we try to debug-print the `DepNode`
719- // and query result. Unfortunately, this can cause us to run additional queries,
720- // which may result in another fingerprint mismatch while we're in the middle
721- // of processing this one. To avoid a double-panic (which kills the process
722- // before we can print out the query static), we print out a terse
723- // but 'safe' message if we detect a reentrant call to this method.
724- thread_local ! {
725- static INSIDE_VERIFY_PANIC : Cell <bool > = const { Cell :: new( false ) } ;
726- } ;
727-
728- let old_in_panic = INSIDE_VERIFY_PANIC . replace ( true ) ;
729-
730- if old_in_panic {
731- tcx. sess ( ) . dcx ( ) . emit_err ( crate :: error:: Reentrant ) ;
732- } else {
733- let run_cmd = if let Some ( crate_name) = & tcx. sess ( ) . opts . crate_name {
734- format ! ( "`cargo clean -p {crate_name}` or `cargo clean`" )
735- } else {
736- "`cargo clean`" . to_string ( )
737- } ;
738-
739- let dep_node = tcx. dep_graph ( ) . data ( ) . unwrap ( ) . prev_node_of ( prev_index) ;
740- tcx. sess ( ) . dcx ( ) . emit_err ( crate :: error:: IncrementCompilation {
741- run_cmd,
742- dep_node : format ! ( "{dep_node:?}" ) ,
743- } ) ;
744- panic ! ( "Found unstable fingerprints for {dep_node:?}: {}" , result( ) ) ;
745- }
746-
747- INSIDE_VERIFY_PANIC . set ( old_in_panic) ;
748- }
749-
750601/// Ensure that either this query has all green inputs or been executed.
751602/// Executing `query::ensure(D)` is considered a read of the dep-node `D`.
752603/// Returns true if the query should still run.
@@ -801,14 +652,13 @@ where
801652 ( !loadable, Some ( dep_node) )
802653}
803654
804- #[ derive( Debug ) ]
805- pub enum QueryMode {
806- Get ,
807- Ensure { check_cache : bool } ,
808- }
809-
810655#[ inline( always) ]
811- pub fn get_query_non_incr < ' tcx , Q > ( query : Q , qcx : Q :: Qcx , span : Span , key : Q :: Key ) -> Q :: Value
656+ pub ( super ) fn get_query_non_incr < ' tcx , Q > (
657+ query : Q ,
658+ qcx : Q :: Qcx ,
659+ span : Span ,
660+ key : Q :: Key ,
661+ ) -> Q :: Value
812662where
813663 Q : QueryDispatcher < ' tcx > ,
814664{
@@ -818,7 +668,7 @@ where
818668}
819669
820670#[ inline( always) ]
821- pub fn get_query_incr < ' tcx , Q > (
671+ pub ( super ) fn get_query_incr < ' tcx , Q > (
822672 query : Q ,
823673 qcx : Q :: Qcx ,
824674 span : Span ,
@@ -848,7 +698,7 @@ where
848698 Some ( result)
849699}
850700
851- pub fn force_query < ' tcx , Q > ( query : Q , qcx : Q :: Qcx , key : Q :: Key , dep_node : DepNode )
701+ pub ( super ) fn force_query < ' tcx , Q > ( query : Q , qcx : Q :: Qcx , key : Q :: Key , dep_node : DepNode )
852702where
853703 Q : QueryDispatcher < ' tcx > ,
854704{
0 commit comments