2014-11-22 17:48:39 +01:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Error handling
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2014-11-22 17:48:39 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2014-11-22 17:48:39 +01:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2014-11-22 17:48:39 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2017-10-19 00:22:58 +02:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
2014-11-22 17:48:39 +01:00
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3FileLine.h"
|
2019-07-15 03:42:03 +02:00
|
|
|
#include "V3String.h"
|
2021-03-04 04:53:50 +01:00
|
|
|
#ifndef V3ERROR_NO_GLOBAL_
|
2014-11-22 17:48:39 +01:00
|
|
|
# include "V3Global.h"
|
|
|
|
|
# include "V3Config.h"
|
2019-06-29 13:39:17 +02:00
|
|
|
# include "V3File.h"
|
2014-11-22 17:48:39 +01:00
|
|
|
#endif
|
2020-05-26 20:38:14 +02:00
|
|
|
#include "V3Waiver.h"
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2014-11-22 17:48:39 +01:00
|
|
|
|
2019-07-15 03:42:03 +02:00
|
|
|
#include <algorithm>
|
2019-07-26 18:52:38 +02:00
|
|
|
#include <iomanip>
|
2022-09-24 17:57:42 +02:00
|
|
|
#include <limits>
|
2020-08-15 16:03:34 +02:00
|
|
|
#include <unordered_set>
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// FileLineSingleton class functions
|
|
|
|
|
|
2023-03-17 00:48:56 +01:00
|
|
|
string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) VL_PURE {
|
2022-01-08 18:01:39 +01:00
|
|
|
constexpr int size
|
|
|
|
|
= 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
|
2014-11-22 17:48:39 +01:00
|
|
|
char out[size];
|
2020-04-15 13:58:34 +02:00
|
|
|
char* op = out + size - 1;
|
2014-11-22 17:48:39 +01:00
|
|
|
*--op = '\0'; // We build backwards
|
2018-10-15 00:39:33 +02:00
|
|
|
int num = fileno;
|
2014-11-22 17:48:39 +01:00
|
|
|
do {
|
2020-04-15 13:58:34 +02:00
|
|
|
*--op = 'a' + num % 26;
|
2018-10-15 00:39:33 +02:00
|
|
|
num /= 26;
|
2014-11-22 17:48:39 +01:00
|
|
|
} while (num);
|
|
|
|
|
return op;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! Convert filenames to a filenameno
|
|
|
|
|
|
|
|
|
|
//! This lets us assign a nice small identifier for debug messages, but more
|
|
|
|
|
//! importantly lets us use a 4 byte int instead of 8 byte pointer in every
|
|
|
|
|
//! FileLine.
|
|
|
|
|
|
|
|
|
|
//! We associate a language with each source file, so we also set the default
|
|
|
|
|
//! for this.
|
2022-09-24 17:57:42 +02:00
|
|
|
FileLineSingleton::fileNameIdx_t FileLineSingleton::nameToNumber(const string& filename) {
|
|
|
|
|
const auto pair = m_namemap.emplace(filename, 0);
|
|
|
|
|
fileNameIdx_t& idx = pair.first->second;
|
|
|
|
|
if (pair.second) {
|
|
|
|
|
const size_t nextIdx = m_names.size();
|
|
|
|
|
UASSERT(nextIdx <= std::numeric_limits<fileNameIdx_t>::max(),
|
|
|
|
|
"Too many input files (" + cvtToStr(nextIdx) + "+).");
|
|
|
|
|
idx = static_cast<fileNameIdx_t>(nextIdx);
|
|
|
|
|
m_names.push_back(filename);
|
|
|
|
|
m_languages.push_back(V3LangCode::mostRecent());
|
|
|
|
|
}
|
|
|
|
|
return idx;
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! Support XML output
|
|
|
|
|
//! Experimental. Updated to also put out the language.
|
2018-02-02 03:24:41 +01:00
|
|
|
void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) {
|
2020-04-15 13:58:34 +02:00
|
|
|
os << "<files>\n";
|
2022-07-30 16:01:25 +02:00
|
|
|
for (const auto& itr : m_namemap) {
|
|
|
|
|
os << "<file id=\"" << filenameLetters(itr.second) << "\" filename=\""
|
|
|
|
|
<< V3OutFormatter::quoteNameControls(itr.first, V3OutFormatter::LA_XML)
|
|
|
|
|
<< "\" language=\"" << numberToLang(itr.second).ascii() << "\"/>\n";
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
os << "</files>\n";
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-24 17:57:42 +02:00
|
|
|
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) {
|
|
|
|
|
const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0);
|
|
|
|
|
msgEnSetIdx_t& idx = pair.first->second;
|
|
|
|
|
if (pair.second) {
|
|
|
|
|
const size_t nextIdx = m_internedMsgEns.size();
|
|
|
|
|
UASSERT(nextIdx <= std::numeric_limits<msgEnSetIdx_t>::max(),
|
|
|
|
|
"Too many unique message enable sets (" + cvtToStr(nextIdx) + "+).");
|
|
|
|
|
idx = static_cast<msgEnSetIdx_t>(nextIdx);
|
|
|
|
|
m_internedMsgEns.push_back(bitSet);
|
|
|
|
|
}
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() {
|
|
|
|
|
MsgEnBitSet msgEnBitSet;
|
|
|
|
|
for (int i = V3ErrorCode::EC_MIN; i < V3ErrorCode::_ENUM_MAX; ++i) {
|
|
|
|
|
msgEnBitSet.set(i, !V3ErrorCode{i}.defaultsOff());
|
|
|
|
|
}
|
|
|
|
|
return addMsgEnBitSet(msgEnBitSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::msgEnSetBit(msgEnSetIdx_t setIdx,
|
|
|
|
|
size_t bitIdx, bool value) {
|
|
|
|
|
if (msgEn(setIdx).test(bitIdx) == value) return setIdx;
|
|
|
|
|
MsgEnBitSet msgEnBitSet{msgEn(setIdx)};
|
|
|
|
|
msgEnBitSet.set(bitIdx, value);
|
|
|
|
|
return addMsgEnBitSet(msgEnBitSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::msgEnAnd(msgEnSetIdx_t lhsIdx,
|
|
|
|
|
msgEnSetIdx_t rhsIdx) {
|
|
|
|
|
MsgEnBitSet msgEnBitSet{msgEn(lhsIdx)};
|
|
|
|
|
msgEnBitSet &= msgEn(rhsIdx);
|
|
|
|
|
if (msgEnBitSet == msgEn(lhsIdx)) return lhsIdx;
|
|
|
|
|
if (msgEnBitSet == msgEn(rhsIdx)) return rhsIdx;
|
|
|
|
|
return addMsgEnBitSet(msgEnBitSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
// VFileContents class functions
|
2019-07-15 03:42:03 +02:00
|
|
|
|
|
|
|
|
void VFileContent::pushText(const string& text) {
|
|
|
|
|
if (m_lines.size() == 0) {
|
2020-11-11 03:40:14 +01:00
|
|
|
m_lines.emplace_back(""); // no such thing as line [0]
|
|
|
|
|
m_lines.emplace_back(""); // start with no leftover
|
2019-07-15 03:42:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Any leftover text is stored on largest line (might be "")
|
2021-06-21 00:32:57 +02:00
|
|
|
const string leftover = m_lines.back() + text;
|
2020-04-15 13:58:34 +02:00
|
|
|
m_lines.pop_back();
|
2019-07-15 03:42:03 +02:00
|
|
|
|
|
|
|
|
// Insert line-by-line
|
|
|
|
|
string::size_type line_start = 0;
|
2020-04-04 04:31:54 +02:00
|
|
|
while (true) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const string::size_type line_end = leftover.find('\n', line_start);
|
2019-07-15 03:42:03 +02:00
|
|
|
if (line_end != string::npos) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const string oneline(leftover, line_start, line_end - line_start + 1);
|
2019-07-15 03:42:03 +02:00
|
|
|
m_lines.push_back(oneline); // Keeps newline
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "PushStream[ct" << m_id << "+" << (m_lines.size() - 1) << "]: " << oneline);
|
|
|
|
|
line_start = line_end + 1;
|
2019-07-15 03:42:03 +02:00
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Keep leftover for next time
|
2020-11-11 03:40:14 +01:00
|
|
|
m_lines.emplace_back(string(leftover, line_start)); // Might be ""
|
2019-07-15 03:42:03 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
string VFileContent::getLine(int lineno) const VL_MT_SAFE {
|
2019-07-15 03:42:03 +02:00
|
|
|
// Return error text rather than asserting so the user isn't left without a message
|
2020-02-04 05:21:56 +01:00
|
|
|
// cppcheck-suppress negativeContainerIndex
|
2019-07-15 03:42:03 +02:00
|
|
|
if (VL_UNCOVERABLE(lineno < 0 || lineno >= (int)m_lines.size())) {
|
|
|
|
|
if (debug() || v3Global.opt.debugCheck()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return ("%Error-internal-contents-bad-ct" + cvtToStr(m_id) + "-ln" + cvtToStr(lineno));
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2019-07-15 03:42:03 +02:00
|
|
|
}
|
2022-07-30 17:52:35 +02:00
|
|
|
string text = m_lines[lineno];
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "Get Stream[ct" << m_id << "+" << lineno << "]: " << text);
|
2019-07-15 03:42:03 +02:00
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, VFileContent* contentp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!contentp) {
|
|
|
|
|
os << "ct0";
|
|
|
|
|
} else {
|
|
|
|
|
os << contentp->ascii();
|
|
|
|
|
}
|
2019-07-15 03:42:03 +02:00
|
|
|
return os;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-24 17:57:42 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// FileLine class functions
|
2014-11-22 17:48:39 +01:00
|
|
|
|
2022-09-24 17:57:42 +02:00
|
|
|
FileLine::~FileLine() {
|
|
|
|
|
if (m_contentp) VL_DO_DANGLING(m_contentp->refDec(), m_contentp);
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2020-04-06 00:30:46 +02:00
|
|
|
void FileLine::newContent() {
|
2022-09-24 17:57:42 +02:00
|
|
|
if (m_contentp) VL_DO_DANGLING(m_contentp->refDec(), m_contentp);
|
|
|
|
|
m_contentp = new VFileContent;
|
|
|
|
|
m_contentp->refInc();
|
2020-04-06 00:30:46 +02:00
|
|
|
m_contentLineno = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-02 05:16:02 +02:00
|
|
|
string FileLine::xmlDetailedLocation() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return "loc=\"" + cvtToStr(filenameLetters()) + "," + cvtToStr(firstLineno()) + ","
|
|
|
|
|
+ cvtToStr(firstColumn()) + "," + cvtToStr(lastLineno()) + "," + cvtToStr(lastColumn())
|
|
|
|
|
+ "\"";
|
2020-01-20 20:08:13 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
string FileLine::lineDirectiveStrg(int enterExit) const {
|
2022-08-30 05:50:32 +02:00
|
|
|
return std::string{"`line "} + cvtToStr(lastLineno()) + " \"" + filename() + "\" "
|
2021-03-06 16:33:43 +01:00
|
|
|
+ cvtToStr(enterExit) + "\n";
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|
|
|
|
// Handle `line directive
|
2019-07-15 03:42:03 +02:00
|
|
|
// Does not parse streamNumber/streamLineno as the next input token
|
|
|
|
|
// will come from the same stream as the previous line.
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
// Skip `line
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && std::isspace(*textp)) ++textp;
|
|
|
|
|
while (*textp && !std::isspace(*textp)) ++textp;
|
|
|
|
|
while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp;
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// Grab linenumber
|
2019-11-16 17:59:21 +01:00
|
|
|
bool fail = false;
|
2021-11-13 19:50:44 +01:00
|
|
|
const char* const ln = textp;
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && !std::isspace(*textp)) ++textp;
|
|
|
|
|
if (std::isdigit(*ln)) {
|
2022-09-15 03:10:19 +02:00
|
|
|
lineno(std::atoi(ln));
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
fail = true;
|
|
|
|
|
}
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && (std::isspace(*textp))) ++textp;
|
2019-11-16 17:59:21 +01:00
|
|
|
if (*textp != '"') fail = true;
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp;
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// Grab filename
|
2021-11-13 19:50:44 +01:00
|
|
|
const char* const fn = textp;
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && !(std::isspace(*textp) || *textp == '"')) ++textp;
|
2014-11-22 17:48:39 +01:00
|
|
|
if (textp != fn) {
|
2019-05-19 22:13:13 +02:00
|
|
|
string strfn = fn;
|
2020-04-15 13:58:34 +02:00
|
|
|
strfn = strfn.substr(0, textp - fn);
|
2019-05-19 22:13:13 +02:00
|
|
|
filename(strfn);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
fail = true;
|
|
|
|
|
}
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// Grab level
|
2023-02-11 02:32:35 +01:00
|
|
|
while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp;
|
|
|
|
|
if (std::isdigit(*textp)) {
|
2022-09-15 03:10:19 +02:00
|
|
|
enterExitRef = std::atoi(textp);
|
2019-11-16 17:59:21 +01:00
|
|
|
if (enterExitRef >= 3) fail = true;
|
|
|
|
|
} else {
|
|
|
|
|
enterExitRef = 0;
|
|
|
|
|
fail = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fail && v3Global.opt.pedantic()) {
|
|
|
|
|
v3error("`line was not properly formed with '`line number \"filename\" level'\n");
|
|
|
|
|
}
|
2014-11-22 17:48:39 +01:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-15 03:42:03 +02:00
|
|
|
void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) {
|
|
|
|
|
for (const char* sp = textp; size && *sp; ++sp, --size) {
|
|
|
|
|
if (*sp == '\n') {
|
|
|
|
|
if (trackLines) linenoInc();
|
|
|
|
|
m_lastColumn = 1;
|
2021-03-08 03:05:15 +01:00
|
|
|
} else if (VL_UNCOVERABLE(*sp == '\r')) { // Generally stripped by preproc
|
2019-07-15 03:42:03 +02:00
|
|
|
} else { // Tabs are considered one column; hence column means number of chars
|
|
|
|
|
++m_lastColumn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
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.
|
2021-03-04 04:53:50 +01:00
|
|
|
#ifndef V3ERROR_NO_GLOBAL_
|
2014-11-22 17:48:39 +01:00
|
|
|
V3Config::applyIgnores(this); // Toggle warnings based on global config file
|
|
|
|
|
#endif
|
2020-08-15 16:12:55 +02:00
|
|
|
static FileLine* lastNewp = nullptr;
|
2014-11-22 17:48:39 +01:00
|
|
|
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
|
2019-05-19 22:13:13 +02:00
|
|
|
return lastNewp;
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2022-11-20 19:11:01 +01:00
|
|
|
FileLine* const newp = new FileLine{this};
|
2014-11-22 17:48:39 +01:00
|
|
|
lastNewp = newp;
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
string FileLine::filebasename() const VL_MT_SAFE {
|
2014-11-22 17:48:39 +01:00
|
|
|
string name = filename();
|
|
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((pos = name.rfind('/')) != string::npos) name.erase(0, pos + 1);
|
2014-11-22 17:48:39 +01:00
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-02 05:16:02 +02:00
|
|
|
string FileLine::filebasenameNoExt() const {
|
2014-11-22 17:48:39 +01:00
|
|
|
string name = filebasename();
|
|
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((pos = name.find('.')) != string::npos) name = name.substr(0, pos);
|
2014-11-22 17:48:39 +01:00
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
string FileLine::firstColumnLetters() const VL_MT_SAFE {
|
2021-11-26 23:55:36 +01:00
|
|
|
const char a = ((firstColumn() / 26) % 26) + 'a';
|
|
|
|
|
const char b = (firstColumn() % 26) + 'a';
|
2020-05-30 16:08:30 +02:00
|
|
|
return string(1, a) + string(1, b);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-02 05:16:02 +02:00
|
|
|
string FileLine::profileFuncname() const {
|
2014-11-22 17:48:39 +01:00
|
|
|
// Return string that is OK as a function name - for profiling
|
2020-04-15 13:58:34 +02:00
|
|
|
string name = filebasenameNoExt();
|
2014-11-22 17:48:39 +01:00
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
while ((pos = name.find_first_not_of(
|
|
|
|
|
"abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
|
2019-05-19 22:13:13 +02:00
|
|
|
!= string::npos) {
|
|
|
|
|
name.replace(pos, 1, "_");
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
name += "__l" + cvtToStr(lastLineno());
|
2014-11-22 17:48:39 +01:00
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-15 03:42:03 +02:00
|
|
|
string FileLine::asciiLineCol() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (cvtToStr(firstLineno()) + "-" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn())
|
|
|
|
|
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
|
|
|
|
|
+ cvtToStr(m_contentLineno) + "]");
|
2019-07-15 03:42:03 +02:00
|
|
|
}
|
2023-02-10 04:15:37 +01:00
|
|
|
string FileLine::ascii() const {
|
2019-07-15 03:42:03 +02:00
|
|
|
// For most errors especially in the parser the lastLineno is more accurate than firstLineno
|
2020-03-15 03:02:42 +01:00
|
|
|
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2018-02-02 03:24:41 +01:00
|
|
|
std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
|
2020-04-15 13:58:34 +02:00
|
|
|
os << fileline->ascii() << ": " << std::hex;
|
|
|
|
|
return (os);
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FileLine::warnOff(const string& msg, bool flag) {
|
2022-10-18 01:52:01 +02:00
|
|
|
const char* cmsg = msg.c_str();
|
2022-10-18 01:51:13 +02:00
|
|
|
// Backward compatibility with msg="UNUSED"
|
|
|
|
|
if (V3ErrorCode::unusedMsg(cmsg)) {
|
|
|
|
|
warnOff(V3ErrorCode::UNUSEDGENVAR, flag);
|
2022-10-18 01:52:01 +02:00
|
|
|
warnOff(V3ErrorCode::UNUSEDPARAM, flag);
|
2022-10-18 01:51:13 +02:00
|
|
|
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-11-20 19:11:01 +01:00
|
|
|
const V3ErrorCode code{cmsg};
|
2014-11-22 17:48:39 +01:00
|
|
|
if (code < V3ErrorCode::EC_FIRST_WARN) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return false;
|
2014-11-22 17:48:39 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
warnOff(code, flag);
|
|
|
|
|
return true;
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileLine::warnLintOff(bool flag) {
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
2022-09-16 01:58:01 +02:00
|
|
|
const V3ErrorCode code{codei};
|
2018-10-15 00:39:33 +02:00
|
|
|
if (code.lintError()) warnOff(code, flag);
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileLine::warnStyleOff(bool flag) {
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
2022-09-16 01:58:01 +02:00
|
|
|
const V3ErrorCode code{codei};
|
2018-10-15 00:39:33 +02:00
|
|
|
if (code.styleError()) warnOff(code, flag);
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-18 01:51:13 +02:00
|
|
|
void FileLine::warnUnusedOff(bool flag) {
|
|
|
|
|
warnOff(V3ErrorCode::UNUSEDGENVAR, flag);
|
|
|
|
|
warnOff(V3ErrorCode::UNUSEDPARAM, flag);
|
|
|
|
|
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:15:37 +01:00
|
|
|
bool FileLine::warnIsOff(V3ErrorCode code) const {
|
2022-09-24 17:57:42 +02:00
|
|
|
if (!msgEn().test(code)) return true;
|
|
|
|
|
if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local
|
|
|
|
|
if ((code.lintError() || code.styleError()) && !msgEn().test(V3ErrorCode::I_LINT)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2022-10-18 01:52:01 +02:00
|
|
|
if ((code.unusedError()) && !msgEn().test(V3ErrorCode::I_UNUSED)) { return true; }
|
2014-11-22 17:48:39 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-27 11:52:40 +01:00
|
|
|
// cppverilator-suppress constParameter
|
2023-02-10 04:15:37 +01:00
|
|
|
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra)
|
|
|
|
|
VL_REQUIRES(V3Error::s().m_mutex) {
|
2018-11-17 02:48:57 +01:00
|
|
|
std::ostringstream nsstr;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (lastLineno()) nsstr << this;
|
2020-04-04 04:31:54 +02:00
|
|
|
nsstr << sstr.str();
|
|
|
|
|
nsstr << endl;
|
2019-07-26 18:52:38 +02:00
|
|
|
std::ostringstream lstr;
|
2022-04-22 23:39:45 +02:00
|
|
|
if (!extra.empty()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
lstr << std::setw(ascii().length()) << " "
|
2022-04-22 23:39:45 +02:00
|
|
|
<< ": " << extra;
|
2019-07-26 18:52:38 +02:00
|
|
|
}
|
2023-02-10 04:15:37 +01:00
|
|
|
m_waive = V3Config::waive(this, V3Error::s().errorCode(), sstr.str());
|
|
|
|
|
if (warnIsOff(V3Error::s().errorCode()) || m_waive) {
|
|
|
|
|
V3Error::s().suppressThisWarning();
|
|
|
|
|
} else if (!V3Error::s().errorContexted()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nsstr << warnContextPrimary();
|
2020-01-12 10:03:17 +01:00
|
|
|
}
|
2023-02-10 04:15:37 +01:00
|
|
|
if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str());
|
|
|
|
|
V3Error::s().v3errorEnd(nsstr, lstr.str());
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:15:37 +01:00
|
|
|
string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) {
|
2019-07-15 03:42:03 +02:00
|
|
|
if (lastLineno()) {
|
2023-02-10 04:15:37 +01:00
|
|
|
return V3Error::s().warnMore() + string(ascii().size(), ' ') + ": ";
|
2019-07-12 01:15:40 +02:00
|
|
|
} else {
|
2023-02-10 04:15:37 +01:00
|
|
|
return V3Error::s().warnMore();
|
2019-07-12 01:15:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-10 04:15:37 +01:00
|
|
|
string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) {
|
2019-07-15 03:42:03 +02:00
|
|
|
if (lastLineno()) {
|
2023-02-10 04:15:37 +01:00
|
|
|
return V3Error::s().warnMore() + ascii() + ": ";
|
2014-11-22 17:48:39 +01:00
|
|
|
} else {
|
2023-02-10 04:15:37 +01:00
|
|
|
return V3Error::s().warnMore();
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2023-02-10 04:15:37 +01:00
|
|
|
};
|
|
|
|
|
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
|
|
|
|
|
const VerilatedLockGuard guard{V3Error::s().m_mutex};
|
|
|
|
|
return warnOther();
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
string FileLine::source() const VL_MT_SAFE {
|
2020-06-05 03:40:40 +02:00
|
|
|
if (VL_UNCOVERABLE(!m_contentp)) { // LCOV_EXCL_START
|
2020-03-15 02:48:26 +01:00
|
|
|
if (debug() || v3Global.opt.debugCheck()) {
|
2020-04-04 02:07:46 +02:00
|
|
|
// The newline here is to work around the " <line#> | "
|
|
|
|
|
return "\n%Error: internal tracking of file contents failed";
|
2020-03-15 02:48:26 +01:00
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2020-06-05 03:40:40 +02:00
|
|
|
} // LCOV_EXCL_STOP
|
2019-07-15 03:42:03 +02:00
|
|
|
return m_contentp->getLine(m_contentLineno);
|
|
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
string FileLine::prettySource() const VL_MT_SAFE {
|
2019-07-15 03:42:03 +02:00
|
|
|
string out = source();
|
|
|
|
|
// Drop ignore trailing newline
|
2021-11-26 23:55:36 +01:00
|
|
|
const string::size_type pos = out.find('\n');
|
2019-07-15 03:42:03 +02:00
|
|
|
if (pos != string::npos) out = string(out, 0, pos);
|
|
|
|
|
// Column tracking counts tabs = 1, so match that when print source
|
|
|
|
|
return VString::spaceUnprintable(out);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:15:37 +01:00
|
|
|
string FileLine::warnContext() const {
|
2019-11-23 16:39:36 +01:00
|
|
|
if (!v3Global.opt.context()) return "";
|
2020-04-04 04:31:54 +02:00
|
|
|
string out;
|
2020-04-04 02:07:46 +02:00
|
|
|
if (firstLineno() == lastLineno() && firstColumn()) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sourceLine = prettySource();
|
2019-07-15 03:42:03 +02:00
|
|
|
// Don't show super-long lines as can fill screen and unlikely to help user
|
2020-04-04 02:07:46 +02:00
|
|
|
if (!sourceLine.empty() && sourceLine.length() < SHOW_SOURCE_MAX_LENGTH
|
|
|
|
|
&& sourceLine.length() >= static_cast<size_t>(lastColumn() - 1)) {
|
|
|
|
|
string linestr = cvtToStr(firstLineno());
|
2020-04-15 13:58:34 +02:00
|
|
|
while (linestr.size() < 5) linestr = ' ' + linestr;
|
2020-04-04 02:07:46 +02:00
|
|
|
out += linestr + " | " + sourceLine + "\n";
|
|
|
|
|
out += std::string(linestr.size(), ' ') + " | ";
|
|
|
|
|
out += string((firstColumn() - 1), ' ') + '^';
|
2019-07-15 03:42:03 +02:00
|
|
|
// Can't use UASSERT_OBJ used in warnings already inside the error end handler
|
2019-10-17 02:05:29 +02:00
|
|
|
if (lastColumn() > firstColumn()) {
|
|
|
|
|
// Note lastColumn() can be <= firstColumn() in some weird preproc expansions
|
2020-04-04 02:07:46 +02:00
|
|
|
out += string((lastColumn() - firstColumn() - 1), '~');
|
2019-07-15 03:42:03 +02:00
|
|
|
}
|
|
|
|
|
out += "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-22 23:01:39 +02:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:15:37 +01:00
|
|
|
string FileLine::warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex) {
|
|
|
|
|
string out;
|
|
|
|
|
for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) {
|
|
|
|
|
if (parentFl->filenameIsGlobal()) break;
|
|
|
|
|
out += parentFl->warnOther() + "... note: In file included from "
|
|
|
|
|
+ parentFl->filebasename() + "\n";
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
2014-11-22 17:48:39 +01:00
|
|
|
#ifdef VL_LEAK_CHECKS
|
2021-03-12 23:26:53 +01:00
|
|
|
std::unordered_set<FileLine*> fileLineLeakChecks;
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
void* FileLine::operator new(size_t size) {
|
2021-11-13 19:50:44 +01:00
|
|
|
FileLine* const objp = static_cast<FileLine*>(::operator new(size));
|
2014-11-22 17:48:39 +01:00
|
|
|
fileLineLeakChecks.insert(objp);
|
|
|
|
|
return objp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileLine::operator delete(void* objp, size_t size) {
|
|
|
|
|
if (!objp) return;
|
2021-11-13 19:50:44 +01:00
|
|
|
FileLine* const flp = static_cast<FileLine*>(objp);
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = fileLineLeakChecks.find(flp);
|
2014-11-22 17:48:39 +01:00
|
|
|
if (it != fileLineLeakChecks.end()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
fileLineLeakChecks.erase(it);
|
2014-11-22 17:48:39 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
flp->v3fatalSrc("Deleting FileLine object that was never tracked");
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
::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.
|
2020-04-04 04:31:54 +02:00
|
|
|
while (true) {
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = fileLineLeakChecks.begin();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (it == fileLineLeakChecks.end()) break;
|
2019-05-19 22:13:13 +02:00
|
|
|
delete *it;
|
|
|
|
|
// Operator delete will remove the iterated object from the list.
|
|
|
|
|
// Eventually the list will be empty and terminate the loop.
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
|
|
|
|
fileLineLeakChecks.clear();
|
|
|
|
|
singleton().clear();
|
|
|
|
|
#endif
|
|
|
|
|
}
|