[llvm-branch-commits] [llvm] [Support] Add custom-prefix and comment-scoping support to SourceMgrDiagnosticVerifier (PR #227568)

Alexander Richardson via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 29 22:49:56 PDT 2026


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

Allow callers of `SourceMgrDiagnosticVerifier` to configure:
- One or more directive prefixes (defaulting to `{"expected"}`) so tools
  can share a single test file across multiple runs with different
  configurations (mirroring `clang -cc1 -verify=<prefixes>` and FileCheck's
  `--check-prefixes`).
- Comment prefixes (e.g. `//`, `#`, `;` for assembly) so directive scanning
  ignores `expected-*` substrings that appear inside instruction operands
  or string literals before a comment marker.

This commit was created with the help of AI tools

>From fecfb02bd69b6c96d48897c7f0352657d7e8c02c Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Tue, 29 Sep 2026 22:49:13 -0700
Subject: [PATCH] [Support] Add custom-prefix and comment-scoping support to
 SourceMgrDiagnosticVerifier

Allow callers of `SourceMgrDiagnosticVerifier` to configure:
- One or more directive prefixes (defaulting to `{"expected"}`) so tools
  can share a single test file across multiple runs with different
  configurations (mirroring `clang -cc1 -verify=<prefixes>` and FileCheck's
  `--check-prefixes`).
- Comment prefixes (e.g. `//`, `#`, `;` for assembly) so directive scanning
  ignores `expected-*` substrings that appear inside instruction operands
  or string literals before a comment marker.

This commit was created with the help of AI tools
---
 .../Support/SourceMgrDiagnosticVerifier.h     | 27 +++++++--
 .../Support/SourceMgrDiagnosticVerifier.cpp   | 58 +++++++++++++++----
 2 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
index 2e22400715c85..2dc5566a48f47 100644
--- a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
+++ b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
@@ -23,6 +23,8 @@
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/SourceMgr.h"
 #include <optional>
+#include <string>
+#include <vector>
 
 namespace llvm {
 
@@ -83,6 +85,18 @@ class LLVM_ABI SourceMgrDiagnosticVerifier {
     Ignored,
   };
 
+  /// \param Prefixes The comment prefixes that introduce an expected
+  /// diagnostic, e.g. \c {"expected"} to recognize 'expected-error'. Matched
+  /// literally, not as a regex. Must not contain an empty string.
+  /// \param CommentPrefixes If non-empty, only text at or after the earliest
+  /// occurrence of one of these strings on a line is scanned for expected
+  /// diagnostics, so a magic string that happens to appear outside of a
+  /// comment (e.g. in an instruction operand) is ignored. If empty, the
+  /// whole line is eligible.
+  explicit SourceMgrDiagnosticVerifier(
+      ArrayRef<std::string> Prefixes = {"expected"},
+      ArrayRef<std::string> CommentPrefixes = {});
+
   /// Computes and caches the list of expected diagnostics for \p Buf, if not
   /// already cached. Returns the (mutable) cached list.
   MutableArrayRef<ExpectedDiag> computeExpectedDiags(raw_ostream &OS,
@@ -120,6 +134,14 @@ class LLVM_ABI SourceMgrDiagnosticVerifier {
   bool verify(raw_ostream &OS, SourceMgr &Mgr);
 
 private:
+  /// Regex used to recognize '<prefix>-<kind>' comments, built from the
+  /// \p Prefixes passed to the constructor.
+  Regex Expected;
+
+  /// If non-empty, only text at or after the earliest occurrence of one of
+  /// these strings on a line is eligible to match \p Expected.
+  std::vector<std::string> CommentPrefixes;
+
   /// The expected diagnostics for each buffer that has been scanned so far,
   /// keyed by buffer identifier (i.e. file name).
   StringMap<SmallVector<ExpectedDiag, 2>> ExpectedDiagsPerFile;
@@ -127,11 +149,6 @@ class LLVM_ABI SourceMgrDiagnosticVerifier {
   /// The expected diagnostics with an '@unknown' location.
   SmallVector<ExpectedDiag, 2> ExpectedUnknownLocDiags;
 
-  /// Regex used to recognize 'expected-<kind>' comments.
-  Regex Expected =
-      Regex("expected-(error|note|remark|warning)(-re)? "
-            "*(@([+-][0-9]+|above|below|unknown))? *{{(.*)}}$");
-
   /// Whether any diagnostic mismatch has been recorded so far.
   bool OK = true;
 };
diff --git a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
index b2102201b43ab..f04602a6e7cc2 100644
--- a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
+++ b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
@@ -7,11 +7,30 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/SourceMgrDiagnosticVerifier.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
+SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier(
+    ArrayRef<std::string> Prefixes, ArrayRef<std::string> CommentPrefixes)
+    : CommentPrefixes(CommentPrefixes.begin(), CommentPrefixes.end()) {
+  std::string PrefixAlt;
+  raw_string_ostream PrefixOS(PrefixAlt);
+  ListSeparator Sep("|");
+  for (const std::string &Prefix : Prefixes) {
+    // An empty prefix would add an empty alternative to the regex below,
+    // letting a bare '-error {{...}}' comment (with no prefix word at all)
+    // match. Callers must not pass one.
+    assert(!Prefix.empty() && "prefixes must be non-empty");
+    PrefixOS << Sep << Regex::escape(Prefix);
+  }
+  Expected = Regex("(" + PrefixAlt +
+                   ")-(error|note|remark|warning)(-re)? "
+                   "*(@([+-][0-9]+|above|below|unknown))? *{{(.*)}}$");
+}
+
 /// Given a diagnostic kind, return a human readable string for it.
 static StringRef getDiagKindStr(SourceMgr::DiagKind Kind) {
   switch (Kind) {
@@ -100,12 +119,29 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(raw_ostream &OS,
   // The indices of designators that apply to the next non designator line.
   SmallVector<unsigned, 1> DesignatorsForNextLine;
 
-  // Scan the file for expected-* designators.
+  // Scan the file for <prefix>-* designators.
   SmallVector<StringRef, 100> Lines;
   Buf->getBuffer().split(Lines, '\n');
   for (unsigned LineNo = 0, E = Lines.size(); LineNo < E; ++LineNo) {
-    SmallVector<StringRef, 4> Matches;
-    if (!Expected.match(Lines[LineNo].rtrim(), &Matches)) {
+    // If comment-scoping is enabled, only the text at or after the earliest
+    // recognized comment prefix on the line is eligible to match, so a magic
+    // string appearing outside of a comment (e.g. in an instruction operand)
+    // is ignored.
+    StringRef Line = Lines[LineNo].rtrim();
+    if (!CommentPrefixes.empty()) {
+      size_t CommentStart = StringRef::npos;
+      for (StringRef Prefix : CommentPrefixes) {
+        size_t Pos = Line.find(Prefix);
+        if (Pos != StringRef::npos &&
+            (CommentStart == StringRef::npos || Pos < CommentStart))
+          CommentStart = Pos;
+      }
+      Line = CommentStart == StringRef::npos ? StringRef()
+                                             : Line.substr(CommentStart);
+    }
+
+    SmallVector<StringRef, 5> Matches;
+    if (!Expected.match(Line, &Matches)) {
       // Check for designators that apply to this line.
       if (!DesignatorsForNextLine.empty()) {
         for (unsigned DiagIndex : DesignatorsForNextLine)
@@ -116,29 +152,29 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(raw_ostream &OS,
       continue;
     }
 
-    // Point to the start of expected-*.
+    // Point to the start of <prefix>-*.
     SMLoc ExpectedStart = SMLoc::getFromPointer(Matches[0].data());
 
     SourceMgr::DiagKind Kind;
-    if (Matches[1] == "error")
+    if (Matches[2] == "error")
       Kind = SourceMgr::DK_Error;
-    else if (Matches[1] == "warning")
+    else if (Matches[2] == "warning")
       Kind = SourceMgr::DK_Warning;
-    else if (Matches[1] == "remark")
+    else if (Matches[2] == "remark")
       Kind = SourceMgr::DK_Remark;
     else {
-      assert(Matches[1] == "note");
+      assert(Matches[2] == "note");
       Kind = SourceMgr::DK_Note;
     }
-    ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[5]);
+    ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[6]);
 
     // Check to see if this is a regex match, i.e. it includes the `-re`.
-    if (!Matches[2].empty() && !Record.computeRegex(OS, Mgr)) {
+    if (!Matches[3].empty() && !Record.computeRegex(OS, Mgr)) {
       OK = false;
       continue;
     }
 
-    StringRef OffsetMatch = Matches[3];
+    StringRef OffsetMatch = Matches[4];
     if (!OffsetMatch.empty()) {
       OffsetMatch = OffsetMatch.drop_front(1);
 



More information about the llvm-branch-commits mailing list