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
