about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2018-02-28 16:17:44 +0100
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2018-03-14 00:52:17 +0100
commit8c75e18e5d23ea88914a8e276037980e96866c76 (patch)
treefcac2bc7c09146cebc73746ce915bb1319580ed8
parentc29085761b0bf5b9add4bd008268651feae495bd (diff)
downloadrust-8c75e18e5d23ea88914a8e276037980e96866c76.tar.gz
rust-8c75e18e5d23ea88914a8e276037980e96866c76.zip
test for putting back check on json
-rw-r--r--src/librustc_errors/diagnostic_builder.rs3
-rw-r--r--src/librustc_errors/emitter.rs89
-rw-r--r--src/librustc_errors/lib.rs51
-rw-r--r--src/tools/compiletest/src/json.rs20
-rw-r--r--src/tools/compiletest/src/runtest.rs43
5 files changed, 127 insertions, 79 deletions
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 2536fc648c7..945ecce7ab3 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -92,7 +92,8 @@ impl<'a> DiagnosticBuilder<'a> {
             Level::Bug |
             Level::Fatal |
             Level::PhaseFatal |
-            Level::Error => {
+            Level::Error |
+            Level::FailureNote => {
                 true
             }
 
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index f481b36daa3..3b6e6db7f46 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -21,7 +21,7 @@ use atty;
 use std::borrow::Cow;
 use std::io::prelude::*;
 use std::io;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::cmp::min;
 use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter};
 use termcolor::{WriteColor, Color, Buffer};
@@ -33,6 +33,11 @@ const ANONYMIZED_LINE_NUM: &str = "LL";
 pub trait Emitter {
     /// Emit a structured diagnostic.
     fn emit(&mut self, db: &DiagnosticBuilder);
+
+    /// Check if should show explanations about "rustc --explain"
+    fn should_show_explain(&self) -> bool {
+        true
+    }
 }
 
 impl Emitter for EmitterWriter {
@@ -80,6 +85,10 @@ impl Emitter for EmitterWriter {
                                    &children,
                                    &suggestions);
     }
+
+    fn should_show_explain(&self) -> bool {
+        !self.short_message
+    }
 }
 
 /// maximum number of lines we will print for each error; arbitrary.
@@ -114,7 +123,6 @@ pub struct EmitterWriter {
     cm: Option<Lrc<CodeMapper>>,
     short_message: bool,
     teach: bool,
-    error_codes: HashSet<String>,
     ui_testing: bool,
 }
 
@@ -124,34 +132,6 @@ struct FileWithAnnotatedLines {
     multiline_depth: usize,
 }
 
-impl Drop for EmitterWriter {
-    fn drop(&mut self) {
-        if !self.short_message && !self.error_codes.is_empty() {
-            let mut error_codes = self.error_codes.clone().into_iter().collect::<Vec<_>>();
-            let mut dst = self.dst.writable();
-            error_codes.sort();
-            if error_codes.len() > 1 {
-                let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
-                writeln!(dst,
-                         "You've got a few errors: {}{}",
-                         error_codes[..limit].join(", "),
-                         if error_codes.len() > 9 { "..." } else { "" }
-                        ).expect("failed to give tips...");
-                writeln!(dst,
-                         "If you want more information on an error, try using \
-                          \"rustc --explain {}\"",
-                         &error_codes[0]).expect("failed to give tips...");
-            } else {
-                writeln!(dst,
-                         "If you want more information on this error, try using \
-                          \"rustc --explain {}\"",
-                         &error_codes[0]).expect("failed to give tips...");
-            }
-            dst.flush().expect("failed to emit errors");
-        }
-    }
-}
-
 impl EmitterWriter {
     pub fn stderr(color_config: ColorConfig,
                   code_map: Option<Lrc<CodeMapper>>,
@@ -164,7 +144,6 @@ impl EmitterWriter {
             cm: code_map,
             short_message,
             teach,
-            error_codes: HashSet::new(),
             ui_testing: false,
         }
     }
@@ -179,7 +158,6 @@ impl EmitterWriter {
             cm: code_map,
             short_message,
             teach,
-            error_codes: HashSet::new(),
             ui_testing: false,
         }
     }
