Index: llvm/include/llvm/Support/FileCheck.h
===================================================================
--- llvm/include/llvm/Support/FileCheck.h
+++ llvm/include/llvm/Support/FileCheck.h
@@ -169,8 +169,9 @@
   /// will malfunction.
   enum MatchType {
     // TODO: More members will appear with later patches in this series.
+    MatchFinalAndExpected, //< the final match for an expected pattern
+    MatchTypeFirst = MatchFinalAndExpected,
     MatchFinalButExcluded, //< the final match for an excluded pattern
-    MatchTypeFirst = MatchFinalButExcluded,
     MatchFinalButIllegal,  //< the final but illegal match for an expected pattern
     MatchNoneButExpected,  //< no match for an expected pattern
     MatchFuzzy,            //< a fuzzy match (because no perfect match)
Index: llvm/lib/Support/FileCheck.cpp
===================================================================
--- llvm/lib/Support/FileCheck.cpp
+++ llvm/lib/Support/FileCheck.cpp
@@ -416,14 +416,19 @@
                                   const SourceMgr &SM, SMLoc Loc,
                                   Check::FileCheckType CheckTy,
                                   StringRef Buffer, size_t Pos, size_t Len,
-                                  std::vector<FileCheckDiag> *Diags) {
+                                  std::vector<FileCheckDiag> *Diags,
+                                  bool AdjustPrevDiag = false) {
   SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
   SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
   SMRange Range(Start, End);
   // TODO: The second condition will disappear when we extend this to handle
   // more match types.
-  if (Diags && MatchTy != FileCheckDiag::MatchTypeCount)
-    Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
+  if (Diags && MatchTy != FileCheckDiag::MatchTypeCount) {
+    if (AdjustPrevDiag)
+      Diags->rbegin()->MatchTy = MatchTy;
+    else
+      Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
+  }
   return Range;
 }
 
@@ -905,7 +910,7 @@
       return;
   }
   SMRange MatchRange = ProcessMatchResult(
-      ExpectedMatch ? FileCheckDiag::MatchTypeCount
+      ExpectedMatch ? FileCheckDiag::MatchFinalAndExpected
                     : FileCheckDiag::MatchFinalButExcluded,
       SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
   std::string Message = formatv("{0}: {1} string found in input",
@@ -1060,7 +1065,7 @@
     if (CheckNext(SM, SkippedRegion)) {
       ProcessMatchResult(FileCheckDiag::MatchFinalButIllegal, SM, Loc,
                          Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
-                         Diags);
+                         Diags, Req.Verbose);
       return StringRef::npos;
     }
 
@@ -1069,7 +1074,7 @@
     if (CheckSame(SM, SkippedRegion)) {
       ProcessMatchResult(FileCheckDiag::MatchFinalButIllegal, SM, Loc,
                          Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
-                         Diags);
+                         Diags, Req.Verbose);
       return StringRef::npos;
     }
 
@@ -1278,6 +1283,8 @@
         SM.PrintMessage(OldStart, SourceMgr::DK_Note,
                         "match discarded, overlaps earlier DAG match here",
                         {OldRange});
+        if (Diags)
+          Diags->pop_back();
       }
       MatchPos = MI->End;
     }
Index: llvm/test/FileCheck/dump-input-annotations.txt
===================================================================
--- llvm/test/FileCheck/dump-input-annotations.txt
+++ llvm/test/FileCheck/dump-input-annotations.txt
@@ -20,6 +20,7 @@
 ; ALIGN:Full input was:
 ; ALIGN-NEXT:<<<<<<
 ; ALIGN-NEXT:         1: hello world
+; ALIGN-NEXT:check:1     ^~~~~
 ; ALIGN-NEXT:check:2           X~~~~
 ; ALIGN-NEXT:         2: goodbye
 ; ALIGN-NEXT:check:2     ~~~~~~~
@@ -50,6 +51,7 @@
 
 ; CHK:        <<<<<<
 ; CHK-NEXT:              1: hello
+; CHK-V-NEXT: check:1       ^~~~~
 ; CHK-NEXT:              2: again
 ; CHK-NEXT:   check:2'0     X~~~~
 ; CHK-NEXT:              3: whirled
@@ -71,19 +73,22 @@
 ; RUN: echo 'CHECK-COUNT-3: pete' > %t.chk
 
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefix=CNT
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-Q
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
 ; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
 ; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V
 
