[clang] [llvm] [clang] Add `-verify-directives` cc1 flag (PR #179835)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 4 17:50:45 PST 2026


https://github.com/Endilll created https://github.com/llvm/llvm-project/pull/179835

Matheus once told me that the various rules I enforce in C++ DR tests should be checked automatically. This is the patch to check some of them.

`-verify-directives` is a cc1 flag that checks how `expected` directives themselves are written. It enforces the following rules on top of `-verify` mode:
1. Directives have to fully match diagnostic text (but regular expressions are still allowed).
2. Lexical order of directives must match the order in which diagnostics are emitted.
3. Each directive must match exactly one diagnostic.
4. Directives has to specify exact source location of the diagnostic, i.e. wildcards (`*`) are not allowed.

The second rule (about order) is the most significant: it doesn't allow to e.g. have `expected-note {{declared here}}` somewhere far away from `expected-error` it attaches to. It also enforces order between notes themselves.

(This patch comes with rather extensive documentation in the internals manual. Check it out for more details.)

See #179813 and #179674 for impact of enforcing this mode in C++ DR tests. Despite my best efforts, this flag uncovered a significant number of deficiencies that I missed.

I've been already enforcing those rules in C++ DR tests, so I'm going to roll this out there when #179813 is merged. I did my best to make UX palatable, so that it can be used outside of C++ DR tests. My hope is that once this is merged, reviewers can go "make this test work with `-verify-directives`" instead of painstakingly reconstructing compiler output from directives scattered all across the test file.

>From ca1232f1945f6a286e14233bd8dfe46fd52960e1 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 31 Oct 2025 21:29:05 +0300
Subject: [PATCH 01/25] Initial implementation of full match check

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |   2 +
 .../include/clang/Basic/DiagnosticOptions.def |   2 +
 clang/include/clang/Driver/Options.td         |   4 +
 .../clang/Frontend/VerifyDiagnosticConsumer.h |  17 ++-
 clang/lib/Frontend/CompilerInvocation.cpp     |   5 +
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 101 +++++++++++++++---
 6 files changed, 111 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 9e344160ff934..464b9de903ee4 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -188,6 +188,8 @@ def err_verify_no_directives : Error<
     "no expected directives found: consider use of '%0-no-diagnostics'">;
 def err_verify_nonconst_addrspace : Error<
   "qualifier 'const' is needed for variables in address space '%0'">;
+def err_verify_message_partial_match
+    : Error<"diagnostic messages not fully matched: %0">;
 
 def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
 def note_fixit_in_macro : Note<
diff --git a/clang/include/clang/Basic/DiagnosticOptions.def b/clang/include/clang/Basic/DiagnosticOptions.def
index 6d0c1b14acc12..960d23b31dfb7 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.def
+++ b/clang/include/clang/Basic/DiagnosticOptions.def
@@ -76,6 +76,8 @@ ENUM_DIAGOPT(VerifyIgnoreUnexpected, DiagnosticLevelMask, 4,
              DiagnosticLevelMask::None) /// Ignore unexpected diagnostics of
                                         /// the specified levels when using
                                         /// -verify.
+DIAGOPT(VerifyDiagnosticsStrict, 1, 0) /// Enable additional checks of
+                                       /// directives to improve readability
 DIAGOPT(ElideType, 1, 0)         /// Elide identical types in template diffing
 DIAGOPT(ShowTemplateTree, 1, 0)  /// Print a template tree when diffing
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index cb5cb888c6da7..77cb21e3b7d8a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -8145,6 +8145,10 @@ def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
   HelpText<"Ignore unexpected diagnostic messages">;
 def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
   HelpText<"Ignore unexpected diagnostic messages">;
+def verify_strict
+    : Flag<["-"], "verify-strict">,
+      HelpText<
+          "Enable additional checks on directives that improve readability">;
 def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
   HelpText<"Silence ObjC rewriting warnings">,
   MarshallingInfoFlag<DiagnosticOpts<"NoRewriteMacros">>;
diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index b4c613712ed9b..bedb6e12c59e6 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -30,6 +30,12 @@ class LangOptions;
 class SourceManager;
 class TextDiagnosticBuffer;
 
+enum class DiagnosticMatchResult {
+  NoMatch,
+  Match,
+  PartialMatch,
+};
+
 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use
 /// markers in the input source to check that all the emitted diagnostics match
 /// those expected. See clang/docs/InternalsManual.rst for details about how to
@@ -46,7 +52,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
     create(bool RegexKind, SourceLocation DirectiveLoc,
            SourceLocation DiagnosticLoc, StringRef Spelling,
            bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
-           unsigned Min, unsigned Max);
+           unsigned Min, unsigned Max, bool FullMatchRequired);
 
   public:
     /// Constant representing n or more matches.
@@ -59,6 +65,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
     unsigned Min, Max;
     bool MatchAnyLine;
     bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
+    bool FullMatchRequired;
 
     Directive(const Directive &) = delete;
     Directive &operator=(const Directive &) = delete;
@@ -69,16 +76,18 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
     virtual bool isValid(std::string &Error) = 0;
 
     // Returns true on match.
-    virtual bool match(StringRef S) = 0;
+    virtual DiagnosticMatchResult match(StringRef S) = 0;
 
   protected:
     Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
               StringRef Spelling, bool MatchAnyFileAndLine, bool MatchAnyLine,
-              StringRef Text, unsigned Min, unsigned Max)
+              StringRef Text, unsigned Min, unsigned Max,
+              bool FullMatchRequired)
         : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
           Spelling(Spelling), Text(Text), Min(Min), Max(Max),
           MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
-          MatchAnyFileAndLine(MatchAnyFileAndLine) {
+          MatchAnyFileAndLine(MatchAnyFileAndLine),
+          FullMatchRequired(FullMatchRequired) {
       assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
       assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
              "DiagnosticLoc is invalid!");
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index bd36eb4ecf9da..7e9365573b82d 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2599,6 +2599,10 @@ void CompilerInvocationBase::GenerateDiagnosticArgs(
     if (Prefix != "expected")
       GenerateArg(Consumer, OPT_verify_EQ, Prefix);
 
+  if (Opts.VerifyDiagnosticsStrict) {
+    GenerateArg(Consumer, OPT_verify_strict);
+  }
+
   DiagnosticLevelMask VIU = Opts.getVerifyIgnoreUnexpected();
   if (VIU == DiagnosticLevelMask::None) {
     // This is the default, don't generate anything.
@@ -2697,6 +2701,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
   Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor);
 
   Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
+  Opts.VerifyDiagnosticsStrict = Args.hasArg(OPT_verify_strict);
   Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
   if (Args.hasArg(OPT_verify))
     Opts.VerifyPrefixes.push_back("expected");
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index c6cbb36d84156..a2358762971e7 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -90,16 +90,25 @@ class StandardDirective : public Directive {
   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
                     StringRef Spelling, bool MatchAnyFileAndLine,
                     bool MatchAnyLine, StringRef Text, unsigned Min,
-                    unsigned Max)
+                    unsigned Max, bool FullMatchRequired)
       : Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
-                  MatchAnyLine, Text, Min, Max) {}
+                  MatchAnyLine, Text, Min, Max, FullMatchRequired) {}
 
   bool isValid(std::string &Error) override {
     // all strings are considered valid; even empty ones
     return true;
   }
 
-  bool match(StringRef S) override { return S.contains(Text); }
+  DiagnosticMatchResult match(StringRef S) override {
+    if (!S.contains(Text)) {
+      return DiagnosticMatchResult::NoMatch;
+    }
+    if (!FullMatchRequired) {
+      return DiagnosticMatchResult::Match;
+    }
+    return S == Text ? DiagnosticMatchResult::Match
+                     : DiagnosticMatchResult::PartialMatch;
+  }
 };
 
 /// RegexDirective - Directive with regular-expression matching.
@@ -108,17 +117,28 @@ class RegexDirective : public Directive {
   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
                  StringRef Spelling, bool MatchAnyFileAndLine,
                  bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,
-                 StringRef RegexStr)
+                 StringRef RegexStr, bool FullMatchRequired)
       : Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
-                  MatchAnyLine, Text, Min, Max),
+                  MatchAnyLine, Text, Min, Max, FullMatchRequired),
         Regex(RegexStr) {}
 
   bool isValid(std::string &Error) override {
     return Regex.isValid(Error);
   }
 
-  bool match(StringRef S) override {
-    return Regex.match(S);
+  DiagnosticMatchResult match(StringRef S) override {
+    if (!FullMatchRequired) {
+      return Regex.match(S) ? DiagnosticMatchResult::Match
+                            : DiagnosticMatchResult::NoMatch;
+    }
+
+    llvm::SmallVector<StringRef, 4> Matches;
+    Regex.match(S, &Matches);
+    if (Matches.empty()) {
+      return DiagnosticMatchResult::NoMatch;
+    }
+    return Matches[0].size() == S.size() ? DiagnosticMatchResult::Match
+                                         : DiagnosticMatchResult::PartialMatch;
   }
 
 private:
@@ -302,7 +322,8 @@ void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
   // Construct new directive.
   std::unique_ptr<Directive> D = Directive::create(
       UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,
-      MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max);
+      MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max,
+      Diags.getDiagnosticOptions().VerifyDiagnosticsStrict);
 
   std::string Error;
   if (!D->isValid(Error)) {
@@ -940,6 +961,47 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags,
   return DL.size();
 }
 
+/// Takes a list of diagnostics that were partially matched,
+/// despite '-verify-strict' option being set.
+static unsigned PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
+                             llvm::SmallVector<Directive *> &DL) {
+  if (DL.empty())
+    return 0;
+
+  const bool IsSinglePrefix =
+      Diags.getDiagnosticOptions().VerifyPrefixes.size() == 1;
+
+  SmallString<256> Fmt;
+  llvm::raw_svector_ostream OS(Fmt);
+  for (const auto *D : DL) {
+    if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
+      OS << "\n  File *";
+    else
+      OS << "\n  File " << SourceMgr.getFilename(D->DiagnosticLoc);
+    if (D->MatchAnyLine)
+      OS << " Line *";
+    else
+      OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
+    if (D->DirectiveLoc != D->DiagnosticLoc) {
+      if (SourceMgr.getFilename(D->DirectiveLoc) !=
+          SourceMgr.getFilename(D->DiagnosticLoc)) {
+        OS << " (directive at " << SourceMgr.getFilename(D->DirectiveLoc) << ':'
+           << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
+      } else {
+        OS << " (directive at line "
+           << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
+      }
+    }
+    if (!IsSinglePrefix)
+      OS << " \'" << D->Spelling << '\'';
+    OS << ": " << D->Text;
+  }
+
+  Diags.Report(diag::err_verify_message_partial_match).setForceEmit()
+      << OS.str();
+  return DL.size();
+}
+
 /// Determine whether two source locations come from the same file.
 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
                            SourceLocation DiagnosticLoc) {
@@ -966,6 +1028,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
                            bool IgnoreUnexpected) {
   std::vector<Directive *> LeftOnly;
   DiagList Right(d2_begin, d2_end);
+  llvm::SmallVector<Directive *> IncompleteMatches;
 
   for (auto &Owner : Left) {
     Directive &D = *Owner;
@@ -985,8 +1048,13 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
           continue;
 
         const std::string &RightText = II->second;
-        if (D.match(RightText))
+        DiagnosticMatchResult MatchResult = D.match(RightText);
+        if (MatchResult == DiagnosticMatchResult::Match)
           break;
+        if (MatchResult == DiagnosticMatchResult::PartialMatch) {
+          IncompleteMatches.push_back(&D);
+          break;
+        }
       }
       if (II == IE) {
         // Not found.
@@ -1002,6 +1070,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
   if (!IgnoreUnexpected)
     num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
+  num += PrintPartial(Diags, SourceMgr, IncompleteMatches);
   return num;
 }
 
@@ -1159,11 +1228,11 @@ std::unique_ptr<Directive>
 Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
                   SourceLocation DiagnosticLoc, StringRef Spelling,
                   bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
-                  unsigned Min, unsigned Max) {
+                  unsigned Min, unsigned Max, bool FullMatchRequired) {
   if (!RegexKind)
-    return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
-                                               Spelling, MatchAnyFileAndLine,
-                                               MatchAnyLine, Text, Min, Max);
+    return std::make_unique<StandardDirective>(
+        DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
+        MatchAnyLine, Text, Min, Max, FullMatchRequired);
 
   // Parse the directive into a regular expression.
   std::string RegexStr;
@@ -1187,7 +1256,7 @@ Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
     }
   }
 
-  return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc, Spelling,
-                                          MatchAnyFileAndLine, MatchAnyLine,
-                                          Text, Min, Max, RegexStr);
+  return std::make_unique<RegexDirective>(
+      DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine, MatchAnyLine,
+      Text, Min, Max, RegexStr, FullMatchRequired);
 }

>From 9ed6fa55b742d20279ecc6d9b79531764a6146df Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 14:56:45 +0300
Subject: [PATCH 02/25] Initial implementation of ordering check

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |   1 +
 .../clang/Frontend/TextDiagnosticBuffer.h     |   7 +-
 .../clang/Frontend/VerifyDiagnosticConsumer.h |   3 +-
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 107 +++++++++++++++++-
 4 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 464b9de903ee4..b73e5da018987 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -190,6 +190,7 @@ def err_verify_nonconst_addrspace : Error<
   "qualifier 'const' is needed for variables in address space '%0'">;
 def err_verify_message_partial_match
     : Error<"diagnostic messages not fully matched: %0">;
+def err_verify_directive_out_of_order : Error<"out of order directive found: %0\nSubsequent directives were skipped">;
 
 def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
 def note_fixit_in_macro : Note<
