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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2003-2022 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
|
|
|
|
2021-03-04 03:57:07 +01:00
|
|
|
#ifndef VERILATOR_V3FILELINE_H_
|
|
|
|
|
#define VERILATOR_V3FILELINE_H_
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
|
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3LangCode.h"
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
#include <bitset>
|
2022-08-05 11:56:57 +02:00
|
|
|
#include <deque>
|
2014-11-22 17:48:39 +01:00
|
|
|
#include <map>
|
2022-05-15 00:15:38 +02:00
|
|
|
#include <memory>
|
2014-11-22 17:48:39 +01:00
|
|
|
#include <set>
|
2022-08-05 11:56:57 +02:00
|
|
|
#include <sstream>
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class FileLine;
|
|
|
|
|
|
|
|
|
|
//! Singleton class with tables of per-file data.
|
|
|
|
|
|
|
|
|
|
//! This singleton class contains tables of data that are unchanging in each
|
|
|
|
|
//! source file (each with its own unique filename number).
|
2020-11-19 03:32:16 +01:00
|
|
|
class FileLineSingleton final {
|
2014-11-22 17:48:39 +01:00
|
|
|
// MEMBERS
|
2021-03-12 23:26:53 +01:00
|
|
|
std::map<const std::string, int> m_namemap; // filenameno for each filename
|
2020-04-15 13:58:34 +02:00
|
|
|
std::deque<string> m_names; // filename text for each filenameno
|
2019-05-19 22:13:13 +02:00
|
|
|
std::deque<V3LangCode> m_languages; // language for each filenameno
|
2019-07-11 04:04:58 +02:00
|
|
|
// CONSTRUCTORS
|
2020-11-17 01:56:16 +01:00
|
|
|
FileLineSingleton() = default;
|
|
|
|
|
~FileLineSingleton() = default;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
protected:
|
|
|
|
|
friend class FileLine;
|
|
|
|
|
int nameToNumber(const string& filename);
|
2020-06-02 05:16:02 +02:00
|
|
|
string numberToName(int filenameno) const { return m_names[filenameno]; }
|
|
|
|
|
V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
|
2014-11-22 17:48:39 +01:00
|
|
|
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
|
2020-04-15 13:58:34 +02:00
|
|
|
void clear() {
|
|
|
|
|
m_namemap.clear();
|
|
|
|
|
m_names.clear();
|
|
|
|
|
m_languages.clear();
|
|
|
|
|
}
|
2018-02-02 03:24:41 +01:00
|
|
|
void fileNameNumMapDumpXml(std::ostream& os);
|
2020-06-02 05:16:02 +02:00
|
|
|
static string filenameLetters(int fileno);
|
2014-11-22 17:48:39 +01:00
|
|
|
};
|
|
|
|
|
|
2019-07-15 03:42:03 +02:00
|
|
|
//! All source lines from a file/stream, to enable errors to show sources
|
2020-11-19 03:32:16 +01:00
|
|
|
class VFileContent final {
|
2019-07-15 03:42:03 +02:00
|
|
|
// MEMBERS
|
|
|
|
|
int m_id; // Content ID number
|
|
|
|
|
std::deque<string> m_lines; // Source text lines
|
|
|
|
|
public:
|
2020-04-15 13:58:34 +02:00
|
|
|
VFileContent() {
|
|
|
|
|
static int s_id = 0;
|
|
|
|
|
m_id = ++s_id;
|
|
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
~VFileContent() = default;
|
2019-07-15 03:42:03 +02:00
|
|
|
// METHODS
|
|
|
|
|
void pushText(const string& text); // Add arbitrary text (need not be line-by-line)
|
|
|
|
|
string getLine(int lineno) const;
|
2020-04-15 13:58:34 +02:00
|
|
|
string ascii() const { return "ct" + cvtToStr(m_id); }
|
2019-07-15 03:42:03 +02:00
|
|
|
};
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, VFileContent* contentp);
|
|
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
//! 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.
|
2020-11-19 03:32:16 +01:00
|
|
|
class FileLine final {
|
2019-07-15 03:42:03 +02:00
|
|
|
// CONSTANTS
|
2020-08-16 20:19:12 +02:00
|
|
|
static constexpr unsigned SHOW_SOURCE_MAX_LENGTH = 400; // Don't show source lines > this long
|
2019-07-15 03:42:03 +02:00
|
|
|
|
2019-07-11 04:04:58 +02:00
|
|
|
// MEMBERS
|
2019-07-15 03:42:03 +02:00
|
|
|
// Columns here means number of chars from beginning (i.e. tabs count as one)
|
2020-11-15 21:40:35 +01:00
|
|
|
int m_firstLineno = 0; // `line corrected token's first line number
|
|
|
|
|
int m_firstColumn = 0; // `line corrected token's first column number
|
|
|
|
|
int m_lastLineno = 0; // `line corrected token's last line number
|
|
|
|
|
int m_lastColumn = 0; // `line corrected token's last column number
|
2019-06-29 03:43:37 +02:00
|
|
|
int m_filenameno; // `line corrected filename number
|
2020-11-15 21:40:35 +01:00
|
|
|
int m_contentLineno = 0; // Line number within source stream
|
2022-05-15 00:15:38 +02:00
|
|
|
std::shared_ptr<VFileContent> m_contentp = nullptr; // Source text contents line is within
|
2020-11-15 21:40:35 +01:00
|
|
|
FileLine* m_parent = nullptr; // Parent line that included this line
|
2018-02-02 03:24:41 +01:00
|
|
|
std::bitset<V3ErrorCode::_ENUM_MAX> m_warnOn;
|
2020-11-15 21:40:35 +01:00
|
|
|
bool m_waive = false; // Waive warning
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
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;
|
2019-03-10 19:09:22 +01:00
|
|
|
friend class V3PreShellImp;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2019-07-11 04:04:58 +02:00
|
|
|
private:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
static FileLineSingleton& singleton() {
|
|
|
|
|
static FileLineSingleton s;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
static FileLine& defaultFileLine() {
|
|
|
|
|
static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
|
|
|
|
|
return *defFilelinep;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2014-11-22 17:48:39 +01:00
|
|
|
public:
|
2020-04-06 00:30:46 +02:00
|
|
|
explicit FileLine(const string& filename)
|
2020-11-15 21:40:35 +01:00
|
|
|
: m_filenameno{singleton().nameToNumber(filename)}
|
|
|
|
|
, m_warnOn{defaultFileLine().m_warnOn} {}
|
2020-04-06 00:30:46 +02:00
|
|
|
explicit FileLine(FileLine* fromp)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_firstLineno{fromp->m_firstLineno}
|
|
|
|
|
, m_firstColumn{fromp->m_firstColumn}
|
|
|
|
|
, m_lastLineno{fromp->m_lastLineno}
|
|
|
|
|
, m_lastColumn{fromp->m_lastColumn}
|
|
|
|
|
, m_filenameno{fromp->m_filenameno}
|
|
|
|
|
, m_contentLineno{fromp->m_contentLineno}
|
|
|
|
|
, m_contentp{fromp->m_contentp}
|
|
|
|
|
, m_parent{fromp->m_parent}
|
|
|
|
|
, m_warnOn{fromp->m_warnOn}
|
|
|
|
|
, m_waive{fromp->m_waive} {}
|
2019-07-11 04:04:58 +02:00
|
|
|
struct EmptySecret {}; // Constructor selection
|
2018-08-25 15:52:45 +02:00
|
|
|
explicit FileLine(EmptySecret);
|
2019-07-11 04:04:58 +02:00
|
|
|
FileLine* copyOrSameFileLine();
|
2014-11-22 17:48:39 +01:00
|
|
|
static void deleteAllRemaining();
|
2020-11-17 01:56:16 +01:00
|
|
|
~FileLine() = default;
|
2014-11-22 17:48:39 +01:00
|
|
|
#ifdef VL_LEAK_CHECKS
|
|
|
|
|
static void* operator new(size_t size);
|
|
|
|
|
static void operator delete(void* obj, size_t size);
|
|
|
|
|
#endif
|
2019-07-11 04:04:58 +02:00
|
|
|
// METHODS
|
2020-04-06 00:30:46 +02:00
|
|
|
void newContent();
|
2021-03-15 02:23:48 +01:00
|
|
|
void contentLineno(int num) {
|
|
|
|
|
lineno(num);
|
|
|
|
|
m_contentLineno = num;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
void lineno(int num) {
|
|
|
|
|
m_firstLineno = num;
|
|
|
|
|
m_lastLineno = num;
|
|
|
|
|
m_firstColumn = m_lastColumn = 1;
|
|
|
|
|
}
|
2021-03-15 02:23:48 +01:00
|
|
|
void column(int firstColumn, int lastColumn) {
|
|
|
|
|
m_firstColumn = firstColumn;
|
|
|
|
|
m_lastColumn = lastColumn;
|
|
|
|
|
}
|
2022-07-30 17:52:35 +02:00
|
|
|
void language(V3LangCode lang) const { singleton().numberToLang(filenameno(), lang); }
|
2019-07-11 04:04:58 +02:00
|
|
|
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
|
|
|
|
|
void parent(FileLine* fileline) { m_parent = fileline; }
|
|
|
|
|
void lineDirective(const char* textp, int& enterExitRef);
|
2020-04-15 13:58:34 +02:00
|
|
|
void linenoInc() {
|
|
|
|
|
m_lastLineno++;
|
|
|
|
|
m_lastColumn = 1;
|
|
|
|
|
m_contentLineno++;
|
|
|
|
|
}
|
|
|
|
|
void startToken() {
|
|
|
|
|
m_firstLineno = m_lastLineno;
|
|
|
|
|
m_firstColumn = m_lastColumn;
|
|
|
|
|
}
|
2019-07-15 03:42:03 +02:00
|
|
|
// Advance last line/column based on given text
|
2020-04-15 13:58:34 +02:00
|
|
|
void forwardToken(const char* textp, size_t size, bool trackLines = true);
|
2019-07-15 03:42:03 +02:00
|
|
|
int firstLineno() const { return m_firstLineno; }
|
|
|
|
|
int firstColumn() const { return m_firstColumn; }
|
|
|
|
|
int lastLineno() const { return m_lastLineno; }
|
|
|
|
|
int lastColumn() const { return m_lastColumn; }
|
2022-05-15 00:15:38 +02:00
|
|
|
std::shared_ptr<VFileContent> contentp() const { return m_contentp; }
|
2019-07-15 03:42:03 +02:00
|
|
|
// If not otherwise more specific, use last lineno for errors etc,
|
|
|
|
|
// as the parser errors etc generally make more sense pointing at the last parse point
|
|
|
|
|
int lineno() const { return m_lastLineno; }
|
|
|
|
|
string source() const;
|
|
|
|
|
string prettySource() const; // Source, w/stripped unprintables and newlines
|
2019-06-22 23:01:39 +02:00
|
|
|
FileLine* parent() const { return m_parent; }
|
2020-05-31 21:52:17 +02:00
|
|
|
V3LangCode language() const { return singleton().numberToLang(filenameno()); }
|
2014-11-22 17:48:39 +01:00
|
|
|
string ascii() const;
|
2019-07-15 03:42:03 +02:00
|
|
|
string asciiLineCol() const;
|
2020-05-31 21:52:17 +02:00
|
|
|
int filenameno() const { return m_filenameno; }
|
2020-06-02 05:16:02 +02:00
|
|
|
string filename() const { return singleton().numberToName(filenameno()); }
|
2020-04-15 13:58:34 +02:00
|
|
|
bool filenameIsGlobal() const {
|
|
|
|
|
return (filename() == commandLineFilename() || filename() == builtInFilename());
|
|
|
|
|
}
|
2020-06-02 05:16:02 +02:00
|
|
|
string filenameLetters() const { return FileLineSingleton::filenameLetters(filenameno()); }
|
|
|
|
|
string filebasename() const;
|
|
|
|
|
string filebasenameNoExt() const;
|
|
|
|
|
string firstColumnLetters() const;
|
|
|
|
|
string profileFuncname() const;
|
|
|
|
|
string xmlDetailedLocation() const;
|
2018-10-15 00:39:33 +02:00
|
|
|
string lineDirectiveStrg(int enterExit) const;
|
2019-06-22 23:01:39 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Turn on/off warning messages on this line.
|
|
|
|
|
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code, flag); }
|
|
|
|
|
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
|
2018-10-15 00:39:33 +02:00
|
|
|
bool warnOff(const string& msg, bool flag); // Returns 1 if ok
|
2014-11-22 17:48:39 +01:00
|
|
|
bool warnIsOff(V3ErrorCode code) const;
|
|
|
|
|
void warnLintOff(bool flag);
|
|
|
|
|
void warnStyleOff(bool flag);
|
2019-05-19 22:13:13 +02:00
|
|
|
void warnStateFrom(const FileLine& from) { m_warnOn = from.m_warnOn; }
|
2014-11-22 17:48:39 +01:00
|
|
|
void warnResetDefault() { warnStateFrom(defaultFileLine()); }
|
2022-07-30 17:52:35 +02:00
|
|
|
bool lastWarnWaived() const { return m_waive; }
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// Specific flag ACCESSORS/METHODS
|
2020-06-07 17:58:53 +02:00
|
|
|
bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); }
|
|
|
|
|
void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); }
|
2014-11-22 17:48:39 +01:00
|
|
|
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
|
2019-05-19 22:13:13 +02:00
|
|
|
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); }
|
2014-11-22 17:48:39 +01:00
|
|
|
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
|
2019-05-19 22:13:13 +02:00
|
|
|
void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING, flag); }
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
bool timingOn() const { return m_warnOn.test(V3ErrorCode::I_TIMING); }
|
|
|
|
|
void timingOn(bool flag) { warnOn(V3ErrorCode::I_TIMING, flag); }
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// METHODS - Global
|
2019-06-29 13:39:17 +02:00
|
|
|
// <command-line> and <built-in> match what GCC outputs
|
|
|
|
|
static string commandLineFilename() { return "<command-line>"; }
|
|
|
|
|
static string builtInFilename() { return "<built-in>"; }
|
2020-04-15 13:58:34 +02:00
|
|
|
static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); }
|
|
|
|
|
static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); }
|
2014-11-22 17:48:39 +01:00
|
|
|
static void globalWarnOff(V3ErrorCode code, bool flag) {
|
2020-04-15 13:58:34 +02:00
|
|
|
defaultFileLine().warnOff(code, flag);
|
|
|
|
|
}
|
2014-11-22 17:48:39 +01:00
|
|
|
static bool globalWarnOff(const string& code, bool flag) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return defaultFileLine().warnOff(code, flag);
|
|
|
|
|
}
|
|
|
|
|
static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); }
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// 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
|
2019-05-19 22:13:13 +02:00
|
|
|
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); }
|
2014-11-22 17:48:39 +01:00
|
|
|
|
|
|
|
|
// OPERATORS
|
2022-04-22 23:39:45 +02:00
|
|
|
void v3errorEnd(std::ostringstream& str, const string& extra = "");
|
2022-09-16 14:17:38 +02:00
|
|
|
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN {
|
|
|
|
|
v3errorEnd(str);
|
|
|
|
|
assert(0); // LCOV_EXCL_LINE
|
|
|
|
|
VL_UNREACHABLE
|
|
|
|
|
}
|
2019-06-22 23:01:39 +02:00
|
|
|
/// When building an error, prefix for printing continuation lines
|
2019-07-12 01:15:40 +02:00
|
|
|
/// e.g. information referring to the same FileLine as before
|
2014-11-22 17:48:39 +01:00
|
|
|
string warnMore() const;
|
2019-07-12 01:15:40 +02:00
|
|
|
/// When building an error, prefix for printing secondary information
|
|
|
|
|
/// from a different FileLine than the original error
|
|
|
|
|
string warnOther() const;
|
2019-06-22 23:01:39 +02:00
|
|
|
/// When building an error, current location in include etc
|
|
|
|
|
/// If not used in a given error, automatically pasted at end of error
|
|
|
|
|
string warnContextPrimary() const { return warnContext(false); }
|
|
|
|
|
/// When building an error, additional location for additional references
|
|
|
|
|
/// Simplified information vs warnContextPrimary() to make dump clearer
|
|
|
|
|
string warnContextSecondary() const { return warnContext(true); }
|
2020-02-02 16:34:29 +01:00
|
|
|
bool operator==(const FileLine& rhs) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
|
|
|
|
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
|
|
|
|
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
|
2014-11-22 17:48:39 +01:00
|
|
|
}
|
2020-06-10 04:39:10 +02:00
|
|
|
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
|
|
|
|
|
// equivalent.
|
|
|
|
|
int operatorCompare(const FileLine& rhs) const {
|
|
|
|
|
if (m_filenameno != rhs.m_filenameno) return (m_filenameno < rhs.m_filenameno) ? -1 : 1;
|
|
|
|
|
if (m_firstLineno != rhs.m_firstLineno)
|
|
|
|
|
return (m_firstLineno < rhs.m_firstLineno) ? -1 : 1;
|
|
|
|
|
if (m_firstColumn != rhs.m_firstColumn)
|
|
|
|
|
return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1;
|
|
|
|
|
if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1;
|
|
|
|
|
if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1;
|
|
|
|
|
for (size_t i = 0; i < m_warnOn.size(); ++i) {
|
|
|
|
|
if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1;
|
|
|
|
|
}
|
|
|
|
|
return 0; // (*this) and rhs are equivalent
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2017-09-14 01:27:59 +02:00
|
|
|
private:
|
2019-06-22 23:01:39 +02:00
|
|
|
string warnContext(bool secondary) const;
|
2014-11-22 17:48:39 +01:00
|
|
|
};
|
2018-02-02 03:24:41 +01:00
|
|
|
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
|
2014-11-22 17:48:39 +01:00
|
|
|
|
2019-05-15 02:51:28 +02:00
|
|
|
#endif // Guard
|