https://github.com/arichardson updated 
https://github.com/llvm/llvm-project/pull/227570

>From f5378ddb94c753cba896965cc54f33bab34194a2 Mon Sep 17 00:00:00 2001
From: Alex Richardson <[email protected]>
Date: Sun, 18 Oct 2026 15:09:09 -0700
Subject: [PATCH] [nspr] initial commit

---
 llvm/docs/CommandGuide/llvm-mc.md             |  7 +++--
 .../Support/SourceMgrDiagnosticVerifier.h     |  5 ++++
 .../Support/SourceMgrDiagnosticVerifier.cpp   | 24 ++++++++++++++--
 llvm/test/tools/llvm-mc/verify/basic.s        | 28 ++++++++++++++++---
 .../SourceMgrDiagnosticVerifierTest.cpp       | 20 ++++++++++++-
 mlir/lib/IR/Diagnostics.cpp                   |  2 +-
 6 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-mc.md 
b/llvm/docs/CommandGuide/llvm-mc.md
index f49861c88173f..9d154dd1638f1 100644
--- a/llvm/docs/CommandGuide/llvm-mc.md
+++ b/llvm/docs/CommandGuide/llvm-mc.md
@@ -163,7 +163,7 @@ printing them, similar to Clang's `-verify`. `<prefixes>` 
is a comma-separated
 list of directive prefixes (default: `expected`). A directive has the form
 
 ```text
-<prefix>-<kind>[-re][@<offset>] {{<text>}}
+<prefix>-<kind>[-re][@<offset>][:<col>] {{<text>}}
 ```
 
 where `<kind>` is `error`, `warning`, `note` or `remark`, and `<text>` must be
@@ -171,10 +171,13 @@ a substring of the diagnostic message (with `-re`, 
`{{...}}` blocks inside
 `<text>` are regular expressions). Without `@<offset>`, the directive applies
 to its own line; `@+N` and `@-N` refer to the line `N` lines below or above,
 `@above` and `@below` to the nearest non-directive line, and `@unknown` to
-diagnostics without a location. For example:
+diagnostics without a location. `:<col>` additionally requires the diagnostic
+to be at the given 1-based column (note that in Clang, `@<file>:<line>` instead
+refers to a line in another file). For example:
 
 ```asm
 .foo # expected-error {{unknown directive}}
+.bar # expected-error:1 {{unknown directive}}
 ```
 
 Directives are only recognized in single-line comments, at most one per line.
diff --git a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h 
b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
index 6bc0335bc9812..5389ddf09701a 100644
--- a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
+++ b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h
@@ -58,6 +58,8 @@ class LLVM_ABI SourceMgrDiagnosticVerifier {
     const MemoryBuffer *Buf;
     /// The 1-based line number of the diagnostic.
     unsigned LineNo;
+    /// The 1-based column number of the diagnostic.
+    unsigned ColNo;
   };
 
   /// Scans all buffers currently registered with \p Mgr for expected
@@ -106,6 +108,9 @@ class LLVM_ABI SourceMgrDiagnosticVerifier {
     SourceMgr::DiagKind Kind;
     /// The line number the expected diagnostic should be on.
     unsigned LineNo;
+    /// The column the expected diagnostic should be at, or 0 if any column
+    /// matches.
+    unsigned ColNo = 0;
     /// The location of the expected diagnostic within the input file.
     SMLoc FileLoc;
     /// A flag indicating if the expected diagnostic has been matched yet.
diff --git a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp 
b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
index 6a11c7b95f222..75b0e27abe612 100644
--- a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
+++ b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp
@@ -30,7 +30,8 @@ SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier(
   // Don't match 'expected' inside a longer word such as 'unexpected'.
   Expected = Regex("(^|[^[:alnum:]_-])(" + PrefixAlt +
                    ")-(error|note|remark|warning)(-re)?"
-                   " *(@([+-][0-9]+|above|below|unknown))? *{{(.*)}}$");
+                   " *(@([+-][0-9]+|above|below|unknown))?(:([0-9]+))?"
+                   " *{{(.*)}}$");
 
   for (StringRef Prefix : CommentPrefixes) {
     assert(!Prefix.empty() && "comment prefixes must be non-empty");
@@ -169,12 +170,19 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(const 
MemoryBuffer *Buf) {
       assert(Matches[3] == "note");
       Kind = SourceMgr::DK_Note;
     }
-    ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[7]);
+    ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[9]);
 
     // Check to see if this is a regex match, i.e. it includes the `-re`.
     if (!Matches[4].empty() && !computeRegex(Record))
       continue;
 
