[llvm] [FileCheck] Extend -dump-input with pattern notes (PR #207486)

Joel E. Denny via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 28 08:21:30 PDT 2026


https://github.com/jdenny-ornl updated https://github.com/llvm/llvm-project/pull/207486

>From 9533aa341e8d36e64161a93d4ea70c4d8c78e3ae Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Sat, 4 Jul 2026 00:48:47 -0400
Subject: [PATCH 1/5] [FileCheck][NFC] Encapsulate more into
 InputAnnotationLabeler

This patch migrates more label-making concerns from
buildInputAnnotations into the InputAnnotationLabeler.  It also
eliminates the brittle approach of creating a new
InputAnnotationLabeler object with a separate label prefix upon each
MatchResultDiag while persisting an object to close the previous
search range.  Instead, this patch creates just one
InputAnnotationLabeler object to handle all diags, and it maintains a
table of label prefixes for check patterns.  That approach seems
easier to understand and more amenable to code evolution.
---
 llvm/utils/FileCheck/FileCheck.cpp | 196 +++++++++++++----------------
 1 file changed, 89 insertions(+), 107 deletions(-)

diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index d507cf2e74051..4252442919da2 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -427,63 +427,84 @@ static std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
 }
 
 namespace {
-/// Stores all information needed to generate \c InputAnnotation labels for a
-/// particular check pattern.  Multiple labelers might be constructed for the
-/// same pattern if the pattern has more than one \c MatchResultDiag (e.g., for
-/// a \c CHECK-COUNT-<N> directive or implicit pattern).
+/// Stores all information needed to generate \c InputAnnotation labels.
 class InputAnnotationLabeler {
 private:
-  unsigned *LabelWidthGlobal;
-  unsigned *LabelIndexPerPattern;
-  std::string LabelPrefix;
+  struct CompareSMLoc {
+    bool operator()(SMLoc LHS, SMLoc RHS) const {
+      return LHS.getPointer() < RHS.getPointer();
+    }
+  };
+
+  const SourceMgr &SM;
+  const unsigned CheckFileBufferID;
+  const std::pair<unsigned, unsigned> ImpPatBufferIDRange;
+
+  /// How many unique input annotation labels does each check pattern need?
+  /// Each check pattern can have multiple \c MatchResultDiag's, each followed
+  /// by a series of zero or more \c MatchNoteDiag's.  Each such
+  /// \c MatchResultDiag and its \c MatchNoteDiag series can require multiple
+  /// labels.
+  std::map<SMLoc, unsigned, CompareSMLoc> LabelCountPerPattern;
+  /// For each check pattern, how many labels have we generated so far?
+  std::map<SMLoc, unsigned, CompareSMLoc> LabelIndexPerPattern;
+  /// For each check pattern, what is the common prefix for all its labels?
+  std::map<SMLoc, std::string, CompareSMLoc> LabelPrefixPerPattern;
+  /// How many total labels have we generated so far over all check patterns?
+  unsigned LabelIndexGlobal;
+  /// The widest label generated so far over all check patterns.
+  unsigned LabelWidthGlobal;
 
 public:
-  /// Make an invalid labeler to be overwritten by a valid one before calling
-  /// \c generateLabel.
-  InputAnnotationLabeler()
-      : LabelWidthGlobal(nullptr), LabelIndexPerPattern(nullptr) {}
   /// - \p CheckFileBufferID is the buffer ID for the check file.
   /// - \p ImpPatBufferIDRange is the buffer ID range for all implicit patterns.
-  /// - \p LabelWidthGlobal is the widest label generated so far over all
-  ///   patterns.  It will be updated by each call to \c generateLabel.
-  /// - \p CheckTy and \p CheckLoc identify the pattern that produced all
-  ///   diagnostics for which this labeler will generate labels.
-  /// - \p LabelIndexPerPattern is either \c nullptr if only one label is
-  ///   required for the pattern for which this labeler will generate labels, or
-  ///   it points to the per-pattern index of the next label to be generated for
-  ///   that pattern.  In the latter case, the index will be incremented by each
-  ///   call to \c generateLabel.
   InputAnnotationLabeler(const SourceMgr &SM, unsigned CheckFileBufferID,
-                         std::pair<unsigned, unsigned> ImpPatBufferIDRange,
-                         unsigned &LabelWidthGlobal,
-                         Check::FileCheckType CheckTy, SMLoc CheckLoc,
-                         unsigned *LabelIndexPerPattern)
-      : LabelWidthGlobal(&LabelWidthGlobal),
-        LabelIndexPerPattern(LabelIndexPerPattern) {
-    llvm::raw_string_ostream LabelStrm(LabelPrefix);
-    LabelStrm << GetCheckTypeAbbreviation(CheckTy) << ":";
-    unsigned CheckBufferID = SM.FindBufferContainingLoc(CheckLoc);
-    if (CheckBufferID == CheckFileBufferID)
-      LabelStrm << SM.getLineAndColumn(CheckLoc, CheckBufferID).first;
-    else if (ImpPatBufferIDRange.first <= CheckBufferID &&
-             CheckBufferID < ImpPatBufferIDRange.second)
-      LabelStrm << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
-    else
-      llvm_unreachable("expected check location to be either in the check file "
-                       "or for an implicit pattern");
+                         std::pair<unsigned, unsigned> ImpPatBufferIDRange)
+      : SM(SM), CheckFileBufferID(CheckFileBufferID),
+        ImpPatBufferIDRange(ImpPatBufferIDRange), LabelIndexGlobal(0),
+        LabelWidthGlobal(0) {}
+  /// Add \c C to the number of expected \c makeLabel calls for \c Diag.
+  /// \c expect must not be called after the first \c makeLabel call.
+  void expect(const FileCheckDiag &Diag, unsigned C) {
+    LabelCountPerPattern[Diag.getMatchResultDiag().getCheckLoc()] += C;
   }
-  /// Write a globally unique label into \p Label.
-  void generateLabel(std::string &Label) {
-    assert(!LabelPrefix.empty() &&
-           "unexpected generateLabel call on invalid labeler");
+  /// Write a new globally unique label for \c Diag into \p Label, and write its
+  /// globally unique index into LabelIndexGlobal.  All \c makeLabel calls must
+  /// have already been predicted by \c expect calls.
+  void makeLabel(const FileCheckDiag &Diag, std::string &Label,
+                 unsigned &LabelIndexGlobal) {
+    const MatchResultDiag &MRD = Diag.getMatchResultDiag();
+    SMLoc CheckLoc = MRD.getCheckLoc();
+    std::string &LabelPrefix = LabelPrefixPerPattern[CheckLoc];
+    if (LabelPrefix.empty()) {
+      llvm::raw_string_ostream LabelStrm(LabelPrefix);
+      LabelStrm << GetCheckTypeAbbreviation(MRD.getCheckTy()) << ":";
+      unsigned CheckBufferID = SM.FindBufferContainingLoc(CheckLoc);
+      if (CheckBufferID == CheckFileBufferID)
+        LabelStrm << SM.getLineAndColumn(CheckLoc, CheckBufferID).first;
+      else if (ImpPatBufferIDRange.first <= CheckBufferID &&
+               CheckBufferID < ImpPatBufferIDRange.second)
+        LabelStrm << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
+      else
+        llvm_unreachable(
+            "expected check location to be either in the check file or for an "
+            "implicit pattern");
+    }
     assert(Label.empty() && "expected empty string for writing label");
     llvm::raw_string_ostream LabelStrm(Label);
     LabelStrm << LabelPrefix;
-    if (LabelIndexPerPattern)
-      LabelStrm << "'" << (*LabelIndexPerPattern)++;
-    *LabelWidthGlobal =
-        std::max((std::string::size_type)*LabelWidthGlobal, Label.size());
+    unsigned LabelCount = LabelCountPerPattern[CheckLoc];
+    unsigned LabelIndex = LabelIndexPerPattern[CheckLoc]++;
+    assert(LabelIndex < LabelCount &&
+           "expected all makeLabel calls to be predicted by expect calls");
+    if (LabelCount > 1)
+      LabelStrm << "'" << LabelIndex;
+    LabelWidthGlobal =
+        std::max((std::string::size_type)LabelWidthGlobal, Label.size());
+    LabelIndexGlobal = this->LabelIndexGlobal++;
   }
+  /// Get the widest label generated.
+  unsigned getLabelWidthGlobal() const { return LabelWidthGlobal; }
 };
 
 /// A range specifying where annotation markers are physically \a drawn in the
@@ -594,17 +615,13 @@ struct MarkerRange {
 class SearchRangeAnnotator {
 private:
   const SourceMgr &SM;
-  /// Where to append search range annotations.
+  InputAnnotationLabeler &Labeler;
   std::vector<InputAnnotation> &Annotations;
-  /// A globally unique index for this annotation.
-  unsigned &LabelIndexGlobal;
+
   /// The most recent \c MatchResultDiag, or \c nullptr if all search range
   /// annotations have been added already for the most recent
   /// \c MatchResultDiag.
   const MatchResultDiag *MRD;
-  /// The labeler for \c MRD.  Stored by value as the original labeler might be
-  /// destroyed by the time we call \c endDiags here.
-  InputAnnotationLabeler Labeler;
   /// Would a \c SearchRangeAnnotator make any search range annotations for
   /// \p MRD?
   static bool makesAnnotationsFor(const MatchResultDiag &MRD) {
@@ -623,8 +640,7 @@ class SearchRangeAnnotator {
   /// Make the next annotation for the current \c MatchResultDiag.
   void makeAnnotation(bool Start) {
     InputAnnotation &A = Annotations.emplace_back();
-    A.LabelIndexGlobal = LabelIndexGlobal++;
-    Labeler.generateLabel(A.Label);
+    Labeler.makeLabel(*MRD, A.Label, A.LabelIndexGlobal);
     A.IsFirstLine = true;
     A.FoundAndExpectedMatch = false;
     MarkerRange SearchRange;
@@ -655,14 +671,13 @@ class SearchRangeAnnotator {
   }
 
 public:
-  /// How many search range annotations would a \c SearchRangeAnnotator generate
-  /// for \c MRD?
-  static unsigned countAnnotationsFor(const SourceMgr &SM,
-                                      const MatchResultDiag &MRD) {
+  /// Tell the labeler how many times this will call
+  /// \c InputAnnotationLabeler::makeLabel for \c MRD.
+  void predictLabelsFor(const MatchResultDiag &MRD) {
     if (!makesAnnotationsFor(MRD))
-      return 0;
+      return;
     MarkerRange SearchRange;
-    return makesOneLinerFor(SM, MRD, SearchRange) ? 1 : 2;
+    Labeler.expect(MRD, makesOneLinerFor(SM, MRD, SearchRange) ? 1 : 2);
   }
   /// Are the search range annotations generated by a \c SearchRangeAnnotator
   /// sufficient for \p MRD?  Otherwise, \p MRD needs to be rendered as a
@@ -671,27 +686,20 @@ class SearchRangeAnnotator {
     return makesAnnotationsFor(MRD) && getMarker(MRD).Note.empty();
   }
   /// \p Annotations is where this annotator should append search range
-  /// annotations.  \p LabelIndexGlobal is the globally unique index of the next
-  /// annotation label to be generated.  This annotator will increment it when
-  /// generating a new label for a search range annotation.
-  SearchRangeAnnotator(const SourceMgr &SM,
-                       std::vector<InputAnnotation> &Annotations,
-                       unsigned &LabelIndexGlobal)
-      : SM(SM), Annotations(Annotations), LabelIndexGlobal(LabelIndexGlobal),
-        MRD(nullptr) {}
+  /// annotations.
+  SearchRangeAnnotator(const SourceMgr &SM, InputAnnotationLabeler &Labeler,
+                       std::vector<InputAnnotation> &Annotations)
+      : SM(SM), Labeler(Labeler), Annotations(Annotations), MRD(nullptr) {}
   /// Emit any search range start annotation or one-line search range annotation
-  /// for \p MRDNew using its labeler \p LabelerNew.  This annotator will emit
-  /// any search range end annotation at the next call to \c newMatchResultDiag
-  /// or \c endDiags.
-  void newMatchResultDiag(const MatchResultDiag &MRDNew,
-                          InputAnnotationLabeler LabelerNew) {
+  /// for \p MRDNew.  Emit any search range end annotation for \p MRDNew at the
+  /// next call to \c newMatchResultDiag or \c endDiags.
+  void newMatchResultDiag(const MatchResultDiag &MRDNew) {
     if (MRD) {
       makeAnnotation(/*Start=*/false);
       MRD = nullptr;
     }
     if (makesAnnotationsFor(MRDNew)) {
       MRD = &MRDNew;
-      Labeler = LabelerNew;
       makeAnnotation(/*Start=*/true);
     }
   }
@@ -710,46 +718,20 @@ buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
                       const FileCheckDiagList &Diags,
                       std::vector<InputAnnotation> &Annotations,
                       unsigned &LabelWidthGlobal) {
-  struct CompareSMLoc {
-    bool operator()(SMLoc LHS, SMLoc RHS) const {
-      return LHS.getPointer() < RHS.getPointer();
-    }
-  };
-
-  // How many unique input annotation labels does each check pattern need?  Each
-  // check pattern can have multiple MatchResultDiag's, each followed by a
-  // series of zero or more MatchNoteDiag's.  Each such MatchResultDiag and its
-  // MatchNoteDiag series can require multiple labels.
-  std::map<SMLoc, unsigned, CompareSMLoc> LabelCountPerPattern;
+  InputAnnotationLabeler Labeler(SM, CheckFileBufferID, ImpPatBufferIDRange);
+  SearchRangeAnnotator TheSearchRangeAnnotator(SM, Labeler, Annotations);
   for (const FileCheckDiag &Diag : Diags) {
-    unsigned &C = LabelCountPerPattern[Diag.getMatchResultDiag().getCheckLoc()];
     if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag)) {
-      C += SearchRangeAnnotator::countAnnotationsFor(SM, *MRD);
+      TheSearchRangeAnnotator.predictLabelsFor(*MRD);
       if (!SearchRangeAnnotator::sufficesFor(*MRD))
-        ++C;
+        Labeler.expect(*MRD, 1);
     } else {
-      ++C;
+      Labeler.expect(Diag, 1);
     }
   }
-  // How many labels have we generated so far per check pattern?
-  std::map<SMLoc, unsigned, CompareSMLoc> LabelIndexPerPattern;
-  // How many total labels have we generated so far?
-  unsigned LabelIndexGlobal = 0;
-  SearchRangeAnnotator TheSearchRangeAnnotator(SM, Annotations,
-                                               LabelIndexGlobal);
-  // What's the widest label we've generated so far?
-  LabelWidthGlobal = 0;
-  // The labeler for the current MatchResultDiag and its MatchNoteDiag series.
-  InputAnnotationLabeler CurLabeler;
   for (const FileCheckDiag &Diag : Diags) {
     if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag)) {
-      CurLabeler = InputAnnotationLabeler(
-          SM, CheckFileBufferID, ImpPatBufferIDRange, LabelWidthGlobal,
-          MRD->getCheckTy(), MRD->getCheckLoc(),
-          LabelCountPerPattern[MRD->getCheckLoc()] > 1
-              ? &LabelIndexPerPattern[MRD->getCheckLoc()]
-              : nullptr);
-      TheSearchRangeAnnotator.newMatchResultDiag(*MRD, CurLabeler);
+      TheSearchRangeAnnotator.newMatchResultDiag(*MRD);
       if (SearchRangeAnnotator::sufficesFor(*MRD))
         continue;
     }
@@ -757,8 +739,7 @@ buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
     // Build label that is unique for this input annotation before it is
     // potentially broken across multiple lines.
     InputAnnotation A;
-    A.LabelIndexGlobal = LabelIndexGlobal++;
-    CurLabeler.generateLabel(A.Label);
+    Labeler.makeLabel(Diag, A.Label, A.LabelIndexGlobal);
 
     // Build the input marker.
     A.Marker = getMarker(Diag);
@@ -817,6 +798,7 @@ buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
     }
   }
   TheSearchRangeAnnotator.endDiags();
+  LabelWidthGlobal = Labeler.getLabelWidthGlobal();
 }
 
 static unsigned FindInputLineInFilter(

>From f43bf1ebb9ae39f98b05e95c01021c458cc82ff1 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Sat, 4 Jul 2026 00:49:35 -0400
Subject: [PATCH 2/5] [FileCheck][NFC] Introduce FileCheckDiagAnnotator

In the way that `SearchRangeAnnotator` encapsulates generating search
range annotations, this patch introduces `FileCheckDiagAnnotator` to
encapsulate generating the main annotation for a `FileCheckDiag`.
This change makes `buildInputAnnotations` easier to read, especially
after a third annotator class that will be introduced in a future
patch.
---
 llvm/utils/FileCheck/FileCheck.cpp | 91 +++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 34 deletions(-)

diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 4252442919da2..33625e0c9e1f1 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -622,11 +622,6 @@ class SearchRangeAnnotator {
   /// annotations have been added already for the most recent
   /// \c MatchResultDiag.
   const MatchResultDiag *MRD;
-  /// Would a \c SearchRangeAnnotator make any search range annotations for
-  /// \p MRD?
-  static bool makesAnnotationsFor(const MatchResultDiag &MRD) {
-    return !MRD.getMatchRange() || MRD.isError();
-  }
   /// Assuming \c makesAnnotationsFor(MRD), would a \c SearchRangeAnnotator make
   /// a one-line search range annotation for \p MRD?  Either way, the search
   /// range computed for \p MRD is stored in \p SearchRange.
@@ -671,6 +666,11 @@ class SearchRangeAnnotator {
   }
 
 public:
+  /// Would a \c SearchRangeAnnotator make any search range annotations for
+  /// \p MRD?
+  static bool makesAnnotationsFor(const MatchResultDiag &MRD) {
+    return !MRD.getMatchRange() || MRD.isError();
+  }
   /// Tell the labeler how many times this will call
   /// \c InputAnnotationLabeler::makeLabel for \c MRD.
   void predictLabelsFor(const MatchResultDiag &MRD) {
@@ -679,12 +679,6 @@ class SearchRangeAnnotator {
     MarkerRange SearchRange;
     Labeler.expect(MRD, makesOneLinerFor(SM, MRD, SearchRange) ? 1 : 2);
   }
-  /// Are the search range annotations generated by a \c SearchRangeAnnotator
-  /// sufficient for \p MRD?  Otherwise, \p MRD needs to be rendered as a
-  /// separate annotation.
-  static bool sufficesFor(const MatchResultDiag &MRD) {
-    return makesAnnotationsFor(MRD) && getMarker(MRD).Note.empty();
-  }
   /// \p Annotations is where this annotator should append search range
   /// annotations.
   SearchRangeAnnotator(const SourceMgr &SM, InputAnnotationLabeler &Labeler,
@@ -710,31 +704,38 @@ class SearchRangeAnnotator {
       makeAnnotation(/*Start=*/false);
   }
 };
-} // namespace
 
-static void
-buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
-                      const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
-                      const FileCheckDiagList &Diags,
-                      std::vector<InputAnnotation> &Annotations,
-                      unsigned &LabelWidthGlobal) {
-  InputAnnotationLabeler Labeler(SM, CheckFileBufferID, ImpPatBufferIDRange);
-  SearchRangeAnnotator TheSearchRangeAnnotator(SM, Labeler, Annotations);
-  for (const FileCheckDiag &Diag : Diags) {
-    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag)) {
-      TheSearchRangeAnnotator.predictLabelsFor(*MRD);
-      if (!SearchRangeAnnotator::sufficesFor(*MRD))
-        Labeler.expect(*MRD, 1);
-    } else {
-      Labeler.expect(Diag, 1);
-    }
+/// Emits the main annotations for each \c FileCheckDiag as it is encountered.
+class FileCheckDiagAnnotator {
+private:
+  const SourceMgr &SM;
+  InputAnnotationLabeler &Labeler;
+  std::vector<InputAnnotation> &Annotations;
+  /// Would a \c FileCheckDiagAnnotator make any annotations for \p Diag?
+  static bool makesAnnotationsFor(const FileCheckDiag &Diag) {
+    const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag);
+    if (!MRD)
+      return true;
+    if (SearchRangeAnnotator::makesAnnotationsFor(*MRD) &&
+        getMarker(*MRD).Note.empty())
+      return false;
+    return true;
   }
-  for (const FileCheckDiag &Diag : Diags) {
-    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag)) {
-      TheSearchRangeAnnotator.newMatchResultDiag(*MRD);
-      if (SearchRangeAnnotator::sufficesFor(*MRD))
-        continue;
-    }
+
+public:
+  /// Tell the labeler how many times this will call
+  /// \c InputAnnotationLabeler::makeLabel for \c Diag.
+  void predictLabelsFor(const FileCheckDiag &Diag) {
+    Labeler.expect(Diag, makesAnnotationsFor(Diag) ? 1 : 0);
+  }
+  /// \p Annotations is where this annotator should append annotations.
+  FileCheckDiagAnnotator(const SourceMgr &SM, InputAnnotationLabeler &Labeler,
+                         std::vector<InputAnnotation> &Annotations)
+      : SM(SM), Labeler(Labeler), Annotations(Annotations) {}
+  /// Emit any annotations for \c Diag.
+  void makeAnnotations(const FileCheckDiag &Diag) {
+    if (!makesAnnotationsFor(Diag))
+      return;
 
     // Build label that is unique for this input annotation before it is
     // potentially broken across multiple lines.
@@ -797,6 +798,28 @@ buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
       }
     }
   }
+};
+} // namespace
+
+static void
+buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
+                      const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
+                      const FileCheckDiagList &Diags,
+                      std::vector<InputAnnotation> &Annotations,
+                      unsigned &LabelWidthGlobal) {
+  InputAnnotationLabeler Labeler(SM, CheckFileBufferID, ImpPatBufferIDRange);
+  SearchRangeAnnotator TheSearchRangeAnnotator(SM, Labeler, Annotations);
+  FileCheckDiagAnnotator TheFileCheckDiagAnnotator(SM, Labeler, Annotations);
+  for (const FileCheckDiag &Diag : Diags) {
+    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag))
+      TheSearchRangeAnnotator.predictLabelsFor(*MRD);
+    TheFileCheckDiagAnnotator.predictLabelsFor(Diag);
+  }
+  for (const FileCheckDiag &Diag : Diags) {
+    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag))
+      TheSearchRangeAnnotator.newMatchResultDiag(*MRD);
+    TheFileCheckDiagAnnotator.makeAnnotations(Diag);
+  }
   TheSearchRangeAnnotator.endDiags();
   LabelWidthGlobal = Labeler.getLabelWidthGlobal();
 }

