1 | //===- Error.cpp - tblgen error handling helper routines --------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains error handling helper routines to pretty-print diagnostic |
10 | // messages from tblgen. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/ADT/Twine.h" |
15 | #include "llvm/Support/raw_ostream.h" |
16 | #include "llvm/Support/Signals.h" |
17 | #include "llvm/Support/WithColor.h" |
18 | #include "llvm/TableGen/Error.h" |
19 | #include "llvm/TableGen/Record.h" |
20 | #include <cstdlib> |
21 | |
22 | namespace llvm { |
23 | |
24 | SourceMgr SrcMgr; |
25 | unsigned ErrorsPrinted = 0; |
26 | |
27 | static void PrintMessage(ArrayRef<SMLoc> Locs, SourceMgr::DiagKind Kind, |
28 | const Twine &Msg) { |
29 | // Count the total number of errors printed. |
30 | // This is used to exit with an error code if there were any errors. |
31 | if (Kind == SourceMgr::DK_Error) |
32 | ++ErrorsPrinted; |
33 | |
34 | SMLoc NullLoc; |
35 | if (Locs.empty()) |
36 | Locs = NullLoc; |
37 | SrcMgr.PrintMessage(Loc: Locs.consume_front(), Kind, Msg); |
38 | for (SMLoc Loc : Locs) |
39 | SrcMgr.PrintMessage(Loc, Kind: SourceMgr::DK_Note, |
40 | Msg: "instantiated from multiclass" ); |
41 | } |
42 | |
43 | // Run file cleanup handlers and then exit fatally (with non-zero exit code). |
44 | [[noreturn]] inline static void fatal_exit() { |
45 | // The following call runs the file cleanup handlers. |
46 | sys::RunInterruptHandlers(); |
47 | std::exit(status: 1); |
48 | } |
49 | |
50 | // Functions to print notes. |
51 | |
52 | void PrintNote(const Twine &Msg) { |
53 | WithColor::note() << Msg << "\n" ; |
54 | } |
55 | |
56 | void PrintNote(function_ref<void(raw_ostream &OS)> PrintMsg) { |
57 | PrintMsg(WithColor::note()); |
58 | } |
59 | |
60 | void PrintNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) { |
61 | PrintMessage(Locs: NoteLoc, Kind: SourceMgr::DK_Note, Msg); |
62 | } |
63 | |
64 | // Functions to print fatal notes. |
65 | |
66 | void PrintFatalNote(const Twine &Msg) { |
67 | PrintNote(Msg); |
68 | fatal_exit(); |
69 | } |
70 | |
71 | void PrintFatalNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) { |
72 | PrintNote(NoteLoc, Msg); |
73 | fatal_exit(); |
74 | } |
75 | |
76 | // This method takes a Record and uses the source location |
77 | // stored in it. |
78 | void PrintFatalNote(const Record *Rec, const Twine &Msg) { |
79 | PrintNote(NoteLoc: Rec->getLoc(), Msg); |
80 | fatal_exit(); |
81 | } |
82 | |
83 | // This method takes a RecordVal and uses the source location |
84 | // stored in it. |
85 | void PrintFatalNote(const RecordVal *RecVal, const Twine &Msg) { |
86 | PrintNote(NoteLoc: RecVal->getLoc(), Msg); |
87 | fatal_exit(); |
88 | } |
89 | |
90 | // Functions to print warnings. |
91 | |
92 | void PrintWarning(const Twine &Msg) { WithColor::warning() << Msg << "\n" ; } |
93 | |
94 | void PrintWarning(ArrayRef<SMLoc> WarningLoc, const Twine &Msg) { |
95 | PrintMessage(Locs: WarningLoc, Kind: SourceMgr::DK_Warning, Msg); |
96 | } |
97 | |
98 | void PrintWarning(const char *Loc, const Twine &Msg) { |
99 | SrcMgr.PrintMessage(Loc: SMLoc::getFromPointer(Ptr: Loc), Kind: SourceMgr::DK_Warning, Msg); |
100 | } |
101 | |
102 | // Functions to print errors. |
103 | |
104 | void PrintError(const Twine &Msg) { WithColor::error() << Msg << "\n" ; } |
105 | |
106 | void PrintError(function_ref<void(raw_ostream &OS)> PrintMsg) { |
107 | PrintMsg(WithColor::error()); |
108 | } |
109 | |
110 | void PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) { |
111 | PrintMessage(Locs: ErrorLoc, Kind: SourceMgr::DK_Error, Msg); |
112 | } |
113 | |
114 | void PrintError(const char *Loc, const Twine &Msg) { |
115 | SrcMgr.PrintMessage(Loc: SMLoc::getFromPointer(Ptr: Loc), Kind: SourceMgr::DK_Error, Msg); |
116 | } |
117 | |
118 | // This method takes a Record and uses the source location |
119 | // stored in it. |
120 | void PrintError(const Record *Rec, const Twine &Msg) { |
121 | PrintMessage(Locs: Rec->getLoc(), Kind: SourceMgr::DK_Error, Msg); |
122 | } |
123 | |
124 | // This method takes a RecordVal and uses the source location |
125 | // stored in it. |
126 | void PrintError(const RecordVal *RecVal, const Twine &Msg) { |
127 | PrintMessage(Locs: RecVal->getLoc(), Kind: SourceMgr::DK_Error, Msg); |
128 | } |
129 | |
130 | // Functions to print fatal errors. |
131 | |
132 | void PrintFatalError(const Twine &Msg) { |
133 | PrintError(Msg); |
134 | fatal_exit(); |
135 | } |
136 | |
137 | void PrintFatalError(function_ref<void(raw_ostream &OS)> PrintMsg) { |
138 | PrintError(PrintMsg); |
139 | fatal_exit(); |
140 | } |
141 | |
142 | void PrintFatalError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) { |
143 | PrintError(ErrorLoc, Msg); |
144 | fatal_exit(); |
145 | } |
146 | |
147 | // This method takes a Record and uses the source location |
148 | // stored in it. |
149 | void PrintFatalError(const Record *Rec, const Twine &Msg) { |
150 | PrintError(ErrorLoc: Rec->getLoc(), Msg); |
151 | fatal_exit(); |
152 | } |
153 | |
154 | // This method takes a RecordVal and uses the source location |
155 | // stored in it. |
156 | void PrintFatalError(const RecordVal *RecVal, const Twine &Msg) { |
157 | PrintError(ErrorLoc: RecVal->getLoc(), Msg); |
158 | fatal_exit(); |
159 | } |
160 | |
161 | // Check an assertion: Obtain the condition value and be sure it is true. |
162 | // If not, print a nonfatal error along with the message. |
163 | bool CheckAssert(SMLoc Loc, const Init *Condition, const Init *Message) { |
164 | auto *CondValue = dyn_cast_or_null<IntInit>(Val: Condition->convertInitializerTo( |
165 | Ty: IntRecTy::get(RK&: Condition->getRecordKeeper()))); |
166 | if (!CondValue) { |
167 | PrintError(ErrorLoc: Loc, Msg: "assert condition must of type bit, bits, or int." ); |
168 | return true; |
169 | } |
170 | if (!CondValue->getValue()) { |
171 | auto *MessageInit = dyn_cast<StringInit>(Val: Message); |
172 | StringRef AssertMsg = MessageInit ? MessageInit->getValue() |
173 | : "(assert message is not a string)" ; |
174 | PrintError(ErrorLoc: Loc, Msg: "assertion failed: " + AssertMsg); |
175 | return true; |
176 | } |
177 | return false; |
178 | } |
179 | |
180 | // Dump a message to stderr. |
181 | void dumpMessage(SMLoc Loc, const Init *Message) { |
182 | if (auto *MessageInit = dyn_cast<StringInit>(Val: Message)) |
183 | PrintNote(NoteLoc: Loc, Msg: MessageInit->getValue()); |
184 | else |
185 | PrintError(ErrorLoc: Loc, Msg: "dump value is not of type string" ); |
186 | } |
187 | |
188 | } // end namespace llvm |
189 | |