diff --git a/clang/include/clang/Frontend/TextDiagnosticBuffer.h b/clang/include/clang/Frontend/TextDiagnosticBuffer.h
index 5945caf89743a..3318d01c0aa6a 100644
--- a/clang/include/clang/Frontend/TextDiagnosticBuffer.h
+++ b/clang/include/clang/Frontend/TextDiagnosticBuffer.h
@@ -28,6 +28,8 @@ class TextDiagnosticBuffer : public DiagnosticConsumer {
   using iterator = DiagList::iterator;
   using const_iterator = DiagList::const_iterator;
 
+  using AllDiagList = std::vector<std::pair<DiagnosticsEngine::Level, size_t>>;
+
 private:
   DiagList Errors, Warnings, Remarks, Notes;
 
@@ -35,7 +37,7 @@ class TextDiagnosticBuffer : public DiagnosticConsumer {
   /// order likely doesn't correspond to user input order, but it at least
   /// keeps notes in the right places.  Each pair in the vector is a diagnostic
   /// level and an index into the corresponding DiagList above.
-  std::vector<std::pair<DiagnosticsEngine::Level, size_t>> All;
+  AllDiagList All;
 
 public:
   const_iterator err_begin() const { return Errors.begin(); }
@@ -50,6 +52,9 @@ class TextDiagnosticBuffer : public DiagnosticConsumer {
   const_iterator note_begin() const { return Notes.begin(); }
   const_iterator note_end() const { return Notes.end(); }
 
+  AllDiagList::const_iterator all_begin() const { return All.begin(); }
+  AllDiagList::const_iterator all_end() const { return All.end(); }
+
   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
                         const Diagnostic &Info) override;
 
diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index bedb6e12c59e6..0d709d878c7ef 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -76,7 +76,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
     virtual bool isValid(std::string &Error) = 0;
 
     // Returns true on match.
-    virtual DiagnosticMatchResult match(StringRef S) = 0;
+    virtual DiagnosticMatchResult match(StringRef S) const = 0;
 
   protected:
     Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
@@ -137,6 +137,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
   unsigned ActiveSourceFiles = 0;
   ParsingState State;
   ExpectedData ED;
+  bool CheckOrderOfDirectives;
 
   void CheckDiagnostics();
 
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a2358762971e7..08f6713bed2e7 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -99,7 +99,7 @@ class StandardDirective : public Directive {
     return true;
   }
 
-  DiagnosticMatchResult match(StringRef S) override {
+  DiagnosticMatchResult match(StringRef S) const override {
     if (!S.contains(Text)) {
       return DiagnosticMatchResult::NoMatch;
     }
@@ -126,7 +126,7 @@ class RegexDirective : public Directive {
     return Regex.isValid(Error);
   }
 
-  DiagnosticMatchResult match(StringRef S) override {
+  DiagnosticMatchResult match(StringRef S) const override {
     if (!FullMatchRequired) {
       return Regex.match(S) ? DiagnosticMatchResult::Match
                             : DiagnosticMatchResult::NoMatch;
@@ -702,6 +702,7 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
       State{HasNoDirectives, {}} {
   if (Diags.hasSourceManager())
     setSourceManager(Diags.getSourceManager());
+  CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
 }
 
 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
@@ -1113,6 +1114,105 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   return NumProblems;
 }
 
+// Checks that directives are lexically in the same order as the emitted
+// diagnostics. Assumes that CheckResults returned 0 problems, i.e. that
+// every diagnostic was matched by every directive without considering the
+// order.
+static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
+                                       const TextDiagnosticBuffer &Buffer,
+                                       const ExpectedData &ED) {
+  // Building a set of all directives ordered by their location
+  auto directiveComparator = [] (const Directive *LHS, const Directive *RHS) {
+      return LHS->DirectiveLoc < RHS->DiagnosticLoc;
+    };
+  auto sortDirectives = [&] (const DirectiveList &Unordered) {
+    std::vector<const Directive *> Ordered(Unordered.size());
+    std::transform(Unordered.cbegin(), Unordered.cend(), Ordered.begin(), [] (const std::unique_ptr<Directive> &D) {
+      return &*D;
+    });
+    std::sort(Ordered.begin(), Ordered.end(), directiveComparator);
+    return Ordered;
+  };
+  std::vector<const Directive *> OrderedErrors = sortDirectives(ED.Errors);
+  std::vector<const Directive *> OrderedWarns = sortDirectives(ED.Warnings);
+  std::vector<const Directive *> OrderedNotes = sortDirectives(ED.Notes);
+  std::vector<const Directive *> OrderedRemarks = sortDirectives(ED.Remarks);
+
+  std::vector<const Directive *> OrderedDirectives = [&]{
+    std::vector<const Directive *> OrderedER(OrderedErrors.size() + OrderedRemarks.size());
+    std::merge(OrderedErrors.cbegin(), OrderedErrors.cend(), OrderedRemarks.cbegin(), OrderedRemarks.cend(), OrderedER.begin(), directiveComparator);
+    std::vector<const Directive *> OrderedWN(OrderedWarns.size() + OrderedNotes.size());
+    std::merge(OrderedWarns.cbegin(), OrderedWarns.cend(), OrderedNotes.cbegin(), OrderedNotes.cend(), OrderedWN.begin(), directiveComparator);
+    std::vector<const Directive *> OrderedDirectives(OrderedER.size() + OrderedWN.size());
+    std::merge(OrderedER.cbegin(), OrderedER.cend(), OrderedWN.cbegin(), OrderedWN.cend(), OrderedDirectives.begin(), directiveComparator);
+    return OrderedDirectives;
+  }();
+
+  auto getLocDiagPair = [&] (DiagnosticsEngine::Level DiagLevel, long DiagIndex) {
+    TextDiagnosticBuffer::const_iterator It = [&]{
+      switch (DiagLevel) {
+        case DiagnosticsEngine::Level::Fatal:
+        case DiagnosticsEngine::Level::Error:
+          assert(DiagIndex < Buffer.err_end() - Buffer.err_begin() && "DiagIndex is out of bounds!");
+          return Buffer.err_begin();
+        case DiagnosticsEngine::Level::Warning:
+          assert(DiagIndex < Buffer.warn_end() - Buffer.warn_begin() && "DiagIndex is out of bounds!");
+          return Buffer.warn_begin();
+        case DiagnosticsEngine::Level::Note:
+          assert(DiagIndex < Buffer.note_end() - Buffer.note_begin()  && "DiagIndex is out of bounds!");
+          return Buffer.note_begin();
+        case DiagnosticsEngine::Level::Remark:
+          assert(DiagIndex < Buffer.remark_end() - Buffer.remark_begin() && "DiagIndex is out of bounds!");
+          return Buffer.remark_begin();
+        case DiagnosticsEngine::Level::Ignored:
+          llvm_unreachable("Unexpected diagnostic level!");
+      }
+    }();
+    
+    std::advance(It, DiagIndex);
+    return *It;
+  };
+
+  using LevelDiagPairT = std::pair<DiagnosticsEngine::Level, size_t>;
+  static_assert(std::is_same_v<LevelDiagPairT, TextDiagnosticBuffer::AllDiagList::value_type>);
+
+  // CheckResults already ensured that there are as many directives as emitted
+  // diagnostics
+  for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(OrderedDirectives, llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
+    assert(!Directive->MatchAnyFileAndLine);
+    assert(!Directive->MatchAnyLine);
+    const auto [DiagLevel, DiagIndex] = LevelDiagPair;
+    const auto [DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
+    const SourceLocation DirLoc = Directive->DirectiveLoc;
+    bool LocsMatch = SourceMgr.getPresumedLineNumber(DiagLoc) == SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) && IsFromSameFile(SourceMgr, DiagLoc, Directive->DiagnosticLoc);
+    if (!LocsMatch || Directive->match(DiagText) != DiagnosticMatchResult::Match) {
+        SmallString<256> Fmt;
+        llvm::raw_svector_ostream OS(Fmt);
+        OS << "\n  directive at " << SourceMgr.getFilename(DirLoc)
+             << ":" << SourceMgr.getPresumedLineNumber(DirLoc)
+             << ": " << Directive->Text
+           << "\n  that expects diagnostic at ";
+        if (IsFromSameFile(SourceMgr, DirLoc, Directive->DiagnosticLoc)) {
+          OS << "line " << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
+        }
+        else {
+          OS << SourceMgr.getFilename(Directive->DiagnosticLoc) << ":" << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
+        }
+           OS << "\n  does not match diagnostic at ";
+        if (IsFromSameFile(SourceMgr, DirLoc, DiagLoc)) {
+          OS << "line " << SourceMgr.getPresumedLineNumber(DiagLoc);
+        }
+        else {
+          OS << SourceMgr.getFilename(DiagLoc) << ":" << SourceMgr.getPresumedLineNumber(DiagLoc);
+        }
+        OS << ": " << DiagText;
+        Diags.Report(diag::err_verify_directive_out_of_order) << OS.str();
+        return 1;
+    }
+  }
+  return 0;
+}
+
 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
                                                       FileID FID,
                                                       ParsedStatus PS) {
@@ -1200,6 +1300,9 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
 
     // Check that the expected diagnostics occurred.
     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
+    if (CheckOrderOfDirectives && NumErrors == 0) {
+      NumErrors += CheckResultsAreInOrder(Diags, *SrcManager, *Buffer, ED);
+    }
   } else {
     const DiagnosticLevelMask DiagMask =
         ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();

>From a49d77d28d2dc5a3566735acedf375a274ccb7e5 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 16:49:53 +0300
Subject: [PATCH 03/25] Stop filling IncompleteMatches if full matches are not
 required

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 08f6713bed2e7..4fdf31115a575 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1050,10 +1050,10 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
 
         const std::string &RightText = II->second;
         DiagnosticMatchResult MatchResult = D.match(RightText);
-        if (MatchResult == DiagnosticMatchResult::Match)
-          break;
-        if (MatchResult == DiagnosticMatchResult::PartialMatch) {
-          IncompleteMatches.push_back(&D);
+        if (MatchResult != DiagnosticMatchResult::NoMatch) {
+          if (D.FullMatchRequired && MatchResult == DiagnosticMatchResult::PartialMatch) {
+            IncompleteMatches.push_back(&D);
+          }
           break;
         }
       }

>From 1e3437c9d597a0b6a61caffc21d91a00c08b3c5a Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 20:44:31 +0300
Subject: [PATCH 04/25] Implement check for one diagnostic per directive

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 ++
 .../clang/Frontend/VerifyDiagnosticConsumer.h |  1 +
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 35 ++++++++++++++++---
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index b73e5da018987..dda0d2a3d361d 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -191,6 +191,8 @@ def err_verify_nonconst_addrspace : Error<
 def err_verify_message_partial_match
     : Error<"diagnostic messages not fully matched: %0">;
 def err_verify_directive_out_of_order : Error<"out of order directive found: %0\nSubsequent directives were skipped">;
+def err_verify_non_singular_match
+    : Error<"exactly one diagnostic can be matched">;
 
 def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
 def note_fixit_in_macro : Note<
diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 0d709d878c7ef..a58624890c71f 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -138,6 +138,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
   ParsingState State;
   ExpectedData ED;
   bool CheckOrderOfDirectives;
+  bool OneDiagPerDirective;
 
   void CheckDiagnostics();
 
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 4fdf31115a575..fae536eaba563 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -432,7 +432,8 @@ static std::string DetailedErrorString(const DiagnosticsEngine &Diags) {
 static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                            Preprocessor *PP, SourceLocation Pos,
                            VerifyDiagnosticConsumer::ParsingState &State,
-                           VerifyDiagnosticConsumer::MarkerTracker &Markers) {
+                           VerifyDiagnosticConsumer::MarkerTracker &Markers,
+                           bool OneDiagPerDirective) {
   DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
 
   // First, scan the comment looking for markers.
@@ -613,12 +614,22 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
 
     // Next optional token: positive integer or a '+'.
     if (PH.Next(D.Min)) {
+      if (OneDiagPerDirective && D.Min != 1) {
+        Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                     diag::err_verify_non_singular_match);
+        continue;
+      }
       PH.Advance();
       // A positive integer can be followed by a '+' meaning min
       // or more, or by a '-' meaning a range from min to max.
       if (PH.Next("+")) {
         D.Max = Directive::MaxCount;
         PH.Advance();
+        if (OneDiagPerDirective) {
+          Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                       diag::err_verify_non_singular_match);
+          continue;
+        }
       } else if (PH.Next("-")) {
         PH.Advance();
         if (!PH.Next(D.Max) || D.Max < D.Min) {
@@ -626,12 +637,22 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                        diag::err_verify_invalid_range) << KindStr;
           continue;
         }
+        if (OneDiagPerDirective && D.Max != 1) {
+          Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                       diag::err_verify_non_singular_match);
+          continue;
+        }
         PH.Advance();
       } else {
         D.Max = D.Min;
       }
     } else if (PH.Next("+")) {
       // '+' on its own means "1 or more".
+      if (OneDiagPerDirective && D.Max != 1) {
+        Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                     diag::err_verify_non_singular_match);
+        continue;
+      }
       D.Max = Directive::MaxCount;
       PH.Advance();
     }
@@ -703,6 +724,7 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
   if (Diags.hasSourceManager())
     setSourceManager(Diags.getSourceManager());
   CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
+  OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
 }
 
 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
@@ -818,7 +840,8 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
   // Fold any "\<EOL>" sequences
   size_t loc = C.find('\\');
   if (loc == StringRef::npos) {
-    ParseDirective(C, &ED, SM, &PP, CommentBegin, State, *Markers);
+    ParseDirective(C, &ED, SM, &PP, CommentBegin, State, *Markers,
+                   OneDiagPerDirective);
     return false;
   }
 
@@ -848,7 +871,8 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
   }
 
   if (!C2.empty())
-    ParseDirective(C2, &ED, SM, &PP, CommentBegin, State, *Markers);
+    ParseDirective(C2, &ED, SM, &PP, CommentBegin, State, *Markers,
+                   OneDiagPerDirective);
   return false;
 }
 
@@ -887,7 +911,7 @@ static bool findDirectives(SourceManager &SM, FileID FID,
 
     // Find first directive.
     if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(), State,
-                       Markers))
+                       Markers, /*OneDiagPerDirective=*/false))
       return true;
   }
   return false;
@@ -1198,7 +1222,7 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags, SourceManager &
         else {
           OS << SourceMgr.getFilename(Directive->DiagnosticLoc) << ":" << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
         }
-           OS << "\n  does not match diagnostic at ";
+        OS << "\n  does not match diagnostic at ";
         if (IsFromSameFile(SourceMgr, DirLoc, DiagLoc)) {
           OS << "line " << SourceMgr.getPresumedLineNumber(DiagLoc);
         }