>From 1d94fea94a67d6bd16deb0ce5282b6efba8e0957 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Sat, 4 Jul 2026 00:50:18 -0400
Subject: [PATCH 3/5] [FileCheck] Extend -dump-input with pattern notes

For example, this patch adds the "for" and "at" annotations below:

```

Input was:
<<<<<<
           1: offload triples:
check:2'0                    {   search range start (exclusive)
check:2'1                        error: no match found
check:2'2                        for: CHECK: nvptx64-nvidia-cuda
check:2'3                        at: /tmp/check.txt:2
           2: - amdgcn-amd-amdhsa
           3: - x86_64-linux-gnu
           4: - x86_64-unknown-linux-gnu
           .
           .
           .
          14: - x86_64-linux-android
          15:
          16: host triples:
check:2'4                  }  search range end (exclusive)
          17: - nvptx64-nvidia-cuda
          18: - x86_64-linux-gnu
           .
           .
           .
>>>>>>
```

This change was previously discussed at:
- <https://reviews.llvm.org/D83650#2146534>
- <https://github.com/llvm/llvm-project/issues/77257#issuecomment-4276117811>
- <https://github.com/llvm/llvm-project/issues/77257#issuecomment-4314101143>

This patch adds the new annotations only for errors.  If people feel
that quoting the patterns for all successful FileCheck directives is
worthwhile, we could pursue that in a subsequent patch.  However, that
might be too verbose, even with `-vv`.  If that much info is needed
while debugging, the user should probably go ahead and open the check
file, and annotation labels (e.g., "check:2") already indicate where
to look up patterns.
---
 .../test/FileCheck/dump-input/annotations.txt | 145 +++--
 llvm/test/FileCheck/dump-input/color.txt      |  21 +-
 llvm/test/FileCheck/dump-input/context.txt    |  85 ++-
 llvm/test/FileCheck/dump-input/enable.txt     |  31 +-
 llvm/test/FileCheck/dump-input/filter.txt     | 604 +++++++++---------
 .../check-label-follows.txt                   |   8 +-
 .../check-next-same.txt                       |  14 +-
 .../search-range-annotations/check-not.txt    |   8 +-
 .../invalid-excluded-pattern.txt              |  21 +-
 .../invalid-expected-pattern.txt              |  18 +-
 .../matched-excluded-pattern.txt              |  21 +-
 .../matched-expected-pattern.txt              |  22 +-
 .../FileCheck/unmatched-substs-captures.txt   |  13 +-
 llvm/utils/FileCheck/FileCheck.cpp            | 126 +++-
 14 files changed, 702 insertions(+), 435 deletions(-)

diff --git a/llvm/test/FileCheck/dump-input/annotations.txt b/llvm/test/FileCheck/dump-input/annotations.txt
index 18ece6b508c5f..213dd529fdaa1 100644
--- a/llvm/test/FileCheck/dump-input/annotations.txt
+++ b/llvm/test/FileCheck/dump-input/annotations.txt
@@ -26,7 +26,7 @@
 ;
 ; DEFINE: %{check-fc} = \
 ; DEFINE:   FileCheck -strict-whitespace -match-full-lines %s \
-; DEFINE:       -allow-unused-prefixes \
+; DEFINE:       -allow-unused-prefixes -DCHK_FILE=%t.chk \
 ; DEFINE:       -implicit-check-not='remark:' -implicit-check-not='error:'
 ;
 ; For each case, it is usually best to run these in order of decreasing
@@ -134,10 +134,12 @@
 ; CHK-V-NEXT:check:1          ^~~~~
 ;   CHK-NEXT:check:2'0            {   search range start (exclusive)
 ;   CHK-NEXT:check:2'1                error: no match found in search range
+;   CHK-NEXT:check:2'2                for: CHECK: world
+;   CHK-NEXT:check:2'3                at: [[CHK_FILE]]:2
 ;   CHK-NEXT:              2: again 
 ;   CHK-NEXT:              3: whirled 
-;   CHK-NEXT:check:2'2        ?         possible intended match
-;   CHK-NEXT:check:2'3                } search range end (exclusive)
+;   CHK-NEXT:check:2'4        ?         possible intended match
+;   CHK-NEXT:check:2'5                } search range end (exclusive)
 ;   CHK-NEXT:>>>>>>
 ;    CHK-NOT:{{.}}
 
@@ -168,9 +170,11 @@
 ; CNT-V-NEXT:count:1'1          ^~~~
 ; CNT-V-NEXT:count:1'2             {   search range start (exclusive)
 ; CNT-V-NEXT:count:1'3                 error: no match found in search range
+; CNT-V-NEXT:count:1'4                 for: CHECK-COUNT-3: pete
+; CNT-V-NEXT:count:1'5                 at: [[CHK_FILE]]:1
 ; CNT-V-NEXT:              3: repeat 
-; CNT-V-NEXT:count:1'4        ?        possible intended match
-; CNT-V-NEXT:count:1'5               } search range end (exclusive)
+; CNT-V-NEXT:count:1'6        ?        possible intended match
+; CNT-V-NEXT:count:1'7               } search range end (exclusive)
 ; CNT-V-NEXT:>>>>>>
 ;  CNT-V-NOT:{{.}}
 
@@ -179,9 +183,11 @@
 ; CNT-Q-NEXT:              2: repete 
 ; CNT-Q-NEXT:count:1'0             {   search range start (exclusive)
 ; CNT-Q-NEXT:count:1'1                 error: no match found in search range
+; CNT-Q-NEXT:count:1'2                 for: CHECK-COUNT-3: pete
+; CNT-Q-NEXT:count:1'3                 at: [[CHK_FILE]]:1
 ; CNT-Q-NEXT:              3: repeat 
-; CNT-Q-NEXT:count:1'2        ?        possible intended match
-; CNT-Q-NEXT:count:1'3               } search range end (exclusive)
+; CNT-Q-NEXT:count:1'4        ?        possible intended match
+; CNT-Q-NEXT:count:1'5               } search range end (exclusive)
 ; CNT-Q-NEXT:>>>>>>
 ;  CNT-Q-NOT:{{.}}
 
@@ -213,6 +219,8 @@
 ; NXT-V-NEXT:next:2           ^~~~~
 ;   NXT-NEXT:next:3'0             { } search range (exclusive bounds)
 ;   NXT-NEXT:next:3'1                 error: no match found in search range
+;   NXT-NEXT:next:3'2                 for: CHECK-NEXT: world
+;   NXT-NEXT:next:3'3                 at: [[CHK_FILE]]:3
 ;   NXT-NEXT:>>>>>>
 ;    NXT-NOT:{{.}}
 
@@ -238,7 +246,9 @@
 ;   NXT2-NEXT:              3: yonder 
 ;   NXT2-NEXT:              4: world 
 ;   NXT2-NEXT:next:3'1         !~~~~   error: match on wrong line
-;   NXT2-NEXT:next:3'2               } search range end (exclusive)
+;   NXT2-NEXT:next:3'2                 for: CHECK-NEXT: world
+;   NXT2-NEXT:next:3'3                 at: [[CHK_FILE]]:3
+;   NXT2-NEXT:next:3'4               } search range end (exclusive)
 ;   NXT2-NEXT:>>>>>>
 ;    NXT2-NOT:{{.}}
 
