@@ -17,6 +17,7 @@ use errors::DiagnosticBuilder;
1717use errors:: Level ;
1818use ty:: tls;
1919use ty:: { TyCtxt } ;
20+ use ty:: maps:: Query ;
2021use ty:: maps:: config:: QueryDescription ;
2122use ty:: maps:: job:: { QueryResult , QueryInfo } ;
2223use ty:: item_path;
@@ -63,7 +64,8 @@ pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized {
6364
6465#[ derive( Clone ) ]
6566pub ( super ) struct CycleError < ' tcx > {
66- pub ( super ) span : Span ,
67+ /// The query and related span which uses the cycle
68+ pub ( super ) usage : Option < ( Span , Query < ' tcx > ) > ,
6769 pub ( super ) cycle : Vec < QueryInfo < ' tcx > > ,
6870}
6971
@@ -79,33 +81,41 @@ pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> {
7981}
8082
8183impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
82- pub ( super ) fn report_cycle ( self , CycleError { span , cycle : stack } : CycleError )
84+ pub ( super ) fn report_cycle ( self , CycleError { usage , cycle : stack } : CycleError < ' gcx > )
8385 -> DiagnosticBuilder < ' a >
8486 {
8587 assert ! ( !stack. is_empty( ) ) ;
8688
89+ let fix_span = |span : Span , query : & Query < ' gcx > | {
90+ self . sess . codemap ( ) . def_span ( query. default_span ( self , span) )
91+ } ;
92+
8793 // Disable naming impls with types in this path, since that
8894 // sometimes cycles itself, leading to extra cycle errors.
8995 // (And cycle errors around impls tend to occur during the
9096 // collect/coherence phases anyhow.)
9197 item_path:: with_forced_impl_filename_line ( || {
92- let span = self . sess . codemap ( ) . def_span ( span) ;
93- let mut err =
94- struct_span_err ! ( self . sess, span, E0391 ,
95- "cyclic dependency detected" ) ;
96- err. span_label ( span, "cyclic reference" ) ;
97-
98- err. span_note ( self . sess . codemap ( ) . def_span ( stack[ 0 ] . span ) ,
99- & format ! ( "the cycle begins when {}..." , stack[ 0 ] . query. describe( self ) ) ) ;
100-
101- for & QueryInfo { span, ref query, .. } in & stack[ 1 ..] {
102- err. span_note ( self . sess . codemap ( ) . def_span ( span) ,
103- & format ! ( "...which then requires {}..." , query. describe( self ) ) ) ;
98+ let span = fix_span ( stack[ 1 % stack. len ( ) ] . span , & stack[ 0 ] . query ) ;
99+ let mut err = struct_span_err ! ( self . sess,
100+ span,
101+ E0391 ,
102+ "cycle detected when {}" ,
103+ stack[ 0 ] . query. describe( self ) ) ;
104+
105+ for i in 1 ..stack. len ( ) {
106+ let query = & stack[ i] . query ;
107+ let span = fix_span ( stack[ ( i + 1 ) % stack. len ( ) ] . span , query) ;
108+ err. span_note ( span, & format ! ( "...which requires {}..." , query. describe( self ) ) ) ;
104109 }
105110
106- err. note ( & format ! ( "...which then again requires {}, completing the cycle. " ,
111+ err. note ( & format ! ( "...which again requires {}, completing the cycle" ,
107112 stack[ 0 ] . query. describe( self ) ) ) ;
108113
114+ if let Some ( ( span, query) ) = usage {
115+ err. span_note ( fix_span ( span, & query) ,
116+ & format ! ( "cycle used when {}" , query. describe( self ) ) ) ;
117+ }
118+
109119 return err
110120 } )
111121 }
@@ -266,6 +276,22 @@ macro_rules! define_maps {
266276 r
267277 }
268278 }
279+
280+ // FIXME(eddyb) Get more valid Span's on queries.
281+ pub fn default_span( & self , tcx: TyCtxt <' _, $tcx, ' _>, span: Span ) -> Span {
282+ if span != DUMMY_SP {
283+ return span;
284+ }
285+ // The def_span query is used to calculate default_span,
286+ // so exit to avoid infinite recursion
287+ match * self {
288+ Query :: def_span( ..) => return span,
289+ _ => ( )
290+ }
291+ match * self {
292+ $( Query :: $name( key) => key. default_span( tcx) , ) *
293+ }
294+ }
269295 }
270296
271297 pub mod queries {
@@ -303,7 +329,7 @@ macro_rules! define_maps {
303329 /// If the query already executed and panicked, this will fatal error / silently panic
304330 fn try_get_lock(
305331 tcx: TyCtxt <' a, $tcx, ' lcx>,
306- mut span: Span ,
332+ span: Span ,
307333 key: & $K
308334 ) -> TryGetLock <' a, $tcx, $V, Self >
309335 {
@@ -329,21 +355,14 @@ macro_rules! define_maps {
329355 } ;
330356 mem:: drop( lock) ;
331357
332- // This just matches the behavior of `try_get_with` so the span when
333- // we await matches the span we would use when executing.
334- // See the FIXME there.
335- if span == DUMMY_SP && stringify!( $name) != "def_span" {
336- span = key. default_span( tcx) ;
337- }
338-
339358 if let Err ( cycle) = job. await ( tcx, span) {
340359 return TryGetLock :: JobCompleted ( Err ( cycle) ) ;
341360 }
342361 }
343362 }
344363
345364 fn try_get_with( tcx: TyCtxt <' a, $tcx, ' lcx>,
346- mut span: Span ,
365+ span: Span ,
347366 key: $K)
348367 -> Result <$V, CycleError <$tcx>>
349368 {
@@ -377,18 +396,6 @@ macro_rules! define_maps {
377396
378397 let mut lock = get_lock_or_return!( ) ;
379398
380- // FIXME(eddyb) Get more valid Span's on queries.
381- // def_span guard is necessary to prevent a recursive loop,
382- // default_span calls def_span query internally.
383- if span == DUMMY_SP && stringify!( $name) != "def_span" {
384- // This might deadlock if we hold the map lock since we might be
385- // waiting for the def_span query and switch to some other fiber
386- // So we drop the lock here and reacquire it
387- mem:: drop( lock) ;
388- span = key. default_span( tcx) ;
389- lock = get_lock_or_return!( ) ;
390- }
391-
392399 // Fast path for when incr. comp. is off. `to_dep_node` is
393400 // expensive for some DepKinds.
394401 if !tcx. dep_graph. is_fully_enabled( ) {
0 commit comments