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;