// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Error handling // // Code available from: http://www.veripool.org/verilator // //************************************************************************* // // Copyright 2003-2014 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. // //************************************************************************* #ifndef _V3ERROR_H_ #define _V3ERROR_H_ 1 #include "config_build.h" #include "verilatedos.h" #include #include #include #include #include #include #include #include "V3LangCode.h" //###################################################################### class V3ErrorCode { public: enum en { EC_MIN=0, // Keep first // EC_INFO, // General information out EC_FATAL, // Kill the program EC_FATALSRC, // Kill the program, for internal source errors EC_ERROR, // General error out, can't suppress // Boolean information we track per-line, but aren't errors I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/ I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ I_LINT, // All lint messages I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE) // Error codes: E_BLKLOOPINIT, // Error: Delayed assignment to array inside for loops E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable E_MULTITOP, // Error: Multiple top level modules E_TASKNSVAR, // Error: Task I/O not simple // // Warning codes: EC_FIRST_WARN, // Just a code so the program knows where to start warnings // ALWCOMBORDER, // Always_comb with unordered statements ASSIGNDLY, // Assignment delays ASSIGNIN, // Assigning to input BLKANDNBLK, // Blocked and non-blocking assignments to same variable BLKSEQ, // Blocking assignments in sequential block CASEINCOMPLETE, // Case statement has missing values CASEOVERLAP, // Case statements overlap CASEWITHX, // Case with X values CASEX, // Casex CDCRSTLOGIC, // Logic in async reset path CMPCONST, // Comparison is constant due to limited range COMBDLY, // Combinatorial delayed assignment DEFPARAM, // Style: Defparam DECLFILENAME, // Declaration doesn't match filename ENDLABEL, // End lable name mismatch GENCLK, // Generated Clock IFDEPTH, // If statements too deep IMPERFECTSCH, // Imperfect schedule (disabled by default) IMPLICIT, // Implicit wire IMPURE, // Impure function not being inlined INCABSPATH, // Include has absolute path INITIALDLY, // Initial delayed statement LITENDIAN, // Little bit endian vector MODDUP, // Duplicate module MULTIDRIVEN, // Driven from multiple blocks PINMISSING, // Cell pin not specified PINNOCONNECT, // Cell pin not connected PINCONNECTEMPTY,// Cell pin connected by name with empty reference: ".name()" (can be used to mark unused pins) REALCVT, // Real conversion REDEFMACRO, // Redefining existing define macro SELRANGE, // Selection index out of range STMTDLY, // Delayed statement SYMRSVDWORD, // Symbol is Reserved Word SYNCASYNCNET, // Mixed sync + async reset UNDRIVEN, // No drivers UNOPT, // Unoptimizable block UNOPTFLAT, // Unoptimizable block after flattening UNPACKED, // Unsupported unpacked UNSIGNED, // Comparison is constant due to unsigned arithmetic UNUSED, // No receivers VARHIDDEN, // Hiding variable WIDTH, // Width mismatch WIDTHCONCAT, // Unsized numbers/parameters in concatenations _ENUM_MAX // ***Add new elements below also*** }; enum en m_e; inline V3ErrorCode () : m_e(EC_MIN) {} inline V3ErrorCode (en _e) : m_e(_e) {} V3ErrorCode (const char* msgp); // Matching code or ERROR explicit inline V3ErrorCode (int _e) : m_e(static_cast(_e)) {} operator en () const { return m_e; } const char* ascii() const { const char* names[] = { // Leading spaces indicate it can't be disabled. " MIN", " INFO", " FATAL", " FATALSRC", " ERROR", // Boolean " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", // Errors "BLKLOOPINIT", "DETECTARRAY", "MULTITOP", "TASKNSVAR", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BLKANDNBLK", "BLKSEQ", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CMPCONST", "COMBDLY", "DEFPARAM", "DECLFILENAME", "ENDLABEL", "GENCLK", "IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE", "INCABSPATH", "INITIALDLY", "LITENDIAN", "MODDUP", "MULTIDRIVEN", "PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "REALCVT", "REDEFMACRO", "SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNPACKED", "UNSIGNED", "UNUSED", "VARHIDDEN", "WIDTH", "WIDTHCONCAT", " MAX" }; return names[m_e]; } // Warnings that default to off bool defaultsOff() const { return ( m_e==IMPERFECTSCH || styleError()); } // Warnings that warn about nasty side effects bool dangerous() const { return ( m_e==COMBDLY ); } // Warnings we'll present to the user as errors // Later -Werror- options may make more of these. bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK || m_e==IMPURE || m_e==MODDUP || m_e==SYMRSVDWORD); } // Warnings to mention manual bool mentionManual() const { return ( m_e==EC_FATALSRC || pretendError() ); } // Warnings that are lint only bool lintError() const { return ( m_e==ALWCOMBORDER || m_e==CASEINCOMPLETE || m_e==CASEOVERLAP || m_e==CASEWITHX || m_e==CASEX || m_e==CMPCONST || m_e==ENDLABEL || m_e==IMPLICIT || m_e==LITENDIAN || m_e==PINMISSING || m_e==REALCVT || m_e==UNSIGNED || m_e==WIDTH); } // Warnings that are style only bool styleError() const { return ( m_e==ASSIGNDLY // More than style, but for backward compatibility || m_e==BLKSEQ || m_e==DEFPARAM || m_e==DECLFILENAME || m_e==INCABSPATH || m_e==PINCONNECTEMPTY || m_e==PINNOCONNECT || m_e==SYNCASYNCNET || m_e==UNDRIVEN || m_e==UNUSED || m_e==VARHIDDEN ); } }; inline bool operator== (V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); } inline bool operator== (V3ErrorCode::en lhs, V3ErrorCode rhs) { return (lhs == rhs.m_e); } inline ostream& operator<<(ostream& os, V3ErrorCode rhs) { return os< MessagesSet; typedef void (*ErrorExitCb)(void); private: static bool s_describedWarnings; // Told user how to disable warns static bool s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error static int s_debugDefault; // Default debugging level static int s_errCount; // Error count static int s_warnCount; // Error count static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable static ostringstream s_errorStr; // Error string being formed static V3ErrorCode s_errorCode; // Error string being formed will abort static bool s_errorSuppressed; // Error being formed should be suppressed static MessagesSet s_messages; // What errors we've outputted static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors V3Error() { cerr<<("Static class"); abort(); } public: // CREATORS // ACCESSORS static void debugDefault(int level) { s_debugDefault = level; } static int debugDefault() { return s_debugDefault; } static string msgPrefix(); // returns %Error/%Warn static int errorCount() { return s_errCount; } static int warnCount() { return s_warnCount; } static int errorOrWarnCount() { return errorCount()+warnCount(); } // METHODS static void incErrors(); static void incWarnings(); static void init(); static void abortIfErrors(); static void abortIfWarnings(); static void suppressThisWarning(); // Suppress next %Warn if user has it off static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code]=flag; } static bool isError(V3ErrorCode code, bool supp); static string lineStr (const char* filename, int lineno); static V3ErrorCode errorCode() { return s_errorCode; } static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; } // When printing an error/warning, print prefix for multiline message static string warnMore(); // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed static void v3errorPrep(V3ErrorCode code) { s_errorStr.str(""); s_errorCode=code; s_errorSuppressed=false; } static ostringstream& v3errorStr() { return s_errorStr; } static void vlAbort(); static void v3errorEnd(ostringstream& sstr); // static, but often overridden in classes. }; // Global versions, so that if the class doesn't define a operator, we get the functions anyways. inline int debug() { return V3Error::debugDefault(); } inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); } // These allow errors using << operators: v3error("foo"<<"bar"); // Careful, you can't put () around msg, as you would in most macro definitions // Note the commas are the comma operator, not separating arguments. These are needed to insure // evaluation order as otherwise we couldn't insure v3errorPrep is called first. #define v3warnCode(code,msg) v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<=(level))) { cout<<"- "<=(level))) { cout< std::string cvtToStr (const T& t) { ostringstream os; os< FileNameNumMap; typedef map FileLangNumMap; // MEMBERS FileNameNumMap m_namemap; // filenameno for each filename deque m_names; // filename text for each filenameno deque m_languages; // language for each filenameno // COSNTRUCTORS FileLineSingleton() { } ~FileLineSingleton() { } protected: friend class FileLine; // METHODS int nameToNumber(const string& filename); const string numberToName(int filenameno) const { return m_names[filenameno]; } const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; } void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; } void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); } void fileNameNumMapDumpXml(ostream& os); static const string filenameLetters(int fileno); }; //! File and line number of an object, mostly for error reporting //! This class is instantiated for every source code line (potentially //! millions). To save space, per-file information (e.g. filename, source //! language is held in tables in the FileLineSingleton class. class FileLine { int m_lineno; int m_filenameno; bitset m_warnOn; private: struct EmptySecret {}; inline static FileLineSingleton& singleton() { static FileLineSingleton s; return s; } inline static FileLine& defaultFileLine() { static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret()); return *defFilelinep; } protected: // User routines should never need to change line numbers // We are storing pointers, so we CAN'T change them after initial reading. friend class FileLineSingleton; friend class V3ParseImp; friend class V3PreLex; friend class V3PreProcImp; void lineno(int num) { m_lineno = num; } void language (V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); } void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); } void lineDirective(const char* textp, int& enterExitRef); void linenoInc() { m_lineno++; } void linenoIncInPlace() { m_lineno++; } FileLine* copyOrSameFileLine(); public: FileLine (const string& filename, int lineno) { m_lineno=lineno; m_filenameno = singleton().nameToNumber(filename); m_warnOn=defaultFileLine().m_warnOn; } FileLine (FileLine* fromp) { m_lineno=fromp->m_lineno; m_filenameno = fromp->m_filenameno; m_warnOn=fromp->m_warnOn; } FileLine (EmptySecret); ~FileLine() { } FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); } FileLine* create(int lineno) { return create(filename(), lineno); } static void deleteAllRemaining(); #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); #endif int lineno () const { return m_lineno; } V3LangCode language () const { return singleton().numberToLang(m_filenameno); } void updateLanguage (); string ascii() const; const string filename () const { return singleton().numberToName(m_filenameno); } const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); } const string filebasename () const; const string filebasenameNoExt () const; const string profileFuncname() const; const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; } string lineDirectiveStrg(int enter_exit_level) const; void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line. void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); } bool warnOff(const string& code, bool flag); // Returns 1 if ok bool warnIsOff(V3ErrorCode code) const; void warnLintOff(bool flag); void warnStyleOff(bool flag); void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; } void warnResetDefault() { warnStateFrom(defaultFileLine()); } // Specific flag ACCESSORS/METHODS bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); } void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE,flag); } bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); } void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); } // METHODS - Global static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); } static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); } static void globalWarnOff(V3ErrorCode code, bool flag) { defaultFileLine().warnOff(code, flag); } static bool globalWarnOff(const string& code, bool flag) { return defaultFileLine().warnOff(code, flag); } static void fileNameNumMapDumpXml(ostream& os) { singleton().fileNameNumMapDumpXml(os); } // METHODS - Called from netlist // Merge warning disables from another fileline void modifyStateInherit(const FileLine* fromp); // Change the current fileline due to actions discovered after parsing // and may have side effects on other nodes sharing this FileLine. // Use only when this is intended void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code,flag); } // OPERATORS void v3errorEnd(ostringstream& str); string warnMore() const; inline bool operator==(FileLine rhs) const { return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn); } }; ostream& operator<<(ostream& os, FileLine* fileline); #endif // Guard