aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2011-10-16 04:47:35 +0000
committerChris Lattner <sabre@nondot.org>2011-10-16 04:47:35 +0000
commitd8b7aa26134d2abee777f745c32005e63dea2455 (patch)
treeedc5453a63624cef371ed386f811fb2651024d33 /lib
parent17730847d59c919d97f097d46a3fcba1888e5300 (diff)
Enhance llvm::SourceMgr to support diagnostic ranges, the same way clang does. Enhance
the X86 asmparser to produce ranges in the one case that was annoying me, for example: test.s:10:15: error: invalid operand for instruction movl 0(%rax), 0(%edx) ^~~~~~~ It should be straight-forward to enhance filecheck, tblgen, and/or the .ll parser to use ranges where appropriate if someone is interested. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142106 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/MC/MCDisassembler/EDDisassembler.cpp10
-rw-r--r--lib/MC/MCParser/AsmParser.cpp38
-rw-r--r--lib/MC/MCParser/MCAsmParser.cpp4
-rw-r--r--lib/Support/SourceMgr.cpp121
-rw-r--r--lib/Target/X86/AsmParser/X86AsmParser.cpp19
5 files changed, 137 insertions, 55 deletions
diff --git a/lib/MC/MCDisassembler/EDDisassembler.cpp b/lib/MC/MCDisassembler/EDDisassembler.cpp
index 83362a21f7..5633cb11e7 100644
--- a/lib/MC/MCDisassembler/EDDisassembler.cpp
+++ b/lib/MC/MCDisassembler/EDDisassembler.cpp
@@ -337,13 +337,9 @@ int EDDisassembler::printInst(std::string &str, MCInst &inst) {
return 0;
}
-static void diag_handler(const SMDiagnostic &diag,
- void *context)
-{
- if (context) {
- EDDisassembler *disassembler = static_cast<EDDisassembler*>(context);
- diag.Print("", disassembler->ErrorStream);
- }
+static void diag_handler(const SMDiagnostic &diag, void *context) {
+ if (context)
+ diag.print("", static_cast<EDDisassembler*>(context)->ErrorStream);
}
int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands,
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 311c3347a5..25f404c703 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -142,8 +142,10 @@ public:
virtual MCContext &getContext() { return Ctx; }
virtual MCStreamer &getStreamer() { return Out; }
- virtual bool Warning(SMLoc L, const Twine &Msg);
- virtual bool Error(SMLoc L, const Twine &Msg);
+ virtual bool Warning(SMLoc L, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = ArrayRef<SMRange>());
+ virtual bool Error(SMLoc L, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = ArrayRef<SMRange>());
const AsmToken &Lex();
@@ -170,8 +172,9 @@ private:
void PrintMacroInstantiations();
void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type,
+ ArrayRef<SMRange> Ranges = ArrayRef<SMRange>(),
bool ShowLine = true) const {
- SrcMgr.PrintMessage(Loc, Msg, Type, ShowLine);
+ SrcMgr.PrintMessage(Loc, Msg, Type, Ranges, ShowLine);
}
static void DiagHandler(const SMDiagnostic &Diag, void *Context);
@@ -393,17 +396,17 @@ void AsmParser::PrintMacroInstantiations() {
"note");
}
-bool AsmParser::Warning(SMLoc L, const Twine &Msg) {
+bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) {
if (FatalAssemblerWarnings)
- return Error(L, Msg);
- PrintMessage(L, Msg, "warning");
+ return Error(L, Msg, Ranges);
+ PrintMessage(L, Msg, "warning", Ranges);
PrintMacroInstantiations();
return false;
}
-bool AsmParser::Error(SMLoc L, const Twine &Msg) {
+bool AsmParser::Error(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) {
HadError = true;
- PrintMessage(L, Msg, "error");
+ PrintMessage(L, Msg, "error", Ranges);
PrintMacroInstantiations();
return true;
}
@@ -496,7 +499,8 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
// first referenced for a source location. We need to add something
// to track that. Currently, we just point to the end of the file.
PrintMessage(getLexer().getLoc(), "assembler local symbol '" +
- Sym->getName() + "' not defined", "error", false);
+ Sym->getName() + "' not defined", "error",
+ ArrayRef<SMRange>(), false);
}
}
@@ -1284,7 +1288,7 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
if (!Parser->CppHashLineNumber ||
&DiagSrcMgr != &Parser->SrcMgr ||
DiagBuf != CppHashBuf) {
- Diag.Print(0, OS);
+ Diag.print(0, OS);
return;
}
@@ -1299,16 +1303,12 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
int LineNo = Parser->CppHashLineNumber - 1 +
(DiagLocLineNo - CppHashLocLineNo);
- SMDiagnostic NewDiag(*Diag.getSourceMgr(),
- Diag.getLoc(),
- Filename,
- LineNo,
- Diag.getColumnNo(),
- Diag.getMessage(),
- Diag.getLineContents(),
- Diag.getShowLine());
+ SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(),
+ Filename, LineNo, Diag.getColumnNo(),
+ Diag.getMessage(), Diag.getLineContents(),
+ Diag.getRanges(), Diag.getShowLine());
- NewDiag.Print(0, OS);
+ NewDiag.print(0, OS);
}
bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body,
diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp
index 5239ec753e..3a825f03b7 100644
--- a/lib/MC/MCParser/MCAsmParser.cpp
+++ b/lib/MC/MCParser/MCAsmParser.cpp
@@ -33,8 +33,8 @@ const AsmToken &MCAsmParser::getTok() {
return getLexer().getTok();
}
-bool MCAsmParser::TokError(const Twine &Msg) {
- Error(getLexer().getLoc(), Msg);
+bool MCAsmParser::TokError(const Twine &Msg, ArrayRef<SMRange> Ranges) {
+ Error(getLexer().getLoc(), Msg, Ranges);
return true;
}
diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp
index de042a9f53..ba2201816e 100644
--- a/lib/Support/SourceMgr.cpp
+++ b/lib/Support/SourceMgr.cpp
@@ -141,7 +141,8 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
/// @param Type - If non-null, the kind of message (e.g., "error") which is
/// prefixed to the message.
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg,
- const char *Type, bool ShowLine) const {
+ const char *Type, ArrayRef<SMRange> Ranges,
+ bool ShowLine) const {
// First thing to do: find the current buffer containing the specified
// location.
@@ -156,15 +157,12 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg,
LineStart[-1] != '\n' && LineStart[-1] != '\r')
--LineStart;
- std::string LineStr;
- if (ShowLine) {
- // Get the end of the line.
- const char *LineEnd = Loc.getPointer();
- while (LineEnd != CurMB->getBufferEnd() &&
- LineEnd[0] != '\n' && LineEnd[0] != '\r')
- ++LineEnd;
- LineStr = std::string(LineStart, LineEnd);
- }
+ // Get the end of the line.
+ const char *LineEnd = Loc.getPointer();
+ while (LineEnd != CurMB->getBufferEnd() &&
+ LineEnd[0] != '\n' && LineEnd[0] != '\r')
+ ++LineEnd;
+ std::string LineStr(LineStart, LineEnd);
std::string PrintedMsg;
raw_string_ostream OS(PrintedMsg);
@@ -172,17 +170,40 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg,
OS << Type << ": ";
OS << Msg;
+ // Convert any ranges to column ranges that only intersect the line of the
+ // location.
+ SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ SMRange R = Ranges[i];
+ if (!R.isValid()) continue;
+
+ // If the line doesn't contain any part of the range, then ignore it.
+ if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
+ continue;
+
+ // Ignore pieces of the range that go onto other lines.
+ if (R.Start.getPointer() < LineStart)
+ R.Start = SMLoc::getFromPointer(LineStart);
+ if (R.End.getPointer() > LineEnd)
+ R.End = SMLoc::getFromPointer(LineEnd);
+
+ // Translate from SMLoc ranges to column ranges.
+ ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
+ R.End.getPointer()-LineStart));
+ }
+
return SMDiagnostic(*this, Loc,
CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf),
Loc.getPointer()-LineStart, OS.str(),
- LineStr, ShowLine);
+ LineStr, ColRanges, ShowLine);
}
void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg,
- const char *Type, bool ShowLine) const {
+ const char *Type, ArrayRef<SMRange> Ranges,
+ bool ShowLine) const {
// Report the message with the diagnostic handler if present.
if (DiagHandler) {
- DiagHandler(GetMessage(Loc, Msg, Type, ShowLine), DiagContext);
+ DiagHandler(GetMessage(Loc, Msg, Type, Ranges, ShowLine), DiagContext);
return;
}
@@ -192,14 +213,23 @@ void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg,
assert(CurBuf != -1 && "Invalid or unspecified location!");
PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
- GetMessage(Loc, Msg, Type, ShowLine).Print(0, OS);
+ GetMessage(Loc, Msg, Type, Ranges, ShowLine).print(0, OS);
}
//===----------------------------------------------------------------------===//
// SMDiagnostic Implementation
//===----------------------------------------------------------------------===//
-void SMDiagnostic::Print(const char *ProgName, raw_ostream &S) const {
+SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN,
+ int Line, int Col, const std::string &Msg,
+ const std::string &LineStr,
+ ArrayRef<std::pair<unsigned,unsigned> > Ranges,
+ bool showline)
+ : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Message(Msg),
+ LineContents(LineStr), ShowLine(showline), Ranges(Ranges.vec()) {}
+
+
+void SMDiagnostic::print(const char *ProgName, raw_ostream &S) const {
if (ProgName && ProgName[0])
S << ProgName << ": ";
@@ -219,14 +249,63 @@ void SMDiagnostic::Print(const char *ProgName, raw_ostream &S) const {
S << Message << '\n';
- if (LineNo != -1 && ColumnNo != -1 && ShowLine) {
- S << LineContents << '\n';
+ if (LineNo == -1 || ColumnNo == -1 || !ShowLine)
+ return;
- // Print out spaces/tabs before the caret.
- for (unsigned i = 0; i != unsigned(ColumnNo); ++i)
- S << (LineContents[i] == '\t' ? '\t' : ' ');
- S << "^\n";
+ // Build the line with the caret and ranges.
+ std::string CaretLine(LineContents.size()+1, ' ');
+
+ // Expand any ranges.
+ for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
+ std::pair<unsigned, unsigned> R = Ranges[r];
+ for (unsigned i = R.first,
+ e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i)
+ CaretLine[i] = '~';
+ }
+
+ // Finally, plop on the caret.
+ if (unsigned(ColumnNo) <= LineContents.size())
+ CaretLine[ColumnNo] = '^';
+ else
+ CaretLine[LineContents.size()] = '^';
+
+ // ... and remove trailing whitespace so the output doesn't wrap for it. We
+ // know that the line isn't completely empty because it has the caret in it at
+ // least.
+ CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
+
+ // Print out the source line one character at a time, so we can expand tabs.
+ for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
+ if (LineContents[i] != '\t') {
+ S << LineContents[i];
+ ++OutCol;
+ continue;
+ }
+
+ // If we have a tab, emit at least one space, then round up to 8 columns.
+ do {
+ S << ' ';
+ ++OutCol;
+ } while (OutCol & 7);
+ }
+ S << '\n';
+
+ // Print out the caret line, matching tabs in the source line.
+ for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
+ if (i >= LineContents.size() || LineContents[i] != '\t') {
+ S << CaretLine[i];
+ ++OutCol;
+ continue;
+ }
+
+ // Okay, we have a tab. Insert the appropriate number of characters.
+ do {
+ S << CaretLine[i];
+ ++OutCol;
+ } while (OutCol & 7);
}
+
+ S << '\n';
}
diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp
index cb4f15ffed..eda180e734 100644
--- a/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -41,7 +41,10 @@ private:
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
- bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
+ bool Error(SMLoc L, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()) {
+ return Parser.Error(L, Msg, Ranges);
+ }
X86Operand *ParseOperand();
X86Operand *ParseMemOperand(unsigned SegReg, SMLoc StartLoc);
@@ -145,6 +148,8 @@ struct X86Operand : public MCParsedAsmOperand {
SMLoc getStartLoc() const { return StartLoc; }
/// getEndLoc - Get the location of the last token of this operand.
SMLoc getEndLoc() const { return EndLoc; }
+
+ SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); }
virtual void print(raw_ostream &OS) const {}
@@ -1083,16 +1088,19 @@ MatchAndEmitInstruction(SMLoc IDLoc,
}
// Recover location info for the operand if we know which was the problem.
- SMLoc ErrorLoc = IDLoc;
if (OrigErrorInfo != ~0U) {
if (OrigErrorInfo >= Operands.size())
return Error(IDLoc, "too few operands for instruction");
- ErrorLoc = ((X86Operand*)Operands[OrigErrorInfo])->getStartLoc();
- if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
+ X86Operand *Operand = (X86Operand*)Operands[OrigErrorInfo];
+ if (Operand->getStartLoc().isValid()) {
+ SMRange OperandRange = Operand->getLocRange();
+ return Error(Operand->getStartLoc(), "invalid operand for instruction",
+ OperandRange);
+ }
}
- return Error(ErrorLoc, "invalid operand for instruction");
+ return Error(IDLoc, "invalid operand for instruction");
}
// If one instruction matched with a missing feature, report this as a
@@ -1112,7 +1120,6 @@ MatchAndEmitInstruction(SMLoc IDLoc,
}
// If all of these were an outright failure, report it in a useless way.
- // FIXME: We should give nicer diagnostics about the exact failure.
Error(IDLoc, "unknown use of instruction mnemonic without a size suffix");
return true;
}