Skip to content

Commit 101ac5a

Browse files
committed
[FileCheck]: Fix diagnostics for NOT prefixes
1 parent 2c78f3b commit 101ac5a

File tree

6 files changed

+126
-42
lines changed

6 files changed

+126
-42
lines changed

llvm/lib/FileCheck/FileCheck.cpp

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,7 +1784,7 @@ bool FileCheck::readCheckFile(
17841784

17851785
PatternContext->createLineVariable();
17861786

1787-
std::vector<Pattern> ImplicitNegativeChecks;
1787+
std::vector<FileCheckString::DagNotPrefixInfo> ImplicitNegativeChecks;
17881788
for (StringRef PatternString : Req.ImplicitCheckNot) {
17891789
// Create a buffer with fake command line content in order to display the
17901790
// command line option responsible for the specific implicit CHECK-NOT.
@@ -1807,14 +1807,15 @@ bool FileCheck::readCheckFile(
18071807
}
18081808
}
18091809

1810-
ImplicitNegativeChecks.push_back(
1811-
Pattern(Check::CheckNot, PatternContext.get()));
1812-
ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
1813-
"IMPLICIT-CHECK", SM, Req);
1810+
ImplicitNegativeChecks.emplace_back(
1811+
Pattern(Check::CheckNot, PatternContext.get()),
1812+
StringRef("IMPLICIT-CHECK"));
1813+
ImplicitNegativeChecks.back().DagNotPat.parsePattern(
1814+
PatternInBuffer, "IMPLICIT-CHECK", SM, Req);
18141815
}
18151816

1816-
std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks;
1817-
1817+
std::vector<FileCheckString::DagNotPrefixInfo> DagNotMatches =
1818+
ImplicitNegativeChecks;
18181819
// LineNumber keeps track of the line on which CheckPrefix instances are
18191820
// found.
18201821
unsigned LineNumber = 1;
@@ -1926,7 +1927,7 @@ bool FileCheck::readCheckFile(
19261927

19271928
// Handle CHECK-DAG/-NOT.
19281929
if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
1929-
DagNotMatches.push_back(P);
1930+
DagNotMatches.emplace_back(P, UsedPrefix);
19301931
continue;
19311932
}
19321933

@@ -2165,7 +2166,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
21652166
FileCheckRequest &Req,
21662167
std::vector<FileCheckDiag> *Diags) const {
21672168
size_t LastPos = 0;
2168-
std::vector<const Pattern *> NotStrings;
2169+
std::vector<const DagNotPrefixInfo *> NotStrings;
21692170

21702171
// IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
21712172
// bounds; we have not processed variable definitions within the bounded block
@@ -2302,17 +2303,19 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
23022303
return false;
23032304
}
23042305

