[llvm] [MC][Support] Track macro definition locations for improved diagnostics (PR #198936)
Alexander Richardson via llvm-commits
llvm-commits at lists.llvm.org
Fri May 22 15:44:24 PDT 2026
https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/198936
>From e4b331ebd9f5dbc74eb921a4098b10a716657836 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Wed, 20 May 2026 16:27:24 -0700
Subject: [PATCH 1/5] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
=?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.8-beta.1
---
llvm/lib/MC/MCParser/AsmParser.cpp | 33 ++++++++++++++++---
llvm/lib/MC/MCParser/MasmParser.cpp | 33 ++++++++++++++++---
.../MC/AsmParser/macro-unknown-directive.s | 4 +--
llvm/test/MC/AsmParser/macros-darwin.s | 4 +--
llvm/test/MC/AsmParser/unmatched-if-macro.s | 3 +-
5 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 80003c8331b82..c448717da7665 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -2412,7 +2412,29 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler && DiagCurBuffer &&
DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);
- DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
+ // Ignore macro instantiation buffers to avoid redundant include stacks.
+ if (DiagSrcMgr.getMemoryBuffer(DiagCurBuffer)->getBufferIdentifier() !=
+ "<instantiation>")
+ DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
+ }
+
+ // Map macro errors from "<instantiation>" buffer back to the definition line.
+ if (DiagBuf && DiagSrcMgr.getMemoryBuffer(DiagBuf)->getBufferIdentifier() ==
+ "<instantiation>") {
+ SMLoc RealLoc = DiagSrcMgr.getParentIncludeLoc(DiagBuf);
+ unsigned RealBuf = DiagSrcMgr.FindBufferContainingLoc(RealLoc);
+ std::string Filename =
+ DiagSrcMgr.getMemoryBuffer(RealBuf)->getBufferIdentifier().str();
+ int LineNo =
+ DiagSrcMgr.FindLineNumber(RealLoc, RealBuf) + Diag.getLineNo() - 1;
+ SMDiagnostic NewDiag(*Diag.getSourceMgr(), RealLoc, Filename, LineNo,
+ Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
+ Diag.getLineContents(), Diag.getRanges());
+ if (Parser->SavedDiagHandler)
+ Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);
+ else
+ Parser->getContext().diagnose(NewDiag);
+ return;
}
// If we have not parsed a cpp hash line filename comment or the source
@@ -2863,8 +2885,10 @@ bool AsmParser::handleMacroEntry(MCAsmMacro *M, SMLoc NameLoc) {
++NumOfMacroInstantiations;
- // Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ // Jump to the macro instantiation and prime the lexer. Use the start of the
+ // macro body in the source manager as the IncludeLoc.
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
+ SMLoc::getFromPointer(M->Body.data()));
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
Lex();
@@ -5798,7 +5822,8 @@ void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
ActiveMacros.push_back(MI);
// Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
+ SMLoc::getFromPointer(M->Body.data()));
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
Lex();
}
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index 9098b8871964d..c27c9e5a0ebb0 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -2400,7 +2400,29 @@ void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler && DiagCurBuffer &&
DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);
- DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
+ // Ignore macro instantiation buffers to avoid redundant include stacks.
+ if (DiagSrcMgr.getMemoryBuffer(DiagCurBuffer)->getBufferIdentifier() !=
+ "<instantiation>")
+ DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
+ }
+
+ // Map macro errors from "<instantiation>" buffer back to the definition line.
+ if (DiagBuf && DiagSrcMgr.getMemoryBuffer(DiagBuf)->getBufferIdentifier() ==
+ "<instantiation>") {
+ SMLoc RealLoc = DiagSrcMgr.getParentIncludeLoc(DiagBuf);
+ unsigned RealBuf = DiagSrcMgr.FindBufferContainingLoc(RealLoc);
+ StringRef Filename =
+ DiagSrcMgr.getMemoryBuffer(RealBuf)->getBufferIdentifier();
+ int LineNo =
+ DiagSrcMgr.FindLineNumber(RealLoc, RealBuf) + Diag.getLineNo() - 1;
+ SMDiagnostic NewDiag(*Diag.getSourceMgr(), RealLoc, Filename, LineNo,
+ Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
+ Diag.getLineContents(), Diag.getRanges());
+ if (Parser->SavedDiagHandler)
+ Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);
+ else
+ NewDiag.print(nullptr, OS);
+ return;
}
// If we have not parsed a cpp hash line filename comment or the source
@@ -2783,8 +2805,10 @@ bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,
++NumOfMacroInstantiations;
- // Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ // Jump to the macro instantiation and prime the lexer. Use the start of the
+ // macro body in the source manager as the IncludeLoc.
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
+ SMLoc::getFromPointer(M->Body.data()));
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
EndStatementAtEOFStack.push_back(true);
Lex();
@@ -5458,7 +5482,8 @@ void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
ActiveMacros.push_back(MI);
// Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
+ SMLoc::getFromPointer(M->Body.data()));
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
EndStatementAtEOFStack.push_back(true);
Lex();
diff --git a/llvm/test/MC/AsmParser/macro-unknown-directive.s b/llvm/test/MC/AsmParser/macro-unknown-directive.s
index 6ae3a61890a8f..9eda8cc66f7ec 100644
--- a/llvm/test/MC/AsmParser/macro-unknown-directive.s
+++ b/llvm/test/MC/AsmParser/macro-unknown-directive.s
@@ -1,9 +1,9 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s --match-full-lines --strict-whitespace
-# CHECK:<instantiation>:1:1: error: unknown directive
+# CHECK:{{.*}}.s:[[#@LINE+10]]:1: error: unknown directive
# CHECK-NEXT:.macrobody0
# CHECK-NEXT:^
-# CHECK-NEXT:<instantiation>:1:1: note: while in macro instantiation
+# CHECK-NEXT:{{.*}}.s:[[#@LINE+10]]:1: note: while in macro instantiation
# CHECK-NEXT:.test0
# CHECK-NEXT:^
# CHECK-NEXT:{{.*}}.s:[[#@LINE+10]]:1: note: while in macro instantiation
diff --git a/llvm/test/MC/AsmParser/macros-darwin.s b/llvm/test/MC/AsmParser/macros-darwin.s
index e22038e7d1b29..c99e3441dccfc 100644
--- a/llvm/test/MC/AsmParser/macros-darwin.s
+++ b/llvm/test/MC/AsmParser/macros-darwin.s
@@ -9,10 +9,10 @@
.endmacro
.test1
-// CHECK-ERRORS: <instantiation>:1:1: error: unknown directive
+// CHECK-ERRORS: 5:1: error: unknown directive
// CHECK-ERRORS-NEXT: macrobody0
// CHECK-ERRORS-NEXT: ^
-// CHECK-ERRORS: <instantiation>:1:1: note: while in macro instantiation
+// CHECK-ERRORS: 8:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test0
// CHECK-ERRORS-NEXT: ^
// CHECK-ERRORS: 11:1: note: while in macro instantiation
diff --git a/llvm/test/MC/AsmParser/unmatched-if-macro.s b/llvm/test/MC/AsmParser/unmatched-if-macro.s
index d158d2cd10c28..42dfbe45947dd 100644
--- a/llvm/test/MC/AsmParser/unmatched-if-macro.s
+++ b/llvm/test/MC/AsmParser/unmatched-if-macro.s
@@ -2,7 +2,7 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s
## This also tests that we don't assert due to an active macro instantiation.
-# CHECK: <instantiation>:4:1: error: unmatched .ifs or .elses
+# CHECK: 11:1: error: unmatched .ifs or .elses
.macro macro parameter=0
.if \parameter
@@ -10,4 +10,3 @@
.endm
macro 1
-
>From af1743d824026cc8653e20dac5178d0cfad4c327 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 22 May 2026 08:54:02 -0700
Subject: [PATCH 2/5] improve tests
Created using spr 1.3.8-beta.1
---
llvm/lib/MC/MCParser/AsmParser.cpp | 2 +-
llvm/lib/MC/MCParser/MasmParser.cpp | 2 +-
.../test/MC/AsmParser/macro-like-diagnostic.s | 19 +++++++++++++++++++
.../MC/AsmParser/macro-unknown-directive.s | 6 +++---
llvm/test/MC/AsmParser/macros-darwin.s | 6 +++---
llvm/test/MC/AsmParser/unmatched-if-macro.s | 2 +-
llvm/test/tools/llvm-ml/macro_diagnostic.asm | 12 ++++++++++++
7 files changed, 40 insertions(+), 9 deletions(-)
create mode 100644 llvm/test/MC/AsmParser/macro-like-diagnostic.s
create mode 100644 llvm/test/tools/llvm-ml/macro_diagnostic.asm
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index cb13df529fc77..7e18ef190008d 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -2411,7 +2411,7 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler)
DiagSrcMgr.printIncludeStackForDiagnostic(DiagLoc, OS);
- // Map macro errors from macro instantiation buffers back to the definition line.
+ // Map macro errors from macro instantiation buffers to the definition line.
if (std::optional<SMDiagnostic> NewDiag =
DiagSrcMgr.mapDiagnosticFromMacroInstantiation(Diag)) {
if (Parser->SavedDiagHandler)
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index 8c801c3e51486..ddafed6154374 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -2399,7 +2399,7 @@ void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler)
DiagSrcMgr.printIncludeStackForDiagnostic(DiagLoc, OS);
- // Map macro errors from macro instantiation buffers back to the definition line.
+ // Map macro errors from macro instantiation buffers to the definition line.
if (std::optional<SMDiagnostic> NewDiag =
DiagSrcMgr.mapDiagnosticFromMacroInstantiation(Diag)) {
if (Parser->SavedDiagHandler)
diff --git a/llvm/test/MC/AsmParser/macro-like-diagnostic.s b/llvm/test/MC/AsmParser/macro-like-diagnostic.s
new file mode 100644
index 0000000000000..59dbbe6658ce7
--- /dev/null
+++ b/llvm/test/MC/AsmParser/macro-like-diagnostic.s
@@ -0,0 +1,19 @@
+# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: macro-like-diagnostic.s:6:1: error: unknown directive
+# CHECK: macro-like-diagnostic.s:5:1: note: while in macro instantiation
+.irp reg,%rax
+ .invalid_irp_directive_here \reg
+.endr
+
+# CHECK: macro-like-diagnostic.s:12:1: error: unknown directive
+# CHECK: macro-like-diagnostic.s:11:1: note: while in macro instantiation
+.irpc char,a
+ .invalid_irpc_directive_here \char
+.endr
+
+# CHECK: macro-like-diagnostic.s:18:1: error: unknown directive
+# CHECK: macro-like-diagnostic.s:17:1: note: while in macro instantiation
+.rept 1
+ .invalid_rept_directive_here
+.endr
diff --git a/llvm/test/MC/AsmParser/macro-unknown-directive.s b/llvm/test/MC/AsmParser/macro-unknown-directive.s
index 9eda8cc66f7ec..bd81a4a3459c4 100644
--- a/llvm/test/MC/AsmParser/macro-unknown-directive.s
+++ b/llvm/test/MC/AsmParser/macro-unknown-directive.s
@@ -1,12 +1,12 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s --match-full-lines --strict-whitespace
-# CHECK:{{.*}}.s:[[#@LINE+10]]:1: error: unknown directive
+# CHECK:{{.*}}macro-unknown-directive.s:13:1: error: unknown directive
# CHECK-NEXT:.macrobody0
# CHECK-NEXT:^
-# CHECK-NEXT:{{.*}}.s:[[#@LINE+10]]:1: note: while in macro instantiation
+# CHECK-NEXT:{{.*}}macro-unknown-directive.s:16:1: note: while in macro instantiation
# CHECK-NEXT:.test0
# CHECK-NEXT:^
-# CHECK-NEXT:{{.*}}.s:[[#@LINE+10]]:1: note: while in macro instantiation
+# CHECK-NEXT:{{.*}}macro-unknown-directive.s:19:1: note: while in macro instantiation
# CHECK-NEXT:.test1
# CHECK-NEXT:^
.macro .test0
diff --git a/llvm/test/MC/AsmParser/macros-darwin.s b/llvm/test/MC/AsmParser/macros-darwin.s
index c99e3441dccfc..fb4940fac1fd8 100644
--- a/llvm/test/MC/AsmParser/macros-darwin.s
+++ b/llvm/test/MC/AsmParser/macros-darwin.s
@@ -9,13 +9,13 @@
.endmacro
.test1
-// CHECK-ERRORS: 5:1: error: unknown directive
+// CHECK-ERRORS: macros-darwin.s:5:1: error: unknown directive
// CHECK-ERRORS-NEXT: macrobody0
// CHECK-ERRORS-NEXT: ^
-// CHECK-ERRORS: 8:1: note: while in macro instantiation
+// CHECK-ERRORS: macros-darwin.s:8:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test0
// CHECK-ERRORS-NEXT: ^
-// CHECK-ERRORS: 11:1: note: while in macro instantiation
+// CHECK-ERRORS: macros-darwin.s:11:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test1
// CHECK-ERRORS-NEXT: ^
diff --git a/llvm/test/MC/AsmParser/unmatched-if-macro.s b/llvm/test/MC/AsmParser/unmatched-if-macro.s
index 42dfbe45947dd..3fa316c29c751 100644
--- a/llvm/test/MC/AsmParser/unmatched-if-macro.s
+++ b/llvm/test/MC/AsmParser/unmatched-if-macro.s
@@ -2,7 +2,7 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s
## This also tests that we don't assert due to an active macro instantiation.
-# CHECK: 11:1: error: unmatched .ifs or .elses
+# CHECK: unmatched-if-macro.s:11:1: error: unmatched .ifs or .elses
.macro macro parameter=0
.if \parameter
diff --git a/llvm/test/tools/llvm-ml/macro_diagnostic.asm b/llvm/test/tools/llvm-ml/macro_diagnostic.asm
new file mode 100644
index 0000000000000..72d808f9d477e
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/macro_diagnostic.asm
@@ -0,0 +1,12 @@
+; RUN: not llvm-ml -filetype=s %s /Fo - 2>&1 | FileCheck %s
+
+.code
+
+test_macro macro
+ invalid_instruction_here
+endm
+
+; CHECK: macro_diagnostic.asm:6:1: error: invalid instruction mnemonic 'invalid_instruction_here'
+; CHECK: macro_diagnostic.asm:11:1: note: while in macro instantiation
+test_macro
+end
>From 9ea4614098965e932d318087f9f2698b9431e368 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 22 May 2026 08:59:09 -0700
Subject: [PATCH 3/5] use includeloc for the call site and the new member for
the def location
Created using spr 1.3.8-beta.1
---
llvm/include/llvm/Support/SourceMgr.h | 13 +++++++------
llvm/lib/Support/SourceMgr.cpp | 4 ++--
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 3ef1f260f6518..fcf92c8ff0ea4 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -82,13 +82,14 @@ class SourceMgr {
const char *getPointerForLineNumberSpecialized(unsigned LineNo) const;
/// This is the location of the parent include, or null if at the top level.
+ /// For macro instantiation buffers, this is the macro call location.
SMLoc IncludeLoc;
/// The parent buffer ID where this macro was expanded, or 0 if not a macro.
unsigned MacroParentBuf = 0;
- /// The location in the parent buffer where this macro was called.
- SMLoc MacroCallLoc;
+ /// The location in the parent buffer where this macro was defined.
+ SMLoc MacroDefLoc;
SrcBuffer() = default;
LLVM_ABI SrcBuffer(SrcBuffer &&);
@@ -170,9 +171,9 @@ class SourceMgr {
return Buffers[i - 1].MacroParentBuf;
}
- SMLoc getMacroCallLoc(unsigned i) const {
+ SMLoc getMacroDefLoc(unsigned i) const {
assert(isValidBufferID(i));
- return Buffers[i - 1].MacroCallLoc;
+ return Buffers[i - 1].MacroDefLoc;
}
/// Add a new source buffer to this source manager. This takes ownership of
@@ -191,9 +192,9 @@ class SourceMgr {
SMLoc CallLoc) {
SrcBuffer NB;
NB.Buffer = std::move(F);
- NB.IncludeLoc = SpellingLoc;
+ NB.IncludeLoc = CallLoc;
NB.MacroParentBuf = ParentBuf;
- NB.MacroCallLoc = CallLoc;
+ NB.MacroDefLoc = SpellingLoc;
Buffers.push_back(std::move(NB));
return Buffers.size();
}
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index bbd6a4318f37e..f48e895c4088c 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -202,7 +202,7 @@ SourceMgr::SrcBuffer::getPointerForLineNumber(unsigned LineNo) const {
SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
: Buffer(std::move(Other.Buffer)), OffsetCache(Other.OffsetCache),
IncludeLoc(Other.IncludeLoc), MacroParentBuf(Other.MacroParentBuf),
- MacroCallLoc(Other.MacroCallLoc) {
+ MacroDefLoc(Other.MacroDefLoc) {
Other.OffsetCache = nullptr;
}
@@ -319,7 +319,7 @@ SourceMgr::mapDiagnosticFromMacroInstantiation(const SMDiagnostic &Diag) const {
if (!DiagBuf || !getMacroParentBuf(DiagBuf))
return std::nullopt;
- SMLoc RealLoc = getParentIncludeLoc(DiagBuf);
+ SMLoc RealLoc = getMacroDefLoc(DiagBuf);
unsigned RealBuf = FindBufferContainingLoc(RealLoc);
StringRef Filename = getMemoryBuffer(RealBuf)->getBufferIdentifier();
int LineNo = FindLineNumber(RealLoc, RealBuf) + Diag.getLineNo() - 1;
>From a14ac018b6cde8eba6e0f7d8a0fecac366c4b6ae Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 22 May 2026 15:42:35 -0700
Subject: [PATCH 4/5] clean up approach, extend tests
Created using spr 1.3.8-beta.1
---
llvm/include/llvm/MC/MCAsmMacro.h | 10 +++--
llvm/include/llvm/Support/SourceMgr.h | 30 ++++++-------
llvm/lib/MC/MCParser/AsmParser.cpp | 26 +++--------
llvm/lib/MC/MCParser/MasmParser.cpp | 31 ++++---------
llvm/lib/Support/SourceMgr.cpp | 26 ++++-------
.../test/MC/AsmParser/macro-like-diagnostic.s | 6 +--
.../MC/AsmParser/macro-unknown-directive.s | 45 ++++++++++++++-----
llvm/test/MC/AsmParser/macros-darwin.s | 10 ++---
llvm/test/MC/AsmParser/unmatched-if-macro.s | 3 +-
llvm/test/tools/llvm-ml/macro_diagnostic.asm | 6 +--
10 files changed, 90 insertions(+), 103 deletions(-)
diff --git a/llvm/include/llvm/MC/MCAsmMacro.h b/llvm/include/llvm/MC/MCAsmMacro.h
index ce50fb6418845..9325e5c3c3f6b 100644
--- a/llvm/include/llvm/MC/MCAsmMacro.h
+++ b/llvm/include/llvm/MC/MCAsmMacro.h
@@ -139,14 +139,16 @@ struct MCAsmMacro {
std::vector<std::string> Locals;
bool IsFunction = false;
unsigned Count = 0;
+ SMLoc Loc;
public:
- MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P)
- : Name(N), Body(B), Parameters(std::move(P)) {}
MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P,
- std::vector<std::string> L, bool F)
+ SMLoc Loc = SMLoc())
+ : Name(N), Body(B), Parameters(std::move(P)), Loc(Loc) {}
+ MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P,
+ std::vector<std::string> L, bool F, SMLoc Loc = SMLoc())
: Name(N), Body(B), Parameters(std::move(P)), Locals(std::move(L)),
- IsFunction(F) {}
+ IsFunction(F), Loc(Loc) {}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void dump() const { dump(dbgs()); }
diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index fcf92c8ff0ea4..3ef4754d751dd 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -85,9 +85,6 @@ class SourceMgr {
/// For macro instantiation buffers, this is the macro call location.
SMLoc IncludeLoc;
- /// The parent buffer ID where this macro was expanded, or 0 if not a macro.
- unsigned MacroParentBuf = 0;
-
/// The location in the parent buffer where this macro was defined.
SMLoc MacroDefLoc;
@@ -167,8 +164,9 @@ class SourceMgr {
}
unsigned getMacroParentBuf(unsigned i) const {
- assert(isValidBufferID(i));
- return Buffers[i - 1].MacroParentBuf;
+ if (SMLoc Loc = getMacroDefLoc(i); Loc.isValid())
+ return FindBufferContainingLoc(getParentIncludeLoc(i));
+ return 0;
}
SMLoc getMacroDefLoc(unsigned i) const {
@@ -176,6 +174,12 @@ class SourceMgr {
return Buffers[i - 1].MacroDefLoc;
}
+ unsigned getMacroDefBuf(unsigned i) const {
+ if (SMLoc Loc = getMacroDefLoc(i); Loc.isValid())
+ return FindBufferContainingLoc(Loc);
+ return 0;
+ }
+
/// Add a new source buffer to this source manager. This takes ownership of
/// the memory buffer.
unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F,
@@ -188,12 +192,10 @@ class SourceMgr {
}
unsigned AddMacroInstantiationBuffer(std::unique_ptr<MemoryBuffer> F,
- SMLoc SpellingLoc, unsigned ParentBuf,
- SMLoc CallLoc) {
+ SMLoc SpellingLoc, SMLoc CallLoc) {
SrcBuffer NB;
NB.Buffer = std::move(F);
NB.IncludeLoc = CallLoc;
- NB.MacroParentBuf = ParentBuf;
NB.MacroDefLoc = SpellingLoc;
Buffers.push_back(std::move(NB));
return Buffers.size();
@@ -308,15 +310,9 @@ class SourceMgr {
LLVM_ABI void printIncludeStackForDiagnostic(SMLoc Loc,
raw_ostream &OS) const;
- /// If the location of the given diagnostic \p Diag is within a macro
- /// instantiation buffer, this maps it back to the location in the parent
- /// buffer where the macro was called and returns a new SMDiagnostic with
- /// the updated location, filename, and adjusted line number.
- ///
- /// Returns \c std::nullopt if the diagnostic is not within a macro
- /// instantiation buffer.
- LLVM_ABI std::optional<SMDiagnostic>
- mapDiagnosticFromMacroInstantiation(const SMDiagnostic &Diag) const;
+ /// Map a virtual macro instantiation location back to the physical
+ /// definition/signature location of the macro it was called from.
+ LLVM_ABI SMLoc getMacroInstantiationLoc(SMLoc Loc) const;
};
/// Represents a single fixit, a replacement of one range of text with another.
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 7e18ef190008d..2a43389df55a6 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -820,8 +820,8 @@ AsmParser::~AsmParser() {
void AsmParser::printMacroInstantiations() {
// Print the active macro instantiation stack.
for (MacroInstantiation *M : reverse(ActiveMacros))
- printMessage(M->InstantiationLoc, SourceMgr::DK_Note,
- "while in macro instantiation");
+ printMessage(SrcMgr.getMacroInstantiationLoc(M->InstantiationLoc),
+ SourceMgr::DK_Note, "while in macro instantiation");
}
void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {
@@ -2411,16 +2411,6 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler)
DiagSrcMgr.printIncludeStackForDiagnostic(DiagLoc, OS);
- // Map macro errors from macro instantiation buffers to the definition line.
- if (std::optional<SMDiagnostic> NewDiag =
- DiagSrcMgr.mapDiagnosticFromMacroInstantiation(Diag)) {
- if (Parser->SavedDiagHandler)
- Parser->SavedDiagHandler(*NewDiag, Parser->SavedDiagContext);
- else
- Parser->getContext().diagnose(*NewDiag);
- return;
- }
-
// If we have not parsed a cpp hash line filename comment or the source
// manager changed or buffer changed (like in a nested include) then just
// print the normal diagnostic using its Filename and LineNo.
@@ -2871,9 +2861,8 @@ bool AsmParser::handleMacroEntry(MCAsmMacro *M, SMLoc NameLoc) {
// Jump to the macro instantiation and prime the lexer. Use the start of the
// macro body in the source manager as the IncludeLoc.
- CurBuffer = SrcMgr.AddMacroInstantiationBuffer(
- std::move(Instantiation), SMLoc::getFromPointer(M->Body.data()),
- CurBuffer, NameLoc);
+ CurBuffer = SrcMgr.AddMacroInstantiationBuffer(std::move(Instantiation),
+ M->Loc, NameLoc);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
Lex();
@@ -4818,7 +4807,7 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
const char *BodyEnd = EndToken.getLoc().getPointer();
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
checkForBadMacro(DirectiveLoc, Name, Body, Parameters);
- MCAsmMacro Macro(Name, Body, std::move(Parameters));
+ MCAsmMacro Macro(Name, Body, std::move(Parameters), DirectiveLoc);
DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";
Macro.dump());
getContext().defineMacro(Name, std::move(Macro));
@@ -5807,9 +5796,8 @@ void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
ActiveMacros.push_back(MI);
// Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddMacroInstantiationBuffer(
- std::move(Instantiation), SMLoc::getFromPointer(M->Body.data()),
- CurBuffer, DirectiveLoc);
+ CurBuffer = SrcMgr.AddMacroInstantiationBuffer(std::move(Instantiation),
+ DirectiveLoc, DirectiveLoc);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
Lex();
}
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index ddafed6154374..4477ae32c15c9 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -1008,12 +1008,9 @@ MasmParser::~MasmParser() {
void MasmParser::printMacroInstantiations() {
// Print the active macro instantiation stack.
- for (std::vector<MacroInstantiation *>::const_reverse_iterator
- it = ActiveMacros.rbegin(),
- ie = ActiveMacros.rend();
- it != ie; ++it)
- printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,
- "while in macro instantiation");
+ for (MacroInstantiation *M : reverse(ActiveMacros))
+ printMessage(SrcMgr.getMacroInstantiationLoc(M->InstantiationLoc),
+ SourceMgr::DK_Note, "while in macro instantiation");
}
void MasmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {
@@ -2399,16 +2396,6 @@ void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->SavedDiagHandler)
DiagSrcMgr.printIncludeStackForDiagnostic(DiagLoc, OS);
- // Map macro errors from macro instantiation buffers to the definition line.
- if (std::optional<SMDiagnostic> NewDiag =
- DiagSrcMgr.mapDiagnosticFromMacroInstantiation(Diag)) {
- if (Parser->SavedDiagHandler)
- Parser->SavedDiagHandler(*NewDiag, Parser->SavedDiagContext);
- else
- NewDiag->print(nullptr, OS);
- return;
- }
-
// If we have not parsed a cpp hash line filename comment or the source
// manager changed or buffer changed (like in a nested include) then just
// print the normal diagnostic using its Filename and LineNo.
@@ -2791,9 +2778,8 @@ bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,
// Jump to the macro instantiation and prime the lexer. Use the start of the
// macro body in the source manager as the IncludeLoc.
- CurBuffer = SrcMgr.AddMacroInstantiationBuffer(
- std::move(Instantiation), SMLoc::getFromPointer(M->Body.data()),
- CurBuffer, NameLoc);
+ CurBuffer = SrcMgr.AddMacroInstantiationBuffer(std::move(Instantiation),
+ M->Loc, NameLoc);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
EndStatementAtEOFStack.push_back(true);
Lex();
@@ -4428,7 +4414,7 @@ bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {
const char *BodyEnd = EndToken.getLoc().getPointer();
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals),
- IsMacroFunction);
+ IsMacroFunction, NameLoc);
DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";
Macro.dump());
getContext().defineMacro(Name.lower(), std::move(Macro));
@@ -5467,9 +5453,8 @@ void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
ActiveMacros.push_back(MI);
// Jump to the macro instantiation and prime the lexer.
- CurBuffer = SrcMgr.AddMacroInstantiationBuffer(
- std::move(Instantiation), SMLoc::getFromPointer(M->Body.data()),
- CurBuffer, DirectiveLoc);
+ CurBuffer = SrcMgr.AddMacroInstantiationBuffer(std::move(Instantiation),
+ DirectiveLoc, DirectiveLoc);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
EndStatementAtEOFStack.push_back(true);
Lex();
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index f48e895c4088c..62fce28486d4a 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -201,8 +201,7 @@ SourceMgr::SrcBuffer::getPointerForLineNumber(unsigned LineNo) const {
SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
: Buffer(std::move(Other.Buffer)), OffsetCache(Other.OffsetCache),
- IncludeLoc(Other.IncludeLoc), MacroParentBuf(Other.MacroParentBuf),
- MacroDefLoc(Other.MacroDefLoc) {
+ IncludeLoc(Other.IncludeLoc), MacroDefLoc(Other.MacroDefLoc) {
Other.OffsetCache = nullptr;
}
@@ -312,21 +311,14 @@ void SourceMgr::printIncludeStackForDiagnostic(SMLoc Loc,
}
}
-std::optional<SMDiagnostic>
-SourceMgr::mapDiagnosticFromMacroInstantiation(const SMDiagnostic &Diag) const {
- SMLoc DiagLoc = Diag.getLoc();
- unsigned DiagBuf = FindBufferContainingLoc(DiagLoc);
- if (!DiagBuf || !getMacroParentBuf(DiagBuf))
- return std::nullopt;
-
- SMLoc RealLoc = getMacroDefLoc(DiagBuf);
- unsigned RealBuf = FindBufferContainingLoc(RealLoc);
- StringRef Filename = getMemoryBuffer(RealBuf)->getBufferIdentifier();
- int LineNo = FindLineNumber(RealLoc, RealBuf) + Diag.getLineNo() - 1;
- return SMDiagnostic(*Diag.getSourceMgr(), RealLoc, Filename, LineNo,
- Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
- Diag.getLineContents(), Diag.getRanges(),
- Diag.getFixIts());
+SMLoc SourceMgr::getMacroInstantiationLoc(SMLoc Loc) const {
+ while (true) {
+ unsigned BufID = FindBufferContainingLoc(Loc);
+ if (!BufID || !getMacroDefLoc(BufID).isValid())
+ break;
+ Loc = getMacroDefLoc(BufID);
+ }
+ return Loc;
}
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
diff --git a/llvm/test/MC/AsmParser/macro-like-diagnostic.s b/llvm/test/MC/AsmParser/macro-like-diagnostic.s
index 59dbbe6658ce7..10f4ebeeb5e37 100644
--- a/llvm/test/MC/AsmParser/macro-like-diagnostic.s
+++ b/llvm/test/MC/AsmParser/macro-like-diagnostic.s
@@ -1,18 +1,18 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s
-# CHECK: macro-like-diagnostic.s:6:1: error: unknown directive
+# CHECK: <instantiation>:1:1: error: unknown directive
# CHECK: macro-like-diagnostic.s:5:1: note: while in macro instantiation
.irp reg,%rax
.invalid_irp_directive_here \reg
.endr
-# CHECK: macro-like-diagnostic.s:12:1: error: unknown directive
+# CHECK: <instantiation>:1:1: error: unknown directive
# CHECK: macro-like-diagnostic.s:11:1: note: while in macro instantiation
.irpc char,a
.invalid_irpc_directive_here \char
.endr
-# CHECK: macro-like-diagnostic.s:18:1: error: unknown directive
+# CHECK: <instantiation>:1:1: error: unknown directive
# CHECK: macro-like-diagnostic.s:17:1: note: while in macro instantiation
.rept 1
.invalid_rept_directive_here
diff --git a/llvm/test/MC/AsmParser/macro-unknown-directive.s b/llvm/test/MC/AsmParser/macro-unknown-directive.s
index bd81a4a3459c4..2fdf3ca54edea 100644
--- a/llvm/test/MC/AsmParser/macro-unknown-directive.s
+++ b/llvm/test/MC/AsmParser/macro-unknown-directive.s
@@ -1,19 +1,42 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s --match-full-lines --strict-whitespace
-# CHECK:{{.*}}macro-unknown-directive.s:13:1: error: unknown directive
-# CHECK-NEXT:.macrobody0
-# CHECK-NEXT:^
-# CHECK-NEXT:{{.*}}macro-unknown-directive.s:16:1: note: while in macro instantiation
-# CHECK-NEXT:.test0
-# CHECK-NEXT:^
-# CHECK-NEXT:{{.*}}macro-unknown-directive.s:19:1: note: while in macro instantiation
-# CHECK-NEXT:.test1
-# CHECK-NEXT:^
+## This test verifies that:
+## * Macro instantiation notes point directly to the `.macro` signature line itself
+## (e.g. `.macro .test1` instead of the first statement of the macro body).
+## * Nested active macro instantiation stacks unwind cleanly.
+## * Column numbers and caret alignments inside `<instantiation>` virtual buffers
+## are reported correctly (e.g. matching `.macrobody0` at column 7 on line 2).
+
+
+# CHECK:<instantiation>:2:7: error: unknown directive
+# CHECK-NEXT:{{^ }}.macrobody0
+# CHECK-NEXT:{{^ }}^
+# CHECK-NEXT:{{.*}}macro-unknown-directive.s:24:1: note: while in macro instantiation
+# CHECK-NEXT:{{^}}.macro .test1
+# CHECK-NEXT:{{^}}^
+# CHECK-NEXT:{{.*}}macro-unknown-directive.s:29:1: note: while in macro instantiation
+# CHECK-NEXT:{{^}}.test1
+# CHECK-NEXT:{{^}}^
.macro .test0
-.macrobody0
+ # comment inside test0
+ .macrobody0
.endm
.macro .test1
-.test0
+ # comment inside test1
+ .test0
.endm
.test1
+
+# CHECK:<instantiation>:1:35: error: literal value out of range for directive
+# CHECK-NEXT:{{^}}mov extremely_long_register_name, 9999999999999999999999999999999999
+# CHECK-NEXT:{{^ }}^
+# CHECK-NEXT:{{.*}}macro-unknown-directive.s:42:1: note: while in macro instantiation
+# CHECK-NEXT:{{^}}test_long_arg extremely_long_register_name
+# CHECK-NEXT:{{^}}^
+
+.macro test_long_arg reg
+ mov \reg, 9999999999999999999999999999999999
+.endm
+
+test_long_arg extremely_long_register_name
diff --git a/llvm/test/MC/AsmParser/macros-darwin.s b/llvm/test/MC/AsmParser/macros-darwin.s
index fb4940fac1fd8..07be3b3ca7d80 100644
--- a/llvm/test/MC/AsmParser/macros-darwin.s
+++ b/llvm/test/MC/AsmParser/macros-darwin.s
@@ -9,13 +9,13 @@
.endmacro
.test1
-// CHECK-ERRORS: macros-darwin.s:5:1: error: unknown directive
-// CHECK-ERRORS-NEXT: macrobody0
+// CHECK-ERRORS: <instantiation>:1:1: error: unknown directive
+// CHECK-ERRORS-NEXT: .macrobody0
// CHECK-ERRORS-NEXT: ^
-// CHECK-ERRORS: macros-darwin.s:8:1: note: while in macro instantiation
-// CHECK-ERRORS-NEXT: .test0
+// CHECK-ERRORS: {{.*}}macros-darwin.s:7:1: note: while in macro instantiation
+// CHECK-ERRORS-NEXT: .macro .test1
// CHECK-ERRORS-NEXT: ^
-// CHECK-ERRORS: macros-darwin.s:11:1: note: while in macro instantiation
+// CHECK-ERRORS: {{.*}}macros-darwin.s:11:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test1
// CHECK-ERRORS-NEXT: ^
diff --git a/llvm/test/MC/AsmParser/unmatched-if-macro.s b/llvm/test/MC/AsmParser/unmatched-if-macro.s
index 3fa316c29c751..d158d2cd10c28 100644
--- a/llvm/test/MC/AsmParser/unmatched-if-macro.s
+++ b/llvm/test/MC/AsmParser/unmatched-if-macro.s
@@ -2,7 +2,7 @@
# RUN: not llvm-mc -triple x86_64 %s -o /dev/null 2>&1 | FileCheck %s
## This also tests that we don't assert due to an active macro instantiation.
-# CHECK: unmatched-if-macro.s:11:1: error: unmatched .ifs or .elses
+# CHECK: <instantiation>:4:1: error: unmatched .ifs or .elses
.macro macro parameter=0
.if \parameter
@@ -10,3 +10,4 @@
.endm
macro 1
+
diff --git a/llvm/test/tools/llvm-ml/macro_diagnostic.asm b/llvm/test/tools/llvm-ml/macro_diagnostic.asm
index 72d808f9d477e..053451cde54e7 100644
--- a/llvm/test/tools/llvm-ml/macro_diagnostic.asm
+++ b/llvm/test/tools/llvm-ml/macro_diagnostic.asm
@@ -6,7 +6,7 @@ test_macro macro
invalid_instruction_here
endm
-; CHECK: macro_diagnostic.asm:6:1: error: invalid instruction mnemonic 'invalid_instruction_here'
-; CHECK: macro_diagnostic.asm:11:1: note: while in macro instantiation
-test_macro
+; CHECK: <instantiation>:1:1: error: invalid instruction mnemonic 'invalid_instruction_here'
+; CHECK: macro_diagnostic.asm:11:7: note: while in macro instantiation
+ test_macro
end
>From e88849bf6c0203407bc53f2ca9d3438c63e7c97e Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 22 May 2026 15:43:54 -0700
Subject: [PATCH 5/5] drop unnecessary include
Created using spr 1.3.8-beta.1
---
llvm/include/llvm/Support/SourceMgr.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 3ef4754d751dd..83cb3de26453a 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -20,7 +20,6 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SMLoc.h"
-#include <optional>
#include <vector>
namespace llvm {
More information about the llvm-commits
mailing list