// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Error handling // // Code available from: https://verilator.org // //************************************************************************* // // Copyright 2003-2020 by Wilson Snyder. This program is free software; you // can redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* #include "V3Error.h" #ifndef _V3ERROR_NO_GLOBAL_ # include "V3Ast.h" # include "V3Global.h" # include "V3Stats.h" #endif #include //====================================================================== // Statics int V3Error::s_errCount = 0; int V3Error::s_warnCount = 0; int V3Error::s_debugDefault = 0; int V3Error::s_errorLimit = V3Error::MAX_ERRORS; bool V3Error::s_warnFatal = true; int V3Error::s_tellManual = 0; std::ostringstream V3Error::s_errorStr; // Error string being formed V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL; bool V3Error::s_errorContexted = false; bool V3Error::s_errorSuppressed = false; bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; bool V3Error::s_describedWarnings = false; bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX]; V3Error::MessagesSet V3Error::s_messages; V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL; struct v3errorIniter { v3errorIniter() { V3Error::init(); } }; v3errorIniter v3errorInit; //###################################################################### // ErrorCode class functions V3ErrorCode::V3ErrorCode(const char* msgp) { // Return error encoding for given string, or ERROR, which is a bad code for (int codei=V3ErrorCode::EC_MIN; codei20) numsp = 20; out<<(spaces + numsp); return out.str(); } void V3Error::incErrors() { s_errCount++; if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse v3fatalExit("Exiting due to too many errors encountered; --error-limit=" << errorCount() << endl); } } void V3Error::abortIfWarnings() { bool exwarn = warnFatal() && warnCount(); if (errorCount() && exwarn) { v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " << warnCount() << " warning(s)\n"); } else if (errorCount()) { v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n"); } else if (exwarn) { v3fatalExit("Exiting due to " << std::dec << warnCount() << " warning(s)\n"); } } bool V3Error::isError(V3ErrorCode code, bool supp) { if (supp) return false; else if (code == V3ErrorCode::USERINFO) return false; else if (code == V3ErrorCode::EC_INFO) return false; else if (code == V3ErrorCode::EC_FATAL) return true; else if (code == V3ErrorCode::EC_FATALEXIT) return true; else if (code == V3ErrorCode::EC_FATALSRC) return true; else if (code == V3ErrorCode::EC_ERROR) return true; else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) return true; else return false; } string V3Error::msgPrefix() { V3ErrorCode code = s_errorCode; bool supp = s_errorSuppressed; if (supp) return "-arning-suppressed: "; else if (code == V3ErrorCode::USERINFO) return "-Info: "; else if (code == V3ErrorCode::EC_INFO) return "-Info: "; else if (code == V3ErrorCode::EC_FATAL) return "%Error: "; else if (code == V3ErrorCode::EC_FATALEXIT) return "%Error: "; else if (code == V3ErrorCode::EC_FATALSRC) return "%Error: Internal Error: "; else if (code == V3ErrorCode::EC_ERROR) return "%Error: "; else if (isError(code, supp)) return "%Error-"+string(code.ascii())+": "; else return "%Warning-"+string(code.ascii())+": "; } //====================================================================== // Abort/exit void V3Error::vlAbort() { if (V3Error::debugDefault()) { std::cerr<=V3ErrorCode::EC_MIN) { #ifndef _V3ERROR_NO_GLOBAL_ V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1); #endif s_errorSuppressed = true; } } string V3Error::warnMore() { return string(msgPrefix().size(), ' '); } void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { #if defined(__COVERITY__) || defined(__cppcheck__) if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x); #endif // Skip suppressed messages if (s_errorSuppressed // On debug, show only non default-off warning to prevent pages of warnings && (!debug() || s_errorCode.defaultsOff())) return; string msg = msgPrefix()+sstr.str(); if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity string::size_type pos; if ((pos = msg.find('\n')) != string::npos) { msg.erase(pos, msg.length()-pos); msg += "..."; } } // Trailing newline (generally not on messages) & remove dup newlines { msg += '\n'; // Trailing newlines generally not put on messages so add string::size_type pos; while ((pos = msg.find("\n\n")) != string::npos) { msg.erase(pos+1, 1); } } // Suppress duplicate messages if (s_messages.find(msg) != s_messages.end()) return; s_messages.insert(msg); if (!locationStr.empty()) { string locationMsg = warnMore()+locationStr+"\n"; size_t pos = msg.find("\n"); msg.insert(pos + 1, locationMsg); } // Output if ( #ifndef _V3ERROR_NO_GLOBAL_ !(v3Global.opt.quietExit() && s_errorCode == V3ErrorCode::EC_FATALEXIT) #else true #endif ) { std::cerr << msg; } if (!s_errorSuppressed && !(s_errorCode==V3ErrorCode::EC_INFO || s_errorCode==V3ErrorCode::USERINFO)) { if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) { s_describedEachWarn[s_errorCode] = true; if (s_errorCode>=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) { std::cerr<dumpTreeFile(v3Global.debugFilename("final.tree", 990)); if (s_errorExitCb) s_errorExitCb(); V3Stats::statsFinalAll(v3Global.rootp()); V3Stats::statsReport(); } #endif } vlAbort(); } else if (isError(s_errorCode, s_errorSuppressed)) { // We don't dump tree on any error because a Visitor may be in middle of // a tree cleanup and cause a false broken problem. if (s_errorExitCb) s_errorExitCb(); } } }