-; CNT:        <<<<<<
-; CNT-NEXT:            1: pete
-; CNT-NEXT:            2: repete
-; CNT-NEXT:            3: repeat
-; CNT-NEXT:   count:1     X~~~~~
-; CNT-NEXT:   >>>>>>
-; CNT-NOT:    {{.}}
+; CNT:          <<<<<<
+; CNT-NEXT:                1: pete
+; CNT-V-NEXT:   count:1'0     ^~~~
+; CNT-NEXT:                2: repete
+; CNT-V-NEXT:   count:1'1       ^~~~
+; CNT-NEXT:                3: repeat
+; CNT-Q-NEXT:   count:1       X~~~~~
+; CNT-V-NEXT:   count:1'2     X~~~~~
+; CNT-NEXT:     >>>>>>
+; CNT-NOT:      {{.}}
 
 ;--------------------------------------------------
 ; CHECK-NEXT (also: EOF search-range, illegal match)
@@ -106,10 +111,12 @@
 ; RUN: | FileCheck -match-full-lines %s -check-prefixes=NXT,NXT-V,NXT-VV
 
 ; NXT:        <<<<<<
-; NXT-NEXT:           1: hello
-; NXT-NEXT:           2: again
-; NXT-NEXT:           3:
-; NXT-NEXT:   next:3     X
+; NXT-NEXT:            1: hello
+; NXT-V-NEXT: check:1     ^~~~~
+; NXT-NEXT:            2: again
+; NXT-V-NEXT: next:2      ^~~~~
+; NXT-NEXT:            3:
+; NXT-NEXT:   next:3      X
 ; NXT-NEXT:   >>>>>>
 ; NXT-NOT:    {{.}}
 
@@ -131,7 +138,8 @@
 ; NXT2-NOT:  {{.}}
 
 ;--------------------------------------------------
-; CHECK-SAME (also: single-char search range, illegal match)
+; CHECK-SAME (also: multiple annotations per line, single-char search range,
+; illegal match)
 ;--------------------------------------------------
 
 ; Good match and no match.
@@ -150,8 +158,10 @@
 ; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM,SAM-V,SAM-VV
 
 ; SAM:        <<<<<<
-; SAM-NEXT:           1: hello world!
-; SAM-NEXT:   same:3                X
+; SAM-NEXT:            1: hello world!
+; SAM-V-NEXT: check:1     ^~~~~
+; SAM-V-NEXT: same:2            ^~~~~
+; SAM-NEXT:   same:3                 X
 ; SAM-NEXT:   >>>>>>
 ; SAM-NOT:    {{.}}
 
@@ -164,13 +174,16 @@
 
 ; SAM2:      <<<<<<
 ; SAM2-NEXT:          1: hello world!
+; SAM2-NEXT: check:1     ^~~~~
+; SAM2-NEXT: same:2            ^~~~~
 ; SAM2-NEXT:          2: again
 ; SAM2-NEXT: same:3      !~~~~
 ; SAM2-NEXT: >>>>>>
 ; SAM2-NOT:  {{.}}
 
 ;--------------------------------------------------
-; CHECK-EMPTY (also: search range ends at label, illegal match)
+; CHECK-EMPTY (also: search range ends at label, single-char match, illegal
+; match)
 ;--------------------------------------------------
 
 ; Good match and no match.
@@ -199,11 +212,14 @@
 
 ; EMP:        <<<<<<
 ; EMP-NEXT:            1: hello
+; EMP-V-NEXT: check:1     ^~~~~
 ; EMP-NEXT:            2:
+; EMP-V-NEXT: empty:2     ^
 ; EMP-NEXT:            3: world
 ; EMP-NEXT:   empty:3     X~~~~
 ; EMP-NEXT:            4: label
 ; EMP-NEXT:   empty:3     ~~~~~
+; EMP-V-NEXT: label:4     ^~~~~
 ; EMP-NEXT:   >>>>>>
 ; EMP-NOT:    {{.}}
 
@@ -224,6 +240,7 @@
 
 ; EMP2:        <<<<<<
 ; EMP2-NEXT:            1: hello
+; EMP2-V-NEXT: check:1     ^~~~~
 ; EMP2-NEXT:            2: world
 ; EMP2-NEXT:            3:
 ; EMP2-NEXT:   empty:2     !
@@ -231,7 +248,7 @@
 ; EMP2-NOT:    {{.}}
 
 ;--------------------------------------------------