@@ -1301,6 +1325,7 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
     // Check that the expected diagnostics occurred.
     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
     if (CheckOrderOfDirectives && NumErrors == 0) {
+      assert(OneDiagPerDirective);
       NumErrors += CheckResultsAreInOrder(Diags, *SrcManager, *Buffer, ED);
     }
   } else {

>From 482bc526ef9561f62a901e536c1179de33e5035e Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 20:47:23 +0300
Subject: [PATCH 05/25] Run clang-format

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |   4 +-
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 142 ++++++++++--------
 2 files changed, 85 insertions(+), 61 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index dda0d2a3d361d..9430f986e05c4 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -190,7 +190,9 @@ def err_verify_nonconst_addrspace : Error<
   "qualifier 'const' is needed for variables in address space '%0'">;
 def err_verify_message_partial_match
     : Error<"diagnostic messages not fully matched: %0">;
-def err_verify_directive_out_of_order : Error<"out of order directive found: %0\nSubsequent directives were skipped">;
+def err_verify_directive_out_of_order
+    : Error<"out of order directive found: %0\nSubsequent directives were "
+            "skipped">;
 def err_verify_non_singular_match
     : Error<"exactly one diagnostic can be matched">;
 
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index fae536eaba563..65cecbb163425 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1075,7 +1075,8 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
         const std::string &RightText = II->second;
         DiagnosticMatchResult MatchResult = D.match(RightText);
         if (MatchResult != DiagnosticMatchResult::NoMatch) {
-          if (D.FullMatchRequired && MatchResult == DiagnosticMatchResult::PartialMatch) {
+          if (D.FullMatchRequired &&
+              MatchResult == DiagnosticMatchResult::PartialMatch) {
             IncompleteMatches.push_back(&D);
           }
           break;
@@ -1142,18 +1143,18 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
 // diagnostics. Assumes that CheckResults returned 0 problems, i.e. that
 // every diagnostic was matched by every directive without considering the
 // order.
-static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
+static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
+                                       SourceManager &SourceMgr,
                                        const TextDiagnosticBuffer &Buffer,
                                        const ExpectedData &ED) {
   // Building a set of all directives ordered by their location
-  auto directiveComparator = [] (const Directive *LHS, const Directive *RHS) {
-      return LHS->DirectiveLoc < RHS->DiagnosticLoc;
-    };
-  auto sortDirectives = [&] (const DirectiveList &Unordered) {
+  auto directiveComparator = [](const Directive *LHS, const Directive *RHS) {
+    return LHS->DirectiveLoc < RHS->DiagnosticLoc;
+  };
+  auto sortDirectives = [&](const DirectiveList &Unordered) {
     std::vector<const Directive *> Ordered(Unordered.size());
-    std::transform(Unordered.cbegin(), Unordered.cend(), Ordered.begin(), [] (const std::unique_ptr<Directive> &D) {
-      return &*D;
-    });
+    std::transform(Unordered.cbegin(), Unordered.cend(), Ordered.begin(),
+                   [](const std::unique_ptr<Directive> &D) { return &*D; });
     std::sort(Ordered.begin(), Ordered.end(), directiveComparator);
     return Ordered;
   };
@@ -1162,76 +1163,97 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags, SourceManager &
   std::vector<const Directive *> OrderedNotes = sortDirectives(ED.Notes);
   std::vector<const Directive *> OrderedRemarks = sortDirectives(ED.Remarks);
 
-  std::vector<const Directive *> OrderedDirectives = [&]{
-    std::vector<const Directive *> OrderedER(OrderedErrors.size() + OrderedRemarks.size());
-    std::merge(OrderedErrors.cbegin(), OrderedErrors.cend(), OrderedRemarks.cbegin(), OrderedRemarks.cend(), OrderedER.begin(), directiveComparator);
-    std::vector<const Directive *> OrderedWN(OrderedWarns.size() + OrderedNotes.size());
-    std::merge(OrderedWarns.cbegin(), OrderedWarns.cend(), OrderedNotes.cbegin(), OrderedNotes.cend(), OrderedWN.begin(), directiveComparator);
-    std::vector<const Directive *> OrderedDirectives(OrderedER.size() + OrderedWN.size());
-    std::merge(OrderedER.cbegin(), OrderedER.cend(), OrderedWN.cbegin(), OrderedWN.cend(), OrderedDirectives.begin(), directiveComparator);
+  std::vector<const Directive *> OrderedDirectives = [&] {
+    std::vector<const Directive *> OrderedER(OrderedErrors.size() +
+                                             OrderedRemarks.size());
+    std::merge(OrderedErrors.cbegin(), OrderedErrors.cend(),
+               OrderedRemarks.cbegin(), OrderedRemarks.cend(),
+               OrderedER.begin(), directiveComparator);
+    std::vector<const Directive *> OrderedWN(OrderedWarns.size() +
+                                             OrderedNotes.size());
+    std::merge(OrderedWarns.cbegin(), OrderedWarns.cend(),
+               OrderedNotes.cbegin(), OrderedNotes.cend(), OrderedWN.begin(),
+               directiveComparator);
+    std::vector<const Directive *> OrderedDirectives(OrderedER.size() +
+                                                     OrderedWN.size());
+    std::merge(OrderedER.cbegin(), OrderedER.cend(), OrderedWN.cbegin(),
+               OrderedWN.cend(), OrderedDirectives.begin(),
+               directiveComparator);
     return OrderedDirectives;
   }();
 
-  auto getLocDiagPair = [&] (DiagnosticsEngine::Level DiagLevel, long DiagIndex) {
-    TextDiagnosticBuffer::const_iterator It = [&]{
+  auto getLocDiagPair = [&](DiagnosticsEngine::Level DiagLevel,
+                            long DiagIndex) {
+    TextDiagnosticBuffer::const_iterator It = [&] {
       switch (DiagLevel) {
-        case DiagnosticsEngine::Level::Fatal:
-        case DiagnosticsEngine::Level::Error:
-          assert(DiagIndex < Buffer.err_end() - Buffer.err_begin() && "DiagIndex is out of bounds!");
-          return Buffer.err_begin();
-        case DiagnosticsEngine::Level::Warning:
-          assert(DiagIndex < Buffer.warn_end() - Buffer.warn_begin() && "DiagIndex is out of bounds!");
-          return Buffer.warn_begin();
-        case DiagnosticsEngine::Level::Note:
-          assert(DiagIndex < Buffer.note_end() - Buffer.note_begin()  && "DiagIndex is out of bounds!");
-          return Buffer.note_begin();
-        case DiagnosticsEngine::Level::Remark:
-          assert(DiagIndex < Buffer.remark_end() - Buffer.remark_begin() && "DiagIndex is out of bounds!");
-          return Buffer.remark_begin();
-        case DiagnosticsEngine::Level::Ignored:
-          llvm_unreachable("Unexpected diagnostic level!");
+      case DiagnosticsEngine::Level::Fatal:
+      case DiagnosticsEngine::Level::Error:
+        assert(DiagIndex < Buffer.err_end() - Buffer.err_begin() &&
+               "DiagIndex is out of bounds!");
+        return Buffer.err_begin();
+      case DiagnosticsEngine::Level::Warning:
+        assert(DiagIndex < Buffer.warn_end() - Buffer.warn_begin() &&
+               "DiagIndex is out of bounds!");
+        return Buffer.warn_begin();
+      case DiagnosticsEngine::Level::Note:
+        assert(DiagIndex < Buffer.note_end() - Buffer.note_begin() &&
+               "DiagIndex is out of bounds!");
+        return Buffer.note_begin();
+      case DiagnosticsEngine::Level::Remark:
+        assert(DiagIndex < Buffer.remark_end() - Buffer.remark_begin() &&
+               "DiagIndex is out of bounds!");
+        return Buffer.remark_begin();
+      case DiagnosticsEngine::Level::Ignored:
+        llvm_unreachable("Unexpected diagnostic level!");
       }
     }();
-    
+
     std::advance(It, DiagIndex);
     return *It;
   };
 
   using LevelDiagPairT = std::pair<DiagnosticsEngine::Level, size_t>;
-  static_assert(std::is_same_v<LevelDiagPairT, TextDiagnosticBuffer::AllDiagList::value_type>);
+  static_assert(std::is_same_v<LevelDiagPairT,
+                               TextDiagnosticBuffer::AllDiagList::value_type>);
 
   // CheckResults already ensured that there are as many directives as emitted
   // diagnostics
-  for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(OrderedDirectives, llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
+  for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(
+           OrderedDirectives,
+           llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
     assert(!Directive->MatchAnyFileAndLine);
     assert(!Directive->MatchAnyLine);
     const auto [DiagLevel, DiagIndex] = LevelDiagPair;
     const auto [DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
     const SourceLocation DirLoc = Directive->DirectiveLoc;
-    bool LocsMatch = SourceMgr.getPresumedLineNumber(DiagLoc) == SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) && IsFromSameFile(SourceMgr, DiagLoc, Directive->DiagnosticLoc);
-    if (!LocsMatch || Directive->match(DiagText) != DiagnosticMatchResult::Match) {
-        SmallString<256> Fmt;
-        llvm::raw_svector_ostream OS(Fmt);
-        OS << "\n  directive at " << SourceMgr.getFilename(DirLoc)
-             << ":" << SourceMgr.getPresumedLineNumber(DirLoc)
-             << ": " << Directive->Text
-           << "\n  that expects diagnostic at ";
-        if (IsFromSameFile(SourceMgr, DirLoc, Directive->DiagnosticLoc)) {
-          OS << "line " << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
-        }
-        else {
-          OS << SourceMgr.getFilename(Directive->DiagnosticLoc) << ":" << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
-        }
-        OS << "\n  does not match diagnostic at ";
-        if (IsFromSameFile(SourceMgr, DirLoc, DiagLoc)) {
-          OS << "line " << SourceMgr.getPresumedLineNumber(DiagLoc);
-        }
-        else {
-          OS << SourceMgr.getFilename(DiagLoc) << ":" << SourceMgr.getPresumedLineNumber(DiagLoc);
-        }
-        OS << ": " << DiagText;
-        Diags.Report(diag::err_verify_directive_out_of_order) << OS.str();
-        return 1;
+    bool LocsMatch =
+        SourceMgr.getPresumedLineNumber(DiagLoc) ==
+            SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) &&
+        IsFromSameFile(SourceMgr, DiagLoc, Directive->DiagnosticLoc);
+    if (!LocsMatch ||
+        Directive->match(DiagText) != DiagnosticMatchResult::Match) {
+      SmallString<256> Fmt;
+      llvm::raw_svector_ostream OS(Fmt);
+      OS << "\n  directive at " << SourceMgr.getFilename(DirLoc) << ":"
+         << SourceMgr.getPresumedLineNumber(DirLoc) << ": " << Directive->Text
+         << "\n  that expects diagnostic at ";
+      if (IsFromSameFile(SourceMgr, DirLoc, Directive->DiagnosticLoc)) {
+        OS << "line "
+           << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
+      } else {
+        OS << SourceMgr.getFilename(Directive->DiagnosticLoc) << ":"
+           << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
+      }
+      OS << "\n  does not match diagnostic at ";
+      if (IsFromSameFile(SourceMgr, DirLoc, DiagLoc)) {
+        OS << "line " << SourceMgr.getPresumedLineNumber(DiagLoc);
+      } else {
+        OS << SourceMgr.getFilename(DiagLoc) << ":"
+           << SourceMgr.getPresumedLineNumber(DiagLoc);
+      }
+      OS << ": " << DiagText;
+      Diags.Report(diag::err_verify_directive_out_of_order) << OS.str();
+      return 1;
     }
   }
   return 0;

>From 3bf79bd63345d1b81af233a29023f698acab8e01 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 20:49:18 +0300
Subject: [PATCH 06/25] Add message to an assertion

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 65cecbb163425..d2b3963984d55 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1347,7 +1347,8 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
     // Check that the expected diagnostics occurred.
     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
     if (CheckOrderOfDirectives && NumErrors == 0) {
-      assert(OneDiagPerDirective);
+      assert(OneDiagPerDirective && "Can't check order of directives unless "
+                                    "they match only one diagnostic!");
       NumErrors += CheckResultsAreInOrder(Diags, *SrcManager, *Buffer, ED);
     }
   } else {

>From c362e08da0607438f4730e178a31da2c3b61c50b Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 1 Nov 2025 21:13:20 +0300
Subject: [PATCH 07/25] Add check for wildcard in diagnostic location

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 ++
 .../clang/Frontend/VerifyDiagnosticConsumer.h |  1 +
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 27 ++++++++++++++++---
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 9430f986e05c4..7f3ebc266a77a 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -195,6 +195,8 @@ def err_verify_directive_out_of_order
             "skipped">;
 def err_verify_non_singular_match
     : Error<"exactly one diagnostic can be matched">;
+def err_verify_wildcard_loc
+    : Error<"cannot use wildcard for diagnostic location">;
 
 def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
 def note_fixit_in_macro : Note<
diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index a58624890c71f..ef1839f25cafd 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -139,6 +139,7 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
   ExpectedData ED;
   bool CheckOrderOfDirectives;
   bool OneDiagPerDirective;
+  bool DisableWildcardInDiagLoc;
 
   void CheckDiagnostics();
 
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index d2b3963984d55..53dff3fe700fc 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -433,7 +433,8 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                            Preprocessor *PP, SourceLocation Pos,
                            VerifyDiagnosticConsumer::ParsingState &State,
                            VerifyDiagnosticConsumer::MarkerTracker &Markers,
-                           bool OneDiagPerDirective) {
+                           bool OneDiagPerDirective,
+                           bool DisableWildcardInDiagLoc) {
   DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
 
   // First, scan the comment looking for markers.
@@ -564,6 +565,11 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         PH.Advance();
 
         if (Filename == "*") {
+          if (DisableWildcardInDiagLoc) {
+            Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                         diag::err_verify_wildcard_loc);
+            continue;
+          }
           MatchAnyFileAndLine = true;
           if (!PH.Next("*")) {
             Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
@@ -592,11 +598,21 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
           if (PH.Next(Line) && Line > 0)
             ExpectedLoc = SM.translateLineCol(FID, Line, 1);
           else if (PH.Next("*")) {
+            if (DisableWildcardInDiagLoc) {
+              Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                           diag::err_verify_wildcard_loc);
+              continue;
+            }
             MatchAnyLine = true;
             ExpectedLoc = SM.translateLineCol(FID, 1, 1);
           }
         }
       } else if (PH.Next("*")) {
+        if (DisableWildcardInDiagLoc) {
+          Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                       diag::err_verify_wildcard_loc);
+          continue;
+        }
         MatchAnyLine = true;
         ExpectedLoc = SourceLocation();
       }
@@ -725,6 +741,8 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
     setSourceManager(Diags.getSourceManager());
   CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
   OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
+  DisableWildcardInDiagLoc =
+      Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
 }
 
 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
@@ -841,7 +859,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
   size_t loc = C.find('\\');
   if (loc == StringRef::npos) {
     ParseDirective(C, &ED, SM, &PP, CommentBegin, State, *Markers,
-                   OneDiagPerDirective);
+                   OneDiagPerDirective, DisableWildcardInDiagLoc);
     return false;
   }
 
@@ -872,7 +890,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
 
   if (!C2.empty())
     ParseDirective(C2, &ED, SM, &PP, CommentBegin, State, *Markers,
-                   OneDiagPerDirective);
+                   OneDiagPerDirective, DisableWildcardInDiagLoc);
   return false;
 }
 
@@ -911,7 +929,8 @@ static bool findDirectives(SourceManager &SM, FileID FID,
 
     // Find first directive.
     if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(), State,
-                       Markers, /*OneDiagPerDirective=*/false))
+                       Markers, /*OneDiagPerDirective=*/false,
+                       /*DisableWildcardInDiagLoc=*/false))
       return true;
   }
   return false;

>From a8b076086afbf3940da0f78cbfabcd98f4184d13 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 2 Nov 2025 18:42:46 +0300
Subject: [PATCH 08/25] Print actual diagnostic message when printing partial
 match

---
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 76 ++++++++-----------
 1 file changed, 33 insertions(+), 43 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 53dff3fe700fc..270cf11feaaa8 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1005,47 +1005,6 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags,
   return DL.size();
 }
 
-/// Takes a list of diagnostics that were partially matched,
-/// despite '-verify-strict' option being set.
-static unsigned PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
-                             llvm::SmallVector<Directive *> &DL) {
-  if (DL.empty())
-    return 0;
-
-  const bool IsSinglePrefix =
-      Diags.getDiagnosticOptions().VerifyPrefixes.size() == 1;
-
-  SmallString<256> Fmt;
-  llvm::raw_svector_ostream OS(Fmt);
-  for (const auto *D : DL) {
-    if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
-      OS << "\n  File *";
-    else
-      OS << "\n  File " << SourceMgr.getFilename(D->DiagnosticLoc);
-    if (D->MatchAnyLine)
-      OS << " Line *";
-    else
-      OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
-    if (D->DirectiveLoc != D->DiagnosticLoc) {
-      if (SourceMgr.getFilename(D->DirectiveLoc) !=
-          SourceMgr.getFilename(D->DiagnosticLoc)) {
-        OS << " (directive at " << SourceMgr.getFilename(D->DirectiveLoc) << ':'
-           << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
-      } else {
-        OS << " (directive at line "
-           << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
-      }
-    }
-    if (!IsSinglePrefix)
-      OS << " \'" << D->Spelling << '\'';
-    OS << ": " << D->Text;
-  }
-
-  Diags.Report(diag::err_verify_message_partial_match).setForceEmit()
-      << OS.str();
-  return DL.size();
-}
-
 /// Determine whether two source locations come from the same file.
 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
                            SourceLocation DiagnosticLoc) {
@@ -1062,6 +1021,37 @@ static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
 }
 
+/// Takes a list of diagnostics that were partially matched,
+/// despite '-verify-strict' option being set.
+static unsigned
+PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
+             llvm::SmallVector<std::pair<Directive *, std::string>> &DL) {
+  if (DL.empty())
+    return 0;
+
+  SmallString<256> Fmt;
+  llvm::raw_svector_ostream OS(Fmt);
+  for (const auto &[D, DiagText] : DL) {
+    assert(!D->MatchAnyLine && !D->MatchAnyFileAndLine &&
+           "Wildcards should not be allowed in strict verify mode");
+    OS << "\n  Directive at " << SourceMgr.getFilename(D->DirectiveLoc) << ":"
+       << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << " \'"
+       << D->Spelling << "\': " << D->Text
+       << "\n    does not fully match diagnostic at ";
+    if (IsFromSameFile(SourceMgr, D->DirectiveLoc, D->DiagnosticLoc)) {
+      OS << "line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
+    } else {
+      OS << SourceMgr.getFilename(D->DiagnosticLoc) << ":"
+         << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
+    }
+    OS << ": " << DiagText;
+  }
+
+  Diags.Report(diag::err_verify_message_partial_match).setForceEmit()
+      << OS.str();
+  return DL.size();
+}
+
 /// CheckLists - Compare expected to seen diagnostic lists and return the
 /// the difference between them.
 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
