Index: llvm/test/FileCheck/dump-input/filter-error-neighbor/check-dag.txt
===================================================================
--- /dev/null
+++ llvm/test/FileCheck/dump-input/filter-error-neighbor/check-dag.txt
@@ -0,0 +1,62 @@
+; The neighboring behavior of -dump-input-filter=error does not reveal lines
+; that are within an error annotation. CHECK-DAG is the reason. In the example
+; below, it would cause all the CHECK-DAG matches to be revealed.
+;
+; Moreover, the neighboring implementation has special handling for CHECK-LABEL
+; in that its match is revealed if it precedes the last line of an error. That
+; special handling shouldn't be applied to other directives. Otherwise, the
+; successful CHECK-DAG match at the end of the CHECK-DAG error here would be
+; revealed accidentally.
+
+ CHECK:<<<<<<
+CHECK-NEXT: 1: loop iter 3
+CHECK-NEXT:dag:4 ^~~~~~~~~~~
+CHECK-NEXT:dag:10 X~~~~~~~~~~ error: no match found
+CHECK-NEXT: 2: loop iter 0
+CHECK-NEXT:dag:1 ^~~~~~~~~~~
+CHECK-NEXT:dag:10 ~~~~~~~~~~~
+CHECK-NEXT: 3: loop iter 4
+CHECK-NEXT:dag:5 ^~~~~~~~~~~
+CHECK-NEXT:dag:10 ~~~~~~~~~~~
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT:>>>>>>
+
+RUN: echo 'CHECK-DAG: loop iter 0' > %t.chk
+RUN: echo 'CHECK-DAG: loop iter 1' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 2' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 3' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 4' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 5' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 6' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 7' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 8' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 9' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 10' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 11' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 12' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 13' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 14' >> %t.chk
+RUN: echo 'CHECK-DAG: loop iter 15' >> %t.chk
+
+RUN: echo 'loop iter 3' > %t.in
+RUN: echo 'loop iter 0' >> %t.in
+RUN: echo 'loop iter 4' >> %t.in
+RUN: echo 'loop iter 6' >> %t.in
+RUN: echo 'loop iter 12' >> %t.in
+RUN: echo 'loop iter 7' >> %t.in
+RUN: echo 'loop iter 8' >> %t.in
+RUN: echo 'loop iter 14' >> %t.in
+RUN: echo 'loop iter 2' >> %t.in
+RUN: echo 'loop iter 11' >> %t.in
+RUN: echo 'loop iter 1' >> %t.in
+RUN: echo 'loop iter 15' >> %t.in
+RUN: echo 'loop iter 13' >> %t.in
+RUN: echo 'loop iter 10' >> %t.in
+RUN: echo 'loop iter 5' >> %t.in
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines
Index: llvm/test/FileCheck/dump-input/filter-error-neighbor/check-label-follows.txt
===================================================================
--- /dev/null
+++ llvm/test/FileCheck/dump-input/filter-error-neighbor/check-label-follows.txt
@@ -0,0 +1,71 @@
+; The neighboring behavior of -dump-input-filter=error reveals input line 14
+; below (neighbor of an error), and -dump-input-context=2 reveals the
+; surrounding lines. Those lines are where the actual problem is: the "host
+; triples:" header is off by one. Sometimes the key to understanding a
+; directive's failure is where the following CHECK-LABEL matched because it
+; limits the search range.
+
+ CHECK:<<<<<<
+CHECK-NEXT: 1: offload triples:
+CHECK-NEXT:label:1'0 ^~~~~~~~~~~~~~~~
+CHECK-NEXT:label:1'1 ^~~~~~~~~~~~~~~~
+CHECK-NEXT: 2: - x86_64-linux-gnu
+CHECK-NEXT:check:2'0 X~~~~~~~~~~~~~~~~~ error: no match found
+CHECK-NEXT:check:2'1 ? possible intended match
+CHECK-NEXT: 3: - x86_64-unknown-linux-gnu
+CHECK-NEXT:check:2'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~
+CHECK-NEXT: 4: - x86_64-pc-linux-gnu
+CHECK-NEXT:check:2'0 ~~~~~~~~~~~~~~~~~~~~~
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 12: - x86_64-amazon-linux
+CHECK-NEXT:check:2'0 ~~~~~~~~~~~~~~~~~~~~~
+CHECK-NEXT: 13: - x86_64-linux-android
+CHECK-NEXT:check:2'0 ~~~~~~~~~~~~~~~~~~~~~~
+CHECK-NEXT: 14: host triples:
+CHECK-NEXT:label:3 ^~~~~~~~~~~~~
+CHECK-NEXT:check:2'0 ~~~~~~~~~~~~~
+CHECK-NEXT: 15: - nvptx64-nvidia-cuda
+CHECK-NEXT: 16: - x86_64-linux-gnu
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT:>>>>>>
+
+RUN: echo 'CHECK-LABEL: offload triples:' > %t.chk
+RUN: echo 'CHECK: nvptx64-nvidia-cuda' >> %t.chk
+RUN: echo 'CHECK-LABEL: host triples:' >> %t.chk
+
+RUN: echo 'offload triples:' > %t.in
+RUN: echo '- x86_64-linux-gnu' >> %t.in
+RUN: echo '- x86_64-unknown-linux-gnu' >> %t.in
+RUN: echo '- x86_64-pc-linux-gnu' >> %t.in
+RUN: echo '- x86_64-redhat-linux6E' >> %t.in
+RUN: echo '- x86_64-redhat-linux' >> %t.in
+RUN: echo '- x86_64-suse-linux' >> %t.in
+RUN: echo '- x86_64-manbo-linux-gnu' >> %t.in
+RUN: echo '- x86_64-linux-gnu' >> %t.in
+RUN: echo '- x86_64-slackware-linux' >> %t.in
+RUN: echo '- x86_64-unknown-linux' >> %t.in
+RUN: echo '- x86_64-amazon-linux' >> %t.in
+RUN: echo '- x86_64-linux-android' >> %t.in
+RUN: echo 'host triples:' >> %t.in
+RUN: echo '- nvptx64-nvidia-cuda' >> %t.in
+RUN: echo '- x86_64-linux-gnu' >> %t.in
+RUN: echo '- x86_64-unknown-linux-gnu' >> %t.in
+RUN: echo '- x86_64-pc-linux-gnu' >> %t.in
+RUN: echo '- x86_64-redhat-linux6E' >> %t.in
+RUN: echo '- x86_64-redhat-linux' >> %t.in
+RUN: echo '- x86_64-suse-linux' >> %t.in
+RUN: echo '- x86_64-manbo-linux-gnu' >> %t.in
+RUN: echo '- x86_64-linux-gnu' >> %t.in
+RUN: echo '- x86_64-slackware-linux' >> %t.in
+RUN: echo '- x86_64-unknown-linux' >> %t.in
+RUN: echo '- x86_64-amazon-linux' >> %t.in
+RUN: echo '- x86_64-linux-android' >> %t.in
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines
Index: llvm/test/FileCheck/dump-input/filter-error-neighbor/check-next-same.txt
===================================================================
--- /dev/null
+++ llvm/test/FileCheck/dump-input/filter-error-neighbor/check-next-same.txt
@@ -0,0 +1,51 @@
+; The neighboring behavior of -dump-input-filter=error reveals input line 1
+; below (neighbor preceding an error), and -dump-input-context=2 reveals input
+; lines 2-3. Those lines are where the actual problem is because that's where
+; the CHECK-NEXT/CHECK-SAME directive was expected to match but didn't. The
+; line where CHECK-NEXT/CHECK-SAME actually matched, line 13, is typically less
+; useful information.
+
+ CHECK:<<<<<<
+CHECK-NEXT: 1: start
+CHECK-NEXT:check:1 ^~~~~
+CHECK-NEXT: 2: foo0
+CHECK-NEXT: 3: foo1
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 11: foo9
+CHECK-NEXT: 12: foo10
+CHECK-NEXT: 13: end
+ NEXT-NEXT:next:2 !~~ error: match on wrong line
+ SAME-NEXT:same:2 !~~ error: match on wrong line
+CHECK-NEXT:>>>>>>
+
+RUN: echo 'CHECK: start' > %t.next.chk
+RUN: echo 'CHECK-NEXT: end' >> %t.next.chk
+
+RUN: echo 'CHECK: start' > %t.same.chk
+RUN: echo 'CHECK-SAME: end' >> %t.same.chk
+
+RUN: echo start > %t.in
+RUN: echo foo0 >> %t.in
+RUN: echo foo1 >> %t.in
+RUN: echo foo2 >> %t.in
+RUN: echo foo3 >> %t.in
+RUN: echo foo4 >> %t.in
+RUN: echo foo5 >> %t.in
+RUN: echo foo6 >> %t.in
+RUN: echo foo7 >> %t.in
+RUN: echo foo8 >> %t.in
+RUN: echo foo9 >> %t.in
+RUN: echo foo10 >> %t.in
+RUN: echo end >> %t.in
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.next.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines -check-prefixes=CHECK,NEXT
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.same.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines -check-prefixes=CHECK,SAME
Index: llvm/test/FileCheck/dump-input/filter-error-neighbor/check-not.txt
===================================================================
--- /dev/null
+++ llvm/test/FileCheck/dump-input/filter-error-neighbor/check-not.txt
@@ -0,0 +1,104 @@
+; The neighboring behavior of -dump-input-filter=error reveals input lines 1 and
+; 62 below, and -dump-input-context=2 reveals the surrounding lines. With only
+; line 1 (neighbor preceding an error), it looks like the host list includes
+; a GPU triple. Line 62 (neighbor following an error) and its context reveals
+; we have an accidentally nested list. Often the key to understanding a
+; CHECK-NOT failure is where the directives before and after it matched because
+; those establish the search range.
+
+ CHECK:<<<<<<
+CHECK-NEXT: 1:
+CHECK-NEXT:check:1 ^~~~~~~~~~~~~~~~~~~~~
+CHECK-NEXT: 2: x86_64-linux-gnu
+CHECK-NEXT: 3: x86_64-unknown-linux-gnu
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 42: x86_64-amazon-linux
+CHECK-NEXT: 43: x86_64-linux-android
+CHECK-NEXT: 44: nvptx64-nvidia-cuda
+CHECK-NEXT:not:2 !~~~~~~~~~~~~~~~~~~ error: no match expected
+CHECK-NEXT: 45: i686-linux-gnu
+CHECK-NEXT: 46: i686-pc-linux-gnu
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 60: i586-gnu
+CHECK-NEXT: 61: i686-gnu
+CHECK-NEXT: 62:
+CHECK-NEXT:check:3 ^~~~~~~~~~
+CHECK-NEXT: 63:
+CHECK-NEXT:>>>>>>
+
+RUN: echo 'CHECK: ' > %t.chk
+RUN: echo 'CHECK-NOT: nvptx64-nvidia-cuda' >> %t.chk
+RUN: echo 'CHECK: ' >> %t.chk
+
+RUN: echo '' > %t.in
+RUN: echo ' x86_64-linux-gnu' >> %t.in
+RUN: echo ' x86_64-unknown-linux-gnu' >> %t.in
+RUN: echo ' x86_64-pc-linux-gnu' >> %t.in
+RUN: echo ' x86_64-redhat-linux6E' >> %t.in
+RUN: echo ' x86_64-redhat-linux' >> %t.in
+RUN: echo ' x86_64-suse-linux' >> %t.in
+RUN: echo ' x86_64-manbo-linux-gnu' >> %t.in
+RUN: echo ' x86_64-linux-gnu' >> %t.in
+RUN: echo ' x86_64-slackware-linux' >> %t.in
+RUN: echo ' x86_64-unknown-linux' >> %t.in
+RUN: echo ' x86_64-amazon-linux' >> %t.in
+RUN: echo ' x86_64-linux-android' >> %t.in
+RUN: echo ' i686-linux-gnu' >> %t.in
+RUN: echo ' i686-pc-linux-gnu' >> %t.in
+RUN: echo ' i486-linux-gnu' >> %t.in
+RUN: echo ' i386-linux-gnu' >> %t.in
+RUN: echo ' i386-redhat-linux6E' >> %t.in
+RUN: echo ' i686-redhat-linux' >> %t.in
+RUN: echo ' i586-redhat-linux' >> %t.in
+RUN: echo ' i386-redhat-linux' >> %t.in
+RUN: echo ' i586-suse-linux' >> %t.in
+RUN: echo ' i486-slackware-linux' >> %t.in
+RUN: echo ' i686-montavista-linux' >> %t.in
+RUN: echo ' i586-linux-gnu' >> %t.in
+RUN: echo ' i686-linux-android' >> %t.in
+RUN: echo ' i386-gnu' >> %t.in
+RUN: echo ' i486-gnu' >> %t.in
+RUN: echo ' i586-gnu' >> %t.in
+RUN: echo ' i686-gnu' >> %t.in
+RUN: echo '' >> %t.in
+RUN: echo ' x86_64-linux-gnu' >> %t.in
+RUN: echo ' x86_64-unknown-linux-gnu' >> %t.in
+RUN: echo ' x86_64-pc-linux-gnu' >> %t.in
+RUN: echo ' x86_64-redhat-linux6E' >> %t.in
+RUN: echo ' x86_64-redhat-linux' >> %t.in
+RUN: echo ' x86_64-suse-linux' >> %t.in
+RUN: echo ' x86_64-manbo-linux-gnu' >> %t.in
+RUN: echo ' x86_64-linux-gnu' >> %t.in
+RUN: echo ' x86_64-slackware-linux' >> %t.in
+RUN: echo ' x86_64-unknown-linux' >> %t.in
+RUN: echo ' x86_64-amazon-linux' >> %t.in
+RUN: echo ' x86_64-linux-android' >> %t.in
+RUN: echo ' nvptx64-nvidia-cuda' >> %t.in
+RUN: echo ' i686-linux-gnu' >> %t.in
+RUN: echo ' i686-pc-linux-gnu' >> %t.in
+RUN: echo ' i486-linux-gnu' >> %t.in
+RUN: echo ' i386-linux-gnu' >> %t.in
+RUN: echo ' i386-redhat-linux6E' >> %t.in
+RUN: echo ' i686-redhat-linux' >> %t.in
+RUN: echo ' i586-redhat-linux' >> %t.in
+RUN: echo ' i386-redhat-linux' >> %t.in
+RUN: echo ' i586-suse-linux' >> %t.in
+RUN: echo ' i486-slackware-linux' >> %t.in
+RUN: echo ' i686-montavista-linux' >> %t.in
+RUN: echo ' i586-linux-gnu' >> %t.in
+RUN: echo ' i686-linux-android' >> %t.in
+RUN: echo ' i386-gnu' >> %t.in
+RUN: echo ' i486-gnu' >> %t.in
+RUN: echo ' i586-gnu' >> %t.in
+RUN: echo ' i686-gnu' >> %t.in
+RUN: echo '' >> %t.in
+RUN: echo '' >> %t.in
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines
Index: llvm/test/FileCheck/dump-input/filter-error-neighbor/multiline.txt
===================================================================
--- /dev/null
+++ llvm/test/FileCheck/dump-input/filter-error-neighbor/multiline.txt
@@ -0,0 +1,117 @@
+; The neighboring behavior of -dump-input-filter=error reveals only the last
+; input line (line 5 below) or the first input line (line 28 below) of an
+; annotation neighboring an error (line 16 below), depending on whether it
+; precedes or follows the error. -dump-input-context=2 reveals the lines
+; surrounding them.
+;
+; This test checks that the implementation doesn't mix up first and last.
+; Otherwise, a preceding or following annotation can accidentally be omitted
+; altogether. Of course, this test is pointless without multiline annotations,
+; for which first != last.
+;
+; This test also checks that CHECK-LABEL is handled in the same way. That is,
+; CHECK-LABEL has additional special handling in that its match is revealed if
+; it precedes the last line of an error, but that special handling alone
+; wouldn't be sufficient for CHECK-LABEL here: it wouldn't reveal the first
+; CHECK-LABEL's match because the CHECK-NOT match has multiple lines.
+
+ CHECK:<<<<<<
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 3: start
+ CHK-NEXT:check:1 ~~~~~
+ LAB-NEXT:label:1'0 ~~~~~
+ LAB-NEXT:label:1'1 ~~~~~
+CHECK-NEXT: 4: start
+ CHK-NEXT:check:1 ~~~~~
+ LAB-NEXT:label:1'0 ~~~~~
+ LAB-NEXT:label:1'1 ~~~~~
+CHECK-NEXT: 5: start
+ CHK-NEXT:check:1 ~~~~~
+ LAB-NEXT:label:1'0 ~~~~~
+ LAB-NEXT:label:1'1 ~~~~~
+CHECK-NEXT: 6: bar
+CHECK-NEXT: 7: bar
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 14: bar
+CHECK-NEXT: 15: bar
+CHECK-NEXT: 16: foo
+CHECK-NEXT:not:2 !~~ error: no match expected
+CHECK-NEXT: 17: foo
+CHECK-NEXT:not:2 ~~~
+CHECK-NEXT: 18: bar
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: 26: bar
+CHECK-NEXT: 27: bar
+CHECK-NEXT: 28: end
+ CHK-NEXT:check:3 ^~~
+ LAB-NEXT:label:3'0 ^~~
+ LAB-NEXT:label:3'1 ^~~
+CHECK-NEXT: 29: end
+ CHK-NEXT:check:3 ~~~
+ LAB-NEXT:label:3'0 ~~~
+ LAB-NEXT:label:3'1 ~~~
+CHECK-NEXT: 30: end
+ CHK-NEXT:check:3 ~~~
+ LAB-NEXT:label:3'0 ~~~
+ LAB-NEXT:label:3'1 ~~~
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT: .
+CHECK-NEXT:>>>>>>
+
+RUN: echo 'CHECK: start{{([[:space:]]*start)+}}' > %t.chk.chk
+RUN: echo 'CHECK-NOT: foo{{([[:space:]]*foo)*}}' >> %t.chk.chk
+RUN: echo 'CHECK: end{{([[:space:]]*end)+}}' >> %t.chk.chk
+
+RUN: echo 'CHECK-LABEL: start{{([[:space:]]*start)+}}' > %t.lab.chk
+RUN: echo 'CHECK-NOT: foo{{([[:space:]]*foo)*}}' >> %t.lab.chk
+RUN: echo 'CHECK-LABEL: end{{([[:space:]]*end)+}}' >> %t.lab.chk
+
+RUN: echo 'start' > %t.in
+RUN: echo 'start' >> %t.in
+RUN: echo 'start' >> %t.in
+RUN: echo 'start' >> %t.in
+RUN: echo 'start' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'foo' >> %t.in
+RUN: echo 'foo' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'bar' >> %t.in
+RUN: echo 'end' >> %t.in
+RUN: echo 'end' >> %t.in
+RUN: echo 'end' >> %t.in
+RUN: echo 'end' >> %t.in
+RUN: echo 'end' >> %t.in
+
+XUN: %ProtectFileCheckOutput \
+XUN: not FileCheck -dump-input-context=2 -v %t.chk.chk < %t.in 2>&1 \
+XUN: -dump-input-filter=error \
+XUN: | FileCheck %s -match-full-lines -check-prefixes=CHECK,CHK
+
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck -dump-input-context=2 -v %t.lab.chk < %t.in 2>&1 \
+RUN: -dump-input-filter=error \
+RUN: | FileCheck %s -match-full-lines -check-prefixes=CHECK,LAB
Index: llvm/test/FileCheck/dump-input/filter.txt
===================================================================
--- llvm/test/FileCheck/dump-input/filter.txt
+++ llvm/test/FileCheck/dump-input/filter.txt
@@ -215,6 +215,7 @@
; ERROR-NEXT: .
; ERROR-NEXT: .
; ERROR-NEXT: .
+; ERROR-NEXT: 10: foo8
; ERROR-NEXT: 11: foo9
; ERROR-NEXT: 12: hello
; ERROR-NEXT: check:2 ^~~~~
Index: llvm/utils/FileCheck/FileCheck.cpp
===================================================================
--- llvm/utils/FileCheck/FileCheck.cpp
+++ llvm/utils/FileCheck/FileCheck.cpp
@@ -155,8 +155,9 @@
clEnumValN(DumpInputFilterAnnotation, "annotation",
"Input lines with starting points of annotations"),
clEnumValN(DumpInputFilterError, "error",
- "Input lines with starting points of error "
- "annotations")));
+ "Input lines with either (1) starting points of "
+ "error annotations or (2) annotations that neighbor "
+ "error annotations")));
static cl::list DumpInputContexts(
"dump-input-context", cl::value_desc("N"),
@@ -306,13 +307,18 @@
/// An annotation for a single input line.
struct InputAnnotation {
- /// The index of the match result across all checks
+ /// The index of the match result across all checks.
unsigned DiagIndex;
+ /// The kind of check that produced the match result.
+ Check::FileCheckType CheckTy;
/// The label for this annotation.
std::string Label;
- /// Is this the initial fragment of a diagnostic that has been broken across
- /// multiple lines?
+ /// Is this the initial annotation for a diagnostic, which might be broken
+ /// across multiple lines?
bool IsFirstLine;
+ /// Is this the last annotation for a diagnostic, which might be broken across
+ /// multiple lines?
+ bool IsLastLine;
/// What input line (one-origin indexing) this annotation marks. This might
/// be different from the starting line of the original diagnostic if
/// !IsFirstLine.
@@ -376,6 +382,7 @@
++DiagItr) {
InputAnnotation A;
A.DiagIndex = DiagCount++;
+ A.CheckTy = DiagItr->CheckTy;
// Build label, which uniquely identifies this check result.
unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
@@ -424,6 +431,7 @@
// Compute the mark location, and break annotation into multiple
// annotations if it spans multiple lines.
A.IsFirstLine = true;
+ A.IsLastLine = false;
A.InputLine = DiagItr->InputStartLine;
A.InputStartCol = DiagItr->InputStartCol;
if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
@@ -446,8 +454,10 @@
break;
InputAnnotation B;
B.DiagIndex = A.DiagIndex;
+ B.CheckTy = A.CheckTy;
B.Label = A.Label;
B.IsFirstLine = false;
+ B.IsLastLine = false;
B.InputLine = L;
B.Marker = A.Marker;
B.Marker.Lead = '~';
@@ -461,16 +471,19 @@
Annotations.push_back(B);
}
}
+ Annotations.back().IsLastLine = true;
}
}
static unsigned FindInputLineInFilter(
DumpInputFilterValue DumpInputFilter, unsigned CurInputLine,
- const std::vector::iterator &AnnotationBeg,
- const std::vector::iterator &AnnotationEnd) {
+ const std::vector::iterator &AnnotationCur,
+ const std::vector &Annotations) {
if (DumpInputFilter == DumpInputFilterAll)
return CurInputLine;
- for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd;
+ auto AnnotationBeg = Annotations.begin();
+ auto AnnotationEnd = Annotations.end();
+ for (auto AnnotationItr = AnnotationCur; AnnotationItr != AnnotationEnd;
++AnnotationItr) {
switch (DumpInputFilter) {
case DumpInputFilterAll:
@@ -483,8 +496,68 @@
return AnnotationItr->InputLine;
break;
case DumpInputFilterError:
+ // If it's the first line of an error, include it.
if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError)
return AnnotationItr->InputLine;
+ // If it's a diagnostic's first line and it's after the last line of an
+ // error, include it. This might reveal an incorrect end to a search
+ // range.
+ if (AnnotationItr->IsFirstLine && AnnotationItr != AnnotationBeg) {
+ auto AnnotationPrev = std::prev(AnnotationItr);
+ if (AnnotationPrev->Marker.FiltersAsError && AnnotationPrev->IsLastLine)
+ return AnnotationItr->InputLine;
+ }
+ // If it's a diagnostic's last line and it's before the first line of an
+ // error, include it. This might reveal an incorrect start to a search
+ // range. It might reveal the incorrect text where a CHECK-NEXT or
+ // CHECK-SAME was expected to match but instead matched on a later line.
+ //
+ // CHECK-LABEL requires a special exception. For example:
+ //
+ // <<<<<<
+ // 1: bar
+ // check:1 X~~ error: no match found
+ // 2: bar
+ // check:1 ~~~
+ // .
+ // .
+ // .
+ // 9: bar
+ // check:1 ~~~
+ // 10: label
+ // label:2 ^~~~~
+ // check:1 ~~~~~
+ // >>>>>>
+ //
+ // Because a CHECK-LABEL directive is processed before all other
+ // directives, its diagnostic can precede the last line of an error that
+ // starts on a preceding line. Thus, as a special exception, if an input
+ // line is the last line of a CHECK-LABEL match before the last line of an
+ // error, include it. Don't apply that exception generally, or a
+ // CHECK-DAG error can produce a spurious inclusion due to a successful
+ // CHECK-DAG at the end of the search range.
+ //
+ // Because we include last lines sometimes, input lines from
+ // DumpInputFilterError are not always a subset of input lines from
+ // DumpInputFilterAnnotation.
+ if (AnnotationItr->IsLastLine) {
+ auto AnnotationNext = std::next(AnnotationItr);
+ if (AnnotationNext != AnnotationEnd &&
+ AnnotationNext->Marker.FiltersAsError &&
+ (AnnotationNext->IsFirstLine ||
+ (AnnotationItr->CheckTy == Check::CheckLabel &&
+ AnnotationNext->IsLastLine)))
+ return AnnotationItr->InputLine;
+ }
+ // We have included only first and last lines of diagnostics so that we
+ // don't include a line within an error just because it's next to a
+ // "possible intended match" diagnostic. The "possible intended match"
+ // diagnostic is included on its own merits anyway, but the amount of
+ // context could be unexpectedly augmented.
+ //
+ // We have not included lines just because they're next to non-first and
+ // non-last error lines. Otherwise, a CHECK-DAG error could include many
+ // lines for successful matches from the same CHECK-DAG block.
break;
}
}
@@ -603,7 +676,7 @@
// Compute the previous and next line included by the filter.
if (NextLineInFilter < Line)
NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line,
- AnnotationItr, AnnotationEnd);
+ AnnotationItr, Annotations);
assert(NextLineInFilter && "expected NextLineInFilter to be computed");
if (NextLineInFilter == Line)
PrevLineInFilter = Line;