llvm.org GIT mirror llvm / d8b7aa2
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 Chris Lattner 8 years ago
20 changed file(s) with 196 addition(s) and 87 deletion(s). Raw diff Collapse all Expand all
1010 #define LLVM_MC_MCASMPARSER_H
1111
1212 #include "llvm/Support/DataTypes.h"
13 #include "llvm/ADT/ArrayRef.h"
1314
1415 namespace llvm {
1516 class AsmToken;
2122 class MCStreamer;
2223 class MCTargetAsmParser;
2324 class SMLoc;
25 class SMRange;
2426 class SourceMgr;
2527 class StringRef;
2628 class Twine;
7173 /// Msg.
7274 ///
7375 /// \return The return value is true, if warnings are fatal.
74 virtual bool Warning(SMLoc L, const Twine &Msg) = 0;
76 virtual bool Warning(SMLoc L, const Twine &Msg,
77 ArrayRef Ranges = ArrayRef()) = 0;
7578
7679 /// Error - Emit an error at the location \arg L, with the message \arg
7780 /// Msg.
7881 ///
7982 /// \return The return value is always true, as an idiomatic convenience to
8083 /// clients.
81 virtual bool Error(SMLoc L, const Twine &Msg) = 0;
84 virtual bool Error(SMLoc L, const Twine &Msg,
85 ArrayRef Ranges = ArrayRef()) = 0;
8286
8387 /// Lex - Get the next AsmToken in the stream, possibly handling file
8488 /// inclusion first.
8892 const AsmToken &getTok();
8993
9094 /// \brief Report an error at the current lexer location.
91 bool TokError(const Twine &Msg);
95 bool TokError(const Twine &Msg,
96 ArrayRef Ranges = ArrayRef());
9297
9398 /// ParseIdentifier - Parse an identifier or string (as a quoted identifier)
9499 /// and set \arg Res to the identifier contents.
1414 #ifndef SUPPORT_SMLOC_H
1515 #define SUPPORT_SMLOC_H
1616
17 #include
18
1719 namespace llvm {
1820
19 // SMLoc - Represents a location in source code.
21 /// SMLoc - Represents a location in source code.
2022 class SMLoc {
2123 const char *Ptr;
2224 public:
3739 }
3840 };
3941
40 }
42 /// SMRange - Represents a range in source code. Note that unlike standard STL
43 /// ranges, the locations specified are considered to be *inclusive*. For
44 /// example, [X,X] *does* include X, it isn't an empty range.
45 class SMRange {
46 public:
47 SMLoc Start, End;
48
49 SMRange() {}
50 SMRange(SMLoc Start, SMLoc End) : Start(Start), End(End) {
51 assert(Start.isValid() == End.isValid() &&
52 "Start and end should either both be valid or both be invalid!");
53 }
54
55 bool isValid() const { return Start.isValid(); }
56 };
57
58 } // end namespace llvm
4159
4260 #endif
4361
1616 #define SUPPORT_SOURCEMGR_H
1717
1818 #include "llvm/Support/SMLoc.h"
19
19 #include "llvm/ADT/ArrayRef.h"
2020 #include
21 #include
22 #include
2321
2422 namespace llvm {
2523 class MemoryBuffer;
124122 /// prefixed to the message.
125123 /// @param ShowLine - Should the diagnostic show the source line.
126124 void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type,
125 ArrayRef Ranges = ArrayRef(),
127126 bool ShowLine = true) const;
128127
129128
135134 /// @param ShowLine - Should the diagnostic show the source line.
136135 SMDiagnostic GetMessage(SMLoc Loc,
137136 const Twine &Msg, const char *Type,
137 ArrayRef Ranges = ArrayRef(),
138138 bool ShowLine = true) const;
139139
140140 /// PrintIncludeStack - Prints the names of included files and the line of the
156156 int LineNo, ColumnNo;
157157 std::string Message, LineContents;
158158 unsigned ShowLine : 1;
159 std::vector > Ranges;
159160
160161 public:
161162 // Null diagnostic.
169170 SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN,
170171 int Line, int Col,
171172 const std::string &Msg, const std::string &LineStr,
172 bool showline = true)
173 : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Message(Msg),
174 LineContents(LineStr), ShowLine(showline) {}
173 ArrayRef > Ranges, bool showline);
175174
176175 const SourceMgr *getSourceMgr() const { return SM; }
177176 SMLoc getLoc() const { return Loc; }
181180 const std::string &getMessage() const { return Message; }
182181 const std::string &getLineContents() const { return LineContents; }
183182 bool getShowLine() const { return ShowLine; }
184
185 void Print(const char *ProgName, raw_ostream &S) const;
183 const std::vector > &getRanges() const {
184 return Ranges;
185 }
186 void print(const char *ProgName, raw_ostream &S) const;
186187 };
187188
188189 } // end llvm namespace
336336 return 0;
337337 }
338338
339 static void diag_handler(const SMDiagnostic &diag,
340 void *context)
341 {
342 if (context) {
343 EDDisassembler *disassembler = static_cast(context);
344 diag.Print("", disassembler->ErrorStream);
345 }
339 static void diag_handler(const SMDiagnostic &diag, void *context) {
340 if (context)
341 diag.print("", static_cast(context)->ErrorStream);
346342 }
347343
348344 int EDDisassembler::parseInst(SmallVectorImpl &operands,
141141 virtual MCContext &getContext() { return Ctx; }
142142 virtual MCStreamer &getStreamer() { return Out; }
143143
144 virtual bool Warning(SMLoc L, const Twine &Msg);
145 virtual bool Error(SMLoc L, const Twine &Msg);
144 virtual bool Warning(SMLoc L, const Twine &Msg,
145 ArrayRef Ranges = ArrayRef());
146 virtual bool Error(SMLoc L, const Twine &Msg,
147 ArrayRef Ranges = ArrayRef());
146148
147149 const AsmToken &Lex();
148150
169171
170172 void PrintMacroInstantiations();
171173 void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type,
174 ArrayRef Ranges = ArrayRef(),
172175 bool ShowLine = true) const {
173 SrcMgr.PrintMessage(Loc, Msg, Type, ShowLine);
176 SrcMgr.PrintMessage(Loc, Msg, Type, Ranges, ShowLine);
174177 }
175178 static void DiagHandler(const SMDiagnostic &Diag, void *Context);
176179
392395 "note");
393396 }
394397
395 bool AsmParser::Warning(SMLoc L, const Twine &Msg) {
398 bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef Ranges) {
396399 if (FatalAssemblerWarnings)
397 return Error(L, Msg);
398 PrintMessage(L, Msg, "warning");
400 return Error(L, Msg, Ranges);
401 PrintMessage(L, Msg, "warning", Ranges);
399402 PrintMacroInstantiations();
400403 return false;
401404 }
402405
403 bool AsmParser::Error(SMLoc L, const Twine &Msg) {
406 bool AsmParser::Error(SMLoc L, const Twine &Msg, ArrayRef Ranges) {
404407 HadError = true;
405 PrintMessage(L, Msg, "error");
408 PrintMessage(L, Msg, "error", Ranges);
406409 PrintMacroInstantiations();
407410 return true;
408411 }
495498 // first referenced for a source location. We need to add something
496499 // to track that. Currently, we just point to the end of the file.
497500 PrintMessage(getLexer().getLoc(), "assembler local symbol '" +
498 Sym->getName() + "' not defined", "error", false);
501 Sym->getName() + "' not defined", "error",
502 ArrayRef(), false);
499503 }
500504 }
501505
12831287 if (!Parser->CppHashLineNumber ||
12841288 &DiagSrcMgr != &Parser->SrcMgr ||
12851289 DiagBuf != CppHashBuf) {
1286 Diag.Print(0, OS);
1290 Diag.print(0, OS);
12871291 return;
12881292 }
12891293
12981302 int LineNo = Parser->CppHashLineNumber - 1 +
12991303 (DiagLocLineNo - CppHashLocLineNo);
13001304
1301 SMDiagnostic NewDiag(*Diag.getSourceMgr(),
1302 Diag.getLoc(),
1303 Filename,
1304 LineNo,
1305 Diag.getColumnNo(),
1306 Diag.getMessage(),
1307 Diag.getLineContents(),
1308 Diag.getShowLine());
1309
1310 NewDiag.Print(0, OS);
1305 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(),
1306 Filename, LineNo, Diag.getColumnNo(),
1307 Diag.getMessage(), Diag.getLineContents(),
1308 Diag.getRanges(), Diag.getShowLine());
1309
1310 NewDiag.print(0, OS);
13111311 }
13121312
13131313 bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body,
3232 return getLexer().getTok();
3333 }
3434
35 bool MCAsmParser::TokError(const Twine &Msg) {
36 Error(getLexer().getLoc(), Msg);
35 bool MCAsmParser::TokError(const Twine &Msg, ArrayRef Ranges) {
36 Error(getLexer().getLoc(), Msg, Ranges);
3737 return true;
3838 }
3939
140140 /// @param Type - If non-null, the kind of message (e.g., "error") which is
141141 /// prefixed to the message.
142142 SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg,
143 const char *Type, bool ShowLine) const {
143 const char *Type, ArrayRef Ranges,
144 bool ShowLine) const {
144145
145146 // First thing to do: find the current buffer containing the specified
146147 // location.
155156 LineStart[-1] != '\n' && LineStart[-1] != '\r')
156157 --LineStart;
157158
158 std::string LineStr;
159 if (ShowLine) {
160 // Get the end of the line.
161 const char *LineEnd = Loc.getPointer();
162 while (LineEnd != CurMB->getBufferEnd() &&
163 LineEnd[0] != '\n' && LineEnd[0] != '\r')
164 ++LineEnd;
165 LineStr = std::string(LineStart, LineEnd);
166 }
159 // Get the end of the line.
160 const char *LineEnd = Loc.getPointer();
161 while (LineEnd != CurMB->getBufferEnd() &&
162 LineEnd[0] != '\n' && LineEnd[0] != '\r')
163 ++LineEnd;
164 std::string LineStr(LineStart, LineEnd);
167165
168166 std::string PrintedMsg;
169167 raw_string_ostream OS(PrintedMsg);
171169 OS << Type << ": ";
172170 OS << Msg;
173171
172 // Convert any ranges to column ranges that only intersect the line of the
173 // location.
174 SmallVector, 4> ColRanges;
175 for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
176 SMRange R = Ranges[i];
177 if (!R.isValid()) continue;
178
179 // If the line doesn't contain any part of the range, then ignore it.
180 if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
181 continue;
182
183 // Ignore pieces of the range that go onto other lines.
184 if (R.Start.getPointer() < LineStart)
185 R.Start = SMLoc::getFromPointer(LineStart);
186 if (R.End.getPointer() > LineEnd)
187 R.End = SMLoc::getFromPointer(LineEnd);
188
189 // Translate from SMLoc ranges to column ranges.
190 ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
191 R.End.getPointer()-LineStart));
192 }
193
174194 return SMDiagnostic(*this, Loc,
175195 CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf),
176196 Loc.getPointer()-LineStart, OS.str(),
177 LineStr, ShowLine);
197 LineStr, ColRanges, ShowLine);
178198 }
179199
180200 void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg,
181 const char *Type, bool ShowLine) const {
201 const char *Type, ArrayRef Ranges,
202 bool ShowLine) const {
182203 // Report the message with the diagnostic handler if present.
183204 if (DiagHandler) {
184 DiagHandler(GetMessage(Loc, Msg, Type, ShowLine), DiagContext);
205 DiagHandler(GetMessage(Loc, Msg, Type, Ranges, ShowLine), DiagContext);
185206 return;
186207 }
187208
191212 assert(CurBuf != -1 && "Invalid or unspecified location!");
192213 PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
193214
194 GetMessage(Loc, Msg, Type, ShowLine).Print(0, OS);
215 GetMessage(Loc, Msg, Type, Ranges, ShowLine).print(0, OS);
195216 }
196217
197218 //===----------------------------------------------------------------------===//
198219 // SMDiagnostic Implementation
199220 //===----------------------------------------------------------------------===//
200221
201 void SMDiagnostic::Print(const char *ProgName, raw_ostream &S) const {
222 SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN,
223 int Line, int Col, const std::string &Msg,
224 const std::string &LineStr,
225 ArrayRef > Ranges,
226 bool showline)
227 : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Message(Msg),
228 LineContents(LineStr), ShowLine(showline), Ranges(Ranges.vec()) {}
229
230
231 void SMDiagnostic::print(const char *ProgName, raw_ostream &S) const {
202232 if (ProgName && ProgName[0])
203233 S << ProgName << ": ";
204234
218248
219249 S << Message << '\n';
220250
221 if (LineNo != -1 && ColumnNo != -1 && ShowLine) {
222 S << LineContents << '\n';
223
224 // Print out spaces/tabs before the caret.
225 for (unsigned i = 0; i != unsigned(ColumnNo); ++i)
226 S << (LineContents[i] == '\t' ? '\t' : ' ');
227 S << "^\n";
228 }
229 }
230
231
251 if (LineNo == -1 || ColumnNo == -1 || !ShowLine)
252 return;
253
254 // Build the line with the caret and ranges.
255 std::string CaretLine(LineContents.size()+1, ' ');
256
257 // Expand any ranges.
258 for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
259 std::pair R = Ranges[r];
260 for (unsigned i = R.first,
261 e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i)
262 CaretLine[i] = '~';
263 }
264
265 // Finally, plop on the caret.
266 if (unsigned(ColumnNo) <= LineContents.size())
267 CaretLine[ColumnNo] = '^';
268 else
269 CaretLine[LineContents.size()] = '^';
270
271 // ... and remove trailing whitespace so the output doesn't wrap for it. We
272 // know that the line isn't completely empty because it has the caret in it at
273 // least.
274 CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
275
276 // Print out the source line one character at a time, so we can expand tabs.
277 for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
278 if (LineContents[i] != '\t') {
279 S << LineContents[i];
280 ++OutCol;
281 continue;
282 }
283
284 // If we have a tab, emit at least one space, then round up to 8 columns.
285 do {
286 S << ' ';
287 ++OutCol;
288 } while (OutCol & 7);
289 }
290 S << '\n';
291
292 // Print out the caret line, matching tabs in the source line.
293 for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
294 if (i >= LineContents.size() || LineContents[i] != '\t') {
295 S << CaretLine[i];
296 ++OutCol;
297 continue;
298 }
299
300 // Okay, we have a tab. Insert the appropriate number of characters.
301 do {
302 S << CaretLine[i];
303 ++OutCol;
304 } while (OutCol & 7);
305 }
306
307 S << '\n';
308 }
309
310
4040
4141 MCAsmLexer &getLexer() const { return Parser.getLexer(); }
4242
43 bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
43 bool Error(SMLoc L, const Twine &Msg,
44 ArrayRef Ranges = ArrayRef()) {
45 return Parser.Error(L, Msg, Ranges);
46 }
4447
4548 X86Operand *ParseOperand();
4649 X86Operand *ParseMemOperand(unsigned SegReg, SMLoc StartLoc);
144147 SMLoc getStartLoc() const { return StartLoc; }
145148 /// getEndLoc - Get the location of the last token of this operand.
146149 SMLoc getEndLoc() const { return EndLoc; }
150
151 SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); }
147152
148153 virtual void print(raw_ostream &OS) const {}
149154
10821087 }
10831088
10841089 // Recover location info for the operand if we know which was the problem.
1085 SMLoc ErrorLoc = IDLoc;
10861090 if (OrigErrorInfo != ~0U) {
10871091 if (OrigErrorInfo >= Operands.size())
10881092 return Error(IDLoc, "too few operands for instruction");
10891093
1090 ErrorLoc = ((X86Operand*)Operands[OrigErrorInfo])->getStartLoc();
1091 if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
1092 }
1093
1094 return Error(ErrorLoc, "invalid operand for instruction");
1094 X86Operand *Operand = (X86Operand*)Operands[OrigErrorInfo];
1095 if (Operand->getStartLoc().isValid()) {
1096 SMRange OperandRange = Operand->getLocRange();
1097 return Error(Operand->getStartLoc(), "invalid operand for instruction",
1098 OperandRange);
1099 }
1100 }
1101
1102 return Error(IDLoc, "invalid operand for instruction");
10951103 }
10961104
10971105 // If one instruction matched with a missing feature, report this as a
11111119 }
11121120
11131121 // If all of these were an outright failure, report it in a useless way.
1114 // FIXME: We should give nicer diagnostics about the exact failure.
11151122 Error(IDLoc, "unknown use of instruction mnemonic without a size suffix");
11161123 return true;
11171124 }
1414
1515 # 8 "test.s"
1616 movi $8,%eax
17
18 movl 0(%rax), 0(%edx) // error: invalid operand for instruction
19
8686 SMDiagnostic Err;
8787 Module *Result = ParseIRFile(Filename, Err, Ctxt);
8888 if (!Result)
89 Err.Print("bugpoint", errs());
89 Err.print("bugpoint", errs());
9090
9191 // If we don't have an override triple, use the first one to configure
9292 // bugpoint, or use the host triple if none provided.
246246
247247 M.reset(ParseIRFile(InputFilename, Err, Context));
248248 if (M.get() == 0) {
249 Err.Print(argv[0], errs());
249 Err.print(argv[0], errs());
250250 return 1;
251251 }
252252 Module &mod = *M.get();
177177 SMDiagnostic Err;
178178 Module *Mod = ParseIRFile(InputFile, Err, Context);
179179 if (!Mod) {
180 Err.Print(argv[0], errs());
180 Err.print(argv[0], errs());
181181 return 1;
182182 }
183183
9595 SMDiagnostic Err;
9696 std::auto_ptr M(ParseAssemblyFile(InputFilename, Err, Context));
9797 if (M.get() == 0) {
98 Err.Print(argv[0], errs());
98 Err.print(argv[0], errs());
9999 return 1;
100100 }
101101
3737 SMDiagnostic Diag;
3838 Module *M = ParseIRFile(Name, Diag, Context);
3939 if (!M)
40 Diag.Print("llvmdiff", errs());
40 Diag.print("llvm-diff", errs());
4141 return M;
4242 }
4343
8989 M.reset(getLazyIRFileModule(InputFilename, Err, Context));
9090
9191 if (M.get() == 0) {
92 Err.Print(argv[0], errs());
92 Err.print(argv[0], errs());
9393 return 1;
9494 }
9595
6868 Result = ParseIRFile(FNStr, Err, Context);
6969 if (Result) return std::auto_ptr(Result); // Load successful!
7070
71 Err.Print(argv0, errs());
71 Err.print(argv0, errs());
7272 return std::auto_ptr();
7373 }
7474
504504 M.reset(ParseIRFile(InputFilename, Err, Context));
505505
506506 if (M.get() == 0) {
507 Err.Print(argv[0], errs());
507 Err.print(argv[0], errs());
508508 return 1;
509509 }
510510
183183 NULL != ParseAssemblyString(assembly, M, Error, M->getContext());
184184 std::string errMsg;
185185 raw_string_ostream os(errMsg);
186 Error.Print("", os);
186 Error.print("", os);
187187 EXPECT_TRUE(success) << os.str();
188188 return success;
189189 }
2525 NULL != ParseAssemblyString(assembly, M, Error, M->getContext());
2626 std::string errMsg;
2727 raw_string_ostream os(errMsg);
28 Error.Print("", os);
28 Error.print("", os);
2929 EXPECT_TRUE(success) << os.str();
3030 return success;
3131 }
383383 }
384384
385385 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), OS.str(), "note",
386 /*ShowLine=*/false);
386 ArrayRef(), /*ShowLine=*/false);
387387 }
388388 }
389389