@@ -1072,7 +1062,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
                            bool IgnoreUnexpected) {
   std::vector<Directive *> LeftOnly;
   DiagList Right(d2_begin, d2_end);
-  llvm::SmallVector<Directive *> IncompleteMatches;
+  llvm::SmallVector<std::pair<Directive *, std::string>> IncompleteMatches;
 
   for (auto &Owner : Left) {
     Directive &D = *Owner;
@@ -1096,7 +1086,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
         if (MatchResult != DiagnosticMatchResult::NoMatch) {
           if (D.FullMatchRequired &&
               MatchResult == DiagnosticMatchResult::PartialMatch) {
-            IncompleteMatches.push_back(&D);
+            IncompleteMatches.push_back({&D, II->second});
           }
           break;
         }

>From cdb615096a175fbaf874b6976766e26854ed3706 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 2 Nov 2025 18:59:06 +0300
Subject: [PATCH 09/25] Trim diagnostic text before checking for full match

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 270cf11feaaa8..db73000af1e83 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -106,8 +106,8 @@ class StandardDirective : public Directive {
     if (!FullMatchRequired) {
       return DiagnosticMatchResult::Match;
     }
-    return S == Text ? DiagnosticMatchResult::Match
-                     : DiagnosticMatchResult::PartialMatch;
+    return S.trim() == Text ? DiagnosticMatchResult::Match
+                            : DiagnosticMatchResult::PartialMatch;
   }
 };
 
@@ -133,7 +133,7 @@ class RegexDirective : public Directive {
     }
 
     llvm::SmallVector<StringRef, 4> Matches;
-    Regex.match(S, &Matches);
+    Regex.match(S.trim(), &Matches);
     if (Matches.empty()) {
       return DiagnosticMatchResult::NoMatch;
     }

>From 2ad4b5cab3cd073a47dc2e4b61a895764e83f66b Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 3 Nov 2025 21:15:22 +0300
Subject: [PATCH 10/25] Fix couple of bugs in directive order check

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index db73000af1e83..dcab85ab54708 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1158,7 +1158,7 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
                                        const ExpectedData &ED) {
   // Building a set of all directives ordered by their location
   auto directiveComparator = [](const Directive *LHS, const Directive *RHS) {
-    return LHS->DirectiveLoc < RHS->DiagnosticLoc;
+    return LHS->DirectiveLoc < RHS->DirectiveLoc;
   };
   auto sortDirectives = [&](const DirectiveList &Unordered) {
     std::vector<const Directive *> Ordered(Unordered.size());
@@ -1191,8 +1191,8 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
     return OrderedDirectives;
   }();
 
-  auto getLocDiagPair = [&](DiagnosticsEngine::Level DiagLevel,
-                            long DiagIndex) {
+  auto getLocDiagPair = [&](DiagnosticsEngine::Level DiagLevel, long DiagIndex)
+      -> const std::pair<clang::SourceLocation, std::basic_string<char>> & {
     TextDiagnosticBuffer::const_iterator It = [&] {
       switch (DiagLevel) {
       case DiagnosticsEngine::Level::Fatal:
@@ -1230,15 +1230,15 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
   for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(
            OrderedDirectives,
            llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
-    assert(!Directive->MatchAnyFileAndLine);
-    assert(!Directive->MatchAnyLine);
+    assert(!Directive->MatchAnyFileAndLine && !Directive->MatchAnyLine &&
+           "Wildcards should not be allowed in strict verify mode!");
     const auto [DiagLevel, DiagIndex] = LevelDiagPair;
-    const auto [DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
+    const auto &[DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
     const SourceLocation DirLoc = Directive->DirectiveLoc;
     bool LocsMatch =
         SourceMgr.getPresumedLineNumber(DiagLoc) ==
             SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) &&
-        IsFromSameFile(SourceMgr, DiagLoc, Directive->DiagnosticLoc);
+        IsFromSameFile(SourceMgr, Directive->DiagnosticLoc, DiagLoc);
     if (!LocsMatch ||
         Directive->match(DiagText) != DiagnosticMatchResult::Match) {
       SmallString<256> Fmt;

>From d86d2c609c40184f697147a7bf100f2d37e8f353 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Wed, 5 Nov 2025 13:33:17 +0300
Subject: [PATCH 11/25] Significantly Improve diagnsotics for out of order case

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |  4 +-
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 37 ++++++-------------
 2 files changed, 14 insertions(+), 27 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 7f3ebc266a77a..0d3255795c5dd 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -191,8 +191,8 @@ def err_verify_nonconst_addrspace : Error<
 def err_verify_message_partial_match
     : Error<"diagnostic messages not fully matched: %0">;
 def err_verify_directive_out_of_order
-    : Error<"out of order directive found: %0\nSubsequent directives were "
-            "skipped">;
+    : Error<"all diagnostics were successfully matched, but out of order "
+            "directives were found: %0">;
 def err_verify_non_singular_match
     : Error<"exactly one diagnostic can be matched">;
 def err_verify_wildcard_loc
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index dcab85ab54708..cf5600e4bd675 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1224,9 +1224,11 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
   using LevelDiagPairT = std::pair<DiagnosticsEngine::Level, size_t>;
   static_assert(std::is_same_v<LevelDiagPairT,
                                TextDiagnosticBuffer::AllDiagList::value_type>);
-
+  int NumProblems = 0;
+  SmallString<256> Fmt;
+  llvm::raw_svector_ostream OS(Fmt);
   // CheckResults already ensured that there are as many directives as emitted
-  // diagnostics
+  // diagnostics, and that all of them match.
   for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(
            OrderedDirectives,
            llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
@@ -1241,31 +1243,16 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
         IsFromSameFile(SourceMgr, Directive->DiagnosticLoc, DiagLoc);
     if (!LocsMatch ||
         Directive->match(DiagText) != DiagnosticMatchResult::Match) {
-      SmallString<256> Fmt;
-      llvm::raw_svector_ostream OS(Fmt);
-      OS << "\n  directive at " << SourceMgr.getFilename(DirLoc) << ":"
-         << SourceMgr.getPresumedLineNumber(DirLoc) << ": " << Directive->Text
-         << "\n  that expects diagnostic at ";
-      if (IsFromSameFile(SourceMgr, DirLoc, Directive->DiagnosticLoc)) {
-        OS << "line "
-           << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
-      } else {
-        OS << SourceMgr.getFilename(Directive->DiagnosticLoc) << ":"
-           << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
-      }
-      OS << "\n  does not match diagnostic at ";
-      if (IsFromSameFile(SourceMgr, DirLoc, DiagLoc)) {
-        OS << "line " << SourceMgr.getPresumedLineNumber(DiagLoc);
-      } else {
-        OS << SourceMgr.getFilename(DiagLoc) << ":"
-           << SourceMgr.getPresumedLineNumber(DiagLoc);
-      }
-      OS << ": " << DiagText;
-      Diags.Report(diag::err_verify_directive_out_of_order) << OS.str();
-      return 1;
+      OS << "\n  '" << Directive->Spelling << "' at line "
+         << SourceMgr.getPresumedLineNumber(DirLoc) << " in "
+         << SourceMgr.getFilename(DirLoc) << ": " << Directive->Text;
+      ++NumProblems;
     }
   }
-  return 0;
+  if (NumProblems > 0) {
+    Diags.Report(diag::err_verify_directive_out_of_order) << OS.str();
+  }
+  return NumProblems;
 }
 
 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,

>From ff657ee7bfa8d25ed615dff3e50da8642338ff22 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 10 Nov 2025 15:44:56 +0300
Subject: [PATCH 12/25] Print severity in diagnostic about partial matches

---
 clang/include/clang/Basic/DiagnosticFrontendKinds.td | 2 +-
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp      | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 0d3255795c5dd..e31692621d2a5 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -189,7 +189,7 @@ def err_verify_no_directives : Error<
 def err_verify_nonconst_addrspace : Error<
   "qualifier 'const' is needed for variables in address space '%0'">;
 def err_verify_message_partial_match
-    : Error<"diagnostic messages not fully matched: %0">;
+    : Error<"diagnostic messages of '%0' severity not fully matched: %1">;
 def err_verify_directive_out_of_order
     : Error<"all diagnostics were successfully matched, but out of order "
             "directives were found: %0">;
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index cf5600e4bd675..729c88501253c 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1025,7 +1025,8 @@ static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
 /// despite '-verify-strict' option being set.
 static unsigned
 PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
-             llvm::SmallVector<std::pair<Directive *, std::string>> &DL) {
+             llvm::SmallVector<std::pair<Directive *, std::string>> &DL,
+             const char *Kind) {
   if (DL.empty())
     return 0;
 
@@ -1048,7 +1049,7 @@ PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   }
 
   Diags.Report(diag::err_verify_message_partial_match).setForceEmit()
-      << OS.str();
+      << Kind << OS.str();
   return DL.size();
 }
 
@@ -1105,7 +1106,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
   if (!IgnoreUnexpected)
     num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
-  num += PrintPartial(Diags, SourceMgr, IncompleteMatches);
+  num += PrintPartial(Diags, SourceMgr, IncompleteMatches, Label);
   return num;
 }
 

>From 6bbdf64fb62abc00af8ce991ab83dc22201f135c Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 21 Nov 2025 17:55:19 +0300
Subject: [PATCH 13/25] Add missing hyphens to diagnostic message

---
 clang/include/clang/Basic/DiagnosticFrontendKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index e31692621d2a5..335b299155b26 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -191,7 +191,7 @@ def err_verify_nonconst_addrspace : Error<
 def err_verify_message_partial_match
     : Error<"diagnostic messages of '%0' severity not fully matched: %1">;
 def err_verify_directive_out_of_order
-    : Error<"all diagnostics were successfully matched, but out of order "
+    : Error<"all diagnostics were successfully matched, but out-of-order "
             "directives were found: %0">;
 def err_verify_non_singular_match
     : Error<"exactly one diagnostic can be matched">;

>From 2825edb3b6aa425057e85e1fd4f417e8ec327f9a Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 21 Nov 2025 17:56:34 +0300
Subject: [PATCH 14/25] Correctly trim strings before checking for full match

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 729c88501253c..85fb818d9e64f 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -133,12 +133,14 @@ class RegexDirective : public Directive {
     }
 
     llvm::SmallVector<StringRef, 4> Matches;
-    Regex.match(S.trim(), &Matches);
+    llvm::StringRef TrimmedText = S.trim();
+    Regex.match(TrimmedText, &Matches);
     if (Matches.empty()) {
       return DiagnosticMatchResult::NoMatch;
     }
-    return Matches[0].size() == S.size() ? DiagnosticMatchResult::Match
-                                         : DiagnosticMatchResult::PartialMatch;
+    return Matches[0].size() == TrimmedText.size()
+               ? DiagnosticMatchResult::Match
+               : DiagnosticMatchResult::PartialMatch;
   }
 
 private:

>From f5b93d6716f85bece3488f1e5eb74ef406577e17 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 21 Nov 2025 17:57:13 +0300
Subject: [PATCH 15/25] Improve diagnostic for out-of-order case

---
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 36 +++++++++++++++----
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 85fb818d9e64f..61f3fe27e062a 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1240,16 +1240,40 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
     const auto [DiagLevel, DiagIndex] = LevelDiagPair;
     const auto &[DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
     const SourceLocation DirLoc = Directive->DirectiveLoc;
+
     bool LocsMatch =
         SourceMgr.getPresumedLineNumber(DiagLoc) ==
             SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) &&
         IsFromSameFile(SourceMgr, Directive->DiagnosticLoc, DiagLoc);
-    if (!LocsMatch ||
-        Directive->match(DiagText) != DiagnosticMatchResult::Match) {
-      OS << "\n  '" << Directive->Spelling << "' at line "
-         << SourceMgr.getPresumedLineNumber(DirLoc) << " in "
-         << SourceMgr.getFilename(DirLoc) << ": " << Directive->Text;
-      ++NumProblems;
+    bool TextMatch = Directive->match(DiagText) == DiagnosticMatchResult::Match;
+    if (LocsMatch && TextMatch) {
+      continue;
+    }
+    ++NumProblems;
+
+    auto printFileNameIfDifferent = [&](SourceLocation DirLoc,
+                                        SourceLocation Loc) {
+      if (!IsFromSameFile(SourceMgr, DirLoc, Loc)) {
+        OS << " in " << SourceMgr.getFilename(Loc);
+      }
+    };
+
+    OS << "\n  '" << Directive->Spelling << "' at line "
+       << SourceMgr.getPresumedLineNumber(DirLoc) << " in "
+       << SourceMgr.getFilename(DirLoc) << ": " << Directive->Text
+       << "\n    matches diagnostic at line "
+       << SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc);
+    printFileNameIfDifferent(DirLoc, Directive->DiagnosticLoc);
+    if (TextMatch) {
+      OS << ", but diagnostic with the same message was first emitted at line "
+         << SourceMgr.getPresumedLineNumber(DiagLoc);
+      printFileNameIfDifferent(DirLoc, DiagLoc);
+    } else {
+      OS << ", but diagnostic at line "
+         << SourceMgr.getPresumedLineNumber(DiagLoc);
+      printFileNameIfDifferent(DirLoc, DiagLoc);
+      OS << " was emitted first:"
+         << "\n      " << DiagText;
     }
   }
   if (NumProblems > 0) {

>From 06ac16a2f9af44d82a556a8898c9383236ff098c Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 21 Nov 2025 17:57:34 +0300
Subject: [PATCH 16/25] Improve diagnostic for partial case

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 61f3fe27e062a..488abec664060 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1037,15 +1037,13 @@ PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   for (const auto &[D, DiagText] : DL) {
     assert(!D->MatchAnyLine && !D->MatchAnyFileAndLine &&
            "Wildcards should not be allowed in strict verify mode");
-    OS << "\n  Directive at " << SourceMgr.getFilename(D->DirectiveLoc) << ":"
-       << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << " \'"
-       << D->Spelling << "\': " << D->Text
-       << "\n    does not fully match diagnostic at ";
-    if (IsFromSameFile(SourceMgr, D->DirectiveLoc, D->DiagnosticLoc)) {
-      OS << "line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
-    } else {
-      OS << SourceMgr.getFilename(D->DiagnosticLoc) << ":"
-         << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
+    OS << "\n  '" << D->Spelling << "' at line "
+       << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << " in "
+       << SourceMgr.getFilename(D->DiagnosticLoc) << ": " << D->Text
+       << "\n    does not fully match diagnostic at line "
+       << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
+    if (!IsFromSameFile(SourceMgr, D->DirectiveLoc, D->DiagnosticLoc)) {
+      OS << " in " << SourceMgr.getFilename(D->DiagnosticLoc);
     }
     OS << ": " << DiagText;
   }

>From f3ddf13c949c42a1dc4f5d184064cb6e9dadaf6e Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 21 Nov 2025 17:58:37 +0300
Subject: [PATCH 17/25] Fix missing diagnostic for non-singular match

---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 488abec664060..d32fcac9f371e 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -666,7 +666,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
       }
     } else if (PH.Next("+")) {
       // '+' on its own means "1 or more".
-      if (OneDiagPerDirective && D.Max != 1) {
+      if (OneDiagPerDirective) {
         Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                      diag::err_verify_non_singular_match);
         continue;

>From ec12c830e929974d788848e45e9284a0e269c370 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Mon, 3 Nov 2025 07:50:25 -0500
Subject: [PATCH 18/25] [C2y] Support WG14 N3457, the __COUNTER__ macro
 (#162662)

This implements the parts of
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm which were
adopted at the recent meeting in Brno.

Clang already implemented `__COUNTER__`, but needed some changes for
conformance. Specifically, we now diagnose when the macro is expanded
more than 2147483647 times. Additionally, we now give the expected
extension and pre-compat warnings for the feature.

To support testing the limits, this also adds a -cc1-only option,
`-finitial-counter-value=`, which lets you specify the initial value the
`__COUNTER__` macro should expand to.
---
 clang/docs/LanguageExtensions.rst             |  5 ++-
 clang/docs/ReleaseNotes.rst                   |  5 +++
 .../include/clang/Basic/DiagnosticLexKinds.td |  8 ++++
 clang/include/clang/Driver/Options.td         |  4 ++
 clang/include/clang/Lex/Preprocessor.h        |  6 +--
 clang/include/clang/Lex/PreprocessorOptions.h |  4 ++
 clang/include/clang/Serialization/ASTReader.h |  8 ++--
 clang/lib/Frontend/ASTUnit.cpp                |  6 +--
 clang/lib/Frontend/InitPreprocessor.cpp       |  3 ++
 clang/lib/Lex/PPMacroExpansion.cpp            | 14 ++++++-
 clang/lib/Serialization/ASTReader.cpp         |  4 +-
 clang/test/C/C2y/n3457.c                      | 38 +++++++++++++++++++
 clang/test/C/C2y/n3457_1.c                    | 20 ++++++++++
 clang/test/C/C2y/n3457_2.c                    | 10 +++++
 clang/www/c_status.html                       |  2 +-
 .../benchmark/include/benchmark/benchmark.h   | 10 +++++
 16 files changed, 132 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/C/C2y/n3457.c
 create mode 100644 clang/test/C/C2y/n3457_1.c
 create mode 100644 clang/test/C/C2y/n3457_2.c

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 495f2ab3926ce..baa0bbb5ea631 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -385,7 +385,9 @@ Builtin Macros
 
 ``__COUNTER__``
   Defined to an integer value that starts at zero and is incremented each time
-  the ``__COUNTER__`` macro is expanded.
+  the ``__COUNTER__`` macro is expanded. This is a standard feature in C2y but
+  is an extension in earlier language modes and in C++. This macro can only be
+  expanded 2147483647 times at most.
 
 ``__INCLUDE_LEVEL__``
   Defined to an integral value that is the include depth of the file currently
@@ -1821,6 +1823,7 @@ Octal literals prefixed with ``0o`` or ``0O``                                  C
 ``_Countof`` (N3369, N3469)                                                    C2y           C89
 ``_Generic`` with a type operand (N3260)                                       C2y           C89, C++
 ``++``/``--`` on ``_Complex`` value (N3259)                                    C2y           C89, C++
+``__COUNTER__`` (N3457)                                                        C2y           C89, C++
 ============================================= ================================ ============= =============
 
 Builtin type aliases
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 73aaaad8b32e5..56fd508e46ff0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -196,6 +196,11 @@ C2y Feature Support
   function or variable within an extern inline function is no longer a
   constraint per `WG14 N3622 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3622.txt>`_.
 - Clang now supports `N3355 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm>`_ Named Loops.
+- Clang's implementation of ``__COUNTER__`` was updated to conform to
+  `WG14 N3457 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm>`_.
+  This includes adding pedantic warnings for the feature being an extension in
+  other language modes as well as an error when the counter is expanded more
+  than 2147483647 times.
 
 C23 Feature Support
 ^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index c7fe6e1db6d1f..417187222e448 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -90,6 +90,14 @@ def err_unterminated___pragma : Error<"missing terminating ')' character">;
 
 def err_conflict_marker : Error<"version control conflict marker in file">;
 
+def err_counter_overflow : Error<
+  "'__COUNTER__' value cannot exceed 2'147'483'647">;
+def ext_counter : Extension<
+  "'__COUNTER__' is a C2y extension">, InGroup<C2y>;
+def warn_counter : Warning<
+  "'__COUNTER__' is incompatible with standards before C2y">,
+  InGroup<CPre2yCompat>, DefaultIgnore;
+
 def err_raw_delim_too_long : Error<
   "raw string delimiter longer than 16 characters"
   "; use PREFIX( )PREFIX to delimit raw string">;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 77cb21e3b7d8a..1ac6725cda7c3 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -8451,6 +8451,10 @@ def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">,
   MarshallingInfoFlag<LangOpts<"AlignedAllocationUnavailable">>,
   ShouldParseIf<faligned_allocation.KeyPath>;
 
+def finitial_counter_value_EQ : Joined<["-"], "finitial-counter-value=">,
+  HelpText<"Sets the initial value for __COUNTER__, defaults to 0.">,
+  MarshallingInfoInt<PreprocessorOpts<"InitialCounterValue">, "0">;
+
 } // let Visibility = [CC1Option]
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 39754847a93e4..412002259c054 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -226,7 +226,7 @@ class Preprocessor {
       LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine;
 
   // Next __COUNTER__ value, starts at 0.
-  unsigned CounterValue = 0;
+  uint32_t CounterValue = 0;
 
   enum {
     /// Maximum depth of \#includes.
@@ -2421,8 +2421,8 @@ class Preprocessor {
   bool SawDateOrTime() const {
     return DATELoc != SourceLocation() || TIMELoc != SourceLocation();
   }
-  unsigned getCounterValue() const { return CounterValue; }
-  void setCounterValue(unsigned V) { CounterValue = V; }
+  uint32_t getCounterValue() const { return CounterValue; }
+  void setCounterValue(uint32_t V) { CounterValue = V; }
 
   LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const {
     assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine &&
diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h
index d4c4e1ccbf2c4..1c2f6e72e1b93 100644
--- a/clang/include/clang/Lex/PreprocessorOptions.h
+++ b/clang/include/clang/Lex/PreprocessorOptions.h
@@ -198,6 +198,10 @@ class PreprocessorOptions {
   /// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
   std::optional<uint64_t> SourceDateEpoch;
 
+  /// The initial value for __COUNTER__; typically is zero but can be set via a
+  /// -cc1 flag for testing purposes.
+  uint32_t InitialCounterValue = 0;
+
 public:
   PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
 
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index af856a8097ab1..4ca45a16408a6 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -220,8 +220,8 @@ class ASTReaderListener {
   }
 
   /// Receives __COUNTER__ value.
-  virtual void ReadCounter(const serialization::ModuleFile &M,
-                           unsigned Value) {}
+  virtual void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) {
+  }
 
   /// This is called for each AST file loaded.
   virtual void visitModuleFile(StringRef Filename,
@@ -312,7 +312,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
                                bool Complain,
                                std::string &SuggestedPredefines) override;
 
-  void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override;
+  void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) override;
   bool needsInputFileVisitation() override;
   bool needsSystemInputFileVisitation() override;
   void visitModuleFile(StringRef Filename,
@@ -352,7 +352,7 @@ class PCHValidator : public ASTReaderListener {
                                StringRef ModuleFilename,
                                StringRef SpecificModuleCachePath,
                                bool Complain) override;
-  void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override;
+  void ReadCounter(const serialization::ModuleFile &M, uint32_t Value) override;
 };
 
 /// ASTReaderListenter implementation to set SuggestedPredefines of
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 6cc7094846155..1169acb389acf 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -518,14 +518,14 @@ class ASTInfoCollector : public ASTReaderListener {
   LangOptions &LangOpts;
   CodeGenOptions &CodeGenOpts;
   TargetOptions &TargetOpts;
-  unsigned &Counter;
+  uint32_t &Counter;
 
 public:
   ASTInfoCollector(HeaderSearchOptions &HSOpts,
                    std::string &SpecificModuleCachePath,
                    PreprocessorOptions &PPOpts, LangOptions &LangOpts,
                    CodeGenOptions &CodeGenOpts, TargetOptions &TargetOpts,
-                   unsigned &Counter)
+                   uint32_t &Counter)
       : HSOpts(HSOpts), SpecificModuleCachePath(SpecificModuleCachePath),
         PPOpts(PPOpts), LangOpts(LangOpts), CodeGenOpts(CodeGenOpts),
         TargetOpts(TargetOpts), Counter(Counter) {}
@@ -577,7 +577,7 @@ class ASTInfoCollector : public ASTReaderListener {
   }
 
   void ReadCounter(const serialization::ModuleFile &M,
-                   unsigned NewCounter) override {
+                   uint32_t NewCounter) override {
     Counter = NewCounter;
   }
 };
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 47f1d5a6b636c..9ddcc366dc1d9 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1542,6 +1542,9 @@ void clang::InitializePreprocessor(Preprocessor &PP,
   llvm::raw_string_ostream Predefines(PredefineBuffer);
   MacroBuilder Builder(Predefines);
 
+  // Ensure that the initial value of __COUNTER__ is hooked up.
+  PP.setCounterValue(InitOpts.InitialCounterValue);
+
   // Emit line markers for various builtin sections of the file. The 3 here
   // marks <built-in> as being a system header, which suppresses warnings when
   // the same macro is defined multiple times.
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index dd80ae586a1f6..5efa4b5b3f872 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1735,7 +1735,19 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
       Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here);
     }
   } else if (II == Ident__COUNTER__) {
-    // __COUNTER__ expands to a simple numeric value.
+    Diag(Tok.getLocation(),
+         getLangOpts().C2y ? diag::warn_counter : diag::ext_counter);
+    // __COUNTER__ expands to a simple numeric value that must be less than
+    // 2147483647.
+    constexpr uint32_t MaxPosValue = std::numeric_limits<int32_t>::max();
+    if (CounterValue > MaxPosValue) {
+      Diag(Tok.getLocation(), diag::err_counter_overflow);
+      // Retain the maximal value so we don't issue conversion-related
+      // diagnostics by overflowing into a long long. While this does produce
+      // a duplicate value, there's no way to ignore this error so there's no
+      // translation anyway.
+      CounterValue = MaxPosValue;
+    }
     OS << CounterValue++;
     Tok.setKind(tok::numeric_constant);
   } else if (II == Ident__has_feature) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index e3106f8d8e13c..d5528219bb7d5 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -225,7 +225,7 @@ bool ChainedASTReaderListener::ReadPreprocessorOptions(
 }
 
 void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M,
-                                           unsigned Value) {
+                                           uint32_t Value) {
   First->ReadCounter(M, Value);
   Second->ReadCounter(M, Value);
 }
@@ -973,7 +973,7 @@ bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
       PP.getPreprocessorOpts());
 }
 
-void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
+void PCHValidator::ReadCounter(const ModuleFile &M, uint32_t Value) {
   PP.setCounterValue(Value);
 }
 
diff --git a/clang/test/C/C2y/n3457.c b/clang/test/C/C2y/n3457.c
new file mode 100644
index 0000000000000..d71a3f37e1343
--- /dev/null
+++ b/clang/test/C/C2y/n3457.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -verify=ext -std=c23 -pedantic %s
+// RUN: %clang_cc1 -verify=ext -pedantic -x c++ %s
+// RUN: %clang_cc1 -verify=pre -std=c2y -pedantic -Wpre-c2y-compat %s
+
+/* WG14 N3457: Clang 22
+ * The __COUNTER__ predefined macro
+ *
+ * This predefined macro was supported as an extension in earlier versions of
+ * Clang, but the required diagnostics for the limits were not added until 22.
+ */
+
+// Ensure that __COUNTER__ starts from 0.
+static_assert(__COUNTER__ == 0); /* ext-warning {{'__COUNTER__' is a C2y extension}}
+                                    pre-warning {{'__COUNTER__' is incompatible with standards before C2y}}
+                                  */
+
+// Ensure that the produced value can be used with token concatenation.
+#define CAT_IMPL(a, b) a ## b
+#define CAT(a, b) CAT_IMPL(a, b)
+#define NAME_WITH_COUNTER(a) CAT(a, __COUNTER__)
+void test() {
+  // Because this is the 2nd expansion, this defines test1.
+  int NAME_WITH_COUNTER(test); /* ext-warning {{'__COUNTER__' is a C2y extension}}
+                                  pre-warning {{'__COUNTER__' is incompatible with standards before C2y}}
+                                */
+  int other_test = test1;      // Ok
+}
+
+// Ensure that __COUNTER__ increments each time you mention it.
+static_assert(__COUNTER__ == 2); /* ext-warning {{'__COUNTER__' is a C2y extension}}
+                                    pre-warning {{'__COUNTER__' is incompatible with standards before C2y}}
+                                 */
+static_assert(__COUNTER__ == 3); /* ext-warning {{'__COUNTER__' is a C2y extension}}
+                                    pre-warning {{'__COUNTER__' is incompatible with standards before C2y}}
+                                 */
+static_assert(__COUNTER__ == 4); /* ext-warning {{'__COUNTER__' is a C2y extension}}
+                                    pre-warning {{'__COUNTER__' is incompatible with standards before C2y}}
+                                 */
diff --git a/clang/test/C/C2y/n3457_1.c b/clang/test/C/C2y/n3457_1.c
new file mode 100644
index 0000000000000..76c5a0b9a700f
--- /dev/null
+++ b/clang/test/C/C2y/n3457_1.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify -std=c2y -finitial-counter-value=2147483646 %s
+
+// The value produced needs to be a type that's representable with a signed
+// long. However, the actual type it expands to does *not* need to be forced to
+// be signed long because that would generally mean suffixing the value with L,
+// which would be very surprising for folks using this to generate unique ids.
+// We'll test this by ensuring the largest value can be expanded properly and
+// an assertion that signed long is always at least four bytes wide (which is
+// what's required to represent that maximal value).
+//
+// So we set the initial counter value to 2147483646, we'll validate that,
+// increment it once to get to the maximal value and ensure there's no
+// diagnostic, then increment again to ensure we get the constraint violation.
+
+static_assert(__COUNTER__ == 2147483646); // Test and increment
+static_assert(__COUNTER__ == 2147483647); // Test and increment
+
+// This one should fail.
+signed long i = __COUNTER__; // expected-error {{'__COUNTER__' value cannot exceed 2'147'483'647}}
+
diff --git a/clang/test/C/C2y/n3457_2.c b/clang/test/C/C2y/n3457_2.c
new file mode 100644
index 0000000000000..018c8f4390767
--- /dev/null
+++ b/clang/test/C/C2y/n3457_2.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -verify=good -std=c2y -finitial-counter-value=2147483648 %s
+// RUN: %clang_cc1 -verify -std=c2y -finitial-counter-value=2147483648 -DEXPAND_IT %s
+// good-no-diagnostics
+
+// This sets the intial __COUNTER__ value to something that's too big. Setting
+// the value too large is fine. Expanding to a too-large value is not.
+#ifdef EXPAND_IT
+  // This one should fail.
+  signed long i = __COUNTER__; // expected-error {{'__COUNTER__' value cannot exceed 2'147'483'647}}
+#endif
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index b8039622fe694..80a52f791dfcf 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -329,7 +329,7 @@ <h2 id="c2y">C2y implementation status</h2>
     <tr>
       <td>The __COUNTER__ predefined macro</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm">N3457</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="unreleased" align="center">Clang 22</td>
 	</tr>
     <tr>
       <td>Chasing Ghosts I: constant expressions v2</td>
diff --git a/third-party/benchmark/include/benchmark/benchmark.h b/third-party/benchmark/include/benchmark/benchmark.h
index 08cfe29da344e..c2debb216d64f 100644
--- a/third-party/benchmark/include/benchmark/benchmark.h
+++ b/third-party/benchmark/include/benchmark/benchmark.h
@@ -250,6 +250,10 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
   _Pragma("GCC diagnostic push")             \
   _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
 #define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("GCC diagnostic pop")
+#define BENCHMARK_DISABLE_PEDANTIC_WARNING \
+  _Pragma("GCC diagnostic push")             \
+  _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
+#define BENCHMARK_RESTORE_PEDANTIC_WARNING _Pragma("GCC diagnostic pop")
 #elif defined(__NVCOMPILER)
 #define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y)
 #define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
@@ -257,6 +261,8 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
   _Pragma("diagnostic push") \
   _Pragma("diag_suppress deprecated_entity_with_custom_message")
 #define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop")
+#define BENCHMARK_DISABLE_PEDANTIC_WARNING
+#define BENCHMARK_RESTORE_PEDANTIC_WARNING
 #else
 #define BENCHMARK_BUILTIN_EXPECT(x, y) x
 #define BENCHMARK_DEPRECATED_MSG(msg)
@@ -265,6 +271,8 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
       __LINE__) ") : warning note: " msg))
 #define BENCHMARK_DISABLE_DEPRECATED_WARNING
 #define BENCHMARK_RESTORE_DEPRECATED_WARNING