@@ -993,18 +971,26 @@ impl EmitterWriter {
                 buffer.prepend(0, " ", Style::NoStyle);
             }
             draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
-            buffer.append(0, &level.to_string(), Style::HeaderMsg);
-            buffer.append(0, ": ", Style::NoStyle);
+            let level_str = level.to_string();
+            if !level_str.is_empty() {
+                buffer.append(0, &level_str, Style::HeaderMsg);
+                buffer.append(0, ": ", Style::NoStyle);
+            }
             self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
         } else {
-            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+            let level_str = level.to_string();
+            if !level_str.is_empty() {
+                buffer.append(0, &level_str, Style::Level(level.clone()));
+            }
             // only render error codes, not lint codes
             if let Some(DiagnosticId::Error(ref code)) = *code {
                 buffer.append(0, "[", Style::Level(level.clone()));
                 buffer.append(0, &code, Style::Level(level.clone()));
                 buffer.append(0, "]", Style::Level(level.clone()));
             }
-            buffer.append(0, ": ", Style::HeaderMsg);
+            if !level_str.is_empty() {
+                buffer.append(0, ": ", Style::HeaderMsg);
+            }
             for &(ref text, _) in msg.iter() {
                 buffer.append(0, text, Style::HeaderMsg);
             }
@@ -1020,14 +1006,12 @@ impl EmitterWriter {
             if primary_span != &&DUMMY_SP {
                 (cm.lookup_char_pos(primary_span.lo()), cm)
             } else {
-                emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
-                                    &mut self.error_codes)?;
+                emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
                 return Ok(());
             }
         } else {
             // If we don't have span information, emit and exit
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
-                                &mut self.error_codes)?;
+            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
             return Ok(());
         };
         if let Ok(pos) =
@@ -1200,8 +1184,7 @@ impl EmitterWriter {
         }
 
         // final step: take our styled buffer, render it, then output it
-        emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
-                            &mut self.error_codes)?;
+        emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
 
         Ok(())
 
@@ -1218,8 +1201,11 @@ impl EmitterWriter {
             let mut buffer = StyledBuffer::new();
 
             // Render the suggestion message
-            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
-            buffer.append(0, ": ", Style::HeaderMsg);
+            let level_str = level.to_string();
+            if !level_str.is_empty() {
+                buffer.append(0, &level_str, Style::Level(level.clone()));
+                buffer.append(0, ": ", Style::HeaderMsg);
+            }
             self.msg_to_buffer(&mut buffer,
                                &[(suggestion.msg.to_owned(), Style::NoStyle)],
                                max_line_num_len,
@@ -1289,8 +1275,7 @@ impl EmitterWriter {
                 let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
                 buffer.puts(row_num, 0, &msg, Style::NoStyle);
             }
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
-                                &mut self.error_codes)?;
+            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         }
         Ok(())
     }
@@ -1321,7 +1306,7 @@ impl EmitterWriter {
                         draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
                     }
                     match emit_to_destination(&buffer.render(), level, &mut self.dst,
-                                              self.short_message, &mut self.error_codes) {
+                                              self.short_message) {
                         Ok(()) => (),
                         Err(e) => panic!("failed to emit error: {}", e)
                     }
@@ -1416,8 +1401,7 @@ fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
 fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
                        lvl: &Level,
                        dst: &mut Destination,
