[llvm] [FileCheck]: Fix diagnostics for NOT prefixes (PR #78412)

Vinayak Dev via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 19 03:32:39 PST 2024


https://github.com/vinayakdsci updated https://github.com/llvm/llvm-project/pull/78412

>From 373b5707c5d5736f57cf7c27fed56f2dc11dbd0e Mon Sep 17 00:00:00 2001
From: Vinayak Dev <vinayakdev.sci at gmail.com>
Date: Mon, 15 Jan 2024 22:40:44 +0530
Subject: [PATCH] [FileCheck]: Fix diagnostics for NOT prefixes

---
 llvm/lib/FileCheck/FileCheck.cpp              | 48 +++++++------
 llvm/lib/FileCheck/FileCheckImpl.h            | 20 ++++--
 llvm/test/FileCheck/check-ignore-case.txt     |  2 +-
 .../FileCheck/check-not-custom-prefix.txt     | 69 +++++++++++++++++++
 .../test/FileCheck/dump-input/annotations.txt |  2 +-
 llvm/test/FileCheck/implicit-check-not.txt    | 14 ++--
 6 files changed, 119 insertions(+), 36 deletions(-)
 create mode 100644 llvm/test/FileCheck/check-not-custom-prefix.txt

diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp
index b728c14d288aa5..94e85ef1ee4260 100644
--- a/llvm/lib/FileCheck/FileCheck.cpp
+++ b/llvm/lib/FileCheck/FileCheck.cpp
@@ -1784,7 +1784,7 @@ bool FileCheck::readCheckFile(
 
   PatternContext->createLineVariable();
 
-  std::vector<Pattern> ImplicitNegativeChecks;
+  std::vector<FileCheckString::DagNotPrefixInfo> ImplicitNegativeChecks;
   for (StringRef PatternString : Req.ImplicitCheckNot) {
     // Create a buffer with fake command line content in order to display the
     // command line option responsible for the specific implicit CHECK-NOT.
@@ -1807,14 +1807,15 @@ bool FileCheck::readCheckFile(
       }
     }
 
-    ImplicitNegativeChecks.push_back(
-        Pattern(Check::CheckNot, PatternContext.get()));
-    ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
-                                               "IMPLICIT-CHECK", SM, Req);
+    ImplicitNegativeChecks.emplace_back(
+        Pattern(Check::CheckNot, PatternContext.get()),
+        StringRef("IMPLICIT-CHECK"));
+    ImplicitNegativeChecks.back().DagNotPat.parsePattern(
+        PatternInBuffer, "IMPLICIT-CHECK", SM, Req);
   }
 
-  std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks;
-
+  std::vector<FileCheckString::DagNotPrefixInfo> DagNotMatches =
+      ImplicitNegativeChecks;
   // LineNumber keeps track of the line on which CheckPrefix instances are
   // found.
   unsigned LineNumber = 1;
@@ -1926,7 +1927,7 @@ bool FileCheck::readCheckFile(
 
     // Handle CHECK-DAG/-NOT.
     if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
-      DagNotMatches.push_back(P);
+      DagNotMatches.emplace_back(P, UsedPrefix);
       continue;
     }
 
@@ -2165,7 +2166,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
                               FileCheckRequest &Req,
                               std::vector<FileCheckDiag> *Diags) const {
   size_t LastPos = 0;
-  std::vector<const Pattern *> NotStrings;
+  std::vector<const DagNotPrefixInfo *> NotStrings;
 
   // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
   // bounds; we have not processed variable definitions within the bounded block
@@ -2303,16 +2304,18 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
 }
 
 bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