+#define BENCHMARK_DISABLE_PEDANTIC_WARNING
+#define BENCHMARK_RESTORE_PEDANTIC_WARNING
 #endif
 // clang-format on
 
@@ -1462,11 +1470,13 @@ class Fixture : public internal::Benchmark {
 // Check that __COUNTER__ is defined and that __COUNTER__ increases by 1
 // every time it is expanded. X + 1 == X + 0 is used in case X is defined to be
 // empty. If X is empty the expression becomes (+1 == +0).
+BENCHMARK_DISABLE_PEDANTIC_WARNING
 #if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0)
 #define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__
 #else
 #define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__
 #endif
+BENCHMARK_RESTORE_PEDANTIC_WARNING
 
 // Helpers for generating unique variable names
 #ifdef BENCHMARK_HAS_CXX11

>From 4576991d7dc4bd7a18b2266e5c1d58d666dcc508 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 30 Jan 2026 13:56:47 +0300
Subject: [PATCH 19/25] Rename enumerators in DiagnosticMatchResult

---
 .../clang/Frontend/VerifyDiagnosticConsumer.h    |  4 ++--
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp  | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index ef1839f25cafd..9098ac685cbb7 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -32,8 +32,8 @@ class TextDiagnosticBuffer;
 
 enum class DiagnosticMatchResult {
   NoMatch,
-  Match,
-  PartialMatch,
+  Partial,
+  Full,
 };
 
 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 2ab54dce477c7..eed799890ce41 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -104,10 +104,10 @@ class StandardDirective : public Directive {
       return DiagnosticMatchResult::NoMatch;
     }
     if (!FullMatchRequired) {
-      return DiagnosticMatchResult::Match;
+      return DiagnosticMatchResult::Full;
     }
-    return S.trim() == Text ? DiagnosticMatchResult::Match
-                            : DiagnosticMatchResult::PartialMatch;
+    return S.trim() == Text ? DiagnosticMatchResult::Full
+                            : DiagnosticMatchResult::Partial;
   }
 };
 