@@ -268,6 +278,8 @@
 ; SAM-V-NEXT:same:2                 ^~~~~
 ;   SAM-NEXT:same:3'0                   {  } search range (exclusive bounds)
 ;   SAM-NEXT:same:3'1                        error: no match found in search range
+;   SAM-NEXT:same:3'2                        for: CHECK-SAME: again
+;   SAM-NEXT:same:3'3                        at: [[CHK_FILE]]:3
 ;   SAM-NEXT:>>>>>>
 ;    SAM-NOT:{{.}}
 
@@ -290,7 +302,9 @@
 ;   SAM2-NEXT:same:3'0                   {    search range start (exclusive)
 ;   SAM2-NEXT:              2: again 
 ;   SAM2-NEXT:same:3'1         !~~~~   error: match on wrong line
-;   SAM2-NEXT:same:3'2               } search range end (exclusive)
+;   SAM2-NEXT:same:3'2                 for: CHECK-SAME: again
+;   SAM2-NEXT:same:3'3                 at: [[CHK_FILE]]:3
+;   SAM2-NEXT:same:3'4               } search range end (exclusive)
 ;   SAM2-NEXT:>>>>>>
 ;    SAM2-NOT:{{.}}
 
@@ -331,10 +345,12 @@
 ; EMP-V-NEXT:empty:2          ^
 ;   EMP-NEXT:empty:3'0       {   search range start (exclusive)
 ;   EMP-NEXT:empty:3'1           error: no match found in search range
+;   EMP-NEXT:empty:3'2           for: CHECK-EMPTY:
+;   EMP-NEXT:empty:3'3           at: [[CHK_FILE]]:3
 ;   EMP-NEXT:              3: world 
 ;   EMP-NEXT:              4: label 
 ; EMP-V-NEXT:label:4          ^~~~~
-;   EMP-NEXT:empty:3'2             }  search range end (exclusive)
+;   EMP-NEXT:empty:3'4             }  search range end (exclusive)
 ;   EMP-NEXT:>>>>>>
 ;    EMP-NOT:{{.}}
 
@@ -369,9 +385,11 @@
 ; EMP2-V-NEXT:check:1          ^~~~~
 ;   EMP2-NEXT:empty:2'0            {   search range start (exclusive)
 ;   EMP2-NEXT:              2: world 
-;   EMP2-NEXT:empty:2'2              } search range end (exclusive)
+;   EMP2-NEXT:empty:2'4              } search range end (exclusive)
 ;   EMP2-NEXT:              3: 
 ;   EMP2-NEXT:empty:2'1        ! error: match on wrong line
+;   EMP2-NEXT:empty:2'2          for: CHECK-EMPTY:
+;   EMP2-NEXT:empty:2'3          at: [[CHK_FILE]]:2
 ;   EMP2-NEXT:>>>>>>
 ;    EMP2-NOT:{{.}}
 
@@ -402,9 +420,11 @@
 ;    NOT-NEXT:not:2'0         {        search range start (exclusive)
 ;    NOT-NEXT:              2: world 
 ;    NOT-NEXT:not:2'1          !~~~~   error: no match expected
+;    NOT-NEXT:not:2'2                  for: CHECK-NOT: world
+;    NOT-NEXT:not:2'3                  at: [[CHK_FILE]]:2
 ;    NOT-NEXT:              3: again 
 ; NOT-VV-NEXT:not:1'1                } search range end (exclusive)
-;    NOT-NEXT:not:2'2                } search range end (exclusive)
+;    NOT-NEXT:not:2'4                } search range end (exclusive)
 ; NOT-VV-NEXT:              4: 
 ; NOT-VV-NEXT:eof:2            ^
 ;    NOT-NEXT:>>>>>>
@@ -428,10 +448,12 @@
 ;    NOT2-NEXT:not:2'0         {        search range start (exclusive)
 ;    NOT2-NEXT:              2: world 
 ;    NOT2-NEXT:not:2'1          !~~~~   error: no match expected
+;    NOT2-NEXT:not:2'2                  for: CHECK-NOT: world
+;    NOT2-NEXT:not:2'3                  at: [[CHK_FILE]]:2
 ;    NOT2-NEXT:              3: again 
 ;  NOT2-V-NEXT:check:3            ^~~
 ; NOT2-VV-NEXT:not:1'1            }     search range end (exclusive)
-;    NOT2-NEXT:not:2'2            }     search range end (exclusive)
+;    NOT2-NEXT:not:2'4            }     search range end (exclusive)
 ;    NOT2-NEXT:>>>>>>
 ;     NOT2-NOT:{{.}}
 
@@ -467,9 +489,11 @@
 ; DAG-VV-NEXT:dag:4'0          !~~   discard: overlaps earlier match
 ; DAG-VV-NEXT:dag:4'1            {   search range start (exclusive)
 ; DAG-VV-NEXT:dag:4'2                error: no match found in search range
+; DAG-VV-NEXT:dag:4'3                for: CHECK-DAG: def
+; DAG-VV-NEXT:dag:4'4                at: [[CHK_FILE]]:4
 ; DAG-VV-NEXT:              3: abc 
 ; DAG-VV-NEXT:dag:3'1          ^~~
-; DAG-VV-NEXT:dag:4'3              } search range end (exclusive)
+; DAG-VV-NEXT:dag:4'5              } search range end (exclusive)
 ; DAG-VV-NEXT:>>>>>>
 ;  DAG-VV-NOT:{{.}}
 
@@ -480,9 +504,11 @@
 ; DAG-VQ-NEXT:dag:1            ^~~
 ; DAG-VQ-NEXT:dag:4'0            {   search range start (exclusive)
 ; DAG-VQ-NEXT:dag:4'1                error: no match found in search range
+; DAG-VQ-NEXT:dag:4'2                for: CHECK-DAG: def
+; DAG-VQ-NEXT:dag:4'3                at: [[CHK_FILE]]:4
 ; DAG-VQ-NEXT:              3: abc 
 ; DAG-VQ-NEXT:dag:3            ^~~
-; DAG-VQ-NEXT:dag:4'2              } search range end (exclusive)
+; DAG-VQ-NEXT:dag:4'4              } search range end (exclusive)
 ; DAG-VQ-NEXT:>>>>>>
 ;  DAG-VQ-NOT:{{.}}
 
@@ -491,8 +517,10 @@
 ; DAG-Q-NEXT:              2: def 
 ; DAG-Q-NEXT:dag:4'0            {   search range start (exclusive)
 ; DAG-Q-NEXT:dag:4'1                error: no match found in search range
+; DAG-Q-NEXT:dag:4'2                for: CHECK-DAG: def
+; DAG-Q-NEXT:dag:4'3                at: [[CHK_FILE]]:4
 ; DAG-Q-NEXT:              3: abc 
-; DAG-Q-NEXT:dag:4'2              } search range end (exclusive)
+; DAG-Q-NEXT:dag:4'4              } search range end (exclusive)
 ; DAG-Q-NEXT:>>>>>>
 ;  DAG-Q-NOT:{{.}}
 
@@ -529,6 +557,8 @@
 ; DAG1L-VV-NEXT:dag:5'1                      !~~   discard: overlaps earlier match
 ; DAG1L-VV-NEXT:dag:5'2                       {  } search range (exclusive bounds)
 ; DAG1L-VV-NEXT:dag:5'3                            error: no match found in search range
+; DAG1L-VV-NEXT:dag:5'4                            for: CHECK-DAG: def
+; DAG1L-VV-NEXT:dag:5'5                            at: [[CHK_FILE]]:5
 ; DAG1L-VV-NEXT:>>>>>>
 ;  DAG1L-VV-NOT:{{.}}
 
@@ -540,6 +570,8 @@
 ; DAG1L-VQ-NEXT:dag:4                        ^~
 ; DAG1L-VQ-NEXT:dag:5'0                       {  } search range (exclusive bounds)
 ; DAG1L-VQ-NEXT:dag:5'1                            error: no match found in search range
+; DAG1L-VQ-NEXT:dag:5'2                            for: CHECK-DAG: def
+; DAG1L-VQ-NEXT:dag:5'3                            at: [[CHK_FILE]]:5
 ; DAG1L-VQ-NEXT:>>>>>>
 ;  DAG1L-VQ-NOT:{{.}}
 
@@ -547,6 +579,8 @@
 ; DAG1L-Q-NEXT:              1: abc def abc def 
 ; DAG1L-Q-NEXT:dag:5'0                       {  } search range (exclusive bounds)
 ; DAG1L-Q-NEXT:dag:5'1                            error: no match found in search range
+; DAG1L-Q-NEXT:dag:5'2                            for: CHECK-DAG: def
+; DAG1L-Q-NEXT:dag:5'3                            at: [[CHK_FILE]]:5
 ; DAG1L-Q-NEXT:>>>>>>
 ;  DAG1L-Q-NOT:{{.}}
 
@@ -614,16 +648,20 @@
 ;  LAB-V-NEXT:label:2'1        ^~~~~~
 ;  LAB-V-NEXT:check:3'0             {   search range start (exclusive)
 ;  LAB-V-NEXT:check:3'1                 error: no match found in search range
+;  LAB-V-NEXT:check:3'2                 for: CHECK: foobar
+;  LAB-V-NEXT:check:3'3                 at: [[CHK_FILE]]:3
 ;  LAB-V-NEXT:              3: textA 
 ;  LAB-V-NEXT:              4: labelB 
 ;  LAB-V-NEXT:label:4          ^~~~~~
-;  LAB-V-NEXT:check:3'2              }  search range end (exclusive)
+;  LAB-V-NEXT:check:3'4              }  search range end (exclusive)
 ;  LAB-V-NEXT:              5: textB 
 ;  LAB-V-NEXT:              6: labelC 
 ;  LAB-V-NEXT:label:6'0        ^~~~~~
 ;  LAB-V-NEXT:check:5          ^~~~~~
 ;  LAB-V-NEXT:label:6'1             {}  search range (exclusive bounds)
 ;  LAB-V-NEXT:label:6'2                 error: no match found in search range
+;  LAB-V-NEXT:label:6'3                 for: CHECK-LABEL: labelC
+;  LAB-V-NEXT:label:6'4                 at: [[CHK_FILE]]:6
 ; LAB-VV-NEXT:not:7'0               {   search range start (exclusive)
 ;  LAB-V-NEXT:              7: textC 
 ; LAB-VV-NEXT:not:7'1                } search range end (exclusive)
@@ -633,7 +671,9 @@
 ;  LAB-V-NEXT:not:9'0               {   search range start (exclusive)
 ;  LAB-V-NEXT:              9: textD 
 ;  LAB-V-NEXT:not:9'1          !~~~~   error: no match expected
-;  LAB-V-NEXT:not:9'2                } search range end (exclusive)
+;  LAB-V-NEXT:not:9'2                  for: CHECK-NOT: textD
+;  LAB-V-NEXT:not:9'3                  at: [[CHK_FILE]]:9
+;  LAB-V-NEXT:not:9'4                } search range end (exclusive)
 ;  LAB-V-NEXT:             10: labelE 
 ;  LAB-V-NEXT:label:10'0       ^~~~~~
 ;  LAB-V-NEXT:label:10'1       ^~~~~~
@@ -651,19 +691,25 @@
 ; LAB-Q-NEXT:              2: labelA 
 ; LAB-Q-NEXT:check:3'0             {   search range start (exclusive)
 ; LAB-Q-NEXT:check:3'1                 error: no match found in search range
+; LAB-Q-NEXT:check:3'2                 for: CHECK: foobar
+; LAB-Q-NEXT:check:3'3                 at: [[CHK_FILE]]:3
 ; LAB-Q-NEXT:              3: textA 
 ; LAB-Q-NEXT:              4: labelB 
-; LAB-Q-NEXT:check:3'2              }  search range end (exclusive)
+; LAB-Q-NEXT:check:3'4              }  search range end (exclusive)
 ; LAB-Q-NEXT:              5: textB 
 ; LAB-Q-NEXT:              6: labelC 
 ; LAB-Q-NEXT:label:6'0             {}  search range (exclusive bounds)
 ; LAB-Q-NEXT:label:6'1                 error: no match found in search range
+; LAB-Q-NEXT:label:6'2                 for: CHECK-LABEL: labelC
+; LAB-Q-NEXT:label:6'3                 at: [[CHK_FILE]]:6
 ; LAB-Q-NEXT:              7: textC 
 ; LAB-Q-NEXT:              8: labelD 
 ; LAB-Q-NEXT:not:9'0               {   search range start (exclusive)
 ; LAB-Q-NEXT:              9: textD 
 ; LAB-Q-NEXT:not:9'1          !~~~~   error: no match expected
-; LAB-Q-NEXT:not:9'2                } search range end (exclusive)
+; LAB-Q-NEXT:not:9'2                  for: CHECK-NOT: textD
+; LAB-Q-NEXT:not:9'3                  at: [[CHK_FILE]]:9
+; LAB-Q-NEXT:not:9'4                } search range end (exclusive)
 ; LAB-Q-NEXT:             10: labelE 
 ; LAB-Q-NEXT:             11: textE 
 ; LAB-Q-NEXT:             12: labelF 
@@ -713,6 +759,7 @@
 ; IMPNOT-VV-NEXT:not:imp2'2               {        }   search range (exclusive bounds)
 ; IMPNOT-VV-NEXT:not:imp3'2               {        }   search range (exclusive bounds)
 ; IMPNOT-VV-NEXT:not:imp3'3                   !~~~~    error: no match expected
+; IMPNOT-VV-NEXT:not:imp3'4                            for: -implicit-check-not='again'
 ; IMPNOT-VV-NEXT:>>>>>>
 ;  IMPNOT-VV-NOT:{{.}}
 
@@ -723,6 +770,7 @@
 ; IMPNOT-VQ-NEXT:check:3                           ^
 ; IMPNOT-VQ-NEXT:not:imp3'0               {        }   search range (exclusive bounds)
 ; IMPNOT-VQ-NEXT:not:imp3'1                   !~~~~    error: no match expected
+; IMPNOT-VQ-NEXT:not:imp3'2                            for: -implicit-check-not='again'
 ; IMPNOT-VQ-NEXT:>>>>>>
 ;  IMPNOT-VQ-NOT:{{.}}
 
@@ -730,6 +778,7 @@
 ; IMPNOT-Q-NEXT:              1: hello world again! 
 ; IMPNOT-Q-NEXT:not:imp3'0               {        }   search range (exclusive bounds)
 ; IMPNOT-Q-NEXT:not:imp3'1                   !~~~~    error: no match expected
+; IMPNOT-Q-NEXT:not:imp3'2                            for: -implicit-check-not='again'
 ; IMPNOT-Q-NEXT:>>>>>>
 ;  IMPNOT-Q-NOT:{{.}}
 
@@ -763,12 +812,14 @@
 ; SUBST-POS-V-NEXT:check:1'2                                with "DEF_MATCH2" equal to "def-match2"
 ;   SUBST-POS-NEXT:check:2'0                            {   search range start (exclusive)
 ;   SUBST-POS-NEXT:check:2'1                                error: match failed for invalid pattern
