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> Loc, 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 (Loc.empty()) 36 Loc = NullLoc; 37 SrcMgr.PrintMessage(Loc.front(), Kind, Msg); 38 for (unsigned i = 1; i < Loc.size(); ++i) 39 SrcMgr.PrintMessage(Loc[i], SourceMgr::DK_Note, 40 "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(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(NoteLoc, 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(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(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(WarningLoc, SourceMgr::DK_Warning, Msg); 96 } 97 98 void PrintWarning(const char *Loc, const Twine &Msg) { 99 SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), 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(ErrorLoc, SourceMgr::DK_Error, Msg); 112 } 113 114 void PrintError(const char *Loc, const Twine &Msg) { 115 SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), 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(Rec->getLoc(), 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(RecVal->getLoc(), 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(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(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>(Condition->convertInitializerTo( 165 IntRecTy::get(Condition->getRecordKeeper()))); 166 if (!CondValue) { 167 PrintError(Loc, "assert condition must of type bit, bits, or int."); 168 return true; 169 } 170 if (!CondValue->getValue()) { 171 auto *MessageInit = dyn_cast<StringInit>(Message); 172 StringRef AssertMsg = MessageInit ? MessageInit->getValue() 173 : "(assert message is not a string)"; 174 PrintError(Loc, "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>(Message)) 183 PrintNote(Loc, MessageInit->getValue()); 184 else 185 PrintError(Loc, "dump value is not of type string"); 186 } 187 188 } // end namespace llvm 189