-; CHECK-NOT
+; CHECK-NOT (also: EOF pattern)
 ;--------------------------------------------------
 
 ; No match (success) and illegal match.
@@ -255,6 +272,8 @@
 ; NOT-NEXT:           2: world
 ; NOT-NEXT:    not:2     !~~~~
 ; NOT-NEXT:           3: again
+; NOT-VV-NEXT:        4:
+; NOT-VV-NEXT: eof:2     ^
 ; NOT-NEXT:    >>>>>>
 ; NOT-NOT:     {{.}}
 
@@ -274,11 +293,12 @@
 ; NOT2-NEXT:             2: world
 ; NOT2-NEXT:    not:2       !~~~~
 ; NOT2-NEXT:             3: again
+; NOT2-V-NEXT:  check:3       ^~~
 ; NOT2-NEXT:    >>>>>>
 ; NOT2-NOT:     {{.}}
 
 ;--------------------------------------------------
-; CHECK-DAG
+; CHECK-DAG (also: matches in different order than directives)
 ;--------------------------------------------------
 
 ; Good match, discarded match plus good match, and no match.
@@ -293,22 +313,28 @@
 ; RUN: echo 'CHECK-DAG: def' >> %t.chk
 
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-Q
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-V
 ; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-V,DAG-VV
 
 ; DAG:         <<<<<<
-; DAG-NEXT:           1: abc
-; DAG-NEXT:           2: def
-; DAG-NEXT:           3: abc
-; DAG-NEXT:    dag:4     X~~
+; DAG-NEXT:             1: abc
+; DAG-V-NEXT:  dag:2       ^~~
+; DAG-NEXT:             2: def
+; DAG-V-NEXT:  dag:1       ^~~
+; DAG-NEXT:             3: abc
+; DAG-V-NEXT:  dag:3       ^~~
+; DAG-NEXT:    dag:4       X~~
 ; DAG-NEXT:    >>>>>>
 ; DAG-NOT:     {{.}}
 
 ;--------------------------------------------------
 ; CHECK-LABEL
+;
+; FIXME: Labels sometimes produce redundant diagnostics for good matches.
+; That bug is independent of but affects -dump-input.
 ;--------------------------------------------------
 
 ; Good match and no match.
@@ -331,6 +357,8 @@
 
 ; LAB:         <<<<<<
 ; LAB-NEXT:               1: lab0
+; LAB-V-NEXT:  label:1'0     ^~~~
+; LAB-V-NEXT:  label:1'1     ^~~~
 ; LAB-NEXT:               2: foo
 ; LAB-NEXT:    label:3'0     X~~
 ; LAB-NEXT:               3: lab1
Index: llvm/test/FileCheck/dump-input-enable.txt
===================================================================
--- llvm/test/FileCheck/dump-input-enable.txt
+++ llvm/test/FileCheck/dump-input-enable.txt
@@ -58,7 +58,9 @@
 ; CHECK-GOOD: Full input was:
 ; CHECK-GOOD-NEXT: <<<<<<
 ; CHECK-GOOD-NEXT:          1: ciao
+; CHECK-GOOD-NEXT: check:1     ^~~~
 ; CHECK-GOOD-NEXT:          2: world
+; CHECK-GOOD-NEXT: next:2      ^~~~~
 ; CHECK-GOOD-NEXT: >>>>>>
 
 ; CHECK-ERR: Full input was:
Index: llvm/utils/FileCheck/FileCheck.cpp
===================================================================
--- llvm/utils/FileCheck/FileCheck.cpp
+++ llvm/utils/FileCheck/FileCheck.cpp
@@ -120,28 +120,36 @@
   char Mark;
   bool HasTildes;
   raw_ostream::Colors Color;
