Skip to content

Commit 21f6e55

Browse files
committed
Call default_span lazily when query cycles occur instead of in the hot path for queries
1 parent 49317cd commit 21f6e55

File tree

1 file changed

+28
-25
lines changed

1 file changed

+28
-25
lines changed

src/librustc/ty/maps/plumbing.rs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use errors::DiagnosticBuilder;
1717
use errors::Level;
1818
use ty::tls;
1919
use ty::{TyCtxt};
20+
use ty::maps::Query;
2021
use ty::maps::config::QueryDescription;
2122
use ty::maps::job::{QueryResult, QueryInfo};
2223
use ty::item_path;
@@ -63,6 +64,7 @@ pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized {
6364

6465
#[derive(Clone)]
6566
pub(super) struct CycleError<'tcx> {
67+
/// The span of the reason the first query in `cycle` ran the last query in `cycle`
6668
pub(super) span: Span,
6769
pub(super) cycle: Vec<QueryInfo<'tcx>>,
6870
}
@@ -79,27 +81,31 @@ pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> {
7981
}
8082

8183
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 { span, 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);
98+
let span = fix_span(span, &stack.first().unwrap().query);
9399
let mut err =
94100
struct_span_err!(self.sess, span, E0391,
95101
"cyclic dependency detected");
96102
err.span_label(span, "cyclic reference");
97103

98-
err.span_note(self.sess.codemap().def_span(stack[0].span),
104+
err.span_note(fix_span(stack[0].span, &stack[0].query),
99105
&format!("the cycle begins when {}...", stack[0].query.describe(self)));
100106

101107
for &QueryInfo { span, ref query, .. } in &stack[1..] {
102-
err.span_note(self.sess.codemap().def_span(span),
108+
err.span_note(fix_span(span, query),
103109
&format!("...which then requires {}...", query.describe(self)));
104110
}
105111

@@ -266,6 +272,22 @@ macro_rules! define_maps {
266272
r
267273
}
268274
}
275+
276+
// FIXME(eddyb) Get more valid Span's on queries.
277+
pub fn default_span(&self, tcx: TyCtxt<'_, $tcx, '_>, span: Span) -> Span {
278+
if span != DUMMY_SP {
279+
return span;
280+
}
281+
// The def_span query is used to calculate default_span,
282+
// so exit to avoid infinite recursion
283+
match *self {
284+
Query::def_span(..) => return span,
285+
_ => ()
286+
}
287+
match *self {
288+
$(Query::$name(key) => key.default_span(tcx),)*
289+
}
290+
}
269291
}
270292

271293
pub mod queries {
@@ -303,7 +325,7 @@ macro_rules! define_maps {
303325
/// If the query already executed and panicked, this will fatal error / silently panic
304326
fn try_get_lock(
305327
tcx: TyCtxt<'a, $tcx, 'lcx>,
306-
mut span: Span,
328+
span: Span,
307329
key: &$K
308330
) -> TryGetLock<'a, $tcx, $V, Self>
309331
{
@@ -329,21 +351,14 @@ macro_rules! define_maps {
329351
};
330352
mem::drop(lock);
331353

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-
339354
if let Err(cycle) = job.await(tcx, span) {
340355
return TryGetLock::JobCompleted(Err(cycle));
341356
}
342357
}
343358
}
344359

345360
fn try_get_with(tcx: TyCtxt<'a, $tcx, 'lcx>,
346-
mut span: Span,
361+
span: Span,
347362
key: $K)
348363
-> Result<$V, CycleError<$tcx>>
349364
{
@@ -377,18 +392,6 @@ macro_rules! define_maps {
377392

378393
let mut lock = get_lock_or_return!();
379394

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-
392395
// Fast path for when incr. comp. is off. `to_dep_node` is
393396
// expensive for some DepKinds.
394397
if !tcx.dep_graph.is_fully_enabled() {

0 commit comments

Comments
 (0)