[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