]> git.lizzy.rs Git - rust.git/commitdiff
rustc_{errors,session}: add `delay_good_path_bug`
authorDan Aloni <alonid@gmail.com>
Sat, 22 Aug 2020 19:24:48 +0000 (22:24 +0300)
committerDan Aloni <alonid@gmail.com>
Wed, 2 Sep 2020 07:43:17 +0000 (10:43 +0300)
The first use case of this detection of regression for trimmed paths
computation, that is in the case of rustc, which should be computed only
in case of errors or warnings.

Our current user of this method is deeply nested, being a side effect
from `Display` formatting on lots of rustc types. So taking only the
caller to the error message is not enough - we should collect the
traceback instead.

compiler/rustc_errors/src/lib.rs
compiler/rustc_session/src/session.rs

index d4f0a9d83ef4e2364e8d570835b05dab921205a7..2abd20869aecf0e66341ada087654164f1973c32 100644 (file)
@@ -4,6 +4,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
+#![feature(backtrace)]
 #![feature(nll)]
 
 #[macro_use]
@@ -296,9 +297,11 @@ struct HandlerInner {
     /// This is not necessarily the count that's reported to the user once
     /// compilation ends.
     err_count: usize,
+    warn_count: usize,
     deduplicated_err_count: usize,
     emitter: Box<dyn Emitter + sync::Send>,
     delayed_span_bugs: Vec<Diagnostic>,
+    delayed_good_path_bugs: Vec<Diagnostic>,
 
     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
     /// emitting the same diagnostic with extended help (`--teach`) twice, which
@@ -361,13 +364,15 @@ fn drop(&mut self) {
 
         if !self.has_errors() {
             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
-            let has_bugs = !bugs.is_empty();
-            for bug in bugs {
-                self.emit_diagnostic(&bug);
-            }
-            if has_bugs {
-                panic!("no errors encountered even though `delay_span_bug` issued");
-            }
+            self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+        }
+
+        if !self.has_any_message() {
+            let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
+            self.flush_delayed(
+                bugs,
+                "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
+            );
         }
     }
 }
@@ -422,10 +427,12 @@ pub fn with_emitter_and_flags(
             inner: Lock::new(HandlerInner {
                 flags,
                 err_count: 0,
+                warn_count: 0,
                 deduplicated_err_count: 0,
                 deduplicated_warn_count: 0,
                 emitter,
                 delayed_span_bugs: Vec::new(),
+                delayed_good_path_bugs: Vec::new(),
                 taught_diagnostics: Default::default(),
                 emitted_diagnostic_codes: Default::default(),
                 emitted_diagnostics: Default::default(),
@@ -448,11 +455,13 @@ pub fn can_emit_warnings(&self) -> bool {
     pub fn reset_err_count(&self) {
         let mut inner = self.inner.borrow_mut();
         inner.err_count = 0;
+        inner.warn_count = 0;
         inner.deduplicated_err_count = 0;
         inner.deduplicated_warn_count = 0;
 
         // actually free the underlying memory (which `clear` would not do)
         inner.delayed_span_bugs = Default::default();
+        inner.delayed_good_path_bugs = Default::default();
         inner.taught_diagnostics = Default::default();
         inner.emitted_diagnostic_codes = Default::default();
         inner.emitted_diagnostics = Default::default();
@@ -629,6 +638,10 @@ pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
         self.inner.borrow_mut().delay_span_bug(span, msg)
     }
 
+    pub fn delay_good_path_bug(&self, msg: &str) {
+        self.inner.borrow_mut().delay_good_path_bug(msg)
+    }
+
     pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
         self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
     }
@@ -768,6 +781,8 @@ fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
         }
         if diagnostic.is_error() {
             self.bump_err_count();
+        } else {
+            self.bump_warn_count();
         }
     }
 
@@ -859,6 +874,9 @@ fn has_errors(&self) -> bool {
     fn has_errors_or_delayed_span_bugs(&self) -> bool {
         self.has_errors() || !self.delayed_span_bugs.is_empty()
     }
+    fn has_any_message(&self) -> bool {
+        self.err_count() > 0 || self.warn_count > 0
+    }
 
     fn abort_if_errors(&mut self) {
         self.emit_stashed_diagnostics();
@@ -892,6 +910,15 @@ fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
         self.delay_as_bug(diagnostic)
     }
 
+    fn delay_good_path_bug(&mut self, msg: &str) {
+        let mut diagnostic = Diagnostic::new(Level::Bug, msg);
+        if self.flags.report_delayed_bugs {
+            self.emit_diagnostic(&diagnostic);
+        }
+        diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
+        self.delayed_good_path_bugs.push(diagnostic);
+    }
+
     fn failure(&mut self, msg: &str) {
         self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
     }
@@ -925,11 +952,25 @@ fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
         self.delayed_span_bugs.push(diagnostic);
     }
 
+    fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) {
+        let has_bugs = !bugs.is_empty();
+        for bug in bugs {
+            self.emit_diagnostic(&bug);
+        }
+        if has_bugs {
+            panic!("{}", explanation);
+        }
+    }
+
     fn bump_err_count(&mut self) {
         self.err_count += 1;
         self.panic_if_treat_err_as_bug();
     }
 
+    fn bump_warn_count(&mut self) {
+        self.warn_count += 1;
+    }
+
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
             let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
index db2059251c0c8f8b02409c26e79d6121b651f567..ff22b4ce4ad9fb89f53503862e7451936969c0fd 100644 (file)
@@ -442,6 +442,24 @@ pub fn opt_span_warn<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) {
     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.diagnostic().delay_span_bug(sp, msg)
     }
+
+    /// Used for code paths of expensive computations that should only take place when
+    /// warnings or errors are emitted. If no messages are emitted ("good path"), then
+    /// it's likely a bug.
+    pub fn delay_good_path_bug(&self, msg: &str) {
+        if self.opts.debugging_opts.print_type_sizes
+            || self.opts.debugging_opts.query_dep_graph
+            || self.opts.debugging_opts.dump_mir.is_some()
+            || self.opts.debugging_opts.unpretty.is_some()
+            || self.opts.output_types.contains_key(&OutputType::Mir)
+            || std::env::var_os("RUSTC_LOG").is_some()
+        {
+            return;
+        }
+
+        self.diagnostic().delay_good_path_bug(msg)
+    }
+
     pub fn note_without_error(&self, msg: &str) {
         self.diagnostic().note_without_error(msg)
     }