2305-
bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
2306-
const std::vector<const Pattern *> &NotStrings,
2307-
const FileCheckRequest &Req,
2308-
std::vector<FileCheckDiag> *Diags) const {
2306+
bool FileCheckString::CheckNot(
2307+
const SourceMgr &SM, StringRef Buffer,
2308+
const std::vector<const DagNotPrefixInfo *> &NotStrings,
2309+
const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {
23092310
bool DirectiveFail = false;
2310-
for (const Pattern *Pat : NotStrings) {
2311-
assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
2312-
Pattern::MatchResult MatchResult = Pat->match(Buffer, SM);
2313-
if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix,
2314-
Pat->getLoc(), *Pat, 1, Buffer,
2315-
std::move(MatchResult), Req, Diags)) {
2311+
for (auto NotInfo : NotStrings) {
2312+
assert((NotInfo->DagNotPat.getCheckTy() == Check::CheckNot) &&
2313+
"Expect CHECK-NOT!");
2314+
Pattern::MatchResult MatchResult = NotInfo->DagNotPat.match(Buffer, SM);
2315+
if (Error Err = reportMatchResult(
2316+
/*ExpectedMatch=*/false, SM, NotInfo->DagNotPrefix,
2317+
NotInfo->DagNotPat.getLoc(), NotInfo->DagNotPat, 1, Buffer,
2318+
std::move(MatchResult), Req, Diags)) {
23162319
cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
23172320
DirectiveFail = true;
23182321
continue;
@@ -2321,10 +2324,11 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
23212324
return DirectiveFail;
23222325
}
23232326

2324-
size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
2325-
std::vector<const Pattern *> &NotStrings,
2326-
const FileCheckRequest &Req,
2327-
std::vector<FileCheckDiag> *Diags) const {
2327+
size_t
2328+
FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
2329+
std::vector<const DagNotPrefixInfo *> &NotStrings,
2330+
const FileCheckRequest &Req,
2331+
std::vector<FileCheckDiag> *Diags) const {
23282332
if (DagNotStrings.empty())
23292333
return 0;
23302334

@@ -2344,13 +2348,14 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
23442348
// group, so we don't use a range-based for loop here.
23452349
for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
23462350
PatItr != PatEnd; ++PatItr) {
2347-
const Pattern &Pat = *PatItr;
2351+
const Pattern &Pat = PatItr->DagNotPat;
2352+
const StringRef DNPrefix = PatItr->DagNotPrefix;
23482353
assert((Pat.getCheckTy() == Check::CheckDAG ||
23492354
Pat.getCheckTy() == Check::CheckNot) &&
23502355
"Invalid CHECK-DAG or CHECK-NOT!");
23512356

23522357
if (Pat.getCheckTy() == Check::CheckNot) {
2353-
NotStrings.push_back(&Pat);
2358+
NotStrings.push_back(&*PatItr);
23542359
continue;
23552360
}
23562361

@@ -2367,7 +2372,7 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
23672372
// With a group of CHECK-DAGs, a single mismatching means the match on
23682373
// that group of CHECK-DAGs fails immediately.
23692374
if (MatchResult.TheError || Req.VerboseVerbose) {
2370-
if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix,
2375+
if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, DNPrefix,
23712376
Pat.getLoc(), Pat, 1, MatchBuffer,
23722377
std::move(MatchResult), Req, Diags)) {
23732378
cantFail(
@@ -2430,13 +2435,13 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
24302435
}
24312436
if (!Req.VerboseVerbose)
24322437
cantFail(printMatch(
2433-
/*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
2438+
/*ExpectedMatch=*/true, SM, DNPrefix, Pat.getLoc(), Pat, 1, Buffer,
24342439
Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req,
24352440
Diags));
24362441

24372442
// Handle the end of a CHECK-DAG group.
24382443
if (std::next(PatItr) == PatEnd ||
2439-
std::next(PatItr)->getCheckTy() == Check::CheckNot) {
2444+
std::next(PatItr)->DagNotPat.getCheckTy() == Check::CheckNot) {
24402445
if (!NotStrings.empty()) {
24412446
// If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
24422447
// CHECK-DAG, verify that there are no 'not' strings occurred in that

llvm/lib/FileCheck/FileCheckImpl.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,19 @@ struct FileCheckString {
823823
/// The location in the match file that the check string was specified.
824824
SMLoc Loc;
825825

826-
/// All of the strings that are disallowed from occurring between this match
827-
/// string and the previous one (or start of file).
828-
std::vector<Pattern> DagNotStrings;
826+
/// Hold the information about the DAG/NOT strings in the program, which are
827+
/// not explicitly stored otherwise. This allows for better and more accurate
828+
/// diagnostic messages.
829+
struct DagNotPrefixInfo {
830+
Pattern DagNotPat;
831+
StringRef DagNotPrefix;
832+
833+
DagNotPrefixInfo(const Pattern &P, StringRef S)
834+
: DagNotPat(P), DagNotPrefix(S) {}
835+
};
836+
837+
/// Hold the DAG/NOT strings occurring in the input file.
838+
std::vector<DagNotPrefixInfo> DagNotStrings;
829839

830840
FileCheckString(const Pattern &P, StringRef S, SMLoc L)
831841
: Pat(P), Prefix(S), Loc(L) {}
@@ -845,12 +855,12 @@ struct FileCheckString {
845855
/// \p Buffer. Errors are reported against \p SM and diagnostics recorded in
846856
/// \p Diags according to the verbosity level set in \p Req.
847857
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
848-
const std::vector<const Pattern *> &NotStrings,
858+
const std::vector<const DagNotPrefixInfo *> &NotStrings,
849859
const FileCheckRequest &Req,
850860
std::vector<FileCheckDiag> *Diags) const;
851861
/// Matches "dag strings" and their mixed "not strings".
852862
size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
853-
std::vector<const Pattern *> &NotStrings,
863+
std::vector<const DagNotPrefixInfo *> &NotStrings,
854864
const FileCheckRequest &Req,
855865
std::vector<FileCheckDiag> *Diags) const;
856866
};

llvm/test/FileCheck/check-ignore-case.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ One Line To Match
4343
# LINE: {{o}}ne line
4444
# LINE-SAME: {{t}}o match
4545

46-
# ERROR: command line:1:{{[0-9]+}}: error: CHECK-NOT: excluded string found in input
46+
# ERROR: command line:1:{{[0-9]+}}: error: IMPLICIT-CHECK-NOT: excluded string found in input
4747
# ERROR-NEXT: -implicit-check-not='sTrInG'
4848
# ERROR: note: found here
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; Test two trailing NOT strings
2+
; RUN: rm -f %t && \
3+
; RUN: echo "LEADING: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING-NOT: placeholder3" >>%t && \
4+
; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file %t %t 2>&1 | \
5+
; RUN: FileCheck --check-prefix TEST1 %s
6+
7+
; Test NOT string occurring in between two allowable strings
8+
; RUN: rm -f %t && \
9+
; RUN: echo "LEADING: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING: placeholder3" >>%t && \
10+
; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file %t %t 2>&1 | \
11+
; RUN: FileCheck --check-prefix TEST2 %s
12+
13+
; Test first prefix found being the NOT string
14+
; RUN: rm -f %t && \
15+
; RUN: echo "LEADING-NOT: placeholder1" >>%t && echo "MIDDLE: placeholder2" >>%t && echo "TRAILING: placeholder3" >>%t && \
16+
; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file %t %t 2>&1 | \
17+
; RUN: FileCheck --check-prefix TEST3 %s
18+
19+
; Test all given prefixes being NOT strings
20+
; RUN: rm -f %t && \
21+
; RUN: echo "LEADING-NOT: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING-NOT: placeholder3" >>%t && \
22+
; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file %t %t 2>&1 | \
23+
; RUN: FileCheck --check-prefix TEST4 %s
24+
25+
; TEST1: error: MIDDLE-NOT: excluded string found in input
26+
; TEST1-NEXT: MIDDLE-NOT: placeholder2
27+
; TEST1-NEXT: {{^}} ^{{$}}
28+
; TEST1-NEXT: note: found here
29+
; TEST1-NEXT: MIDDLE-NOT: placeholder2
30+
; TEST1-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
31+
; TEST1-NEXT: error: TRAILING-NOT: excluded string found in input
32+
; TEST1-NEXT: TRAILING-NOT: placeholder3
33+
; TEST1-NEXT: {{^}} ^{{$}}
34+
; TEST1-NEXT: note: found here
35+
; TEST1-NEXT: TRAILING-NOT: placeholder3
36+
; TEST1-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
37+
38+
; TEST2: error: MIDDLE-NOT: excluded string found in input
39+
; TEST2-NEXT: MIDDLE-NOT: placeholder2
40+
; TEST2-NEXT: {{^}} ^{{$}}
41+
; TEST2-NEXT: note: found here
42+
; TEST2-NEXT: MIDDLE-NOT: placeholder2
43+
; TEST2-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
44+
45+
; TEST3: error: LEADING-NOT: excluded string found in input
46+
; TEST3-NEXT: LEADING-NOT: placeholder1
47+
; TEST3-NEXT: {{^}} ^{{$}}
48+
; TEST3-NEXT: note: found here
49+
; TEST3-NEXT: LEADING-NOT: placeholder1
50+
; TEST3-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
51+
52+
; TEST4: error: LEADING-NOT: excluded string found in input
53+
; TEST4-NEXT: LEADING-NOT: placeholder1
54+
; TEST4-NEXT: {{^}} ^{{$}}
55+
; TEST4-NEXT: note: found here
56+
; TEST4-NEXT: LEADING-NOT: placeholder1
57+
; TEST4-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
58+
; TEST4-NEXT: error: MIDDLE-NOT: excluded string found in input
59+
; TEST4-NEXT: MIDDLE-NOT: placeholder2
60+
; TEST4-NEXT: {{^}} ^{{$}}
61+
; TEST4-NEXT: note: found here
62+
; TEST4-NEXT: MIDDLE-NOT: placeholder2
63+
; TEST4-NEXT: {{^}} ^~~~~~~~~~~~{{$}}
64+
; TEST4-NEXT: error: TRAILING-NOT: excluded string found in input
65+
; TEST4-NEXT: TRAILING-NOT: placeholder3
66+
; TEST4-NEXT: {{^}} ^{{$}}
67+
; TEST4-NEXT: note: found here
68+
; TEST4-NEXT: TRAILING-NOT: placeholder3
69+
; TEST4-NEXT: {{^}} ^~~~~~~~~~~~{{$}}

llvm/test/FileCheck/dump-input/annotations.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@
650650
; RUN: -implicit-check-not='{{remark:|error:}}'
651651

652652
; Verbose diagnostics are suppressed but not errors.
653-
; IMPNOT:{{.*}}command line:1:22: error: CHECK-NOT: excluded string found in input
653+
; IMPNOT:{{.*}}command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
654654

655655
; IMPNOT:<<<<<<
656656
; IMPNOT-NEXT: 1: hello world again!

llvm/test/FileCheck/implicit-check-not.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,36 @@
2121

2222
warning: aaa
2323
; CHECK-PASS: warning: aaa
24-
; CHECK-ERROR1: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
24+
; CHECK-ERROR1: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
2525
; CHECK-ERROR1-NEXT: -implicit-check-not='warning:'
2626
; CHECK-ERROR1: note: found here
2727
; CHECK-FAIL2: warning: aaa
2828
; CHECK-FAIL3: warning: aaa
29-
; CHECK-ERROR4: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
29+
; CHECK-ERROR4: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
3030
; CHECK-ERROR4-NEXT: {{-implicit-check-not='\{\{aaa\|bbb\|ccc\}\}'}}
3131
; CHECK-ERROR4: note: found here
32-
; CHECK-ERROR5: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
32+
; CHECK-ERROR5: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
3333
; CHECK-ERROR5-NEXT: -implicit-check-not='aaa'
3434
; CHECK-ERROR5: note: found here
3535

3636
warning: bbb
3737
; CHECK-PASS: warning: bbb
3838
; CHECK-FAIL1: warning: bbb
39-
; CHECK-ERROR2: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input
39+
; CHECK-ERROR2: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
4040
; CHECK-ERROR2-NEXT: -implicit-check-not='warning:'
4141
; CHECK-ERROR2: note: found here
4242
; CHECK-FAIL3: warning: bbb
43-
; CHECK-ERROR6: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input
43+
; CHECK-ERROR6: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
4444
; CHECK-ERROR6-NEXT: -implicit-check-not='bbb'
4545
; CHECK-ERROR6: note: found here
4646

4747
warning: ccc
4848
; CHECK-PASS: warning: ccc
4949
; CHECK-FAIL1: warning: ccc
5050
; CHECK-FAIL2: warning: ccc
51-
; CHECK-ERROR3: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input
51+
; CHECK-ERROR3: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
5252
; CHECK-ERROR3-NEXT: -implicit-check-not='warning:'
5353
; CHECK-ERROR3: note: found here
54-
; CHECK-ERROR7: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input
54+
; CHECK-ERROR7: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
5555
; CHECK-ERROR7-NEXT: -implicit-check-not='ccc'
5656
; CHECK-ERROR7: note: found here

0 commit comments

Comments
 (0)