about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-05-26 13:21:58 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-05-31 17:30:55 -0400
commit717fd665ad1095b12907ed0f2426d8eb06c2bddc (patch)
tree1b0ff7c2958b6022035bbacf5820ef3688e60270
parent8c5402efdda733d163895d1edb9bcf7f401dd33b (diff)
downloadrust-717fd665ad1095b12907ed0f2426d8eb06c2bddc.tar.gz
rust-717fd665ad1095b12907ed0f2426d8eb06c2bddc.zip
Make `SourceMap` available for early debug-printing of `Span`s
Normally, we debug-print `Spans` using the `SourceMap` retrieved from
the global `TyCtxt`. However, we fall back to printing out the `Span`'s
raw fields (instead of a file and line number) when we try to print a
`Span` before a `TyCtxt` is available. This makes debugging early phases
of the compile, such as parsing, much more difficult.

This commit stores a `SourceMap` in `rustc_span::GlOBALS` as a fallback.
When a `TyCtxt` is not available, we try to retrieve one from `GLOBALS`
- only if this is not available do we fall back to the raw field output.

I'm not sure how to write a test for this - however, this can be
verified locally by setting `RUSTC_LOG="rustc_parse=debug"`, and
verifying that the output contains filenames and line numbers.
-rw-r--r--src/librustc_interface/interface.rs24
-rw-r--r--src/librustc_span/lib.rs45
2 files changed, 53 insertions, 16 deletions
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index f127a239eea..5aad64f84ce 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -186,17 +186,19 @@ pub fn run_compiler_in_existing_thread_pool<R>(
         override_queries: config.override_queries,
     };
 
-    let r = {
-        let _sess_abort_error = OnDrop(|| {
-            compiler.sess.finish_diagnostics(registry);
-        });
-
-        f(&compiler)
-    };
-
-    let prof = compiler.sess.prof.clone();
-    prof.generic_activity("drop_compiler").run(move || drop(compiler));
-    r
+    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
+        let r = {
+            let _sess_abort_error = OnDrop(|| {
+                compiler.sess.finish_diagnostics(registry);
+            });
+
+            f(&compiler)
+        };
+
+        let prof = compiler.sess.prof.clone();
+        prof.generic_activity("drop_compiler").run(move || drop(compiler));
+        r
+    })
 }
 
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 616876d4b02..0f2eec48b48 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -25,6 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 mod caching_source_map_view;
 pub mod source_map;
 pub use self::caching_source_map_view::CachingSourceMapView;
+use source_map::SourceMap;
 
 pub mod edition;
 use edition::Edition;
@@ -67,6 +68,7 @@ pub struct Globals {
     symbol_interner: Lock<symbol::Interner>,
     span_interner: Lock<span_encoding::SpanInterner>,
     hygiene_data: Lock<hygiene::HygieneData>,
+    source_map: Lock<Option<Lrc<SourceMap>>>,
 }
 
 impl Globals {
@@ -75,6 +77,7 @@ impl Globals {
             symbol_interner: Lock::new(symbol::Interner::fresh()),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
+            source_map: Lock::new(None),
         }
     }
 }
@@ -641,12 +644,44 @@ impl rustc_serialize::UseSpecializedDecodable for Span {
     }
 }
 
+/// Calls the provided closure, using the provided `SourceMap` to format
+/// any spans that are debug-printed during the closure'e exectuino.
+///
+/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
+/// (see `rustc_interface::callbacks::span_debug1). However, some parts
+/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
+/// a `TyCtxt` is available. In this case, we fall back to
+/// the `SourceMap` provided to this function. If that is not available,
+/// we fall back to printing the raw `Span` field values
+pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
+    GLOBALS.with(|globals| {
+        *globals.source_map.borrow_mut() = Some(source_map);
+    });
+    struct ClearSourceMap;
+    impl Drop for ClearSourceMap {
+        fn drop(&mut self) {
+            GLOBALS.with(|globals| {
+                globals.source_map.borrow_mut().take();
+            });
+        }
+    }
+
+    let _guard = ClearSourceMap;
+    f()
+}
+
 pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    f.debug_struct("Span")
-        .field("lo", &span.lo())
-        .field("hi", &span.hi())
-        .field("ctxt", &span.ctxt())
-        .finish()
+    GLOBALS.with(|globals| {
+        if let Some(source_map) = &*globals.source_map.borrow() {
+            write!(f, "{}", source_map.span_to_string(span))
+        } else {
+            f.debug_struct("Span")
+                .field("lo", &span.lo())
+                .field("hi", &span.hi())
+                .field("ctxt", &span.ctxt())
+                .finish()
+        }
+    })
 }
 
 impl fmt::Debug for Span {