@@ -128,7 +128,7 @@ class RegexDirective : public Directive {
 
   DiagnosticMatchResult match(StringRef S) const override {
     if (!FullMatchRequired) {
-      return Regex.match(S) ? DiagnosticMatchResult::Match
+      return Regex.match(S) ? DiagnosticMatchResult::Full
                             : DiagnosticMatchResult::NoMatch;
     }
 
@@ -139,8 +139,8 @@ class RegexDirective : public Directive {
       return DiagnosticMatchResult::NoMatch;
     }
     return Matches[0].size() == TrimmedText.size()
-               ? DiagnosticMatchResult::Match
-               : DiagnosticMatchResult::PartialMatch;
+               ? DiagnosticMatchResult::Full
+               : DiagnosticMatchResult::Partial;
   }
 
 private:
@@ -1086,7 +1086,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
         DiagnosticMatchResult MatchResult = D.match(RightText);
         if (MatchResult != DiagnosticMatchResult::NoMatch) {
           if (D.FullMatchRequired &&
-              MatchResult == DiagnosticMatchResult::PartialMatch) {
+              MatchResult == DiagnosticMatchResult::Partial) {
             IncompleteMatches.push_back({&D, II->second});
           }
           break;
@@ -1243,7 +1243,7 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
         SourceMgr.getPresumedLineNumber(DiagLoc) ==
             SourceMgr.getPresumedLineNumber(Directive->DiagnosticLoc) &&
         IsFromSameFile(SourceMgr, Directive->DiagnosticLoc, DiagLoc);
-    bool TextMatch = Directive->match(DiagText) == DiagnosticMatchResult::Match;
+    bool TextMatch = Directive->match(DiagText) == DiagnosticMatchResult::Full;
     if (LocsMatch && TextMatch) {
       continue;
     }

>From 56cbcbae7861b7f1b28b380e8ef2673ffcc0dfe9 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 30 Jan 2026 14:59:20 +0300
Subject: [PATCH 20/25] Add tests

---
 .../Frontend/verify-strict-full-match.cpp     | 10 ++++
 .../test/Frontend/verify-strict-one-diag.cpp  | 58 +++++++++++++++++++
 clang/test/Frontend/verify-strict-order.cpp   | 14 +++++
 .../test/Frontend/verify-strict-wildcard.cpp  | 22 +++++++
 4 files changed, 104 insertions(+)
 create mode 100644 clang/test/Frontend/verify-strict-full-match.cpp
 create mode 100644 clang/test/Frontend/verify-strict-one-diag.cpp
 create mode 100644 clang/test/Frontend/verify-strict-order.cpp
 create mode 100644 clang/test/Frontend/verify-strict-wildcard.cpp

diff --git a/clang/test/Frontend/verify-strict-full-match.cpp b/clang/test/Frontend/verify-strict-full-match.cpp
new file mode 100644
index 0000000000000..c84b1451a82af
--- /dev/null
+++ b/clang/test/Frontend/verify-strict-full-match.cpp
@@ -0,0 +1,10 @@
+// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+
+void f1(A);
+// expected-error at -1 {{unknown type}}
+
+// CHECK:      error: diagnostic messages of 'error' severity not fully matched:
+// CHECK-NEXT:   'expected-error' at line 4 in {{.*}}: unknown type
+// CHECK-NEXT:      does not fully match diagnostic at line 3: unknown type name 'A'
+
+// CHECK-NEXT: 1 error generated.
diff --git a/clang/test/Frontend/verify-strict-one-diag.cpp b/clang/test/Frontend/verify-strict-one-diag.cpp
new file mode 100644
index 0000000000000..1888ceb549f49
--- /dev/null
+++ b/clang/test/Frontend/verify-strict-one-diag.cpp
@@ -0,0 +1,58 @@
+// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+
+void f1(A, A);
+// expected-error at -1 {{unknown type name 'A'}}
+// expected-error at -2 1 {{unknown type name 'A'}}
+
+void f2(A, A);
+// expected-error at -1 2 {{unknown type name 'A'}}
+
+// CHECK:      error: 'expected-error' diagnostics seen but not expected:
+// CHECK-NEXT:   Line 7: unknown type name 'A'
+// CHECK-NEXT:   Line 7: unknown type name 'A'
+// CHECK-NEXT:   Line 8: exactly one diagnostic can be matched
+
+void f3(A, A);
+// expected-error at -1 0-1 {{unknown type name 'A'}}
+// expected-error at -2 0-1 {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 15: unknown type name 'A'
+// CHECK-NEXT:   Line 15: unknown type name 'A'
+// CHECK-NEXT:   Line 16: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 17: exactly one diagnostic can be matched
+
+void f4(A, A);
+// expected-error at -1 1-2 {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 24: unknown type name 'A'
+// CHECK-NEXT:   Line 24: unknown type name 'A'
+// CHECK-NEXT:   Line 25: exactly one diagnostic can be matched
+
+void f5(A);
+// expected-error at -1 0-2 {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 31: unknown type name 'A'
+// CHECK-NEXT:   Line 32: exactly one diagnostic can be matched
+
+void f6(A, A);
+// expected-error at -1 + {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 37: unknown type name 'A'
+// CHECK-NEXT:   Line 37: unknown type name 'A'
+// CHECK-NEXT:   Line 38: exactly one diagnostic can be matched
+
+void f7(A, A);
+// expected-error at -1 0+ {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 44: unknown type name 'A'
+// CHECK-NEXT:   Line 44: unknown type name 'A'
+// CHECK-NEXT:   Line 45: exactly one diagnostic can be matched
+
+void f8(A, A);
+// expected-error at -1 1+ {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 51: unknown type name 'A'
+// CHECK-NEXT:   Line 51: unknown type name 'A'
+// CHECK-NEXT:   Line 52: exactly one diagnostic can be matched
+
+// CHECK-NEXT: 21 errors generated.
diff --git a/clang/test/Frontend/verify-strict-order.cpp b/clang/test/Frontend/verify-strict-order.cpp
new file mode 100644
index 0000000000000..6e1dd877cb6b0
--- /dev/null
+++ b/clang/test/Frontend/verify-strict-order.cpp
@@ -0,0 +1,14 @@
+// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+
+void f1(A); // #f1
+void f2(B); // #f2
+// expected-error@#f2 {{unknown type name 'B'}}
+// expected-error@#f1 {{unknown type name 'A'}}
+
+// CHECK:      error: all diagnostics were successfully matched, but out-of-order directives were found:
+// CHECK-NEXT:   'expected-error' at line 5 in {{.*}}: unknown type name 'B'
+// CHECK-NEXT:     matches diagnostic at line 4, but diagnostic at line 3 was emitted first:
+// CHECK-NEXT:       unknown type name 'A'
+// CHECK-NEXT:   'expected-error' at line 6 in {{.*}}: unknown type name 'A'
+// CHECK-NEXT:     matches diagnostic at line 3, but diagnostic at line 4 was emitted first:
+// CHECK-NEXT:       unknown type name 'B'
diff --git a/clang/test/Frontend/verify-strict-wildcard.cpp b/clang/test/Frontend/verify-strict-wildcard.cpp
new file mode 100644
index 0000000000000..64069ebced5e9
--- /dev/null
+++ b/clang/test/Frontend/verify-strict-wildcard.cpp
@@ -0,0 +1,22 @@
+// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+
+void f1(A);
+// expected-error@* {{unknown type name 'A'}}
+
+// CHECK:      error: 'expected-error' diagnostics seen but not expected:
+// CHECK-NEXT:   Line 3: unknown type name 'A'
+// CHECK-NEXT:   Line 4: cannot use wildcard for diagnostic location
+
+void f2(A);
+// expected-error@*:6 {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 10: unknown type name 'A'
+// CHECK-NEXT:   Line 11: cannot use wildcard for diagnostic location
+
+void f3(A);
+// expected-error@*:* {{unknown type name 'A'}}
+
+// CHECK-NEXT:   Line 16: unknown type name 'A'
+// CHECK-NEXT:   Line 17: cannot use wildcard for diagnostic location
+
+// CHECK-NEXT: 6 errors generated.

>From 4a23cb849fed044e9abecc97abcafab46c16b5db Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 31 Jan 2026 02:48:19 +0300
Subject: [PATCH 21/25] Don't ignore directives which have wildcards or don't
 match exactly one diag

---
 .../clang/Frontend/VerifyDiagnosticConsumer.h |  2 +
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 41 +++++++++++--------
 .../test/Frontend/verify-strict-one-diag.cpp  | 31 +++++---------
 .../test/Frontend/verify-strict-wildcard.cpp  | 12 +-----
 4 files changed, 38 insertions(+), 48 deletions(-)

diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 9098ac685cbb7..f30f29233f1f5 100644
--- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -121,6 +121,8 @@ class VerifyDiagnosticConsumer: public DiagnosticConsumer,
   struct ParsingState {
     DirectiveStatus Status;
     std::string FirstNoDiagnosticsDirective;
+    bool AllDirectivesMatchExactlyOneDiag = true;
+    bool WildcardsAreErroneouslyPresent = false;
   };
 
   class MarkerTracker;
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index eed799890ce41..a54be5a12342d 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -570,7 +570,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
           if (DisableWildcardInDiagLoc) {
             Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                          diag::err_verify_wildcard_loc);
-            continue;
+            State.WildcardsAreErroneouslyPresent = true;
           }
           MatchAnyFileAndLine = true;
           if (!PH.Next("*")) {
@@ -603,7 +603,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
             if (DisableWildcardInDiagLoc) {
               Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                            diag::err_verify_wildcard_loc);
-              continue;
+              State.WildcardsAreErroneouslyPresent = true;
             }
             MatchAnyLine = true;
             ExpectedLoc = SM.translateLineCol(FID, 1, 1);
@@ -613,7 +613,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         if (DisableWildcardInDiagLoc) {
           Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                        diag::err_verify_wildcard_loc);
-          continue;
+          State.WildcardsAreErroneouslyPresent = true;
         }
         MatchAnyLine = true;
         ExpectedLoc = SourceLocation();
@@ -632,10 +632,10 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
 
     // Next optional token: positive integer or a '+'.
     if (PH.Next(D.Min)) {
-      if (OneDiagPerDirective && D.Min != 1) {
+      if (D.Min != 1 && OneDiagPerDirective) {
         Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                      diag::err_verify_non_singular_match);
-        continue;
+        State.AllDirectivesMatchExactlyOneDiag = false;
       }
       PH.Advance();
       // A positive integer can be followed by a '+' meaning min
@@ -646,7 +646,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         if (OneDiagPerDirective) {
           Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                        diag::err_verify_non_singular_match);
-          continue;
+          State.AllDirectivesMatchExactlyOneDiag = false;
         }
       } else if (PH.Next("-")) {
         PH.Advance();
@@ -658,7 +658,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         if (OneDiagPerDirective && D.Max != 1) {
           Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                        diag::err_verify_non_singular_match);
-          continue;
+          State.AllDirectivesMatchExactlyOneDiag = false;
         }
         PH.Advance();
       } else {
@@ -669,7 +669,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
       if (OneDiagPerDirective) {
         Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                      diag::err_verify_non_singular_match);
-        continue;
+        State.AllDirectivesMatchExactlyOneDiag = false;
       }
       D.Max = Directive::MaxCount;
       PH.Advance();
@@ -1150,9 +1150,11 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
 }
 
 // Checks that directives are lexically in the same order as the emitted
-// diagnostics. Assumes that CheckResults returned 0 problems, i.e. that
-// every diagnostic was matched by every directive without considering the
-// order.
+// diagnostics. Assumes that:
+//   - every directive matches exactly one diagnostic,
+//   - there are no wildcards, and
+//   - CheckResults returned 0 problems, i.e. every diagnostic
+//     was matched by every directive without considering the order.
 static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
                                        SourceManager &SourceMgr,
                                        const TextDiagnosticBuffer &Buffer,
@@ -1228,13 +1230,13 @@ static unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags,
   int NumProblems = 0;
   SmallString<256> Fmt;
   llvm::raw_svector_ostream OS(Fmt);
