about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorFederico Poli <federpoli@gmail.com>2018-07-19 14:15:43 +0200
committerFederico Poli <federpoli@gmail.com>2018-07-23 14:31:06 +0200
commit8ec9d7242c3352fbc617d907bec3632215811356 (patch)
treefecf6df248e2ba6dea669b97a4e080dc1e3fb0e0 /src/tools
parent3900bf8ae3aafdd3ab13a0e6400d47bc5cb2e121 (diff)
downloadrust-8ec9d7242c3352fbc617d907bec3632215811356.tar.gz
rust-8ec9d7242c3352fbc617d907bec3632215811356.zip
Match errors using the callsite of macro expansions
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/compiletest/src/json.rs32
-rw-r--r--src/tools/compiletest/src/runtest.rs6
2 files changed, 32 insertions, 6 deletions
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 165f2914ae2..201a661726e 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -40,6 +40,21 @@ struct DiagnosticSpan {
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
 
+impl DiagnosticSpan {
+    /// Returns the deepest source span in the macro call stack with a given file name.
+    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
+    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
+        if self.file_name == file_name {
+            self
+        } else {
+            self.expansion
+                .as_ref()
+                .map(|origin| origin.span.first_callsite_in_file(file_name))
+                .unwrap_or(self)
+        }
+    }
+}
+
 #[derive(Deserialize, Clone)]
 struct DiagnosticSpanMacroExpansion {
     /// span where macro was applied to generate this code
@@ -115,16 +130,23 @@ fn push_expected_errors(
     default_spans: &[&DiagnosticSpan],
     file_name: &str,
 ) {
-    let spans_in_this_file: Vec<_> = diagnostic
+    // In case of macro expansions, we need to get the span of the callsite
+    let spans_info_in_this_file: Vec<_> = diagnostic
         .spans
         .iter()
-        .filter(|span| Path::new(&span.file_name) == Path::new(&file_name))
+        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
+        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
         .collect();
 
-    let primary_spans: Vec<_> = spans_in_this_file.iter()
-        .cloned()
-        .filter(|span| span.is_primary)
+    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter()
+        .map(|(_, span)| span)
+        .collect();
+
+    let primary_spans: Vec<_> = spans_info_in_this_file.iter()
+        .filter(|(is_primary, _)| *is_primary)
+        .map(|(_, span)| span)
         .take(1) // sometimes we have more than one showing up in the json; pick first
+        .cloned()
         .collect();
     let primary_spans = if primary_spans.is_empty() {
         // subdiagnostics often don't have a span of their own;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index fcc47436225..ad86844cec3 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1194,6 +1194,10 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("process did not return an error status", proc_res);
         }
 
+        // On Windows, keep all '\' path separators to match the paths reported in the JSON output
+        // from the compiler
+        let os_file_name = self.testpaths.file.display().to_string();
+
         // on windows, translate all '\' path separators to '/'
         let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
 
@@ -1209,7 +1213,7 @@ impl<'test> TestCx<'test> {
             .any(|ee| ee.kind == Some(ErrorKind::Note));
 
         // Parse the JSON output from the compiler and extract out the messages.
-        let actual_errors = json::parse_output(&file_name, &proc_res.stderr, proc_res);
+        let actual_errors = json::parse_output(&os_file_name, &proc_res.stderr, proc_res);
         let mut unexpected = Vec::new();
         let mut found = vec![false; expected_errors.len()];
         for actual_error in &actual_errors {