//************************************************************************* // DESCRIPTION: Verilator: Error handling // // Code available from: http://www.veripool.org/verilator // // AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli // //************************************************************************* // // Copyright 2003-2011 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. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* #include #include #include #include #include "V3Error.h" #ifndef _V3ERROR_NO_GLOBAL_ # include "V3Ast.h" # include "V3Global.h" # include "V3Stats.h" # include "V3Config.h" #endif //====================================================================== // Statics FileLine FileLine::s_defaultFileLine = FileLine(EmptySecret()); int V3Error::s_errCount = 0; int V3Error::s_warnCount = 0; int V3Error::s_debugDefault = 0; int V3Error::s_tellManual = 0; ostringstream V3Error::s_errorStr; // Error string being formed V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL; bool V3Error::s_errorSuppressed = false; bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; bool V3Error::s_describedWarnings = false; bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX]; 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_FIRST_WARN; codeilineno(atoi(ln)); } while (*textp && (isspace(*textp) || *textp=='"')) textp++; // Grab filename const char *fn = textp; while (*textp && !(isspace(*textp) || *textp=='"')) textp++; if (textp != fn) { string strfn = fn; strfn = strfn.substr(0, textp-fn); this->filename(strfn); } // Grab level while (*textp && (isspace(*textp) || *textp=='"')) textp++; if (isdigit(*textp)) enterExitRef = atoi(textp); else enterExitRef = 0; //printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str()); } FileLine* FileLine::copyOrSameFileLine() { // When a fileline is "used" to produce a node, calls this function. // Return this, or a copy of this // There are often more than one token per line, thus we use the // same pointer as long as we're on the same line, file & warn state. #ifndef _V3ERROR_NO_GLOBAL_ V3Config::applyIgnores(this); // Toggle warnings based on global config file #endif static FileLine* lastNewp = NULL; if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc return lastNewp; } FileLine* newp = new FileLine(this); lastNewp = newp; return newp; } const string FileLine::filebasename() const { string name = filename(); string::size_type pos; if ((pos = name.rfind("/")) != string::npos) { name.erase(0,pos+1); } return name; } const string FileLine::filebasenameNoExt() const { string name = filebasename(); string::size_type pos; if ((pos = name.find(".")) != string::npos) { name = name.substr(0,pos); } return name; } const string FileLine::profileFuncname() const { // Return string that is OK as a function name - for profiling string name = filebasenameNoExt(); string::size_type pos; while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_")) != string::npos) { name.replace(pos, 1, "_"); } name += "__l"+cvtToStr(lineno()); return name; } string FileLine::ascii() const { return filename()+":"+cvtToStr(lineno()); } ostream& operator<<(ostream& os, FileLine* fileline) { os <ascii()<<": "<warnIsOff(code)) { this->warnOff(code, true); } } } void FileLine::v3errorEnd(ostringstream& str) { if (this && m_lineno) { ostringstream nsstr; nsstr< FileLineCheckSet; FileLineCheckSet fileLineLeakChecks; void* FileLine::operator new(size_t size) { FileLine* objp = static_cast(::operator new(size)); fileLineLeakChecks.insert(objp); return objp; } void FileLine::operator delete(void* objp, size_t size) { if (!objp) return; FileLine* flp = static_cast(objp); FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp); if (it != fileLineLeakChecks.end()) { fileLineLeakChecks.erase(it); } else { flp->v3fatalSrc("Deleting FileLine object that was never tracked\n"); } ::operator delete(objp); } #endif void FileLine::deleteAllRemaining() { #ifdef VL_LEAK_CHECKS // FileLines are allocated, but never nicely freed, as it's much faster // that way. Unfortunately this makes our leak checking a big mess, so // only when leak checking we'll track them all and cleanup. while (1) { FileLineCheckSet::iterator it=fileLineLeakChecks.begin(); if (it==fileLineLeakChecks.end()) break; delete *it; // Operator delete will remove the iterated object from the list. // Eventually the list will be empty and terminate the loop. } fileLineLeakChecks.clear(); #endif } //###################################################################### // V3Error class functions void V3Error::init() { for (int i=0; i20) numsp = 20; out<<(spaces + numsp); return out.str(); } void V3Error::incWarnings() { s_warnCount++; // We don't exit on a lot of warnings. } void V3Error::incErrors() { s_errCount++; if (errorCount() == v3Global.opt.errorLimit()) { // Not >= as would otherwise recurse v3fatal ("Exiting due to too many errors encountered; --error-limit="<=V3ErrorCode::EC_FIRST_WARN) { V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1); s_errorSuppressed = true; } } void V3Error::v3errorEnd (ostringstream& sstr) { #ifdef __COVERITY__ if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x); #endif if (!s_errorSuppressed // On debug, show only non default-off warning to prevent pages of warnings || (debug() && !s_errorCode.defaultsOff())) { cerr<=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) { cerr<dumpTreeFile(v3Global.debugFilename("final.tree",99)); V3Stats::statsFinalAll(v3Global.rootp()); V3Stats::statsReport(); } #endif } vlAbort(); } } } }