[llvm-branch-commits] [llvm] [Support] Prefer unmatched directives when matching diagnostics (PR #233308)

Alexander Richardson via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Oct 18 15:10:07 PDT 2026


https://github.com/arichardson created https://github.com/llvm/llvm-project/pull/233308

When several directives on a line matched a diagnostic, the first one
was used even if it had already been matched. A second diagnostic on
that line then could not match a later directive with overlapping text,
e.g. `{{operand}}` followed by `{{invalid operand}}`. Prefer directives
that have not been matched yet, and do not report a near miss against a
directive that has already been matched.

Assisted-by: AI tooling

>From afb08dbb733171a404aa5dae93d49d3196e7070c Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Sun, 18 Oct 2026 15:09:11 -0700
Subject: [PATCH] [nspr] initial commit

---
 .../Support/SourceMgrDiagnosticVerifier.cpp   | 20 +++++++----
 .../SourceMgrDiagnosticVerifierTest.cpp       | 33 +++++++++++++++++++
 2 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
index a005487ed3122..9e567d5e49f51 100644
--- a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
+++ b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
@@ -262,11 +262,13 @@ SourceMgrDiagnosticVerifier::process(SourceMgr::DiagKind Kind,
     Diags = ExpectedUnknownLocDiags;
   }
 
-  // Search for a matching expected diagnostic.
+  // Search for a matching expected diagnostic, preferring one that has not
+  // been matched yet so that several directives with overlapping text on the
+  // same line can each match a diagnostic.
   // If we find something that is close then emit a more specific error.
+  ExpectedDiag *AlreadyMatched = nullptr;
   ExpectedDiag *NearMiss = nullptr;
 
-  // If this was an expected error, remember that we saw it and return.
   for (auto &E : Diags) {
     // File line must match (unless it's an unknown location).
     if (Loc && E.LineNo != Loc->LineNo)
@@ -274,17 +276,23 @@ SourceMgrDiagnosticVerifier::process(SourceMgr::DiagKind Kind,
     // The column only needs to match if the directive specified one.
     if (Loc && E.ColNo != 0 && E.ColNo != Loc->ColNo)
       continue;
-    if (E.match(Message)) {
-      if (E.Kind == Kind) {
+    if (!E.match(Message))
+      continue;
+    if (E.Kind == Kind) {
+      if (!E.Matched) {
         E.Matched = true;
         return MatchResult::Matched;
       }
-
+      AlreadyMatched = &E;
+    } else if (!E.Matched) {
       // If this only differs based on the diagnostic kind, then consider it
-      // to be a near miss.
+      // to be a near miss. A directive that already matched another
+      // diagnostic is not a near miss.
       NearMiss = &E;
     }
   }
+  if (AlreadyMatched)
+    return MatchResult::Matched;
 
   if (!ReportUnexpected)
     return MatchResult::Ignored;
diff --git a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
index c70bedc69048f..6bbd12e720c80 100644
--- a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
+++ b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
@@ -229,3 +229,36 @@ TEST_F(SourceMgrDiagnosticVerifierTest, BufferAddedLater) {
   EXPECT_FALSE(Verifier.verify());
   EXPECT_EQ(Output, FirstOutput);
 }
+
+TEST_F(SourceMgrDiagnosticVerifierTest, PreferUnmatchedDirective) {
+  const MemoryBuffer *Buf =
+      addBuffer("op\n"
+                "# expected-error at -1 {{operand}}\n"
+                "# expected-error at -2 {{invalid operand}}\n");
+  SourceMgrDiagnosticVerifier Verifier(SM, OS);
+
+  // Both diagnostics match the first directive, but the second one must be
+  // matched by the second directive.
+  EXPECT_EQ(Verifier.process(getMessage(Buf, SourceMgr::DK_Error, "operand")),
+            MatchResult::Matched);
+  EXPECT_EQ(
+      Verifier.process(getMessage(Buf, SourceMgr::DK_Error, "invalid operand")),
+      MatchResult::Matched);
+  EXPECT_TRUE(Verifier.verify());
+  EXPECT_EQ(Output, "");
+}
+
+TEST_F(SourceMgrDiagnosticVerifierTest, AlreadyMatchedIsNotNearMiss) {
+  const MemoryBuffer *Buf = addBuffer("op\n# expected-error at -1 {{operand}}\n");
+  SourceMgrDiagnosticVerifier Verifier(SM, OS);
+
+  EXPECT_EQ(
+      Verifier.process(getMessage(Buf, SourceMgr::DK_Error, "bad operand")),
+      MatchResult::Matched);
+  EXPECT_EQ(
+      Verifier.process(getMessage(Buf, SourceMgr::DK_Note, "note operand")),
+      MatchResult::Unexpected);
+  EXPECT_FALSE(Verifier.verify());
+  EXPECT_EQ(StringRef(Output).find("diagnostic emitted when expecting"),
+            StringRef::npos);
+}



More information about the llvm-branch-commits mailing list