+  enum Verbosity { Quiet, Verbose, VerboseVerbose } RequiredVerbosity;
   const char *What;
   MatchTypeStyle(char Mark, bool HasTildes, raw_ostream::Colors Color,
-                 const char *What)
-      : Mark(Mark), HasTildes(HasTildes), Color(Color), What(What) {}
+                 Verbosity RequiredVerbosity, const char *What)
+      : Mark(Mark), HasTildes(HasTildes), Color(Color),
+        RequiredVerbosity(RequiredVerbosity), What(What) {}
 };
 
 static MatchTypeStyle GetMatchTypeStyle(unsigned MatchTy) {
   switch (MatchTy) {
+  case FileCheckDiag::MatchFinalAndExpected:
+    return MatchTypeStyle('^', true, raw_ostream::GREEN,
+                          MatchTypeStyle::Verbose,
+                          "the final match for an expected pattern (e.g., "
+                          "CHECK)");
   case FileCheckDiag::MatchFinalButExcluded:
-    return MatchTypeStyle('!', true, raw_ostream::RED,
+    return MatchTypeStyle('!', true, raw_ostream::RED, MatchTypeStyle::Quiet,
                           "the final match for an excluded pattern (e.g., "
                           "CHECK-NOT)");
   case FileCheckDiag::MatchFinalButIllegal:
-    return MatchTypeStyle('!', true, raw_ostream::RED,
+    return MatchTypeStyle('!', true, raw_ostream::RED, MatchTypeStyle::Quiet,
                           "the final but illegal match for an expected "
                           "pattern (e.g., CHECK-NEXT)");
   case FileCheckDiag::MatchNoneButExpected:
-    return MatchTypeStyle('X', true, raw_ostream::RED,
+    return MatchTypeStyle('X', true, raw_ostream::RED, MatchTypeStyle::Quiet,
                           "the search range for an unmatched expected "
                           "pattern (e.g., CHECK)");
   case FileCheckDiag::MatchFuzzy:
     return MatchTypeStyle('?', false, raw_ostream::MAGENTA,
+                          MatchTypeStyle::Quiet,
                           "a fuzzy match start for an otherwise unmatched "
                           "pattern");
   case FileCheckDiag::MatchTypeCount:
@@ -174,6 +182,9 @@
 
   // Markers on annotation lines.
   OS << "  - ";
+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
+  OS << "    marks good match (requires -v)\n"
+     << "  - ";
   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
   OS << "    marks bad match\n"
      << "  - ";
@@ -186,7 +197,15 @@
   // Colors.
   if (WithColor(OS).colorsEnabled()) {
     OS << "  - color  ";
+    if (Req.Verbose) {
+      WithColor(OS, raw_ostream::GREEN, true) << "success";
+      OS << ", ";
+    }
     WithColor(OS, raw_ostream::RED, true) << "error";
+    if (Req.Verbose) {
+      OS << ", ";
+      WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched";
+    }
     OS << ", ";
     WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy";
     OS << '\n';
@@ -194,10 +213,17 @@
 
   OS << "\nDetailed description of currently enabled markers:\n\n";
 
+  MatchTypeStyle::Verbosity Verbosity =
+      Req.VerboseVerbose
+          ? MatchTypeStyle::VerboseVerbose
+          : Req.Verbose ? MatchTypeStyle::Verbose : MatchTypeStyle::Quiet;
   for (unsigned StyleIdx = FileCheckDiag::MatchTypeFirst;
        StyleIdx < FileCheckDiag::MatchTypeCount; ++StyleIdx) {
     MatchTypeStyle Style = GetMatchTypeStyle(StyleIdx);
+    if (Verbosity < Style.RequiredVerbosity)
+      continue;
     if (StyleIdx == FileCheckDiag::MatchTypeFirst ||
+        Verbosity < GetMatchTypeStyle(StyleIdx - 1).RequiredVerbosity ||
         Style.Mark != GetMatchTypeStyle(StyleIdx - 1).Mark ||
         Style.HasTildes != GetMatchTypeStyle(StyleIdx - 1).HasTildes ||
         (WithColor(OS).colorsEnabled() &&
@@ -207,6 +233,7 @@
           << Style.Mark << (Style.HasTildes ? "~~" : "  ");
       OS << "    marks ";
       if (StyleIdx + 1 != FileCheckDiag::MatchTypeCount &&
+          Verbosity >= GetMatchTypeStyle(StyleIdx + 1).RequiredVerbosity &&
           Style.Mark == GetMatchTypeStyle(StyleIdx + 1).Mark &&
           Style.HasTildes == GetMatchTypeStyle(StyleIdx + 1).HasTildes &&
           (!WithColor(OS).colorsEnabled() ||
@@ -218,6 +245,13 @@
     OS << Style.What << "\n";
   }
 
+  if (WithColor(OS).colorsEnabled() && Req.Verbose) {
+    OS << "  - ";
+    WithColor(OS, raw_ostream::CYAN, true, true) << "input";
+    OS << "  is style of input text with no final match for any expected "
+       << "pattern\n";
+  }
+
   // Files.
   OS << "\nInput file: ";
   if (InputFilename == "-")
@@ -247,6 +281,8 @@
   unsigned InputStartCol, InputEndCol;
   /// The starting char (before tildes) for marking the line.
   char Mark;
+  /// Whether this annotation represents a final match for an expected pattern.
+  bool FinalAndExpectedMatch;
   /// What color to use for this annotation.
   raw_ostream::Colors Color;
 };
@@ -317,6 +353,8 @@
     MatchTypeStyle MatchTyStyle = GetMatchTypeStyle(DiagItr->MatchTy);
     A.Mark = MatchTyStyle.Mark;
     A.Color = MatchTyStyle.Color;
+    A.FinalAndExpectedMatch =
+        DiagItr->MatchTy == FileCheckDiag::MatchFinalAndExpected;
 
     // Compute the mark location, and break annotation into multiple
     // annotations if it spans multiple lines.
@@ -358,6 +396,7 @@
           B.InputEndCol = UINT_MAX;
         else
           B.InputEndCol = DiagItr->InputEndCol;
+        B.FinalAndExpectedMatch = A.FinalAndExpectedMatch;
         B.Color = A.Color;
         Annotations.push_back(B);
       }
@@ -366,7 +405,7 @@
 }
 
 static void DumpAnnotatedInput(
-    raw_ostream &OS, StringRef InputFileText,
+    raw_ostream &OS, const FileCheckRequest &Req, StringRef InputFileText,
     std::vector<InputAnnotation> &Annotations, unsigned LabelWidth) {
   OS << "Full input was:\n<<<<<<\n";
 
@@ -390,9 +429,15 @@
                 return A.InputLine < B.InputLine;
               if (A.CheckLine != B.CheckLine)
                 return A.CheckLine < B.CheckLine;
-              assert(A.CheckDiagIndex != B.CheckDiagIndex &&
-                     "expected diagnostic indices to be unique within a "
-                     " check line");
+              // FIXME: Sometimes CHECK-LABEL reports its match twice with
+              // other diagnostics in between, and then diag index incrementing
+              // fails to work properly, and then this assert fails.  We should
+              // suppress one of those diagnostics or do a better job of
+              // computing this index.  For now, we just produce a redundant
+              // CHECK-LABEL annotation.
+              // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
+              //        "expected diagnostic indices to be unique within a "
+              //        " check line");
               return A.CheckDiagIndex < B.CheckDiagIndex;
             });
 
@@ -424,14 +469,44 @@
     WithColor(OS, raw_ostream::BLACK, true)
         << format_decimal(Line, LabelWidth) << ": ";
 
-    // Print numbered line.
+    // For case where -v and colors are enabled, find the annotations for final
+    // matches for expected patterns in order to highlight everything else in
+    // the line.  There are no such annotations if -v is disabled.
+    std::list<InputAnnotation> FinalAndExpectedMatches;
+    if (Req.Verbose && WithColor(OS).colorsEnabled()) {
+      for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
+           ++I) {
+        if (I->FinalAndExpectedMatch)
+          FinalAndExpectedMatches.push_back(*I);
+      }
+    }
+
+    // Print numbered line with highlighting where there are no matches for
+    // expected patterns.
     bool Newline = false;
-    while (InputFilePtr != InputFileEnd && !Newline) {
-      if (*InputFilePtr == '\n')
-        Newline = true;
-      else
-        OS << *InputFilePtr;
-      ++InputFilePtr;
+    {
+      WithColor COS(OS);
+      if (Req.Verbose)
+        COS.changeColor(raw_ostream::CYAN, true, true);
+      for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
+        bool StartsMatch = false;
+        bool EndsMatch = false;
+        for (auto M : FinalAndExpectedMatches) {
+          if (Col == M.InputEndCol)
+            EndsMatch = true;
+          else if (Col == M.InputStartCol)
+            StartsMatch = true;
+        }
+        if (StartsMatch)
+          COS.resetColor();
+        else if (EndsMatch)
+          COS.changeColor(raw_ostream::CYAN, true, true);
+        if (*InputFilePtr == '\n')
+          Newline = true;
+        else
+          COS << *InputFilePtr;
+        ++InputFilePtr;
+      }
     }
     OS << '\n';
     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
@@ -571,7 +646,7 @@
     unsigned LabelWidth;
     BuildInputAnnotations(Diags, Annotations, LabelWidth);
     errs() << '\n';
-    DumpAnnotatedInput(errs(), InputFileText, Annotations, LabelWidth);
+    DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
   }
 
   return ExitCode;