-  // CheckResults already ensured that there are as many directives as emitted
-  // diagnostics, and that all of them match.
+  // zip_equal asserts that there're as many directives as emitted diagnostics.
+  // CheckResults has already ensured that all diagnostics were matched.
   for (const auto [Directive, LevelDiagPair] : llvm::zip_equal(
            OrderedDirectives,
            llvm::iterator_range{Buffer.all_begin(), Buffer.all_end()})) {
     assert(!Directive->MatchAnyFileAndLine && !Directive->MatchAnyLine &&
-           "Wildcards should not be allowed in strict verify mode!");
+           "Cannot compare source locations when wildcards are present");
     const auto [DiagLevel, DiagIndex] = LevelDiagPair;
     const auto &[DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
     const SourceLocation DirLoc = Directive->DirectiveLoc;
@@ -1367,9 +1369,14 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
 
     // Check that the expected diagnostics occurred.
     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
-    if (CheckOrderOfDirectives && NumErrors == 0) {
-      assert(OneDiagPerDirective && "Can't check order of directives unless "
-                                    "they match only one diagnostic!");
+
+    // If either wildcards are present or there are directives that
+    // do not match exactly one diagnostic, we already issued
+    // errors about that. In such case we cannot check that directives
+    // are in order.
+    if (CheckOrderOfDirectives && NumErrors == 0 &&
+        State.AllDirectivesMatchExactlyOneDiag &&
+        !State.WildcardsAreErroneouslyPresent) {
       NumErrors += CheckResultsAreInOrder(Diags, *SrcManager, *Buffer, ED);
     }
   } else {
diff --git a/clang/test/Frontend/verify-strict-one-diag.cpp b/clang/test/Frontend/verify-strict-one-diag.cpp
index 1888ceb549f49..700c1100507d6 100644
--- a/clang/test/Frontend/verify-strict-one-diag.cpp
+++ b/clang/test/Frontend/verify-strict-one-diag.cpp
@@ -8,51 +8,40 @@ void f2(A, A);
 // expected-error at -1 2 {{unknown type name 'A'}}
 
 // CHECK:      error: 'expected-error' diagnostics seen but not expected:
-// CHECK-NEXT:   Line 7: unknown type name 'A'
-// CHECK-NEXT:   Line 7: unknown type name 'A'
 // CHECK-NEXT:   Line 8: exactly one diagnostic can be matched
 
 void f3(A, A);
 // expected-error at -1 0-1 {{unknown type name 'A'}}
 // expected-error at -2 0-1 {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 15: unknown type name 'A'
-// CHECK-NEXT:   Line 15: unknown type name 'A'
-// CHECK-NEXT:   Line 16: exactly one diagnostic can be matched
-// CHECK-NEXT:   Line 17: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 14: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 15: exactly one diagnostic can be matched
 
 void f4(A, A);
 // expected-error at -1 1-2 {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 24: unknown type name 'A'
-// CHECK-NEXT:   Line 24: unknown type name 'A'
-// CHECK-NEXT:   Line 25: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 21: exactly one diagnostic can be matched
 
 void f5(A);
 // expected-error at -1 0-2 {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 31: unknown type name 'A'
-// CHECK-NEXT:   Line 32: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 26: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 26: exactly one diagnostic can be matched
 
 void f6(A, A);
 // expected-error at -1 + {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 37: unknown type name 'A'
-// CHECK-NEXT:   Line 37: unknown type name 'A'
-// CHECK-NEXT:   Line 38: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 32: exactly one diagnostic can be matched
 
 void f7(A, A);
 // expected-error at -1 0+ {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 44: unknown type name 'A'
-// CHECK-NEXT:   Line 44: unknown type name 'A'
-// CHECK-NEXT:   Line 45: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 37: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 37: exactly one diagnostic can be matched
 
 void f8(A, A);
 // expected-error at -1 1+ {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 51: unknown type name 'A'
-// CHECK-NEXT:   Line 51: unknown type name 'A'
-// CHECK-NEXT:   Line 52: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 43: exactly one diagnostic can be matched
 
-// CHECK-NEXT: 21 errors generated.
+// CHECK-NEXT: 10 errors generated.
diff --git a/clang/test/Frontend/verify-strict-wildcard.cpp b/clang/test/Frontend/verify-strict-wildcard.cpp
index 64069ebced5e9..0865a23cf8b2d 100644
--- a/clang/test/Frontend/verify-strict-wildcard.cpp
+++ b/clang/test/Frontend/verify-strict-wildcard.cpp
@@ -4,19 +4,11 @@ void f1(A);
 // expected-error@* {{unknown type name 'A'}}
 
 // CHECK:      error: 'expected-error' diagnostics seen but not expected:
-// CHECK-NEXT:   Line 3: unknown type name 'A'
 // CHECK-NEXT:   Line 4: cannot use wildcard for diagnostic location
 
 void f2(A);
-// expected-error@*:6 {{unknown type name 'A'}}
-
-// CHECK-NEXT:   Line 10: unknown type name 'A'
-// CHECK-NEXT:   Line 11: cannot use wildcard for diagnostic location
-
-void f3(A);
 // expected-error@*:* {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 16: unknown type name 'A'
-// CHECK-NEXT:   Line 17: cannot use wildcard for diagnostic location
+// CHECK-NEXT:   Line 10: cannot use wildcard for diagnostic location
 
-// CHECK-NEXT: 6 errors generated.
+// CHECK-NEXT: 2 errors generated.

>From 1458933bbb7f7f4309f216ce1efd41fc9d81eed0 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 31 Jan 2026 14:14:49 +0300
Subject: [PATCH 22/25] Don't issue diagnostic about non-singular match more
 than once for a given directive

---
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 26 +++++++++----------
 .../test/Frontend/verify-strict-one-diag.cpp  | 10 +++----
 2 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a54be5a12342d..de7cb0a56570e 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -630,12 +630,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
     // Skip optional whitespace.
     PH.SkipWhitespace();
 
+    std::optional<std::ptrdiff_t> NonSingularMatchDiagOffset;
+
     // Next optional token: positive integer or a '+'.
     if (PH.Next(D.Min)) {
-      if (D.Min != 1 && OneDiagPerDirective) {
-        Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
-                     diag::err_verify_non_singular_match);
-        State.AllDirectivesMatchExactlyOneDiag = false;
+      if (OneDiagPerDirective && D.Min != 1) {
+        NonSingularMatchDiagOffset = PH.C - PH.Begin;
       }
       PH.Advance();
       // A positive integer can be followed by a '+' meaning min
@@ -644,9 +644,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         D.Max = Directive::MaxCount;
         PH.Advance();
         if (OneDiagPerDirective) {
-          Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
-                       diag::err_verify_non_singular_match);
-          State.AllDirectivesMatchExactlyOneDiag = false;
+          NonSingularMatchDiagOffset = PH.C - PH.Begin;
         }
       } else if (PH.Next("-")) {
         PH.Advance();
@@ -656,9 +654,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
           continue;
         }
         if (OneDiagPerDirective && D.Max != 1) {
-          Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
-                       diag::err_verify_non_singular_match);
-          State.AllDirectivesMatchExactlyOneDiag = false;
+          NonSingularMatchDiagOffset = PH.C - PH.Begin;
         }
         PH.Advance();
       } else {
@@ -667,14 +663,18 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
     } else if (PH.Next("+")) {
       // '+' on its own means "1 or more".
       if (OneDiagPerDirective) {
-        Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
-                     diag::err_verify_non_singular_match);
-        State.AllDirectivesMatchExactlyOneDiag = false;
+        NonSingularMatchDiagOffset = PH.C - PH.Begin;
       }
       D.Max = Directive::MaxCount;
       PH.Advance();
     }
 
+    if (NonSingularMatchDiagOffset) {
+      Diags.Report(Pos.getLocWithOffset(*NonSingularMatchDiagOffset),
+                   diag::err_verify_non_singular_match);
+      State.AllDirectivesMatchExactlyOneDiag = false;
+    }
+
     // Skip optional whitespace.
     PH.SkipWhitespace();
 
diff --git a/clang/test/Frontend/verify-strict-one-diag.cpp b/clang/test/Frontend/verify-strict-one-diag.cpp
index 700c1100507d6..3f2152306462b 100644
--- a/clang/test/Frontend/verify-strict-one-diag.cpp
+++ b/clang/test/Frontend/verify-strict-one-diag.cpp
@@ -25,23 +25,21 @@ void f4(A, A);
 void f5(A);
 // expected-error at -1 0-2 {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 26: exactly one diagnostic can be matched
 // CHECK-NEXT:   Line 26: exactly one diagnostic can be matched
 
 void f6(A, A);
 // expected-error at -1 + {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 32: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 31: exactly one diagnostic can be matched
 
 void f7(A, A);
 // expected-error at -1 0+ {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 37: exactly one diagnostic can be matched
-// CHECK-NEXT:   Line 37: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 36: exactly one diagnostic can be matched
 
 void f8(A, A);
 // expected-error at -1 1+ {{unknown type name 'A'}}
 
-// CHECK-NEXT:   Line 43: exactly one diagnostic can be matched
+// CHECK-NEXT:   Line 41: exactly one diagnostic can be matched
 
-// CHECK-NEXT: 10 errors generated.
+// CHECK-NEXT: 8 errors generated.

>From 593492afe984c675a51ae619c59a5ab92fea1e70 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 31 Jan 2026 14:39:06 +0300
Subject: [PATCH 23/25] Rename '-verify-strict' to `-verify-directives`

---
 clang/include/clang/Basic/DiagnosticOptions.def     |  4 ++--
 clang/include/clang/Options/Options.td              |  6 +++---
 clang/lib/Frontend/CompilerInvocation.cpp           |  6 +++---
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp     | 13 +++++--------
 ...l-match.cpp => verify-directives-full-match.cpp} |  2 +-
 ...-one-diag.cpp => verify-directives-one-diag.cpp} |  2 +-
 ...strict-order.cpp => verify-directives-order.cpp} |  2 +-
 ...-wildcard.cpp => verify-directives-wildcard.cpp} |  2 +-
 8 files changed, 17 insertions(+), 20 deletions(-)
 rename clang/test/Frontend/{verify-strict-full-match.cpp => verify-directives-full-match.cpp} (81%)
 rename clang/test/Frontend/{verify-strict-one-diag.cpp => verify-directives-one-diag.cpp} (94%)
 rename clang/test/Frontend/{verify-strict-order.cpp => verify-directives-order.cpp} (90%)
 rename clang/test/Frontend/{verify-strict-wildcard.cpp => verify-directives-wildcard.cpp} (83%)

diff --git a/clang/include/clang/Basic/DiagnosticOptions.def b/clang/include/clang/Basic/DiagnosticOptions.def
index 960d23b31dfb7..17d518c2b7fdd 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.def
+++ b/clang/include/clang/Basic/DiagnosticOptions.def
@@ -76,8 +76,8 @@ ENUM_DIAGOPT(VerifyIgnoreUnexpected, DiagnosticLevelMask, 4,
              DiagnosticLevelMask::None) /// Ignore unexpected diagnostics of
                                         /// the specified levels when using
                                         /// -verify.
-DIAGOPT(VerifyDiagnosticsStrict, 1, 0) /// Enable additional checks of
-                                       /// directives to improve readability
+DIAGOPT(VerifyDirectives, 1, 0) /// Enable checks of 'expected' directives
+                                /// themselves.
 DIAGOPT(ElideType, 1, 0)         /// Elide identical types in template diffing
 DIAGOPT(ShowTemplateTree, 1, 0)  /// Print a template tree when diffing
 
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c9f688c7c092f..301de5fcbed2f 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -8322,10 +8322,10 @@ def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
   HelpText<"Ignore unexpected diagnostic messages">;
 def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
   HelpText<"Ignore unexpected diagnostic messages">;
-def verify_strict
-    : Flag<["-"], "verify-strict">,
+def verify_directives
+    : Flag<["-"], "verify-directives">,
       HelpText<
-          "Enable additional checks on directives that improve readability">;
+          "Enable additional checks on 'expected' directives themselves">;
 def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
   HelpText<"Silence ObjC rewriting warnings">,
   MarshallingInfoFlag<DiagnosticOpts<"NoRewriteMacros">>;
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 99f9fb2e3a5d0..73cbeeeb243f1 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2540,8 +2540,8 @@ void CompilerInvocationBase::GenerateDiagnosticArgs(
     if (Prefix != "expected")
       GenerateArg(Consumer, OPT_verify_EQ, Prefix);
 
-  if (Opts.VerifyDiagnosticsStrict) {
-    GenerateArg(Consumer, OPT_verify_strict);
+  if (Opts.VerifyDirectives) {
+    GenerateArg(Consumer, OPT_verify_directives);
   }
 
   DiagnosticLevelMask VIU = Opts.getVerifyIgnoreUnexpected();
@@ -2642,7 +2642,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
   Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor);
 
   Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
-  Opts.VerifyDiagnosticsStrict = Args.hasArg(OPT_verify_strict);
+  Opts.VerifyDirectives = Args.hasArg(OPT_verify_directives);
   Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
   if (Args.hasArg(OPT_verify))
     Opts.VerifyPrefixes.push_back("expected");
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index de7cb0a56570e..4d99f0620d58c 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -325,7 +325,7 @@ void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
   std::unique_ptr<Directive> D = Directive::create(
       UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,
       MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max,
-      Diags.getDiagnosticOptions().VerifyDiagnosticsStrict);
+      Diags.getDiagnosticOptions().VerifyDirectives);
 
   std::string Error;
   if (!D->isValid(Error)) {
@@ -741,10 +741,10 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
       State{HasNoDirectives, {}} {
   if (Diags.hasSourceManager())
     setSourceManager(Diags.getSourceManager());
-  CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
-  OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
+  CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDirectives;
+  OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDirectives;
   DisableWildcardInDiagLoc =
-      Diags.getDiagnosticOptions().VerifyDiagnosticsStrict;
+      Diags.getDiagnosticOptions().VerifyDirectives;
 }
 
 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
@@ -1023,8 +1023,7 @@ static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
 }
 
-/// Takes a list of diagnostics that were partially matched,
-/// despite '-verify-strict' option being set.
+/// Takes a list of diagnostics that were partially matched and prints them.
 static unsigned
 PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
              llvm::SmallVector<std::pair<Directive *, std::string>> &DL,
