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