@@ -17,6 +17,7 @@ use errors::DiagnosticBuilder;
17
17
use errors:: Level ;
18
18
use ty:: tls;
19
19
use ty:: { TyCtxt } ;
20
+ use ty:: maps:: Query ;
20
21
use ty:: maps:: config:: QueryDescription ;
21
22
use ty:: maps:: job:: { QueryResult , QueryInfo } ;
22
23
use ty:: item_path;
@@ -63,7 +64,8 @@ pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized {
63
64
64
65
#[ derive( Clone ) ]
65
66
pub ( 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 > ) > ,
67
69
pub ( super ) cycle : Vec < QueryInfo < ' tcx > > ,
68
70
}
69
71
@@ -79,33 +81,41 @@ pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> {
79
81
}
80
82
81
83
impl < ' 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 > )
83
85
-> DiagnosticBuilder < ' a >
84
86
{
85
87
assert ! ( !stack. is_empty( ) ) ;
86
88
89
+ let fix_span = |span : Span , query : & Query < ' gcx > | {
90
+ self . sess . codemap ( ) . def_span ( query. default_span ( self , span) )
91
+ } ;
92
+
87
93
// Disable naming impls with types in this path, since that
88
94
// sometimes cycles itself, leading to extra cycle errors.
89
95
// (And cycle errors around impls tend to occur during the
90
96
// collect/coherence phases anyhow.)
91
97
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 ) ) ) ;
104
109
}
105
110
106
- err. note ( & format ! ( "...which then again requires {}, completing the cycle. " ,
111
+ err. note ( & format ! ( "...which again requires {}, completing the cycle" ,
107
112
stack[ 0 ] . query. describe( self ) ) ) ;
108
113
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
+
109
119
return err
110
120
} )
111
121
}
@@ -266,6 +276,22 @@ macro_rules! define_maps {
266
276
r
267
277
}
268
278
}
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
+ }
269
295
}
270
296
271
297
pub mod queries {
@@ -303,7 +329,7 @@ macro_rules! define_maps {
303
329
/// If the query already executed and panicked, this will fatal error / silently panic
304
330
fn try_get_lock(
305
331
tcx: TyCtxt <' a, $tcx, ' lcx>,
306
- mut span: Span ,
332
+ span: Span ,
307
333
key: & $K
308
334
) -> TryGetLock <' a, $tcx, $V, Self >
309
335
{
@@ -329,21 +355,14 @@ macro_rules! define_maps {
329
355
} ;
330
356
mem:: drop( lock) ;
331
357
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
-
339
358
if let Err ( cycle) = job. await ( tcx, span) {
340
359
return TryGetLock :: JobCompleted ( Err ( cycle) ) ;
341
360
}
342
361
}
343
362
}
344
363
345
364
fn try_get_with( tcx: TyCtxt <' a, $tcx, ' lcx>,
346
- mut span: Span ,
365
+ span: Span ,
347
366
key: $K)
348
367
-> Result <$V, CycleError <$tcx>>
349
368
{
@@ -377,18 +396,6 @@ macro_rules! define_maps {
377
396
378
397
let mut lock = get_lock_or_return!( ) ;
379
398
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
-
392
399
// Fast path for when incr. comp. is off. `to_dep_node` is
393
400
// expensive for some DepKinds.
394
401
if !tcx. dep_graph. is_fully_enabled( ) {
0 commit comments