-                               const std::vector<const Pattern *> &NotStrings,
+                               const std::vector<const DagNotPrefixInfo *> &NotStrings,
                                const FileCheckRequest &Req,
                                std::vector<FileCheckDiag> *Diags) const {
   bool DirectiveFail = false;
-  for (const Pattern *Pat : NotStrings) {
-    assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
-    Pattern::MatchResult MatchResult = Pat->match(Buffer, SM);
-    if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix,
-                                      Pat->getLoc(), *Pat, 1, Buffer,
-                                      std::move(MatchResult), Req, Diags)) {
+  for (auto NotInfo : NotStrings) {
+    assert((NotInfo->DagNotPat.getCheckTy() == Check::CheckNot) &&
+           "Expect CHECK-NOT!");
+    Pattern::MatchResult MatchResult = NotInfo->DagNotPat.match(Buffer, SM);
+    if (Error Err =
+            reportMatchResult(/*ExpectedMatch=*/false, SM, NotInfo->DagNotPrefix,
+                              NotInfo->DagNotPat.getLoc(), NotInfo->DagNotPat, 1,
+                              Buffer, std::move(MatchResult), Req, Diags)) {
       cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
       DirectiveFail = true;
       continue;
@@ -2322,7 +2325,7 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
 }
 
 size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
-                                 std::vector<const Pattern *> &NotStrings,
+                                 std::vector<const DagNotPrefixInfo *> &NotStrings,
                                  const FileCheckRequest &Req,
                                  std::vector<FileCheckDiag> *Diags) const {
   if (DagNotStrings.empty())
@@ -2344,13 +2347,14 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
   // group, so we don't use a range-based for loop here.
   for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
        PatItr != PatEnd; ++PatItr) {
-    const Pattern &Pat = *PatItr;
+    const Pattern &Pat = PatItr->DagNotPat;
+    const StringRef DNPrefix = PatItr->DagNotPrefix;
     assert((Pat.getCheckTy() == Check::CheckDAG ||
             Pat.getCheckTy() == Check::CheckNot) &&
            "Invalid CHECK-DAG or CHECK-NOT!");
 
     if (Pat.getCheckTy() == Check::CheckNot) {
-      NotStrings.push_back(&Pat);
+      NotStrings.push_back(&*PatItr);
       continue;
     }
 
@@ -2367,7 +2371,7 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
       // With a group of CHECK-DAGs, a single mismatching means the match on
       // that group of CHECK-DAGs fails immediately.
       if (MatchResult.TheError || Req.VerboseVerbose) {
-        if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix,
+        if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, DNPrefix,
                                           Pat.getLoc(), Pat, 1, MatchBuffer,
                                           std::move(MatchResult), Req, Diags)) {
           cantFail(
@@ -2430,13 +2434,13 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
     }
     if (!Req.VerboseVerbose)
       cantFail(printMatch(
-          /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
+          /*ExpectedMatch=*/true, SM, DNPrefix, Pat.getLoc(), Pat, 1, Buffer,
           Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req,
           Diags));
 
     // Handle the end of a CHECK-DAG group.
     if (std::next(PatItr) == PatEnd ||
-        std::next(PatItr)->getCheckTy() == Check::CheckNot) {
+        std::next(PatItr)->DagNotPat.getCheckTy() == Check::CheckNot) {
       if (!NotStrings.empty()) {
         // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
         // CHECK-DAG, verify that there are no 'not' strings occurred in that
diff --git a/llvm/lib/FileCheck/FileCheckImpl.h b/llvm/lib/FileCheck/FileCheckImpl.h
index c15461684ea392..c772eddd8ecd5e 100644
--- a/llvm/lib/FileCheck/FileCheckImpl.h
+++ b/llvm/lib/FileCheck/FileCheckImpl.h
@@ -823,9 +823,19 @@ struct FileCheckString {
   /// The location in the match file that the check string was specified.
   SMLoc Loc;
 
-  /// All of the strings that are disallowed from occurring between this match
-  /// string and the previous one (or start of file).
-  std::vector<Pattern> DagNotStrings;
+  /// Hold the information about the DAG/NOT strings in the program, which are
+  /// not explicitly stored otherwise. This allows for better and more accurate
+  /// diagnostic messages.
+  struct DagNotPrefixInfo {
+    Pattern DagNotPat;
+    StringRef DagNotPrefix;
+
+    DagNotPrefixInfo(const Pattern &P, StringRef S)
+        : DagNotPat(P), DagNotPrefix(S) {}
+  };
+
+  /// Hold the DAG/NOT strings occurring in the input file.
+  std::vector<DagNotPrefixInfo> DagNotStrings;
 
   FileCheckString(const Pattern &P, StringRef S, SMLoc L)
       : Pat(P), Prefix(S), Loc(L) {}
@@ -845,12 +855,12 @@ struct FileCheckString {
   /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in
   /// \p Diags according to the verbosity level set in \p Req.
   bool CheckNot(const SourceMgr &SM, StringRef Buffer,
-                const std::vector<const Pattern *> &NotStrings,
+                const std::vector<const DagNotPrefixInfo *> &NotStrings,
                 const FileCheckRequest &Req,
                 std::vector<FileCheckDiag> *Diags) const;
   /// Matches "dag strings" and their mixed "not strings".
   size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
-                  std::vector<const Pattern *> &NotStrings,
+                  std::vector<const DagNotPrefixInfo *> &NotStrings,
                   const FileCheckRequest &Req,
                   std::vector<FileCheckDiag> *Diags) const;
 };
diff --git a/llvm/test/FileCheck/check-ignore-case.txt b/llvm/test/FileCheck/check-ignore-case.txt
index c3b4d97ab5e417..47999ff2935157 100644
--- a/llvm/test/FileCheck/check-ignore-case.txt
+++ b/llvm/test/FileCheck/check-ignore-case.txt
@@ -43,6 +43,6 @@ One Line To Match
 # LINE: {{o}}ne line
 # LINE-SAME: {{t}}o match
 
-# ERROR: command line:1:{{[0-9]+}}: error: CHECK-NOT: excluded string found in input
+# ERROR: command line:1:{{[0-9]+}}: error: IMPLICIT-CHECK-NOT: excluded string found in input
 # ERROR-NEXT: -implicit-check-not='sTrInG'
 # ERROR: note: found here
diff --git a/llvm/test/FileCheck/check-not-custom-prefix.txt b/llvm/test/FileCheck/check-not-custom-prefix.txt
new file mode 100644
index 00000000000000..ddd8a7109ded9e
--- /dev/null
+++ b/llvm/test/FileCheck/check-not-custom-prefix.txt
@@ -0,0 +1,69 @@
+; Test two trailing NOT strings
+; RUN: rm -f %t && \
+; RUN: echo "LEADING: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING-NOT: placeholder3" >>%t && \
+; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file  %t %t 2>&1 | \
+; RUN: FileCheck --check-prefix TEST1 %s
+
+; Test NOT string occurring in between two allowable strings
+; RUN: rm -f %t && \
+; RUN: echo "LEADING: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING: placeholder3" >>%t && \
+; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file  %t %t 2>&1 | \
+; RUN: FileCheck --check-prefix TEST2 %s
+
+; Test first prefix found being the NOT string
+; RUN: rm -f %t && \
+; RUN: echo "LEADING-NOT: placeholder1" >>%t && echo "MIDDLE: placeholder2" >>%t && echo "TRAILING: placeholder3" >>%t && \
+; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file  %t %t 2>&1 | \
+; RUN: FileCheck --check-prefix TEST3 %s
+
+; Test all given prefixes being NOT strings
+; RUN: rm -f %t && \
+; RUN: echo "LEADING-NOT: placeholder1" >>%t && echo "MIDDLE-NOT: placeholder2" >>%t && echo "TRAILING-NOT: placeholder3" >>%t && \
+; RUN: %ProtectFileCheckOutput not FileCheck --strict-whitespace --check-prefixes LEADING,MIDDLE,TRAILING --dump-input=never --input-file  %t %t 2>&1 | \
+; RUN: FileCheck --check-prefix TEST4 %s
+
+; TEST1:           error: MIDDLE-NOT: excluded string found in input
+; TEST1-NEXT:      MIDDLE-NOT: placeholder2
+; TEST1-NEXT: {{^}}            ^{{$}}
+; TEST1-NEXT:      note: found here
+; TEST1-NEXT:      MIDDLE-NOT: placeholder2
+; TEST1-NEXT: {{^}}            ^~~~~~~~~~~~{{$}}
+; TEST1-NEXT:      error: TRAILING-NOT: excluded string found in input
+; TEST1-NEXT:      TRAILING-NOT: placeholder3
+; TEST1-NEXT: {{^}}              ^{{$}}
+; TEST1-NEXT:      note: found here
+; TEST1-NEXT:      TRAILING-NOT: placeholder3
+; TEST1-NEXT: {{^}}              ^~~~~~~~~~~~{{$}}
+
+; TEST2:           error: MIDDLE-NOT: excluded string found in input
+; TEST2-NEXT:      MIDDLE-NOT: placeholder2
+; TEST2-NEXT: {{^}}            ^{{$}}
+; TEST2-NEXT:      note: found here
+; TEST2-NEXT:      MIDDLE-NOT: placeholder2
+; TEST2-NEXT: {{^}}            ^~~~~~~~~~~~{{$}}
+
+; TEST3:           error: LEADING-NOT: excluded string found in input
+; TEST3-NEXT:      LEADING-NOT: placeholder1
+; TEST3-NEXT: {{^}}            ^{{$}}
+; TEST3-NEXT:      note: found here
+; TEST3-NEXT:      LEADING-NOT: placeholder1
+; TEST3-NEXT: {{^}}            ^~~~~~~~~~~~{{$}}
+
+; TEST4:           error: LEADING-NOT: excluded string found in input
+; TEST4-NEXT:      LEADING-NOT: placeholder1
+; TEST4-NEXT: {{^}}            ^{{$}}
+; TEST4-NEXT:      note: found here
+; TEST4-NEXT:      LEADING-NOT: placeholder1
+; TEST4-NEXT: {{^}}            ^~~~~~~~~~~~{{$}}
+; TEST4-NEXT:      error: MIDDLE-NOT: excluded string found in input
+; TEST4-NEXT:      MIDDLE-NOT: placeholder2
+; TEST4-NEXT: {{^}}            ^{{$}}
+; TEST4-NEXT:      note: found here
+; TEST4-NEXT:      MIDDLE-NOT: placeholder2
+; TEST4-NEXT: {{^}}            ^~~~~~~~~~~~{{$}}
+; TEST4-NEXT:      error: TRAILING-NOT: excluded string found in input
+; TEST4-NEXT:      TRAILING-NOT: placeholder3
+; TEST4-NEXT: {{^}}              ^{{$}}
+; TEST4-NEXT:      note: found here
+; TEST4-NEXT:      TRAILING-NOT: placeholder3
+; TEST4-NEXT: {{^}}              ^~~~~~~~~~~~{{$}}
diff --git a/llvm/test/FileCheck/dump-input/annotations.txt b/llvm/test/FileCheck/dump-input/annotations.txt
index 45bf54698bca00..367ea3377e6aeb 100644
--- a/llvm/test/FileCheck/dump-input/annotations.txt
+++ b/llvm/test/FileCheck/dump-input/annotations.txt
@@ -650,7 +650,7 @@
 ; RUN:             -implicit-check-not='{{remark:|error:}}'
 
 ; Verbose diagnostics are suppressed but not errors.
-; IMPNOT:{{.*}}command line:1:22: error: CHECK-NOT: excluded string found in input
+; IMPNOT:{{.*}}command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 
 ;         IMPNOT:<<<<<<
 ;    IMPNOT-NEXT:            1: hello world again! 
diff --git a/llvm/test/FileCheck/implicit-check-not.txt b/llvm/test/FileCheck/implicit-check-not.txt
index 95dd9fa782df8f..eaca0d37fcb291 100644
--- a/llvm/test/FileCheck/implicit-check-not.txt
+++ b/llvm/test/FileCheck/implicit-check-not.txt
@@ -21,26 +21,26 @@
 
 warning: aaa
 ; CHECK-PASS: warning: aaa
-; CHECK-ERROR1: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
+; CHECK-ERROR1: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR1-NEXT: -implicit-check-not='warning:'
 ; CHECK-ERROR1: note: found here
 ; CHECK-FAIL2: warning: aaa
 ; CHECK-FAIL3: warning: aaa
-; CHECK-ERROR4: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
+; CHECK-ERROR4: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR4-NEXT: {{-implicit-check-not='\{\{aaa\|bbb\|ccc\}\}'}}
 ; CHECK-ERROR4: note: found here
-; CHECK-ERROR5: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input
+; CHECK-ERROR5: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR5-NEXT: -implicit-check-not='aaa'
 ; CHECK-ERROR5: note: found here
 
 warning: bbb
 ; CHECK-PASS: warning: bbb
 ; CHECK-FAIL1: warning: bbb
-; CHECK-ERROR2: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input
+; CHECK-ERROR2: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR2-NEXT: -implicit-check-not='warning:'
 ; CHECK-ERROR2: note: found here
 ; CHECK-FAIL3: warning: bbb
-; CHECK-ERROR6: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input
+; CHECK-ERROR6: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR6-NEXT: -implicit-check-not='bbb'
 ; CHECK-ERROR6: note: found here
 
@@ -48,9 +48,9 @@ warning: ccc
 ; CHECK-PASS: warning: ccc
 ; CHECK-FAIL1: warning: ccc
 ; CHECK-FAIL2: warning: ccc
-; CHECK-ERROR3: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input
+; CHECK-ERROR3: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR3-NEXT: -implicit-check-not='warning:'
 ; CHECK-ERROR3: note: found here
-; CHECK-ERROR7: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input
+; CHECK-ERROR7: command line:1:22: error: IMPLICIT-CHECK-NOT: excluded string found in input
 ; CHECK-ERROR7-NEXT: -implicit-check-not='ccc'
 ; CHECK-ERROR7: note: found here



More information about the llvm-commits mailing list