-;   SUBST-POS-NEXT:check:2'2                                undefined variable: UNDEF
-;   SUBST-POS-NEXT:check:2'3                                with "DEF_MATCH1" equal to "def-match1"
-;   SUBST-POS-NEXT:check:2'4                                with "DEF_NOMATCH" equal to "foobar"
+;   SUBST-POS-NEXT:check:2'2                                for: CHECK: {{\[}}[DEF_MATCH1]] {{\[}}[UNDEF]] {{\[}}[DEF_NOMATCH]]
+;   SUBST-POS-NEXT:check:2'3                                at: [[CHK_FILE]]:2
+;   SUBST-POS-NEXT:check:2'4                                undefined variable: UNDEF
+;   SUBST-POS-NEXT:check:2'5                                with "DEF_MATCH1" equal to "def-match1"
+;   SUBST-POS-NEXT:check:2'6                                with "DEF_NOMATCH" equal to "foobar"
 ;   SUBST-POS-NEXT:              2: def-match1 def-nomatch 
-;   SUBST-POS-NEXT:check:2'5                 ?               possible intended match
-;   SUBST-POS-NEXT:check:2'6                               } search range end (exclusive)
+;   SUBST-POS-NEXT:check:2'7                 ?               possible intended match
+;   SUBST-POS-NEXT:check:2'8                               } search range end (exclusive)
 ;   SUBST-POS-NEXT:>>>>>>
 
 ;--------------------------------------------------
@@ -799,16 +850,20 @@
 ;   SUBST-NEG-NEXT:              1: def-match1 def-nomatch 
 ;   SUBST-NEG-NEXT:not:1'0         {                         search range start (exclusive)
 ;   SUBST-NEG-NEXT:not:1'1                                   error: match failed for invalid pattern
-;   SUBST-NEG-NEXT:not:1'2                                   undefined variable: UNDEF
-;   SUBST-NEG-NEXT:not:1'3                                   with "DEF_MATCH1" equal to "def-match1"
-;   SUBST-NEG-NEXT:not:1'4                                   with "DEF_NOMATCH" equal to "foobar"
+;   SUBST-NEG-NEXT:not:1'2                                   for: CHECK-NOT: {{\[}}[DEF_MATCH1]] {{\[}}[UNDEF]] {{\[}}[DEF_NOMATCH]]
+;   SUBST-NEG-NEXT:not:1'3                                   at: [[CHK_FILE]]:1
+;   SUBST-NEG-NEXT:not:1'4                                   undefined variable: UNDEF
+;   SUBST-NEG-NEXT:not:1'5                                   with "DEF_MATCH1" equal to "def-match1"
+;   SUBST-NEG-NEXT:not:1'6                                   with "DEF_NOMATCH" equal to "foobar"
 ;   SUBST-NEG-NEXT:not:2'0         {                         search range start (exclusive)
 ;   SUBST-NEG-NEXT:              2: def-match1 def-match2 
-;   SUBST-NEG-NEXT:not:1'5                                } search range end (exclusive)
+;   SUBST-NEG-NEXT:not:1'7                                } search range end (exclusive)
 ;   SUBST-NEG-NEXT:not:2'1          !~~~~~~~~~~~~~~~~~~~~   error: no match expected
-;   SUBST-NEG-NEXT:not:2'2                                  with "DEF_MATCH1" equal to "def-match1"
-;   SUBST-NEG-NEXT:not:2'3                                  with "DEF_MATCH2" equal to "def-match2"
-;   SUBST-NEG-NEXT:not:2'4                                } search range end (exclusive)
+;   SUBST-NEG-NEXT:not:2'2                                  for: CHECK-NOT: {{\[}}[DEF_MATCH1]] {{\[}}[DEF_MATCH2]]
+;   SUBST-NEG-NEXT:not:2'3                                  at: [[CHK_FILE]]:2
+;   SUBST-NEG-NEXT:not:2'4                                  with "DEF_MATCH1" equal to "def-match1"
+;   SUBST-NEG-NEXT:not:2'5                                  with "DEF_MATCH2" equal to "def-match2"
+;   SUBST-NEG-NEXT:not:2'6                                } search range end (exclusive)
 ;   SUBST-NEG-NEXT:              3: END 
 ; SUBST-NEG-V-NEXT:check:3          ^~~
 ;   SUBST-NEG-NEXT:>>>>>>
@@ -864,8 +919,10 @@
 ;   CAPTURE-NEG-NEXT:not:5'0                            {   search range start (exclusive)
 ;   CAPTURE-NEG-NEXT:              5: var in neg match: foo 
 ;   CAPTURE-NEG-NEXT:not:5'1          !~~~~~~~~~~~~~~~~~~~~   error: no match expected
-;   CAPTURE-NEG-NEXT:not:5'2                            !~~   captured var "VAR"
-;   CAPTURE-NEG-NEXT:not:5'3                                } search range end (exclusive)
+;   CAPTURE-NEG-NEXT:not:5'2                                  for: CHECK-NOT: var in neg match: {{\[}}[VAR:foo]]
+;   CAPTURE-NEG-NEXT:not:5'3                                  at: [[CHK_FILE]]:5
+;   CAPTURE-NEG-NEXT:not:5'4                            !~~   captured var "VAR"
+;   CAPTURE-NEG-NEXT:not:5'5                                } search range end (exclusive)
 ;   CAPTURE-NEG-NEXT:              6: END 
 ; CAPTURE-NEG-V-NEXT:check:6          ^~~
 ;   CAPTURE-NEG-NEXT:>>>>>>
@@ -904,7 +961,9 @@
 ; SUBST_NEXT-V-NEXT:check:1          ^~~
 ;   SUBST_NEXT-NEXT:next:2'0           {     } search range (exclusive bounds)
 ;   SUBST_NEXT-NEXT:next:2'1             !~~   error: match on wrong line
-; SUBST_NEXT-V-NEXT:next:2'2                   with "VAR" equal to "var"
+;   SUBST_NEXT-NEXT:next:2'2                   for: CHECK-NEXT: {{\[}}[VAR]]
+;   SUBST_NEXT-NEXT:next:2'3                   at: [[CHK_FILE]]:2
+; SUBST_NEXT-V-NEXT:next:2'4                   with "VAR" equal to "var"
 ;   SUBST_NEXT-NEXT:>>>>>>
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -933,8 +992,10 @@
 ; SUBST_SAME-V-NEXT:same:2'0           {   search range start (exclusive)
 ; SUBST_SAME-V-NEXT:              2: var 
 ; SUBST_SAME-V-NEXT:same:2'1         !~~   error: match on wrong line
-; SUBST_SAME-V-NEXT:same:2'2               with "VAR" equal to "var"
-; SUBST_SAME-V-NEXT:same:2'3             } search range end (exclusive)
+; SUBST_SAME-V-NEXT:same:2'2               for: CHECK-SAME: {{\[}}[VAR]]
+; SUBST_SAME-V-NEXT:same:2'3               at: [[CHK_FILE]]:2
+; SUBST_SAME-V-NEXT:same:2'4               with "VAR" equal to "var"
+; SUBST_SAME-V-NEXT:same:2'5             } search range end (exclusive)
 ; SUBST_SAME-V-NEXT:>>>>>>
 
 ;      SUBST_SAME-Q:<<<<<<
@@ -942,7 +1003,9 @@
 ; SUBST_SAME-Q-NEXT:same:2'0           {   search range start (exclusive)
 ; SUBST_SAME-Q-NEXT:              2: var 
 ; SUBST_SAME-Q-NEXT:same:2'1         !~~   error: match on wrong line
-; SUBST_SAME-Q-NEXT:same:2'2             } search range end (exclusive)
+; SUBST_SAME-Q-NEXT:same:2'2               for: CHECK-SAME: {{\[}}[VAR]]
+; SUBST_SAME-Q-NEXT:same:2'3               at: [[CHK_FILE]]:2
+; SUBST_SAME-Q-NEXT:same:2'4             } search range end (exclusive)
 ; SUBST_SAME-Q-NEXT:>>>>>>
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1084,6 +1147,8 @@
 ; POS-SEARCH-EMPTY-FILE-NEXT:              1: 
 ; POS-SEARCH-EMPTY-FILE-NEXT:check:1'0       {} search range (exclusive bounds)
 ; POS-SEARCH-EMPTY-FILE-NEXT:check:1'1          error: no match found in search range
+; POS-SEARCH-EMPTY-FILE-NEXT:check:1'2          for: CHECK: foo
+; POS-SEARCH-EMPTY-FILE-NEXT:check:1'3          at: [[CHK_FILE]]:1
 ; POS-SEARCH-EMPTY-FILE-NEXT:>>>>>>
 
 ; REDEFINE: %{opts} =
@@ -1125,8 +1190,10 @@
 ; SEARCH-BOF-EOF-MULTI-LINE-NEXT:              1: line 1 
 ; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'0       {         search range start (exclusive)
 ; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'1                 error: no match found in search range
+; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'2                 for: CHECK: foo
+; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'3                 at: [[CHK_FILE]]:1
 ; SEARCH-BOF-EOF-MULTI-LINE-NEXT:              2: line 2 
-; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'2               } search range end (exclusive)
+; SEARCH-BOF-EOF-MULTI-LINE-NEXT:check:1'4               } search range end (exclusive)
 ; SEARCH-BOF-EOF-MULTI-LINE-NEXT:>>>>>>
 
 ;--------------------------------------------------
diff --git a/llvm/test/FileCheck/dump-input/color.txt b/llvm/test/FileCheck/dump-input/color.txt
index 9d343c0e0fb08..e65651bb11884 100644
--- a/llvm/test/FileCheck/dump-input/color.txt
+++ b/llvm/test/FileCheck/dump-input/color.txt
@@ -17,7 +17,8 @@
 ; DEFINE:       -dump-input-context=2 %{opts} %t/check.txt < %t/input.txt \
 ; DEFINE:       2>&1 | \
 ; DEFINE:     %{reveal-ansi-escapes} | \
-; DEFINE:     FileCheck %s -match-full-lines -check-prefixes
+; DEFINE:     FileCheck %s -match-full-lines -DCHK_FILE=%t/check.txt \
+; DEFINE:         -check-prefixes
 
 ; REDEFINE: %{opts} =
 ; RUN: %{run} CHECK-Q
@@ -37,10 +38,12 @@
 ; CHECK-Q-NEXT: <bold><reset><bold-bright-black> 1: <reset><bold><reset>hello <reset>
 ; CHECK-Q-NEXT: <bold-red>dag:2'0                                            {          search range start (exclusive)
 ; CHECK-Q-NEXT: <reset><bold-red>dag:2'1                                                error: no match found in search range
+; CHECK-Q-NEXT: <reset><bold-red>dag:2'2                                                for: CHECK-DAG: hello
+; CHECK-Q-NEXT: <reset><bold-red>dag:2'3                                                at: [[CHK_FILE]]:2
 ; CHECK-Q-NEXT: <reset><bold-bright-black>       2: <reset><bold><reset>jello <reset>
-; CHECK-Q-NEXT: <bold-magenta>dag:2'2                                   ?               possible intended match
+; CHECK-Q-NEXT: <bold-magenta>dag:2'4                                   ?               possible intended match
 ; CHECK-Q-NEXT: <reset><bold-bright-black>       3: <reset><bold><reset>end <reset>
-; CHECK-Q-NEXT: <bold-red>dag:2'3                                           }           search range end (exclusive)
+; CHECK-Q-NEXT: <bold-red>dag:2'5                                           }           search range end (exclusive)
 ; CHECK-Q-NEXT: <reset><bold-bright-black>       4: <reset><bold><reset>foo <reset>
 ; CHECK-Q-NEXT: <bold-bright-black>              5: <reset><bold><reset>foo <reset>
 ; CHECK-Q-NEXT: <bold-bright-black>              .<reset>
@@ -58,11 +61,13 @@
 ; CHECK-V-NEXT: <bold-green>dag:1                                                      ^~~~~
 ; CHECK-V-NEXT: <reset><bold-red>dag:2'0                                                                  {        search range start (exclusive)
 ; CHECK-V-NEXT: <reset><bold-red>dag:2'1                                                                           error: no match found in search range
+; CHECK-V-NEXT: <reset><bold-red>dag:2'2                                                                           for: CHECK-DAG: hello
+; CHECK-V-NEXT: <reset><bold-red>dag:2'3                                                                           at: [[CHK_FILE]]:2
 ; CHECK-V-NEXT: <reset><bold-bright-black>        2: <reset><bold><bg-bold-cyan>jello <reset>
-; CHECK-V-NEXT: <bold-magenta>dag:2'2                                           ?                                  possible intended match
+; CHECK-V-NEXT: <bold-magenta>dag:2'4                                           ?                                  possible intended match
 ; CHECK-V-NEXT: <reset><bold-bright-black>        3: <reset><bold><bg-bold-cyan><reset>end<bg-bold-cyan> <reset>
 ; CHECK-V-NEXT: <bold-green>label:3                                                    ^~~
-; CHECK-V-NEXT: <reset><bold-red>dag:2'3                                                                }          search range end (exclusive)
+; CHECK-V-NEXT: <reset><bold-red>dag:2'5                                                                }          search range end (exclusive)
 ; CHECK-V-NEXT: <reset><bold-bright-black>        4: <reset><bold><bg-bold-cyan>foo <reset>
 ; CHECK-V-NEXT: <bold-bright-black>               5: <reset><bold><bg-bold-cyan>foo <reset>
 ; CHECK-V-NEXT: <bold-bright-black>               .<reset>
@@ -80,11 +85,13 @@
 ; CHECK-VV-NEXT: <reset><bold-cyan>dag:2'0                                              !~~~~                       discard: overlaps earlier match
 ; CHECK-VV-NEXT: <reset><bold-red>dag:2'1                                                                  {        search range start (exclusive)
 ; CHECK-VV-NEXT: <reset><bold-red>dag:2'2                                                                           error: no match found in search range
+; CHECK-VV-NEXT: <reset><bold-red>dag:2'3                                                                           for: CHECK-DAG: hello
+; CHECK-VV-NEXT: <reset><bold-red>dag:2'4                                                                           at: [[CHK_FILE]]:2
 ; CHECK-VV-NEXT: <reset><bold-bright-black>        2: <reset><bold><bg-bold-cyan>jello <reset>
-; CHECK-VV-NEXT: <bold-magenta>dag:2'3                                           ?                                  possible intended match
+; CHECK-VV-NEXT: <bold-magenta>dag:2'5                                           ?                                  possible intended match
 ; CHECK-VV-NEXT: <reset><bold-bright-black>        3: <reset><bold><bg-bold-cyan><reset>end<bg-bold-cyan> <reset>
 ; CHECK-VV-NEXT: <bold-green>label:3                                                    ^~~