@@ -1035,8 +1034,6 @@ PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
   SmallString<256> Fmt;
   llvm::raw_svector_ostream OS(Fmt);
   for (const auto &[D, DiagText] : DL) {
-    assert(!D->MatchAnyLine && !D->MatchAnyFileAndLine &&
-           "Wildcards should not be allowed in strict verify mode");
     OS << "\n  '" << D->Spelling << "' at line "
        << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << " in "
        << SourceMgr.getFilename(D->DiagnosticLoc) << ": " << D->Text
diff --git a/clang/test/Frontend/verify-strict-full-match.cpp b/clang/test/Frontend/verify-directives-full-match.cpp
similarity index 81%
rename from clang/test/Frontend/verify-strict-full-match.cpp
rename to clang/test/Frontend/verify-directives-full-match.cpp
index c84b1451a82af..ea769d0c256bd 100644
--- a/clang/test/Frontend/verify-strict-full-match.cpp
+++ b/clang/test/Frontend/verify-directives-full-match.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -verify -verify-directives %s 2>&1 | FileCheck %s
 
 void f1(A);
 // expected-error at -1 {{unknown type}}
diff --git a/clang/test/Frontend/verify-strict-one-diag.cpp b/clang/test/Frontend/verify-directives-one-diag.cpp
similarity index 94%
rename from clang/test/Frontend/verify-strict-one-diag.cpp
rename to clang/test/Frontend/verify-directives-one-diag.cpp
index 3f2152306462b..328c8cde23cbc 100644
--- a/clang/test/Frontend/verify-strict-one-diag.cpp
+++ b/clang/test/Frontend/verify-directives-one-diag.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -verify -verify-directives %s 2>&1 | FileCheck %s
 
 void f1(A, A);
 // expected-error at -1 {{unknown type name 'A'}}
diff --git a/clang/test/Frontend/verify-strict-order.cpp b/clang/test/Frontend/verify-directives-order.cpp
similarity index 90%
rename from clang/test/Frontend/verify-strict-order.cpp
rename to clang/test/Frontend/verify-directives-order.cpp
index 6e1dd877cb6b0..d1cc6b8d6291b 100644
--- a/clang/test/Frontend/verify-strict-order.cpp
+++ b/clang/test/Frontend/verify-directives-order.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -verify -verify-directives %s 2>&1 | FileCheck %s
 
 void f1(A); // #f1
 void f2(B); // #f2
diff --git a/clang/test/Frontend/verify-strict-wildcard.cpp b/clang/test/Frontend/verify-directives-wildcard.cpp
similarity index 83%
rename from clang/test/Frontend/verify-strict-wildcard.cpp
rename to clang/test/Frontend/verify-directives-wildcard.cpp
index 0865a23cf8b2d..a45a382356d97 100644
--- a/clang/test/Frontend/verify-strict-wildcard.cpp
+++ b/clang/test/Frontend/verify-directives-wildcard.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -verify -verify-strict %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -verify -verify-directives %s 2>&1 | FileCheck %s
 
 void f1(A);
 // expected-error@* {{unknown type name 'A'}}

>From d2a96f81d16227c4ebfe2e4fa7bcb263359dceab Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Wed, 4 Feb 2026 01:56:19 +0300
Subject: [PATCH 24/25] Add documentation

---
 clang/docs/InternalsManual.rst | 228 +++++++++++++++++++++++++++++++--
 1 file changed, 214 insertions(+), 14 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index 42004bcac56b2..d2bf4fdf4c365 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -3451,22 +3451,40 @@ are similar.
 Testing
 -------
 All functional changes to Clang should come with test coverage demonstrating
-the change in behavior.
+the change in behavior. There are four kinds of such tests.
+
+The first kind is unit tests. Such tests are placed in ``clang/test/unittest``.
+
+The second kind of tests ensures that only specific diagnostics are emitted at
+specific source lines. Those tests are using ``-verify`` mode of ``-cc1``,
+which is described below in
+:ref:`"Verifying Diagnostics" <verifying-diagnostics>`. Additional
+provisions for tests for C++ defect reports are described in ... section. 
+
+The third kind of tests checks AST dump. Such tests pass AST dump to
+`FileCheck <https://llvm.org/docs/CommandGuide/FileCheck.html>`_ utility,
+which check presence of certain patterns (or lack of thereof).
+
+The fourth kind of tests checks LLVM IR output of Clang in cases when checking
+diagnostics is not sufficient (e.g. when testing exception handling or object
+lifetime). Such tests pass LLVM IR output to
+`FileCheck <https://llvm.org/docs/CommandGuide/FileCheck.html>`_ utility,
+which check presence of certain IR patterns (or lack of thereof).
 
 .. _verifying-diagnostics:
 
 Verifying Diagnostics
 ^^^^^^^^^^^^^^^^^^^^^
 Clang ``-cc1`` supports the ``-verify`` command line option as a way to
-validate diagnostic behavior. This option will use special comments within the
-test file to verify that expected diagnostics appear in the correct source
-locations. If all of the expected diagnostics match the actual output of Clang,
-then the invocation will return normally. If there are discrepancies between
-the expected and actual output, Clang will emit detailed information about
-which expected diagnostics were not seen or which unexpected diagnostics were
-seen, etc. A complete example is:
+validate diagnostic behavior. This option will use special comments, called
+directives, within the test file to verify that expected diagnostics appear in
+the correct source locations. If all of the expected diagnostics match the
+actual output of Clang, then the invocation will return normally. If there are
+discrepancies between the expected and actual output, Clang will emit detailed
+information about which expected diagnostics were not seen or which unexpected
+diagnostics were seen, etc. A complete example is:
 
-.. code-block: c++
+.. code-block:: c++
 
   // RUN: %clang_cc1 -verify %s
   int A = B; // expected-error {{use of undeclared identifier 'B'}}
@@ -3476,6 +3494,42 @@ diagnostic verifier will pass. However, if the expected error does not appear
 or appears in a different location than expected, or if additional diagnostics
 appear, the diagnostic verifier will fail and emit information as to why.
 
+Directive Syntax
+~~~~~~~~~~~~~~~~
+EBNF syntax description of the directives is the following:
+
+.. productionlist:: verify-grammar
+  directive: prefix , "-" , diagnostic-kind , [ regex-match ] , [ diagnotic-loc ] , [ " " , quantifier ] , "{" , [ delimiter-open ], "{", [ diagnostic-text ] , "}" , [ delimiter-close ], "}" ;
+  diagnostic-kind : "error" | "warning" | "note" | "remark" ;
+  regex-match : "-re" ;
+  diagnostic-loc : "@" , ( "+" | "-" ) , number
+                 : | "@" , line
+                 : | "@" , file-path , ":" , line
+                 : | "@" , "*" , [ ":" , "*" ]
+                 : | "@" , "#" , marker-name ;
+  line : number | "*" ;
+  number : digit, { digit } ;
+  quantifier : "+"
+             : | number , [ "+" ]
+             : | number , "-" , number ;
+  delimiter-open : { "{" } ;
+  delimiter-close : { "}" } ;
+
+Where:
+
+- ``prefix`` is "expected" or a custom string
+  (:ref:`Custom Prefixes <custom-prefixes>`).
+- ``delimiter-open`` and ``delimiter-close`` have to have the same length
+  (:ref:`Diagnostic Text <diagnostic-text>`).
+- ``file-path`` is relative or absolte path to a file
+  (:ref:`Diagnostic Location <diagnostic-location>`).
+- ``marker-name`` is name of the marker somewhere in the source
+  (:ref:`Diagnostic Location <diagnostic-location>`).
+- ``diagnostic-text`` is text of the expected diagnostic
+  (:ref:`Diagnostic Text <diagnostic-text>`).
+
+Custom Prefixes
+~~~~~~~~~~~~~~~
 The ``-verify`` command optionally accepts a comma-delimited list of one or
 more verification prefixes that can be used to craft those special comments.
 Each prefix must start with a letter and contain only alphanumeric characters,
@@ -3502,8 +3556,8 @@ Multiple occurrences accumulate prefixes.  For example,
 ``-verify -verify=foo,bar -verify=baz`` is equivalent to
 ``-verify=expected,foo,bar,baz``.
 
-Specifying Diagnostics
-^^^^^^^^^^^^^^^^^^^^^^
+Dianogstic Location
+^^^^^^^^^^^^^^^^^^^
 Indicating that a line expects an error or a warning is easy. Put a comment
 on the line that has the diagnostic, use
 ``expected-{error,warning,remark,note}`` to tag if it's an expected error,
@@ -3565,6 +3619,8 @@ appending the marker to the diagnostic with ``@#<marker>``, as with:
 
 The name of a marker used in a directive must be unique within the compilation.
 
+Quantifiers
+~~~~~~~~~~~
 The simple syntax above allows each specification to match exactly one
 diagnostic. You can use the extended syntax to customize this. The extended
 syntax is ``expected-<type> <n> {{diag text}}``, where ``<type>`` is one of
@@ -3603,9 +3659,8 @@ In this example, the diagnostic may appear only once, if at all.
 
 .. _DiagnosticMatching:
 
-Matching Modes
-~~~~~~~~~~~~~~
-
+Diagnostic Text
+~~~~~~~~~~~~~~~
 The default matching mode is simple string, which looks for the expected text
 that appears between the first `{{` and `}}` pair of the comment. The string is
 interpreted just as-is, with one exception: the sequence `\n` is converted to a
@@ -3647,6 +3702,151 @@ Examples matching error: "variable has incomplete type 'struct s'"
   // expected-error-re {{variable has type 'struct {{(.*)}}'}}
   // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
 
+Verifying the Directives
+~~~~~~~~~~~~~~~~~~~~~~~~
+Clang ``-cc1`` also has ``-verify-directives`` mode, which can be enabled
+alongside ``-verify`` to place additional restrictions on directives,
+and strives to improve readability of the expected compiler output
+for reviewers and future readers, but makes it a bit harder to write the test:
+
+- Diagnostic text specified in a directive has to be a full match.
+- Lexical order of directives has to match order in which diagnostics are
+  emitted.
+- Each directive can match exactly one diagnostic.
+- Wildcards (``*``) are not allowed in diagnostic location.
+
+It is recommended to write new tests with this mode enabled, but for some tests
+it's not possible. Typical problems and their solutions are listed below.
+
+- **Diagnostic is issued only sometimes.**
+  The cause of variance needs to be identified and captured. Typically it is
+  either a compiler option like language mode, in which case additional custom
+  prefix should be sufficient, or platform, in which case triple has to be
+  explicitly passed in command-line arguments.
+- **Template instantiations at the end of translation unit.**
+  Instantiations at the end of the TU cause associated diagnostics to appear
+  too late. Instantiations need to happen before the next directive, and when
+  it is possible, it still takes some creativity to achieve, especially in
+  C++98 mode. Typical solutions include explicit template instantiations,
+  manifestly constant-evaluated expressions, ``enable_if``, and removing
+  template parameters altogether.
+- **Analysis-based warnings.** Some warnings, like ``-Wunused``, are based
+  on CFG analysis and are emitted later than e.g. parser would emit them,
+  because some lookahead is required to collect all the necessary information
+  for such analysis. Not much can be done in this case.
+- **Lambdas.** When lambda is mentioned in diagnostic message, it is identified
+  by its source location, which is typically not salient for the test,
+  and would make it overspecified. In this case regex match can be used to skip
+  over source location.
+
+C++ Defect Report Tests
+^^^^^^^^^^^^^^^^^^^^^^^
+C++ Defect Report tests are placed in ``clang/test/CXX/drs`` directory, which
+consists of two types of files:
+- files where tests are grouped by 100 by issue number, e.g. ``cwg15xx.cpp``
+  ("big files");
+- files with individual tests or smaller groups of tests, e.g. ``cwg177x.cpp``
+  or ``cwg787.cpp``.
+
+C++ defect report tests are run in all language modes available via ``-std=``,
+except for modes with GNU extensions and ``c++03``, as it is synonymous to
+``c++98``. Exceptions, pedantic errors, and ``-verify-directives`` are enabled.
+
+Big files are where most of the tests end up being placed to save on process
+startup cost during test runs. Big files also serve as an index of tests:
+even if test is placed in its individual file, it's still mentioned in the
+big file where this test would be placed otherwise. Big files need all tests
+to work with the same set of compiler options specified in RUN lines, but
+sometimes tests need special provisions, in which case they should be placed
+in their own file. Typical reasons for that include:
+
+- **Test is checking AST dump or LLVM IR.** We don't yet know how
+  to concatenate FileCheck directives from multiple tests into a single file
+  without avoiding test interference. 
+- **Test is not compatible with ``-verify-directives``.** For instance, some
+  tests can't be rewritten to prevent instantiations at the end of TU.
+- **Test needs C++20 modules.** Such tests require special RUN lines to compile
+  modules in the right order.
+- **Test prevents compiler from checking subsequent tests.** In some cases
+  that involve templates Clang refuses to recover from expected errors and will
+  skip over expected errors in subsequent tests.
+
+C++ defect report tests make heavy use of markers. Marker names need to
+be prefixed with ``cwgNNN-``, where NNN is number of the core issue being
+tested. This is especially needed in big files, because all markers share
+the same namespace.
+
+Some diagnostics are expected only in certain language modes. This in handled
+in two parts. First, C++ defect report tests share a common pool of custom
+prefixes:
+- ``expected`` for diagnostics issued in all language modes;
+- ``cxxNN`` (e.g. ``cxx98``) for diagnostics issued only in one language mode;
+- ``since-cxxNN`` (e.g. ``since-cxx11``) for diagnostics that are issued
+  in a certain language mode and all newer language modes;
+- ``cxxNN-MM`` (e.g. ``cxx98-14``) for diagnostics that appear in all language
+  modes within a certain range.
+
+Second, parts of tests that test features not univerally available in all
+language modes are guarded with ``#if __cplusplus``. Prefixes of directives
+in such parts need to reflect the latest ``#if __cplusplus`` guard to make
+tests require less context to understand, even though this is not strictly
+necessary to make the test work:
+
+.. code-block:: c++
+
+  #if __cplusplus >= 201103L
+  enum : int { a };
+  enum class { b };
+  // since-cxx11-error at -1 {{scoped enumeration requires a name}}
+  #endif
+
+On top of `-verify-directives`, C++ defect report tests use the following
+conventions to make it easier to reconstruct compiler output while looking at
+directives:
+
+- Errors and warnings are placed on the next line after the line they are
+  expecting a diagnostic at, and at the same indentation.
+
+  .. code-block:: c++
+
+    namespace X::Y {}
+    // cxx98-14-error at -1 {{nested namespace definition is a C++17 extension; define each namespace separately}}
+    namespace X {
+      namespace X::Y {}
+      // cxx98-14-error at -1 {{nested namespace definition is a C++17 extension; define each namespace separately}}
+    }
+
+- Directives that are placed right after the line they are expecting
+  a diagnostic at use relative offsets (``@-1``, ``@-2``, and so on),
+  as long as it's obvious that all relative offsets point to the same line.
+  If there is a feeling readers would start counting lines to make sure
+  they know where the diagnostic is expected, markers should be used instead.
+
+  .. code-block:: c++
+
+    bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-;
+    // cxx98-17-warning at -1 {{ordered comparison of function pointers ('void (*)(S, S)' and 'void (*)(S, S)')}}
+    // cxx20-23-error at -2 {{expected '>'}}
+    //   cxx20-23-note at -3 {{to match this '<'}}
+
+    int *q = new int[T()]; // #cwg299-q
+    // cxx98-11-error@#cwg299-q {{ambiguous conversion of array size expression of type 'T' to an integral or enumeration type}}
+    //   cxx98-11-note@#cwg299-int {{conversion to integral type 'int' declared here}}
+    //   cxx98-11-note@#cwg299-ushort {{conversion to integral type 'unsigned short' declared here}}
+    // since-cxx14-error-re@#cwg299-q {{conversion from 'T' to '__size_t' (aka 'unsigned {{long long|long|int}}') is ambiguous}}
+    //   since-cxx14-note@#cwg299-int {{candidate function}}
+    //   since-cxx14-note@#cwg299-ushort {{candidate function}}
+
+- Notes and remarks are indented by two spaces relative to the error or warning
+  they are attached to.
+
+  .. code-block:: c++
+
+    void (*p)() throw(int) = &f; // #cwg92-p
+    // since-cxx17-error@#cwg92-p {{ISO C++17 does not allow dynamic exception specifications}}
+    //   since-cxx17-note@#cwg92-p {{use 'noexcept(false)' instead}}
+    // cxx98-14-error@#cwg92-p {{target exception specification is not superset of source}}
+
 Feature Test Macros
 ===================
 Clang implements several ways to test whether a feature is supported or not.

>From 27a88b2437ac4c6ff92116fdd0c0190546f291c3 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 5 Feb 2026 02:34:52 +0300
Subject: [PATCH 25/25] Run clang-format

---
 clang/include/clang/Options/Options.td          |  3 +--
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 11 +++++------
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 301de5fcbed2f..8238d220a5d60 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -8324,8 +8324,7 @@ def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected="
   HelpText<"Ignore unexpected diagnostic messages">;
 def verify_directives
     : Flag<["-"], "verify-directives">,
-      HelpText<
-          "Enable additional checks on 'expected' directives themselves">;
+      HelpText<"Enable additional checks on 'expected' directives themselves">;
 def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
   HelpText<"Silence ObjC rewriting warnings">,
   MarshallingInfoFlag<DiagnosticOpts<"NoRewriteMacros">>;
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 4d99f0620d58c..2fc24dc1c9680 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -322,10 +322,10 @@ void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
                      bool MatchAnyFileAndLine = false,
                      bool MatchAnyLine = false) {
   // Construct new directive.
-  std::unique_ptr<Directive> D = Directive::create(
-      UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,
-      MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max,
-      Diags.getDiagnosticOptions().VerifyDirectives);
+  std::unique_ptr<Directive> D =
+      Directive::create(UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,
+                        MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min,
+                        UD.Max, Diags.getDiagnosticOptions().VerifyDirectives);
 
   std::string Error;
   if (!D->isValid(Error)) {
@@ -743,8 +743,7 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
     setSourceManager(Diags.getSourceManager());
   CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDirectives;
   OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDirectives;
-  DisableWildcardInDiagLoc =
-      Diags.getDiagnosticOptions().VerifyDirectives;
+  DisableWildcardInDiagLoc = Diags.getDiagnosticOptions().VerifyDirectives;
 }
 
 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {



More information about the cfe-commits mailing list