+    // Parse the optional ':<col>'.
+    if (!Matches[8].empty() &&
+        (Matches[8].getAsInteger(10, Record.ColNo) || Record.ColNo == 0)) {
+      emitError(Record, "invalid column '" + Matches[7] + "'");
+      continue;
+    }
+
     StringRef OffsetMatch = Matches[5];
     if (!OffsetMatch.empty()) {
       OffsetMatch = OffsetMatch.drop_front(1);
@@ -189,6 +197,10 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(const 
MemoryBuffer *Buf) {
         else
           Record.LineNo -= Offset;
       } else if (OffsetMatch.consume_front("unknown")) {
+        if (Record.ColNo != 0) {
+          emitError(Record, "cannot specify a column with '@unknown'");
+          continue;
+        }
         // This is matching unknown locations.
         Record.FileLoc = SMLoc();
         ExpectedUnknownLocDiags.emplace_back(std::move(Record));
@@ -241,6 +253,9 @@ SourceMgrDiagnosticVerifier::process(SourceMgr::DiagKind 
Kind,
     // File line must match (unless it's an unknown location).
     if (Loc && E.LineNo != Loc->LineNo)
       continue;
+    // 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) {
         E.Matched = true;
@@ -277,7 +292,10 @@ SourceMgrDiagnosticVerifier::process(const SMDiagnostic 
&Diag,
     const MemoryBuffer *Buf = nullptr;
     if (unsigned ID = Mgr.FindBufferContainingLoc(Diag.getLoc()))
       Buf = Mgr.getMemoryBuffer(ID);
-    Loc = Location{Buf, static_cast<unsigned>(Diag.getLineNo())};
+    // SMDiagnostic columns are 0-based, but printed (and written in
+    // directives) as 1-based.
+    Loc = Location{Buf, static_cast<unsigned>(Diag.getLineNo()),
+                   static_cast<unsigned>(Diag.getColumnNo()) + 1};
   }
   MatchResult Result =
       process(Diag.getKind(), Loc, Diag.getMessage(), ReportUnexpected);
diff --git a/llvm/test/tools/llvm-mc/verify/basic.s 
b/llvm/test/tools/llvm-mc/verify/basic.s
index cd5ee445c45e1..e38d76fcc9777 100644
--- a/llvm/test/tools/llvm-mc/verify/basic.s
+++ b/llvm/test/tools/llvm-mc/verify/basic.s
@@ -4,9 +4,16 @@
 # RUN: rm -rf %t && split-file %s %t && cd %t
 
 ## Matching directives: a substring match, a '-re' regex match, '@+N' and
-## '@-N' offsets, '@above'/'@below', and directives in '#' and '//' comments.
+## '@-N' offsets, '@above'/'@below', ':<col>' columns, and directives in '#'
+## and '//' comments.
 # RUN: llvm-mc --triple=riscv32 --verify match.s
 
+## A directive with the wrong column, or an invalid column, fails.
+# RUN: not llvm-mc --triple=riscv32 --verify wrong-column.s 2>&1 \
+# RUN:   | FileCheck wrong-column.s
+# RUN: not llvm-mc --triple=riscv32 --verify invalid-column.s 2>&1 \
+# RUN:   | FileCheck invalid-column.s
+
 ## Custom prefixes are recognized instead of 'expected', but not as the suffix
 ## of a longer word such as 'uncheck'.
 # RUN: llvm-mc --triple=riscv32 --verify=check,alt custom-prefix.s
@@ -76,11 +83,24 @@
 
 .qux_directive # expected-error {{unknown directive}}
 .quux_directive // expected-error {{unknown directive}}
+.col_directive # expected-error:1 {{unknown directive}}
 
 sfence.vma a0, 0x10
-# expected-error@-1 {{invalid instruction, any one of the following would fix 
this:}}
-# expected-note@-2 {{unexpected extra operand for instruction}}
-# expected-note@-3 {{register must be a GPR}}
+# expected-error@-1:1 {{invalid instruction, any one of the following would 
fix this:}}
+# expected-note@-2:16 {{unexpected extra operand for instruction}}
+# expected-note@-3:16 {{register must be a GPR}}
+
+#--- wrong-column.s
+.foo_directive # expected-error:2 {{unknown directive}}
+# CHECK: error: unknown directive
+# CHECK: error: expected error "unknown directive" was not produced
+
+#--- invalid-column.s
+addi a0, a0, 1
+# expected-error@-1:0 {{never happens}}
+# expected-error@unknown:1 {{never happens}}
+# CHECK: error: invalid column ':0'
+# CHECK: error: cannot specify a column with '@unknown'
 
 #--- custom-prefix.s
 .foo_directive