-; CHECK-VV-NEXT: <reset><bold-red>dag:2'4                                                                }          search range end (exclusive)
+; CHECK-VV-NEXT: <reset><bold-red>dag:2'6                                                                }          search range end (exclusive)
 ; CHECK-VV-NEXT: <reset><bold-bright-black>        4: <reset><bold><bg-bold-cyan>foo <reset>
 ; CHECK-VV-NEXT: <bold-bright-black>               5: <reset><bold><bg-bold-cyan>foo <reset>
 ; CHECK-VV-NEXT: <bold-bright-black>               .<reset>
diff --git a/llvm/test/FileCheck/dump-input/context.txt b/llvm/test/FileCheck/dump-input/context.txt
index f5bfc78f656af..81585bda9dba2 100644
--- a/llvm/test/FileCheck/dump-input/context.txt
+++ b/llvm/test/FileCheck/dump-input/context.txt
@@ -70,6 +70,8 @@
 ; C0-NEXT:label:1'1     ^~~~
 ; C0-NEXT:next:2'0         {         search range start (exclusive)
 ; C0-NEXT:next:2'1           !~~~~   error: match on wrong line
+; C0-NEXT:next:2'2                   for: CHECK-NEXT: hello
+; C0-NEXT:next:2'3                   at: [[CHK_FILE]]:2
 ; C1-NEXT:          10: foo1 
 ; C2-NEXT:          11: foo2 
 ; C3-NEXT:          12: foo3 
@@ -89,7 +91,7 @@
 ; C1-NEXT:          23: foo1 
 ; C0-NEXT:          24: lab2 world 
 ; C0-NEXT:label:3       ^~~~
-; C0-NEXT:next:2'2          }        search range end (exclusive)
+; C0-NEXT:next:2'4          }        search range end (exclusive)
 ; C1-NEXT:          25: foo1 
 ; C2-NEXT:          26: foo2 
 ; C3-NEXT:          27: foo3 
@@ -122,9 +124,11 @@
 ; W5-NEXT:dag:2              ^~~~~~
 ; W5-NEXT:dag:3'0          {         search range start (exclusive)
 ; W5-NEXT:dag:3'1                    error: no match found in search range
+; W5-NEXT:dag:3'2                    for: CHECK-DAG: goodbye
+; W5-NEXT:dag:3'3                    at: [[CHK_FILE]]:3
 ; W5-NEXT:          10: foo1 
 ; W5-NEXT:dag:2         ~~~~~
-; W5-NEXT:dag:3'2       ?      possible intended match
+; W5-NEXT:dag:3'4       ?      possible intended match
 ; W5-NEXT:          11: foo2 
 ; W5-NEXT:dag:2         ~~~~~
 ; W5-NEXT:          12: foo3 
@@ -156,7 +160,7 @@
 ; W5-NEXT:dag:2         ~~~~~
 ; W5-NEXT:          24: lab2 world 
 ; W5-NEXT:label:4       ^~~~
-; W5-NEXT:dag:3'3           }        search range end (exclusive)
+; W5-NEXT:dag:3'5           }        search range end (exclusive)
 ; W5-NEXT:next:5'0         {         search range start (exclusive)
 ; W5-NEXT:next:5'1           !~~~~   error: match on wrong line
 
@@ -183,52 +187,60 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]
 ; 0 is an important boundary case.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv  %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=0 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,CS,CM,CE
+; RUN:               -dump-input-context=0 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,CS,CM,CE
 
 ; 1 is an important boundary case.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ; 4 is the boundary case at which all ellipses are present in our test.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=4 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,CS,CM,CE
+; RUN:               -dump-input-context=4 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,CS,CM,CE
 
 ; 5 is the boundary case at which the start ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=5 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
+; RUN:               -dump-input-context=5 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
 
 ; 6 is the boundary case at which the middle ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=6 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,CE
+; RUN:               -dump-input-context=6 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,C5,C6,CE
 
 ; 7 is the boundary case at which the end ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=7 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
+; RUN:               -dump-input-context=7 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
 
 ; Make sure all is fine when -dump-input-context is far larger than the input.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=200 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
+; RUN:               -dump-input-context=200 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
 
 ;--------------------------------------------------
 ; Check that -dump-input-context default is 5.
 ;--------------------------------------------------
 
 ; RUN: %ProtectFileCheckOutput \
-; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
+; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
 
 ;--------------------------------------------------
 ; Check multiple -dump-input-context options.
@@ -246,8 +258,9 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=1 -dump-input-context=1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=1 -dump-input-context=1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
 ; Check precedence.
@@ -255,13 +268,15 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=0 -dump-input-context=1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=0 -dump-input-context=1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=1 -dump-input-context=0 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=1 -dump-input-context=0 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
 ; Check that FILECHECK_OPTS isn't handled differently.
@@ -269,13 +284,15 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]
 
 ; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-context=0 \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-context=1 \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=0 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+; RUN:               -dump-input-context=0 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=C0,C1,CS,CM,CE
 
 ;--------------------------------------------------
 ; Check how annotations on input lines that might be elided by ellipses affect
@@ -286,12 +303,14 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]
 ; elided input lines are considered.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.wide.chk < %t.wide.in 2>&1 \
-; RUN:               -dump-input-context=5 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=W5,WM
+; RUN:               -dump-input-context=5 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.wide.chk \
+; RUN:             -check-prefixes=W5,WM
 
 ; At -dump-input-context=6, the ellipsis is not useful even when annotations on
 ; elided input lines are considered.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.wide.chk < %t.wide.in 2>&1 \
-; RUN:               -dump-input-context=6 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=W5,W6
+; RUN:               -dump-input-context=6 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.wide.chk \
+; RUN:             -check-prefixes=W5,W6
diff --git a/llvm/test/FileCheck/dump-input/enable.txt b/llvm/test/FileCheck/dump-input/enable.txt
index 3708ef94a4f9d..43699f31b71b7 100644
--- a/llvm/test/FileCheck/dump-input/enable.txt
+++ b/llvm/test/FileCheck/dump-input/enable.txt
@@ -87,8 +87,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; FileCheck fail, -v => dump, no trace.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
-; RUN:               -match-full-lines -v 2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
+; RUN:               -match-full-lines -v 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
 ; RUN:                -check-prefixes=NOTRACE,ERR,DUMP-ERR,DUMP-ERR-V
 
 ;--------------------------------------------------
@@ -107,8 +107,9 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; FileCheck fail, no -v => dump, no trace.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
-; RUN:               -match-full-lines -dump-input=fail 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=NOTRACE,ERR,DUMP-ERR
+; RUN:               -match-full-lines -dump-input=fail 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
+; RUN:             -check-prefixes=NOTRACE,ERR,DUMP-ERR
 
 ; FileCheck success, -v => no dump, no trace.
 ; RUN: %ProtectFileCheckOutput \
@@ -120,8 +121,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; FileCheck fail, -v => dump, no trace.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
-; RUN:               -match-full-lines -dump-input=fail -v 2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
+; RUN:               -match-full-lines -dump-input=fail -v 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
 ; RUN:                -check-prefixes=NOTRACE,ERR,DUMP-ERR,DUMP-ERR-V
 
 ;--------------------------------------------------
@@ -137,8 +138,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; FileCheck fail, -v => dump, no trace.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
-; RUN:               -match-full-lines -dump-input=always -v 2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
+; RUN:               -match-full-lines -dump-input=always -v 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
 ; RUN:                -check-prefixes=NOTRACE,ERR,DUMP-ERR,DUMP-ERR-V
 
 ;--------------------------------------------------
@@ -160,8 +161,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
 ; RUN:               -match-full-lines -dump-input=fail -dump-input=fail -v \
-; RUN:               2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
+; RUN:               2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
 ; RUN:                -check-prefixes=NOTRACE,ERR,DUMP-ERR,DUMP-ERR-V
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -185,8 +186,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
 ; RUN:               -match-full-lines -dump-input=fail -dump-input=never -v \
-; RUN:               2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
+; RUN:               2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.check \
 ; RUN:                -check-prefixes=NOTRACE,ERR,DUMP-ERR,DUMP-ERR-V
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -250,7 +251,9 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find opt
 ; DUMP-ERR-V-NEXT:check:1      ^~~~~
 ;   DUMP-ERR-NEXT:next:2'0         {   search range start (exclusive)
 ;   DUMP-ERR-NEXT:next:2'1             error: no match found in search range
+;   DUMP-ERR-NEXT:next:2'2             for: CHECK-NEXT: world
+;   DUMP-ERR-NEXT:next:2'3             at: [[CHK_FILE]]:2
 ;   DUMP-ERR-NEXT:          2: whirled 
-;   DUMP-ERR-NEXT:next:2'2     ?         possible intended match
-;   DUMP-ERR-NEXT:next:2'3             } search range end (exclusive)
+;   DUMP-ERR-NEXT:next:2'4     ?         possible intended match
+;   DUMP-ERR-NEXT:next:2'5             } search range end (exclusive)
 ;   DUMP-ERR-NEXT:>>>>>>
diff --git a/llvm/test/FileCheck/dump-input/filter.txt b/llvm/test/FileCheck/dump-input/filter.txt
index 5d8696830a6e5..db26bdbacf3d3 100644
--- a/llvm/test/FileCheck/dump-input/filter.txt
+++ b/llvm/test/FileCheck/dump-input/filter.txt
@@ -76,256 +76,264 @@
 ; Directives for checking the dump.
 ;--------------------------------------------------
 
