diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 3b852b8ccf9..03c75655d6a 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -25,6 +25,14 @@ fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result }) } +fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { + tls::with_opt(|tcx| { + if let Some(tcx) = tcx { + let _ = tcx.source_span(def_id); + } + }) +} + /// This is a callback from `rustc_ast` as it cannot access the implicit state /// in `rustc_middle` otherwise. It is used to when diagnostic messages are /// emitted and stores them in the current query, if there is one. @@ -56,6 +64,7 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 34aee4f1b3b..c8ea7454f0b 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -153,6 +153,7 @@ pub fn provide(providers: &mut Providers) { index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) }; providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; + providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c93996162e3..d6f3b6f3248 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -20,6 +20,14 @@ rustc_queries! { desc { "get the resolver outputs" } } + /// Return the span for a definition. + /// Contrary to `def_span` below, this query returns the full absolute span of the definition. + /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside + /// of rustc_middle::hir::source_map. + query source_span(key: LocalDefId) -> Span { + desc { "get the source span" } + } + /// Represents crate as a whole (as distinct from the top-level crate module). /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), /// we will have to assume that any change means that you need to be recompiled. diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 63000a295f6..08565812278 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -840,7 +840,7 @@ impl<'a, 'tcx> Decodable> for Span { let dlo = u32::decode(decoder)?; let dto = u32::decode(decoder)?; - let enclosing = decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data(); + let enclosing = decoder.tcx.definitions_untracked().def_span(parent.unwrap()).decode(); let span = Span::new( enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto), @@ -1022,7 +1022,7 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - let span_data = self.data(); + let span_data = self.decode(); span_data.ctxt.encode(s)?; span_data.parent.encode(s)?; @@ -1031,7 +1031,7 @@ where } if let Some(parent) = span_data.parent { - let enclosing = s.tcx.definitions_untracked().def_span(parent).data(); + let enclosing = s.tcx.definitions_untracked().def_span(parent).decode(); if enclosing.contains(span_data) { TAG_RELATIVE_SPAN.encode(s)?; (span_data.lo - enclosing.lo).to_u32().encode(s)?; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index de08c5d8a55..60b5ffb1d3e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1947,6 +1947,7 @@ pub struct FileLines { pub static SPAN_DEBUG: AtomicRef) -> fmt::Result> = AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); +pub static SPAN_TRACK: AtomicRef = AtomicRef::new(&((|_| {}) as fn(_))); // _____________________________________________________________________________ // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions @@ -2031,7 +2032,7 @@ where return; } - let span = self.data(); + let span = self.decode(); span.ctxt.hash_stable(ctx, hasher); span.parent.hash_stable(ctx, hasher); @@ -2041,7 +2042,7 @@ where } if let Some(parent) = span.parent { - let def_span = ctx.def_span(parent).data(); + let def_span = ctx.def_span(parent).decode(); if def_span.contains(span) { // This span is enclosed in a definition: only hash the relative position. Hash::hash(&TAG_RELATIVE_SPAN, hasher); diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 58d639082b0..f74c259d53d 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -6,6 +6,7 @@ use crate::def_id::LocalDefId; use crate::hygiene::SyntaxContext; +use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; @@ -55,6 +56,10 @@ use rustc_data_structures::fx::FxIndexSet; /// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`, /// but larger crates might need more than 16 bits. /// +/// In order to reliably use parented spans in incremental compilation, +/// the dependency to the parent definition's span. This is performed +/// using the callback `SPAN_TRACK` to access the query engine. +/// #[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct Span { base_or_index: u32, @@ -96,6 +101,17 @@ impl Span { #[inline] pub fn data(self) -> SpanData { + let data = self.decode(); + if let Some(parent) = data.parent { + (*SPAN_TRACK)(parent); + } + data + } + + /// Internal function to translate between an encoded span and the expanded representation. + /// This function must not be used outside the incremental engine. + #[inline] + pub fn decode(self) -> SpanData { if self.len_or_tag != LEN_TAG { // Inline format. debug_assert!(self.len_or_tag as u32 <= MAX_LEN);