-                       short_message: bool,
-                       error_codes: &mut HashSet<String>)
+                       short_message: bool)
                        -> io::Result<()> {
     use lock;
 
@@ -1436,16 +1420,13 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
     // same buffering approach.  Instead, we use a global Windows mutex, which we acquire long
     // enough to output the full error message, then we release.
     let _buffer_lock = lock::acquire_global_lock("rustc_errors");
-    for line in rendered_buffer {
+    for (pos, line) in rendered_buffer.iter().enumerate() {
         for part in line {
             dst.apply_style(lvl.clone(), part.style)?;
             write!(dst, "{}", part.text)?;
-            if !short_message && part.text.len() == 12 && part.text.starts_with("error[E") {
-                error_codes.insert(part.text[6..11].to_owned());
-            }
             dst.reset()?;
         }
-        if !short_message {
+        if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) {
             write!(dst, "\n")?;
         }
     }
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 924ed71ef0d..7148969191f 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -509,12 +509,14 @@ impl Handler {
     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
         self.span_bug(sp, &format!("unimplemented {}", msg));
     }
+    pub fn failure(&self, msg: &str) {
+        DiagnosticBuilder::new(self, FailureNote, msg).emit()
+    }
     pub fn fatal(&self, msg: &str) -> FatalError {
         if self.flags.treat_err_as_bug {
             self.bug(msg);
         }
-        let mut db = DiagnosticBuilder::new(self, Fatal, msg);
-        db.emit();
+        DiagnosticBuilder::new(self, Fatal, msg).emit();
         FatalError
     }
     pub fn err(&self, msg: &str) {
@@ -567,8 +569,39 @@ impl Handler {
                 s = format!("aborting due to {} previous errors", self.err_count());
             }
         }
+        let err = self.fatal(&s);
+
+        let can_show_explain = self.emitter.borrow().should_show_explain();
+        let are_there_diagnostics = !self.tracked_diagnostic_codes.borrow().is_empty();
+        if can_show_explain && are_there_diagnostics {
+            let mut error_codes =
+                self.tracked_diagnostic_codes.borrow()
+                                             .clone()
+                                             .into_iter()
+                                             .filter_map(|x| match x {
+                                                 DiagnosticId::Error(ref s) => Some(s.clone()),
+                                                 _ => None,
+                                             })
+                                             .collect::<Vec<_>>();
+            if !error_codes.is_empty() {
+                error_codes.sort();
+                if error_codes.len() > 1 {
+                    let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
+                    self.failure(&format!("Some errors occurred: {}{}",
+                                          error_codes[..limit].join(", "),
+                                          if error_codes.len() > 9 { "..." } else { "." }));
+                    self.failure(&format!("For more information about an error, try \
+                                           `rustc --explain {}`.",
+                                          &error_codes[0]));
+                } else {
+                    self.failure(&format!("For more information about this error, try \
+                                           `rustc --explain {}`.",
+                                          &error_codes[0]));
+                }
+            }
+        }
 
-        self.fatal(&s).raise();
+        err.raise();
     }
     pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
         if lvl == Warning && !self.flags.can_emit_warnings {
@@ -654,6 +687,7 @@ pub enum Level {
     Note,
     Help,
     Cancelled,
+    FailureNote,
 }
 
 impl fmt::Display for Level {
@@ -682,9 +716,10 @@ impl Level {
                 spec.set_fg(Some(Color::Cyan))
                     .set_intense(true);
             }
+            FailureNote => {}
             Cancelled => unreachable!(),
         }
-        return spec
+        spec
     }
 
     pub fn to_str(self) -> &'static str {
@@ -694,7 +729,15 @@ impl Level {
             Warning => "warning",
             Note => "note",
             Help => "help",
+            FailureNote => "",
             Cancelled => panic!("Shouldn't call on cancelled error"),
         }
     }
+
+    pub fn is_failure_note(&self) -> bool {
+        match *self {
+            FailureNote => true,
+            _ => false,
+        }
+    }
 }
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 08630628b71..761d1e511d5 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -24,6 +24,7 @@ struct Diagnostic {
     level: String,
     spans: Vec<DiagnosticSpan>,
     children: Vec<Diagnostic>,
+    rendered: Option<String>,
 }
 
 #[derive(Deserialize, Clone)]
@@ -56,6 +57,25 @@ struct DiagnosticCode {
     explanation: Option<String>,
 }
 
+pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
+    output.lines()
+        .filter_map(|line| if line.starts_with('{') {
+            match serde_json::from_str::<Diagnostic>(line) {
+                Ok(diagnostic) => diagnostic.rendered,
+                Err(error) => {
+                    proc_res.fatal(Some(&format!("failed to decode compiler output as json: \
+                                                  `{}`\noutput: {}\nline: {}",
+                                                 error,
+                                                 line,
+                                                 output)));
+                }
+            }
+        } else {
+            None
+        })
+        .collect()
+}
+
 pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
     output.lines()
         .flat_map(|line| parse_line(file_name, line, output, proc_res))
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 6619838cce0..953a13a3f58 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -248,7 +248,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_cfail_test(&self) {
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
         self.check_if_test_should_compile(&proc_res);
         self.check_no_compiler_crash(&proc_res);
 
@@ -267,7 +267,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_rfail_test(&self) {
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -309,7 +309,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_rpass_test(&self) {
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -336,7 +336,7 @@ impl<'test> TestCx<'test> {
             return self.run_rpass_test();
         }
 
-        let mut proc_res = self.compile_test(&[]);
+        let mut proc_res = self.compile_test();
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -578,7 +578,7 @@ impl<'test> TestCx<'test> {
         let mut cmds = commands.join("\n");
 
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compiler_run_result = self.compile_test(&[]);
+        let compiler_run_result = self.compile_test();
         if !compiler_run_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
         }
@@ -835,7 +835,7 @@ impl<'test> TestCx<'test> {
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compile_result = self.compile_test(&[]);
+        let compile_result = self.compile_test();
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
@@ -1272,15 +1272,12 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compile_test(&self, extra_args: &[&'static str]) -> ProcRes {
+    fn compile_test(&self) -> ProcRes {
         let mut rustc = self.make_compile_args(
             &self.testpaths.file,
             TargetLocation::ThisFile(self.make_exe_name()),
         );
 
-        if !extra_args.is_empty() {
-            rustc.args(extra_args);
-        }
         rustc.arg("-L").arg(&self.aux_output_dir_name());
 
         match self.config.mode {
@@ -1626,12 +1623,14 @@ impl<'test> TestCx<'test> {
                 if self.props.error_patterns.is_empty() {
                     rustc.args(&["--error-format", "json"]);
                 }
+                if !self.props.disable_ui_testing_normalization {
+                    rustc.arg("-Zui-testing");
+                }
             }
             Ui => {
-                // In case no "--error-format" has been given in the test, we'll compile
-                // a first time to get the compiler's output then compile with
-                // "--error-format json" to check if all expected errors are actually there
-                // and that no new one appeared.
+                if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
+                    rustc.args(&["--error-format", "json"]);
+                }
                 if !self.props.disable_ui_testing_normalization {
                     rustc.arg("-Zui-testing");
                 }
@@ -2114,7 +2113,7 @@ impl<'test> TestCx<'test> {
     fn run_codegen_units_test(&self) {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -2505,7 +2504,7 @@ impl<'test> TestCx<'test> {
             .iter()
             .any(|s| s.contains("--error-format"));
 
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
         self.check_if_test_should_compile(&proc_res);
 
         let expected_stderr_path = self.expected_output_path(UI_STDERR);
@@ -2517,8 +2516,13 @@ impl<'test> TestCx<'test> {
         let normalized_stdout =
             self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
 
-        let normalized_stderr = self.normalize_output(&proc_res.stderr,
-                                                      &self.props.normalize_stderr);
+        let stderr = if explicit {
+            proc_res.stderr.clone()
+        } else {
+            json::extract_rendered(&proc_res.stderr, &proc_res)
+        };
+
+        let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
 
         let mut errors = 0;
         errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
@@ -2551,7 +2555,6 @@ impl<'test> TestCx<'test> {
             }
         }
         if !explicit {
-            let proc_res = self.compile_test(&["--error-format", "json"]);
             if !expected_errors.is_empty() || !proc_res.status.success() {
                 // "// error-pattern" comments
                 self.check_expected_errors(expected_errors, &proc_res);
@@ -2563,7 +2566,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_mir_opt_test(&self) {
-        let proc_res = self.compile_test(&[]);
+        let proc_res = self.compile_test();
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);