-;      ALL:<<<<<<
-; ALL-NEXT:         1: start 
-; ALL-NEXT:check:1     ^~~~~
-; ALL-NEXT:         2: foo0 
-; ALL-NEXT:         3: foo1 
-; ALL-NEXT:         4: foo2 
-; ALL-NEXT:         5: foo3 
-; ALL-NEXT:         6: foo4 
-; ALL-NEXT:         7: foo5 
-; ALL-NEXT:         8: foo6 
-; ALL-NEXT:         9: foo7 
-; ALL-NEXT:        10: foo8 
-; ALL-NEXT:        11: foo9 
-; ALL-NEXT:        12: hello 
-; ALL-NEXT:check:2     ^~~~~~
-; ALL-NEXT:        13: foo0 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        14: foo1 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        15: foo2 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        16: foo3 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        17: foo4 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        18: foo5 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        19: foo6 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        20: foo7 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        21: foo8 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        22: foo9 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:        23: world 
-; ALL-NEXT:check:2     ~~~~~
-; ALL-NEXT:not:3'0         {   search range start (exclusive)
-; ALL-NEXT:        24: foo0 
-; ALL-NEXT:        25: foo1 
-; ALL-NEXT:        26: foo2 
-; ALL-NEXT:        27: foo3 
-; ALL-NEXT:        28: foo4 
-; ALL-NEXT:        29: foo5 
-; ALL-NEXT:        30: foo6 
-; ALL-NEXT:        31: foo7 
-; ALL-NEXT:        32: foo8 
-; ALL-NEXT:        33: foo9 
-; ALL-NEXT:        34: bye 
-; ALL-NEXT:not:3'1     !~~~  error: no match expected
-; ALL-NEXT:        35: foo0 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        36: foo1 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        37: foo2 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        38: foo3 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        39: foo4 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        40: foo5 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        41: foo6 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        42: foo7 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        43: foo8 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        44: foo9 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        45: sleep 
-; ALL-NEXT:not:3'1     ~~~~~
-; ALL-NEXT:        46: foo0 
-; ALL-NEXT:        47: foo1 
-; ALL-NEXT:        48: foo2 
-; ALL-NEXT:        49: foo3 
-; ALL-NEXT:        50: foo4 
-; ALL-NEXT:        51: foo5 
-; ALL-NEXT:        52: foo6 
-; ALL-NEXT:        53: foo7 
-; ALL-NEXT:        54: foo8 
-; ALL-NEXT:        55: foo9 
-; ALL-NEXT:not:3'2          } search range end (exclusive)
-; ALL-NEXT:        56: end 
-; ALL-NEXT:check:4     ^~~
-; ALL-NEXT:>>>>>>
-
-;      ANNOTATION-FULL:<<<<<<
-; ANNOTATION-FULL-NEXT:         1: start 
-; ANNOTATION-FULL-NEXT:check:1     ^~~~~
-; ANNOTATION-FULL-NEXT:         2: foo0 
-; ANNOTATION-FULL-NEXT:         3: foo1 
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:        10: foo8 
-; ANNOTATION-FULL-NEXT:        11: foo9 
-; ANNOTATION-FULL-NEXT:        12: hello 
-; ANNOTATION-FULL-NEXT:check:2     ^~~~~~
-; ANNOTATION-FULL-NEXT:        13: foo0 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        14: foo1 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        15: foo2 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        16: foo3 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        17: foo4 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        18: foo5 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        19: foo6 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        20: foo7 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        21: foo8 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        22: foo9 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:        23: world 
-; ANNOTATION-FULL-NEXT:check:2     ~~~~~
-; ANNOTATION-FULL-NEXT:not:3'0         {   search range start (exclusive)
-; ANNOTATION-FULL-NEXT:        24: foo0 
-; ANNOTATION-FULL-NEXT:        25: foo1 
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:        32: foo8 
-; ANNOTATION-FULL-NEXT:        33: foo9 
-; ANNOTATION-FULL-NEXT:        34: bye 
-; ANNOTATION-FULL-NEXT:not:3'1     !~~~  error: no match expected
-; ANNOTATION-FULL-NEXT:        35: foo0 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        36: foo1 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        37: foo2 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        38: foo3 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        39: foo4 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        40: foo5 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        41: foo6 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        42: foo7 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        43: foo8 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        44: foo9 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        45: sleep 
-; ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
-; ANNOTATION-FULL-NEXT:        46: foo0 
-; ANNOTATION-FULL-NEXT:        47: foo1 
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:         .
-; ANNOTATION-FULL-NEXT:        53: foo7 
-; ANNOTATION-FULL-NEXT:        54: foo8 
-; ANNOTATION-FULL-NEXT:        55: foo9 
-; ANNOTATION-FULL-NEXT:not:3'2          } search range end (exclusive)
-; ANNOTATION-FULL-NEXT:        56: end 
-; ANNOTATION-FULL-NEXT:check:4     ^~~
-; ANNOTATION-FULL-NEXT:>>>>>>
-
-;      ANNOTATION:<<<<<<
-; ANNOTATION-NEXT:         1: start 
-; ANNOTATION-NEXT:check:1     ^~~~~
-; ANNOTATION-NEXT:         2: foo0 
-; ANNOTATION-NEXT:         3: foo1 
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:        10: foo8 
-; ANNOTATION-NEXT:        11: foo9 
-; ANNOTATION-NEXT:        12: hello 
-; ANNOTATION-NEXT:check:2     ^~~~~~
-; ANNOTATION-NEXT:        13: foo0 
-; ANNOTATION-NEXT:check:2     ~~~~~
-; ANNOTATION-NEXT:        14: foo1 
-; ANNOTATION-NEXT:check:2     ~~~~~
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:        21: foo8 
-; ANNOTATION-NEXT:check:2     ~~~~~
-; ANNOTATION-NEXT:        22: foo9 
-; ANNOTATION-NEXT:check:2     ~~~~~
-; ANNOTATION-NEXT:        23: world 
-; ANNOTATION-NEXT:check:2     ~~~~~
-; ANNOTATION-NEXT:not:3'0         {   search range start (exclusive)
-; ANNOTATION-NEXT:        24: foo0 
-; ANNOTATION-NEXT:        25: foo1 
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:        32: foo8 
-; ANNOTATION-NEXT:        33: foo9 
-; ANNOTATION-NEXT:        34: bye 
-; ANNOTATION-NEXT:not:3'1     !~~~  error: no match expected
-; ANNOTATION-NEXT:        35: foo0 
-; ANNOTATION-NEXT:not:3'1     ~~~~~
-; ANNOTATION-NEXT:        36: foo1 
-; ANNOTATION-NEXT:not:3'1     ~~~~~
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:         .
-; ANNOTATION-NEXT:        53: foo7 
-; ANNOTATION-NEXT:        54: foo8 
-; ANNOTATION-NEXT:        55: foo9 
-; ANNOTATION-NEXT:not:3'2          } search range end (exclusive)
-; ANNOTATION-NEXT:        56: end 
-; ANNOTATION-NEXT:check:4     ^~~
-; ANNOTATION-NEXT:>>>>>>
-
-;      ERROR:<<<<<<
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:        21: foo8 
-; ERROR-NEXT:check:2     ~~~~~
-; ERROR-NEXT:        22: foo9 
-; ERROR-NEXT:check:2     ~~~~~
-; ERROR-NEXT:        23: world 
-; ERROR-NEXT:check:2     ~~~~~
-; ERROR-NEXT:not:3'0         {   search range start (exclusive)
-; ERROR-NEXT:        24: foo0 
-; ERROR-NEXT:        25: foo1 
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:        32: foo8 
-; ERROR-NEXT:        33: foo9 
-; ERROR-NEXT:        34: bye 
-; ERROR-NEXT:not:3'1     !~~~  error: no match expected
-; ERROR-NEXT:        35: foo0 
-; ERROR-NEXT:not:3'1     ~~~~~
-; ERROR-NEXT:        36: foo1 
-; ERROR-NEXT:not:3'1     ~~~~~
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:         .
-; ERROR-NEXT:        53: foo7 
-; ERROR-NEXT:        54: foo8 
-; ERROR-NEXT:        55: foo9 
-; ERROR-NEXT:not:3'2          } search range end (exclusive)
-; ERROR-NEXT:        56: end 
-; ERROR-NEXT:check:4     ^~~
-; ERROR-NEXT:>>>>>>
+;               ALL:<<<<<<
+;          ALL-NEXT:         1: start 
+;          ALL-NEXT:check:1     ^~~~~
+;          ALL-NEXT:         2: foo0 
+;          ALL-NEXT:         3: foo1 
+;          ALL-NEXT:         4: foo2 
+;          ALL-NEXT:         5: foo3 
+;          ALL-NEXT:         6: foo4 
+;          ALL-NEXT:         7: foo5 
+;          ALL-NEXT:         8: foo6 
+;          ALL-NEXT:         9: foo7 
+;          ALL-NEXT:        10: foo8 
+;          ALL-NEXT:        11: foo9 
+;          ALL-NEXT:        12: hello 
+;          ALL-NEXT:check:2     ^~~~~~
+;          ALL-NEXT:        13: foo0 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        14: foo1 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        15: foo2 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        16: foo3 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        17: foo4 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        18: foo5 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        19: foo6 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        20: foo7 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        21: foo8 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        22: foo9 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:        23: world 
+;          ALL-NEXT:check:2     ~~~~~
+;          ALL-NEXT:not:3'0         {   search range start (exclusive)
+;          ALL-NEXT:        24: foo0 
+;          ALL-NEXT:        25: foo1 
+;          ALL-NEXT:        26: foo2 
+;          ALL-NEXT:        27: foo3 
+;          ALL-NEXT:        28: foo4 
+;          ALL-NEXT:        29: foo5 
+;          ALL-NEXT:        30: foo6 
+;          ALL-NEXT:        31: foo7 
+;          ALL-NEXT:        32: foo8 
+;          ALL-NEXT:        33: foo9 
+;          ALL-NEXT:        34: bye 
+;          ALL-NEXT:not:3'1     !~~~  error: no match expected
+; ALL-NEXT{LITERAL}:not:3'2           for: CHECK-NOT: bye{{(.|[[:space:]])*}}sleep
+;          ALL-NEXT:not:3'3           at: [[CHK_FILE]]:3
+;          ALL-NEXT:        35: foo0 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        36: foo1 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        37: foo2 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        38: foo3 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        39: foo4 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        40: foo5 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        41: foo6 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        42: foo7 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        43: foo8 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        44: foo9 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        45: sleep 
+;          ALL-NEXT:not:3'1     ~~~~~
+;          ALL-NEXT:        46: foo0 
+;          ALL-NEXT:        47: foo1 
+;          ALL-NEXT:        48: foo2 
+;          ALL-NEXT:        49: foo3 
+;          ALL-NEXT:        50: foo4 
+;          ALL-NEXT:        51: foo5 
+;          ALL-NEXT:        52: foo6 
+;          ALL-NEXT:        53: foo7 
+;          ALL-NEXT:        54: foo8 
+;          ALL-NEXT:        55: foo9 
+;          ALL-NEXT:not:3'4          } search range end (exclusive)
+;          ALL-NEXT:        56: end 
+;          ALL-NEXT:check:4     ^~~
+;          ALL-NEXT:>>>>>>
+
+;               ANNOTATION-FULL:<<<<<<
+;          ANNOTATION-FULL-NEXT:         1: start 
+;          ANNOTATION-FULL-NEXT:check:1     ^~~~~
+;          ANNOTATION-FULL-NEXT:         2: foo0 
+;          ANNOTATION-FULL-NEXT:         3: foo1 
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:        10: foo8 
+;          ANNOTATION-FULL-NEXT:        11: foo9 
+;          ANNOTATION-FULL-NEXT:        12: hello 
+;          ANNOTATION-FULL-NEXT:check:2     ^~~~~~
+;          ANNOTATION-FULL-NEXT:        13: foo0 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        14: foo1 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        15: foo2 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        16: foo3 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        17: foo4 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        18: foo5 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        19: foo6 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        20: foo7 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        21: foo8 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        22: foo9 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:        23: world 
+;          ANNOTATION-FULL-NEXT:check:2     ~~~~~
+;          ANNOTATION-FULL-NEXT:not:3'0         {   search range start (exclusive)
+;          ANNOTATION-FULL-NEXT:        24: foo0 
+;          ANNOTATION-FULL-NEXT:        25: foo1 
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:        32: foo8 
+;          ANNOTATION-FULL-NEXT:        33: foo9 
+;          ANNOTATION-FULL-NEXT:        34: bye 
+;          ANNOTATION-FULL-NEXT:not:3'1     !~~~  error: no match expected
+; ANNOTATION-FULL-NEXT{LITERAL}:not:3'2           for: CHECK-NOT: bye{{(.|[[:space:]])*}}sleep
+;          ANNOTATION-FULL-NEXT:not:3'3           at: [[CHK_FILE]]:3
+;          ANNOTATION-FULL-NEXT:        35: foo0 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        36: foo1 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        37: foo2 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        38: foo3 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        39: foo4 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        40: foo5 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        41: foo6 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        42: foo7 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        43: foo8 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        44: foo9 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        45: sleep 
+;          ANNOTATION-FULL-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-FULL-NEXT:        46: foo0 
+;          ANNOTATION-FULL-NEXT:        47: foo1 
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:         .
+;          ANNOTATION-FULL-NEXT:        53: foo7 
+;          ANNOTATION-FULL-NEXT:        54: foo8 
+;          ANNOTATION-FULL-NEXT:        55: foo9 
+;          ANNOTATION-FULL-NEXT:not:3'4          } search range end (exclusive)
+;          ANNOTATION-FULL-NEXT:        56: end 
+;          ANNOTATION-FULL-NEXT:check:4     ^~~
+;          ANNOTATION-FULL-NEXT:>>>>>>
+
+;               ANNOTATION:<<<<<<
+;          ANNOTATION-NEXT:         1: start 
+;          ANNOTATION-NEXT:check:1     ^~~~~
+;          ANNOTATION-NEXT:         2: foo0 
+;          ANNOTATION-NEXT:         3: foo1 
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:        10: foo8 
+;          ANNOTATION-NEXT:        11: foo9 
+;          ANNOTATION-NEXT:        12: hello 
+;          ANNOTATION-NEXT:check:2     ^~~~~~
+;          ANNOTATION-NEXT:        13: foo0 
+;          ANNOTATION-NEXT:check:2     ~~~~~
+;          ANNOTATION-NEXT:        14: foo1 
+;          ANNOTATION-NEXT:check:2     ~~~~~
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:        21: foo8 
+;          ANNOTATION-NEXT:check:2     ~~~~~
+;          ANNOTATION-NEXT:        22: foo9 
+;          ANNOTATION-NEXT:check:2     ~~~~~
+;          ANNOTATION-NEXT:        23: world 
+;          ANNOTATION-NEXT:check:2     ~~~~~
+;          ANNOTATION-NEXT:not:3'0         {   search range start (exclusive)
+;          ANNOTATION-NEXT:        24: foo0 
+;          ANNOTATION-NEXT:        25: foo1 
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:        32: foo8 
+;          ANNOTATION-NEXT:        33: foo9 
+;          ANNOTATION-NEXT:        34: bye 
+;          ANNOTATION-NEXT:not:3'1     !~~~  error: no match expected
+; ANNOTATION-NEXT{LITERAL}:not:3'2           for: CHECK-NOT: bye{{(.|[[:space:]])*}}sleep
+;          ANNOTATION-NEXT:not:3'3           at: [[CHK_FILE]]:3
+;          ANNOTATION-NEXT:        35: foo0 
+;          ANNOTATION-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-NEXT:        36: foo1 
+;          ANNOTATION-NEXT:not:3'1     ~~~~~
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:         .
+;          ANNOTATION-NEXT:        53: foo7 
+;          ANNOTATION-NEXT:        54: foo8 
+;          ANNOTATION-NEXT:        55: foo9 
+;          ANNOTATION-NEXT:not:3'4          } search range end (exclusive)
+;          ANNOTATION-NEXT:        56: end 
+;          ANNOTATION-NEXT:check:4     ^~~
+;          ANNOTATION-NEXT:>>>>>>
+
+;               ERROR:<<<<<<
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:        21: foo8 
+;          ERROR-NEXT:check:2     ~~~~~
+;          ERROR-NEXT:        22: foo9 
+;          ERROR-NEXT:check:2     ~~~~~
+;          ERROR-NEXT:        23: world 
+;          ERROR-NEXT:check:2     ~~~~~
+;          ERROR-NEXT:not:3'0         {   search range start (exclusive)
+;          ERROR-NEXT:        24: foo0 
+;          ERROR-NEXT:        25: foo1 
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:        32: foo8 
+;          ERROR-NEXT:        33: foo9 
+;          ERROR-NEXT:        34: bye 
+;          ERROR-NEXT:not:3'1     !~~~  error: no match expected
+; ERROR-NEXT{LITERAL}:not:3'2           for: CHECK-NOT: bye{{(.|[[:space:]])*}}sleep
+;          ERROR-NEXT:not:3'3           at: [[CHK_FILE]]:3
+;          ERROR-NEXT:        35: foo0 
+;          ERROR-NEXT:not:3'1     ~~~~~
+;          ERROR-NEXT:        36: foo1 
+;          ERROR-NEXT:not:3'1     ~~~~~
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:         .
+;          ERROR-NEXT:        53: foo7 
+;          ERROR-NEXT:        54: foo8 
+;          ERROR-NEXT:        55: foo9 
+;          ERROR-NEXT:not:3'4          } search range end (exclusive)
+;          ERROR-NEXT:        56: end 
+;          ERROR-NEXT:check:4     ^~~
+;          ERROR-NEXT:>>>>>>
 
 ;--------------------------------------------------
 ; Check -dump-input-filter=<bad value>.
@@ -344,23 +352,26 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=all \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL
+; RUN:               -dump-input-filter=all | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ALL
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=annotation-full \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION-FULL
+; RUN:               -dump-input-filter=annotation-full | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=ANNOTATION-FULL
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=annotation \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION
+; RUN:               -dump-input-filter=annotation | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=ANNOTATION
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=error \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR
+; RUN:               -dump-input-filter=error | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:             -check-prefixes=ERROR
 
 ;--------------------------------------------------
 ; Check -dump-input-filter defaults.
@@ -368,20 +379,20 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 
 ; no -dump-input => -dump-input-filter=error
 ; RUN: %ProtectFileCheckOutput \
-; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR
+; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERROR
 
 ; -dump-input=fail => -dump-input-filter=error
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input=fail \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR
+; RUN:               -dump-input=fail | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERROR
 
 ; -dump-input=always => -dump-input-filter=all
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input=always \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL
+; RUN:               -dump-input=always | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ALL
 
 ;--------------------------------------------------
 ; Check multiple -dump-input-filter options.
@@ -400,8 +411,8 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 ; all, all => all
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=all -dump-input-filter=all \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL
+; RUN:               -dump-input-filter=all -dump-input-filter=all | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ALL
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
 ; Check precedence.
@@ -410,21 +421,22 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 ; all, annotation-full => all
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=all -dump-input-filter=annotation-full \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL
+; RUN:     -dump-input-filter=all -dump-input-filter=annotation-full | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ALL
 
 ; annotation-full, annotation => annotation-full
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=annotation-full \
-; RUN:               -dump-input-filter=annotation \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION-FULL
+; RUN:     -dump-input-filter=annotation-full -dump-input-filter=annotation | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:       -check-prefixes=ANNOTATION-FULL
 
 ; annotation, error => annotation
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=annotation -dump-input-filter=error \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION
+; RUN:     -dump-input-filter=annotation -dump-input-filter=error | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:       -check-prefixes=ANNOTATION
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
 ; Check that order doesn't matter.
@@ -433,8 +445,9 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 ; error, annotation => annotation
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=error -dump-input-filter=annotation \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION
+; RUN:     -dump-input-filter=error -dump-input-filter=annotation | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:       -check-prefixes=ANNOTATION
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
 ; Check that FILECHECK_OPTS isn't handled differently.
@@ -443,14 +456,16 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 ; annotation, error => annotation
 ; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-filter=annotation \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=error \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION
+; RUN:               -dump-input-filter=error | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:     -check-prefixes=ANNOTATION
 
 ; error, annotation => annotation
 ; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-filter=error \
 ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-filter=annotation \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION
+; RUN:               -dump-input-filter=annotation | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+; RUN:     -check-prefixes=ANNOTATION
 
 ;--------------------------------------------------
 ; Check the case where all input lines are filtered out.