diff --git a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp 
b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
index 6fd5837c35921..433c4d9de0291 100644
--- a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
+++ b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp
@@ -96,7 +96,8 @@ TEST_F(SourceMgrDiagnosticVerifierTest, 
UnknownFileNeverMatches) {
   addBuffer("# expected-error {{anything}}\n");
   SourceMgrDiagnosticVerifier Verifier(SM, OS);
 
-  SourceMgrDiagnosticVerifier::Location Loc{/*Buf=*/nullptr, /*LineNo=*/1};
+  SourceMgrDiagnosticVerifier::Location Loc{/*Buf=*/nullptr, /*LineNo=*/1,
+                                            /*ColNo=*/1};
   EXPECT_EQ(Verifier.process(SourceMgr::DK_Error, Loc, "anything"),
             MatchResult::Unexpected);
   EXPECT_FALSE(Verifier.verify());
@@ -141,3 +142,20 @@ TEST_F(SourceMgrDiagnosticVerifierTest, 
CustomPrefixesAndCommentScoping) {
   EXPECT_TRUE(Verifier.verify());
   EXPECT_EQ(Output, "");
 }
+
+TEST_F(SourceMgrDiagnosticVerifierTest, ColumnChecking) {
+  const MemoryBuffer *Buf = addBuffer("bad_op arg1, arg2\n"
+                                      "# expected-error@-1:8 {{bad arg1}}\n");
+  SourceMgrDiagnosticVerifier Verifier(SM, OS);
+
+  // Column 8 ('arg1') matches; column 1 ('bad_op') does not.
+  SMLoc Col1Loc = SMLoc::getFromPointer(Buf->getBufferStart());
+  SMLoc Col8Loc = SMLoc::getFromPointer(Buf->getBufferStart() + 7);
+  EXPECT_EQ(
+      Verifier.process(SM.GetMessage(Col1Loc, SourceMgr::DK_Error, "bad 
arg1")),
+      MatchResult::Unexpected);
+  EXPECT_EQ(
+      Verifier.process(SM.GetMessage(Col8Loc, SourceMgr::DK_Error, "bad 
arg1")),
+      MatchResult::Matched);
+  EXPECT_FALSE(Verifier.verify());
+}
diff --git a/mlir/lib/IR/Diagnostics.cpp b/mlir/lib/IR/Diagnostics.cpp
index dd4494a6d1ba6..b840edac3c8ee 100644
--- a/mlir/lib/IR/Diagnostics.cpp
+++ b/mlir/lib/IR/Diagnostics.cpp
@@ -717,7 +717,7 @@ void 
SourceMgrDiagnosticVerifierHandler::process(LocationAttr loc,
   std::optional<Verifier::Location> verifierLoc;
   if (FileLineColLoc fileLoc = loc.findInstanceOf<FileLineColLoc>())
     verifierLoc = Verifier::Location{getBufferForFile(fileLoc.getFilename()),
-                                     fileLoc.getLine()};
+                                     fileLoc.getLine(), fileLoc.getColumn()};
   bool reportUnexpected = impl->level != Level::OnlyExpected;
 
   Verifier::MatchResult result = impl->verifier.process(

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to