@@ -496,23 +511,26 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=0 -dump-input-filter=error \
-; RUN:               %t.chk-err.chk < %t.chk-err.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=CHK-ERR
+; RUN:     %t.chk-err.chk < %t.chk-err.in 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk-err.chk \
+; RUN:       -check-prefixes=CHK-ERR
 
 ;      CHK-ERR:<<<<<<
 ; CHK-ERR-NEXT:           1: start 
 ; CHK-ERR-NEXT:check:1'0    {        search range start (exclusive)
 ; CHK-ERR-NEXT:check:1'1             error: no match found in search range
+; CHK-ERR-NEXT:check:1'2             for: CHECK: jello
+; CHK-ERR-NEXT:check:1'3             at: [[CHK_FILE]]:1
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:           6: hello 
-; CHK-ERR-NEXT:check:1'2     ?       possible intended match
+; CHK-ERR-NEXT:check:1'4     ?       possible intended match
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:           .
 ; CHK-ERR-NEXT:          11: end 
-; CHK-ERR-NEXT:check:1'3         } search range end (exclusive)
+; CHK-ERR-NEXT:check:1'5         } search range end (exclusive)
 ; CHK-ERR-NEXT:>>>>>>
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -536,8 +554,9 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=0 -dump-input-filter=error \
-; RUN:               %t.next-err.chk < %t.next-err.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=NEXT-ERR
+; RUN:     %t.next-err.chk < %t.next-err.in 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.next-err.chk \
+; RUN:       -check-prefixes=NEXT-ERR
 
 ;      NEXT-ERR:<<<<<<
 ; NEXT-ERR-NEXT:          1: start 
@@ -547,11 +566,13 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 ; NEXT-ERR-NEXT:          .
 ; NEXT-ERR-NEXT:          6: hello 
 ; NEXT-ERR-NEXT:next:2'1     !~~~~   error: match on wrong line
+; NEXT-ERR-NEXT:next:2'2             for: CHECK-NEXT: hello
+; NEXT-ERR-NEXT:next:2'3             at: [[CHK_FILE]]:2
 ; NEXT-ERR-NEXT:          .
 ; NEXT-ERR-NEXT:          .
 ; NEXT-ERR-NEXT:          .
 ; NEXT-ERR-NEXT:         11: end 
-; NEXT-ERR-NEXT:next:2'2         } search range end (exclusive)
+; NEXT-ERR-NEXT:next:2'4         } search range end (exclusive)
 ; NEXT-ERR-NEXT:>>>>>>
 
 ;- - - - - - - - - - - - - - - - - - - - - - - - -
@@ -569,17 +590,20 @@ BADVAL:{{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot f
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input-context=0 -dump-input-filter=error \
-; RUN:               %t.invalid.chk < %t.invalid.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines -check-prefixes=INVALID -strict-whitespace
+; RUN:     %t.invalid.chk < %t.invalid.in 2>&1 | \
+; RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.invalid.chk \
+; RUN:       -check-prefixes=INVALID -strict-whitespace
 
 ;      INVALID:<<<<<<
 ; INVALID-NEXT:           1: start 
 ; INVALID-NEXT:check:1'0    {        search range start (exclusive)
 ; INVALID-NEXT:check:1'1             error: match failed for invalid pattern
-; INVALID-NEXT:check:1'2             unable to substitute variable or numeric expression: overflow error
+; INVALID-NEXT:check:1'2             for: CHECK: {{\[}}[#0x0 - 0x1]]
+; INVALID-NEXT:check:1'3             at: [[CHK_FILE]]:1
+; INVALID-NEXT:check:1'4             unable to substitute variable or numeric expression: overflow error
 ; INVALID-NEXT:           .
 ; INVALID-NEXT:           .
 ; INVALID-NEXT:           .
 ; INVALID-NEXT:           6: end 
-; INVALID-NEXT:check:1'3         } search range end (exclusive)
+; INVALID-NEXT:check:1'5         } search range end (exclusive)
 ; INVALID-NEXT:>>>>>>
diff --git a/llvm/test/FileCheck/dump-input/search-range-annotations/check-label-follows.txt b/llvm/test/FileCheck/dump-input/search-range-annotations/check-label-follows.txt
index 098c63765c0ca..81623a8452148 100644
--- a/llvm/test/FileCheck/dump-input/search-range-annotations/check-label-follows.txt
+++ b/llvm/test/FileCheck/dump-input/search-range-annotations/check-label-follows.txt
@@ -11,7 +11,7 @@ RUN: split-file %s %t
 RUN: %ProtectFileCheckOutput \
 RUN: not FileCheck -dump-input-context=2 -v %t/check.txt < %t/input.txt \
 RUN:               -dump-input-filter=error 2>&1 | \
-RUN:   FileCheck %s -match-full-lines -check-prefix=DMP
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t/check.txt -check-prefix=DMP
 
      DMP:<<<<<<
 DMP-NEXT:           1: offload triples: 
@@ -19,8 +19,10 @@ DMP-NEXT:label:1'0     ^~~~~~~~~~~~~~~~
 DMP-NEXT:label:1'1     ^~~~~~~~~~~~~~~~
 DMP-NEXT:check:2'0                    {   search range start (exclusive)
 DMP-NEXT:check:2'1                        error: no match found in search range
+DMP-NEXT:check:2'2                        for: CHECK: nvptx64-nvidia-cuda
+DMP-NEXT:check:2'3                        at: [[CHK_FILE]]:2
 DMP-NEXT:           2: - x86_64-linux-gnu 
-DMP-NEXT:check:2'2       ?                  possible intended match
+DMP-NEXT:check:2'4       ?                  possible intended match
 DMP-NEXT:           3: - x86_64-unknown-linux-gnu 
 DMP-NEXT:           4: - x86_64-pc-linux-gnu 
 DMP-NEXT:           .
@@ -30,7 +32,7 @@ DMP-NEXT:          13: - x86_64-linux-android
 DMP-NEXT:          14: - amdgcn-amd-amdhsa
 DMP-NEXT:          15: host triples: 
 DMP-NEXT:label:3       ^~~~~~~~~~~~~
-DMP-NEXT:check:2'3                  }  search range end (exclusive)
+DMP-NEXT:check:2'5                  }  search range end (exclusive)
 DMP-NEXT:          16: - nvptx64-nvidia-cuda 
 DMP-NEXT:          17: - x86_64-linux-gnu 
 DMP-NEXT:           .
diff --git a/llvm/test/FileCheck/dump-input/search-range-annotations/check-next-same.txt b/llvm/test/FileCheck/dump-input/search-range-annotations/check-next-same.txt
index 0767d4b734590..93c8b1a841b33 100644
--- a/llvm/test/FileCheck/dump-input/search-range-annotations/check-next-same.txt
+++ b/llvm/test/FileCheck/dump-input/search-range-annotations/check-next-same.txt
@@ -11,12 +11,14 @@ RUN: split-file %s %t
 RUN: %ProtectFileCheckOutput \
 RUN: not FileCheck -dump-input-context=2 -v %t/next.txt < %t/input.txt \
 RUN:               -dump-input-filter=error 2>&1 | \
-RUN:   FileCheck %s -match-full-lines -check-prefixes=DMP,DMP_NEXT
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t/next.txt \
+RUN:             -check-prefixes=DMP,DMP_NEXT
 
 RUN: %ProtectFileCheckOutput \
 RUN: not FileCheck -dump-input-context=2 -v %t/same.txt < %t/input.txt \
 RUN:               -dump-input-filter=error 2>&1 | \
-RUN:   FileCheck %s -match-full-lines -check-prefixes=DMP,DMP_SAME
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t/same.txt \
+RUN:             -check-prefixes=DMP,DMP_SAME
 
           DMP:<<<<<<
      DMP-NEXT:          1: start 
@@ -33,8 +35,12 @@ DMP_SAME-NEXT:same:2'0         {   search range start (exclusive)
      DMP-NEXT:         13: end 
 DMP_NEXT-NEXT:next:2'1     !~~   error: match on wrong line
 DMP_SAME-NEXT:same:2'1     !~~   error: match on wrong line
-DMP_NEXT-NEXT:next:2'2         } search range end (exclusive)
-DMP_SAME-NEXT:same:2'2         } search range end (exclusive)
+DMP_NEXT-NEXT:next:2'2           for: CHECK-NEXT: end
+DMP_SAME-NEXT:same:2'2           for: CHECK-SAME: end
+DMP_NEXT-NEXT:next:2'3           at: [[CHK_FILE]]:2
+DMP_SAME-NEXT:same:2'3           at: [[CHK_FILE]]:2
+DMP_NEXT-NEXT:next:2'4         } search range end (exclusive)
+DMP_SAME-NEXT:same:2'4         } search range end (exclusive)
      DMP-NEXT:>>>>>>
 
 ;--- next.txt
diff --git a/llvm/test/FileCheck/dump-input/search-range-annotations/check-not.txt b/llvm/test/FileCheck/dump-input/search-range-annotations/check-not.txt
index 7cae1b85bb47a..d79d6025f9fc5 100644
--- a/llvm/test/FileCheck/dump-input/search-range-annotations/check-not.txt
+++ b/llvm/test/FileCheck/dump-input/search-range-annotations/check-not.txt
@@ -1,4 +1,4 @@
-; Because -dump-input-filter=error includes a failed directive's search range,
+SAME Because -dump-input-filter=error includes a failed directive's search range,
 ; input lines 1 and 62 below are revealed, and -dump-input-context=2 reveals the
 ; surrounding lines.  Even with only line 1, it looks like the host list
 ; includes a GPU triple.  Line 62 and its context reveals we have an
@@ -12,7 +12,7 @@ RUN: split-file %s %t
 RUN: %ProtectFileCheckOutput \
 RUN: not FileCheck -dump-input-context=2 -v %t/check.txt < %t/input.txt \
 RUN:               -dump-input-filter=error 2>&1 | \
-RUN:   FileCheck %s -match-full-lines -check-prefix=DMP
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t/check.txt -check-prefix=DMP
 
      DMP:<<<<<<
 DMP-NEXT:         1: <triples kind="host"> 
@@ -27,6 +27,8 @@ DMP-NEXT:        42:  x86_64-amazon-linux
 DMP-NEXT:        43:  x86_64-linux-android 
 DMP-NEXT:        44:  nvptx64-nvidia-cuda 
 DMP-NEXT:not:2'1      !~~~~~~~~~~~~~~~~~~   error: no match expected
+DMP-NEXT:not:2'2                            for: CHECK-NOT: nvptx64-nvidia-cuda
+DMP-NEXT:not:2'3                            at: [[CHK_FILE]]:2
 DMP-NEXT:        45:  i686-linux-gnu 
 DMP-NEXT:        46:  i686-pc-linux-gnu 
 DMP-NEXT:         .
@@ -35,7 +37,7 @@ DMP-NEXT:         .
 DMP-NEXT:        59:  i486-gnu 
 DMP-NEXT:        60:  i586-gnu 
 DMP-NEXT:        61:  i686-gnu 
-DMP-NEXT:not:2'2               } search range end (exclusive)
+DMP-NEXT:not:2'4               } search range end (exclusive)
 DMP-NEXT:        62: </triples> 
 DMP-NEXT:check:3     ^~~~~~~~~~
 DMP-NEXT:        63: </triples> 
diff --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
index 001f74c0c5a3d..411d810f895ba 100644
--- a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
+++ b/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
@@ -30,8 +30,10 @@ ERR-VV-EMPTY:
    DUMP-NEXT:         1: -1 
    DUMP-NEXT:not:1'0    {   } search range (exclusive bounds)
    DUMP-NEXT:not:1'1          error: match failed for invalid pattern
-   DUMP-NEXT:not:1'2          unable to substitute variable or numeric expression: overflow error
-   DUMP-NEXT:not:1'3          undefined variable: UNDEFVAR
+   DUMP-NEXT:not:1'2          for: CHECK-NOT: {{\[}}[#0x0 - 0x1]] {{\[}}[UNDEFVAR]]
+   DUMP-NEXT:not:1'3          at: [[CHK_FILE]]:1
+   DUMP-NEXT:not:1'4          unable to substitute variable or numeric expression: overflow error
+   DUMP-NEXT:not:1'5          undefined variable: UNDEFVAR
 DUMP-VV-NEXT:         2: 
 DUMP-VV-NEXT:eof:1       ^
    DUMP-NEXT:>>>>>>
@@ -57,13 +59,16 @@ RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV
 ;--------------------------------------------------
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+RUN:             -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+RUN:             -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV
+RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+RUN:             -check-prefixes=ERR,DUMP,DUMP-VV
diff --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
index c633a98b76c9a..435760748e088 100644
--- a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
+++ b/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
@@ -19,8 +19,10 @@ RUN: echo > %t.in '-1'
 DUMP-NEXT:           1: -1 
 DUMP-NEXT:check:1'0    {   } search range (exclusive bounds)
 DUMP-NEXT:check:1'1          error: match failed for invalid pattern
-DUMP-NEXT:check:1'2          unable to substitute variable or numeric expression: overflow error
-DUMP-NEXT:check:1'3          undefined variable: UNDEFVAR
+DUMP-NEXT:check:1'2          for: CHECK: {{\[}}[#0x0 - 0x1]] {{\[}}[UNDEFVAR]]
+DUMP-NEXT:check:1'3          at: [[CHK_FILE]]:1
+DUMP-NEXT:check:1'4          unable to substitute variable or numeric expression: overflow error
+DUMP-NEXT:check:1'5          undefined variable: UNDEFVAR
 DUMP-NEXT:>>>>>>
 
 ;--------------------------------------------------
@@ -44,13 +46,13 @@ RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
 ;--------------------------------------------------
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
diff --git a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
index 9773cc0b7efeb..53350330ad18d 100644
--- a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
+++ b/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
@@ -28,9 +28,11 @@ ERR-VV-EMPTY:
    DUMP-NEXT:         1: 123 abc -1 
    DUMP-NEXT:not:1'0    {           } search range (exclusive bounds)
    DUMP-NEXT:not:1'1                  error: match failed for invalid pattern
-   DUMP-NEXT:not:1'2                  unable to substitute variable or numeric expression: overflow error
-   DUMP-NEXT:not:1'3                  with "122+1" equal to "123"
-   DUMP-NEXT:not:1'4                  pattern attempts to capture variables: "STR", "NUM"
+   DUMP-NEXT:not:1'2                  for: CHECK-NOT: {{\[}}[#122+1]] {{\[}}[STR:abc]] {{\[}}[#NUM:0x0 - 0x1]]
+   DUMP-NEXT:not:1'3                  at: [[CHK_FILE]]:1
+   DUMP-NEXT:not:1'4                  unable to substitute variable or numeric expression: overflow error
+   DUMP-NEXT:not:1'5                  with "122+1" equal to "123"
+   DUMP-NEXT:not:1'6                  pattern attempts to capture variables: "STR", "NUM"
 DUMP-VV-NEXT:         2: 
 DUMP-VV-NEXT:eof:1       ^
    DUMP-NEXT:>>>>>>
@@ -56,13 +58,14 @@ RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV
 ;--------------------------------------------------
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV
+RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk \
+RUN:             -check-prefixes=ERR,DUMP,DUMP-VV
diff --git a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt
index a8109d8dcdd4c..4f8b093f5985a 100644
--- a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt
+++ b/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt
@@ -24,10 +24,12 @@ RUN: echo > %t.in '123 abc -1'
 DUMP-NEXT:           1: 123 abc -1 
 DUMP-NEXT:check:1'0    {           } search range (exclusive bounds)
 DUMP-NEXT:check:1'1                  error: match failed for invalid pattern
-DUMP-NEXT:check:1'2                  unable to substitute variable or numeric expression: overflow error
-DUMP-NEXT:check:1'3                  with "122+1" equal to "123"
-DUMP-NEXT:check:1'4                  pattern attempts to capture variables: "STR", "NUM"
-DUMP-NEXT:check:1'5       ?          possible intended match
+DUMP-NEXT:check:1'2                  for: CHECK: {{\[}}[#122+1]] {{\[}}[STR:abc]] {{\[}}[#NUM:0x0 - 0x1]]
+DUMP-NEXT:check:1'3                  at: [[CHK_FILE]]:1
+DUMP-NEXT:check:1'4                  unable to substitute variable or numeric expression: overflow error
+DUMP-NEXT:check:1'5                  with "122+1" equal to "123"
+DUMP-NEXT:check:1'6                  pattern attempts to capture variables: "STR", "NUM"
+DUMP-NEXT:check:1'7       ?          possible intended match
 DUMP-NEXT:>>>>>>
 
 ;--------------------------------------------------
@@ -51,13 +53,13 @@ RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
 ;--------------------------------------------------
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
 
 RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
+RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 | \
+RUN:   FileCheck %s -match-full-lines -DCHK_FILE=%t.chk -check-prefixes=ERR,DUMP
diff --git a/llvm/test/FileCheck/unmatched-substs-captures.txt b/llvm/test/FileCheck/unmatched-substs-captures.txt
index f963d999f13c0..57f2aea434024 100644
--- a/llvm/test/FileCheck/unmatched-substs-captures.txt
+++ b/llvm/test/FileCheck/unmatched-substs-captures.txt
@@ -16,7 +16,8 @@ DEFINE: %{opts} =
 DEFINE: %{run} = \
 DEFINE:  %ProtectFileCheckOutput \
 DEFINE:  not FileCheck %{opts} %t/check.txt < %t/input.txt 2>&1 | \
-DEFINE:    FileCheck %s -match-full-lines -strict-whitespace -check-prefixes
+DEFINE:    FileCheck %s -match-full-lines -strict-whitespace \
+DEFINE:              -DCHK_FILE=%t/check.txt -check-prefixes
 
 REDEFINE: %{opts} = -dump-input=never
 RUN: %{run} ERR
@@ -106,10 +107,12 @@ DMP-VV-NEXT:not:2'4                pattern attempts to capture variables: "STR_N
 DMP-VV-NEXT:check:3       ^~~
    DMP-NEXT:check:4'0       { } search range (exclusive bounds)
    DMP-NEXT:check:4'1           error: no match found in search range
-   DMP-NEXT:check:4'2           with "STR_OLD" equal to "abc"
-   DMP-NEXT:check:4'3           with "NUM_OLD + 1" equal to "17"
-   DMP-NEXT:check:4'4           with "NUM_NEW:456" equal to "456"
-   DMP-NEXT:check:4'5           pattern attempts to capture variables: "STR_NEW", "clang", "NUM_NEW"
+   DMP-NEXT:check:4'2           for: CHECK: {{\[}}[STR_OLD]] {{\[}}[STR_NEW:xyz]] {{\[}}[clang::optnone]] {{\[}}[#NUM_OLD + 1]] {{\[}}[#NUM_NEW:456]]
+   DMP-NEXT:check:4'3           at: [[CHK_FILE]]:4
+   DMP-NEXT:check:4'4           with "STR_OLD" equal to "abc"
+   DMP-NEXT:check:4'5           with "NUM_OLD + 1" equal to "17"
+   DMP-NEXT:check:4'6           with "NUM_NEW:456" equal to "456"
+   DMP-NEXT:check:4'7           pattern attempts to capture variables: "STR_NEW", "clang", "NUM_NEW"
    DMP-NEXT:>>>>>>
 
 ;--- check.txt
diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 33625e0c9e1f1..881cd8d142278 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -16,6 +16,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/FileCheck/FileCheck.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -799,6 +800,119 @@ class FileCheckDiagAnnotator {
     }
   }
 };
+
+/// Emits "for:" and "at:" note annotations identifying the pattern upon each
+/// \c MatchResultDiag that indicates an error.
+///
+/// The input dump prologue (e.g., "Check file: /your/check/file") combined with
+/// annotation labels (e.g., "check:1") already tell the user where to look up
+/// all patterns from the input dump.  Upon an error, this class additionally
+/// prints the failing pattern and its location immediately to the input dump.
+/// That adds minimal verbosity that sometimes provides just enough additional
+/// info to identify the problem without requiring the user to investigate
+/// further.  However, for all preceding successful patterns, this class does
+/// not print the patterns or their locations.  That seems like more noise than
+/// would be worthwhile.  If that much info is needed, the user should have the
+/// check file open while debugging.
+class PatternNoteAnnotator {
+private:
+  const SourceMgr &SM;
+  const unsigned CheckFileBufferID;
+  const std::pair<unsigned, unsigned> ImpPatBufferIDRange;
+  InputAnnotationLabeler &Labeler;
+  std::vector<InputAnnotation> &Annotations;
+  /// Would a \c PatternNoteAnnotator make any annotations for \p MRD?
+  static bool makesAnnotationsFor(const MatchResultDiag &MRD) {
+    // If we ever decide to emit pattern notes for successful patterns, we
+    // should skip MRD.getCheckTy() == CheckEOF here because EOF patterns are
+    // internally generated by FileCheck and thus have no user-provided pattern
+    // to report.
+    return MRD.isError();
+  }
+  void addAnnotation(const MatchResultDiag &MRD, std::string Note) {
+    InputAnnotation &A = Annotations.emplace_back();
+    Labeler.makeLabel(MRD, A.Label, A.LabelIndexGlobal);
+    A.IsFirstLine = true;
+    MarkerRange InputRange = MRD.getMatchRange()
+                                 ? MarkerRange(SM, *MRD.getMatchRange())
+                                 : MarkerRange(SM, MRD.getSearchRange());
+    InputRange = MarkerRange(InputRange.getFirstLoc());
+    A.InputLine = InputRange.getFirstLoc().Line;
+    A.InputFirstCol = InputRange.getFirstLoc().Col;
+    A.InputLastCol = InputRange.getLastLoc().Col;
+    MatchCustomNoteDiag NoteDiag(Note);
+    NoteDiag.setMatchResultDiag(&MRD);
+    A.Marker = getMarker(NoteDiag);
+    A.FoundAndExpectedMatch = false;
+  }
+
+public:
+  /// Tell the labeler how many times this will call
+  /// \c InputAnnotationLabeler::makeLabel for \c MRD.
+  void predictLabelsFor(const MatchResultDiag &MRD) {
+    Labeler.expect(MRD, makesAnnotationsFor(MRD) ? 2 : 0);
+  }
+  /// - \p CheckFileBufferID is the buffer ID for the check file.
+  /// - \p ImpPatBufferIDRange is the buffer ID range for all implicit patterns.
+  /// - \p Annotations is where this annotator should append annotations.
+  PatternNoteAnnotator(const SourceMgr &SM, unsigned CheckFileBufferID,
+                       std::pair<unsigned, unsigned> ImpPatBufferIDRange,
+                       InputAnnotationLabeler &Labeler,
+                       std::vector<InputAnnotation> &Annotations)
+      : SM(SM), CheckFileBufferID(CheckFileBufferID),
+        ImpPatBufferIDRange(ImpPatBufferIDRange), Labeler(Labeler),
+        Annotations(Annotations) {}
+  /// Emit any annotations for \c MRD.
+  void makeAnnotations(const MatchResultDiag &MRD) {
+    if (!makesAnnotationsFor(MRD))
+      return;
+
+    // This can be helpful for debugging.
+    SMLoc CheckLoc = MRD.getCheckLoc();
+    // SM.PrintMessage(CheckLoc, SourceMgr::DK_Error, "PATTERN");
+
+    // Get the buffer containing the pattern.
+    unsigned CheckBufferID = SM.FindBufferContainingLoc(CheckLoc);
+    const MemoryBuffer *MB = SM.getMemoryBuffer(CheckBufferID);
+    const char *BufStart = MB->getBufferStart();
+    StringRef Pat(BufStart, MB->getBufferEnd() - BufStart);
+    size_t CheckLocStart = CheckLoc.getPointer() - BufStart;
+
+    // Find the end of the directive (e.g., "CHECK:") or command-line option
+    // (e.g., "-implicit-check-not=") before CheckLoc.
+    size_t P = Pat.rfind_if_not(isSpace, CheckLocStart);
+    auto IsEOL = [](char C) { return C == '\n' || C == '\r'; };
+    assert(P != StringRef::npos &&
+           Pat.substr(P, CheckLocStart - P).find_if(IsEOL) == StringRef::npos &&
+           "expected directive or command-line option on the pattern line");
+
+    // Now find its start, and trim off everything before it.
+    P = Pat.rfind_if(isSpace, P);
+    if (P != StringRef::npos)
+      Pat = Pat.drop_front(P + 1);
+
+    // Trim off all lines after the pattern.
+    Pat = Pat.take_until(IsEOL);
+
+    // Add the annotations.
+    addAnnotation(MRD, "for: " + std::string(Pat));
+    if (CheckBufferID == CheckFileBufferID) {
+      addAnnotation(
+          MRD, "at: " + SM.getFormattedLocationNoOffset(CheckLoc,
+                                                        /*IncludePath=*/true));
+    } else {
+      // This seems sufficient:
+      //
+      //   for: -implicit-check-note='foobar'
+      //
+      // Adding the following seems useless:
+      //
+      //   at: command line: 1
+      assert(ImpPatBufferIDRange.first <= CheckBufferID &&
+             CheckBufferID < ImpPatBufferIDRange.second);
+    }
+  }
+};
 } // namespace
 
 static void
@@ -810,15 +924,23 @@ buildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
   InputAnnotationLabeler Labeler(SM, CheckFileBufferID, ImpPatBufferIDRange);
   SearchRangeAnnotator TheSearchRangeAnnotator(SM, Labeler, Annotations);
   FileCheckDiagAnnotator TheFileCheckDiagAnnotator(SM, Labeler, Annotations);
+  PatternNoteAnnotator ThePatternNoteAnnotator(
+      SM, CheckFileBufferID, ImpPatBufferIDRange, Labeler, Annotations);
   for (const FileCheckDiag &Diag : Diags) {
-    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag))
+    const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag);
+    if (MRD)
       TheSearchRangeAnnotator.predictLabelsFor(*MRD);
     TheFileCheckDiagAnnotator.predictLabelsFor(Diag);
+    if (MRD)
+      ThePatternNoteAnnotator.predictLabelsFor(*MRD);
   }
   for (const FileCheckDiag &Diag : Diags) {
-    if (const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag))
+    const MatchResultDiag *MRD = dyn_cast<MatchResultDiag>(&Diag);
+    if (MRD)
       TheSearchRangeAnnotator.newMatchResultDiag(*MRD);
     TheFileCheckDiagAnnotator.makeAnnotations(Diag);
+    if (MRD)
+      ThePatternNoteAnnotator.makeAnnotations(*MRD);
   }
   TheSearchRangeAnnotator.endDiags();
   LabelWidthGlobal = Labeler.getLabelWidthGlobal();

>From 1561bb2c9e96a26f38743ff9fd6ebb12de4da086 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Tue, 7 Jul 2026 00:37:23 -0400
Subject: [PATCH 4/5] Use DenseMap not std::map

---
 llvm/utils/FileCheck/FileCheck.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 4252442919da2..fa5807d58cc2d 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -24,7 +24,6 @@
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cmath>
-#include <map>
 using namespace llvm;
 
 static cl::extrahelp FileCheckOptsEnv(
@@ -426,16 +425,17 @@ static std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
   llvm_unreachable("unknown FileCheckType");
 }
 
+template <> struct DenseMapInfo<SMLoc> {
+  static unsigned getHashValue(const SMLoc &Loc) {
+    return DenseMapInfo<const char *>::getHashValue(Loc.getPointer());
+  }
+  static bool isEqual(const SMLoc &LHS, SMLoc &RHS) { return LHS == RHS; }
+};
+
 namespace {
 /// Stores all information needed to generate \c InputAnnotation labels.
 class InputAnnotationLabeler {
 private:
-  struct CompareSMLoc {
-    bool operator()(SMLoc LHS, SMLoc RHS) const {
-      return LHS.getPointer() < RHS.getPointer();
-    }
-  };
-
   const SourceMgr &SM;
   const unsigned CheckFileBufferID;
   const std::pair<unsigned, unsigned> ImpPatBufferIDRange;
@@ -445,11 +445,11 @@ class InputAnnotationLabeler {
   /// by a series of zero or more \c MatchNoteDiag's.  Each such
   /// \c MatchResultDiag and its \c MatchNoteDiag series can require multiple
   /// labels.
-  std::map<SMLoc, unsigned, CompareSMLoc> LabelCountPerPattern;
+  DenseMap<SMLoc, unsigned> LabelCountPerPattern;
   /// For each check pattern, how many labels have we generated so far?
-  std::map<SMLoc, unsigned, CompareSMLoc> LabelIndexPerPattern;
+  DenseMap<SMLoc, unsigned> LabelIndexPerPattern;
   /// For each check pattern, what is the common prefix for all its labels?
-  std::map<SMLoc, std::string, CompareSMLoc> LabelPrefixPerPattern;
+  DenseMap<SMLoc, std::string> LabelPrefixPerPattern;
   /// How many total labels have we generated so far over all check patterns?
   unsigned LabelIndexGlobal;
   /// The widest label generated so far over all check patterns.

>From 602a09f617abae3572998e81ab8e3cd637675217 Mon Sep 17 00:00:00 2001
From: "Joel E. Denny" <jdenny.ornl at gmail.com>
Date: Mon, 20 Jul 2026 16:31:20 -0400
Subject: [PATCH 5/5] Namespace-qualify DenseMapInfo

g++ 13.3.0 complained without that.  clang++ does not seem to care.
---
 llvm/utils/FileCheck/FileCheck.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index fa5807d58cc2d..c491782e1bbf8 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -425,7 +425,7 @@ static std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
   llvm_unreachable("unknown FileCheckType");
 }
 
-template <> struct DenseMapInfo<SMLoc> {
+template <> struct llvm::DenseMapInfo<SMLoc> {
   static unsigned getHashValue(const SMLoc &Loc) {
     return DenseMapInfo<const char *>::getHashValue(Loc.getPointer());
   }



More information about the llvm-commits mailing list