Disable symbol from parser: Support redeclaring type as non-type; major parsing change (#2412).

This commit is contained in:
Wilson Snyder 2025-05-17 22:21:14 -04:00
parent 2c465d9741
commit 6bb16d6c52
35 changed files with 263 additions and 198 deletions

View File

@ -1,11 +0,0 @@
.. comment: generated by t_lint_pkgnodecl_bad
.. code-block:: sv
:linenos:
:emphasize-lines: 2
module t;
initial Pkg::hello(); //<--- Warning
endmodule
package Pkg;
function void hello(); endfunction
endpackage

View File

@ -1,4 +0,0 @@
.. comment: generated by t_lint_pkgnodecl_bad
.. code-block::
%Error-PKGNODECL: example.v:1:12 Package/class 'Pkg' not found, and needs to be predeclared (IEEE 1800-2023 26.3)

View File

@ -1401,23 +1401,11 @@ List Of Warnings
.. option:: PKGNODECL
An error that a package/class appears to have been referenced that has
not yet been declared. According to IEEE 1800-2023 26.3, all packages
must be declared before being used.
Faulty example:
.. include:: ../../docs/gen/ex_PKGNODECL_faulty.rst
Results in:
.. include:: ../../docs/gen/ex_PKGNODECL_msg.rst
Often the package is declared in its own header file. In this case add
an include of that package header file to the referencing file. (And
make sure you have header guards in the package's header file to prevent
multiple declarations of the package.)
Never issued since version 5.038. Historically an error that a
package/class appears to have been referenced that has not yet been
declared. According to IEEE 1800-2023 26.3, all packages must be
declared before being used. However, several standard libraries
including UVM violate this, and other tools do not warn.
.. option:: PORTSHORT

View File

@ -2128,6 +2128,9 @@ protected:
// Use instead isSame(), this is for each Ast* class, and assumes node is of same type
virtual bool sameNode(const AstNode*) const { return true; }
// Generated by 'astgen'. If do an oldp->replaceNode(newp), would cause a broken()
virtual bool wouldBreakGen(const AstNode* const oldp,
const AstNode* const newp) const = 0; // Generated by 'astgen'
public:
// ACCESSORS
@ -2527,6 +2530,8 @@ public:
virtual const char* broken() const { return nullptr; }
// Generated by 'astgen'. Calls 'broken()', which can be used to add extra checks
virtual const char* brokenGen() const = 0; // Generated by 'astgen'
// If do a this->replaceNode(newp), would cause a broken()
bool wouldBreak(const AstNode* const newp) const { return backp()->wouldBreakGen(this, newp); }
// INVOKERS
virtual void accept(VNVisitorConst& v) = 0;

View File

@ -742,10 +742,10 @@ public:
class AstCellRef final : public AstNodeExpr {
// As-of-yet unlinkable reference into a cell
// @astgen op1 := cellp : AstNode
// @astgen op2 := exprp : AstNodeExpr
// @astgen op2 := exprp : AstNode<AstNodeExpr|AstNodeDType>
string m_name; // Cell name
public:
AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNodeExpr* exprp)
AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp)
: ASTGEN_SUPER_CellRef(fl)
, m_name{name} {
this->cellp(cellp);
@ -1206,8 +1206,8 @@ public:
class AstDot final : public AstNodeExpr {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op1 := lhsp : AstNode<AstNodeExpr|AstNodeDType>
// @astgen op2 := rhsp : AstNode<AstNodeExpr|AstNodeDType>
//
// We don't have a list of elements as it's probably legal to do '(foo.bar).(baz.bap)'
const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)

View File

@ -529,7 +529,10 @@ public:
"Unsupported: Interfaced port on top level module");
}
ifacerefp->v3error("Parent instance's interface is not found: "
<< AstNode::prettyNameQ(ifacerefp->ifaceName()));
<< AstNode::prettyNameQ(ifacerefp->ifaceName()) << '\n'
<< ifacerefp->warnMore()
<< "... Perhaps intended an interface instantiation but "
"are missing parenthesis (IEEE 1800-2023 25.3)?");
} else {
ifacerefp->v3warn(
E_UNSUPPORTED,
@ -1550,11 +1553,11 @@ class LinkDotFindVisitor final : public VNVisitor {
if (tdefp && tdefp->name() == nodep->name() && m_statep->forPrimary()) {
UINFO(8, "Replacing type of" << nodep << endl
<< " with " << tdefp << endl);
AstNodeDType* const newType = tdefp->childDTypep();
AstNodeDType* const oldType = nodep->childDTypep();
AstNodeDType* const newDtp = tdefp->childDTypep();
AstNodeDType* const oldDtp = nodep->childDTypep();
oldType->replaceWith(newType->cloneTree(false));
oldType->deleteTree();
oldDtp->replaceWith(newDtp->cloneTree(false));
oldDtp->deleteTree();
}
}
}
@ -2477,7 +2480,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
void checkNoDot(AstNode* nodep) {
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
// UINFO(9, indent() << "ds=" << m_ds.ascii() << endl);
UINFO(9, indent() << "ds=" << m_ds.ascii() << endl);
nodep->v3error("Syntax error: Not expecting "
<< nodep->type() << " under a " << nodep->backp()->type()
<< " in dotted expression\n"
@ -2608,6 +2611,15 @@ class LinkDotResolveVisitor final : public VNVisitor {
symIterateNull(nodep, m_statep->getNodeSym(nodep));
}
void replaceWithCheckBreak(AstNode* oldp, AstNodeDType* newp) {
// Flag now to avoid V3Broken throwing an internal error
if (oldp->wouldBreak(newp)) {
newp->v3error(
"Data type used where a non-data type is expected: " << newp->prettyNameQ());
}
oldp->replaceWith(newp);
}
// Marks the current module to be revisited after the initial AST iteration
void revisitLater(AstNode* deferredNodep) {
// Need to revisit entire module to build up all the necessary context
@ -2951,7 +2963,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // Dot midpoint
AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack();
AstNode* newp = nodep->rhsp()->unlinkFrBack();
if (m_ds.m_unresolvedCell) {
AstCellRef* const crp = new AstCellRef{
nodep->fileline(), nodep->name(), nodep->lhsp()->unlinkFrBack(), newp};
@ -3059,7 +3071,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
return;
} else if (m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
AstNodeExpr* const varEtcp = VN_AS(m_ds.m_dotp->lhsp()->unlinkFrBack(), NodeExpr);
AstNodeExpr* const newp
= new AstMemberSel{nodep->fileline(), varEtcp, VFlagChildDType{}, nodep->name()};
if (m_ds.m_dotErr) {
@ -3348,6 +3360,14 @@ class LinkDotResolveVisitor final : public VNVisitor {
ok = true;
m_ds.m_dotPos = DP_MEMBER;
m_ds.m_dotText = "";
} else if (AstClass* const defp = VN_CAST(foundp->nodep(), Class)) {
if (allowVar) {
AstRefDType* const newp = new AstRefDType{nodep->fileline(), nodep->name()};
replaceWithCheckBreak(nodep, newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
ok = true;
m_ds.m_dotText = "";
}
} else if (AstEnumItem* const valuep = VN_CAST(foundp->nodep(), EnumItem)) {
if (allowVar) {
AstNode* const newp
@ -3386,6 +3406,22 @@ class LinkDotResolveVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
} else if (AstTypedef* const defp = VN_CAST(foundp->nodep(), Typedef)) {
ok = m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE;
if (ok) {
AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()};
refp->typedefp(defp);
replaceWithCheckBreak(nodep, refp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else if (AstParamTypeDType* const defp = VN_CAST(foundp->nodep(), ParamTypeDType)) {
ok = (m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE);
if (ok) {
AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()};
refp->refDTypep(defp);
replaceWithCheckBreak(nodep, refp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
if (!ok) {
if (m_insideClassExtParam) {
@ -3795,7 +3831,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is method call.
// {scope}.{var}.HERE {method} ( ARGS )
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
AstNodeExpr* const varEtcp = VN_AS(m_ds.m_dotp->lhsp()->unlinkFrBack(), NodeExpr);
AstNodeExpr* argsp = nullptr;
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
AstNode* const newp = new AstMethodCall{nodep->fileline(), varEtcp, VFlagChildDType{},
@ -4373,7 +4409,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
VL_DO_DANGLING(cpackagep->unlinkFrBack()->deleteTree(), cpackagep);
}
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
if (m_ds.m_dotp && (m_ds.m_dotPos == DP_PACKAGE || m_ds.m_dotPos == DP_SCOPE)) {
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
"Bad package link");
auto* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);

View File

@ -196,7 +196,6 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
if (GRAMMARP->m_varIO == VDirection::NONE // In non-ANSI port list
&& GRAMMARP->m_varDecl == VVarType::PORT) {
// Just a port list with variable name (not v2k format); AstPort already created
if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists");
if (arrayp) VL_DO_DANGLING(arrayp->deleteTree(), arrayp);
if (attrsp) {
// TODO: Merge attributes across list? Or warn attribute is ignored

View File

@ -429,6 +429,35 @@ size_t V3ParseImp::tokenPipeScanIdInst(size_t depthIn) {
return depth;
}
size_t V3ParseImp::tokenPipeScanIdType(size_t depthIn) {
// Search around IEEE data type identifier
// Return location of following token, or input if not found
// tokenPipeScanIdCell has precedence over this search
// yaID/*type_identifier*/ [ '#' '('...')' ] [{ '['...']' }] yaID/*identifier*/
// assignment_pattern_expression:
// yaID/*type_identifier*/ [ '#' '('...')' ] [{ '['...']' }] yP_TICKBRA
// class_type parameter_value_assignment // often followed by ) as in e.g. ClsA#(ClsB#(...))
// yaID/*type_identifier*/ '#' '('...')' [^ '::']
// and caller must check does NOT match tokenPipeScanIdCell
size_t depth = depthIn;
// UINFO(9, "tokenPipeScanType START d="
// << depth << " " << V3ParseImp::tokenName(tokenPeekp(depth)->token) << endl);
if (tokenPeekp(depth)->token == '#' && tokenPeekp(depth + 1)->token == '(') {
depth = tokenPipeScanParam(depth, false);
// Not :: as then it's a yaID__CC, we'll parse that in tokenPipeScanId
if (tokenPeekp(depth)->token != yP_COLONCOLON) return depth;
}
depth = tokenPipeScanBracket(depth); // [ '['..']' ]*
if (tokenPeekp(depth)->token != yaID__LEX && tokenPeekp(depth)->token != yP_TICKBRA)
return depthIn;
++depth;
// UINFO(9, "tokenPipeScanType MATCH\n");
return depth;
}
size_t V3ParseImp::tokenPipeScanBracket(size_t inDepth) {
// Return location of following token, or input if not found
// [ '['...']' ]*
@ -531,6 +560,7 @@ int V3ParseImp::tokenPipelineId(int token) {
if (m_tokenLastBison.token != '@' && m_tokenLastBison.token != '#'
&& m_tokenLastBison.token != '.') {
if (const size_t depth = tokenPipeScanIdInst(0)) return yaID__aINST;
if (const size_t depth = tokenPipeScanIdType(0)) return yaID__aTYPE;
}
if (nexttok == '#') { // e.g. class_type parameter_value_assignment '::'
const size_t depth = tokenPipeScanParam(0, false);
@ -683,6 +713,8 @@ void V3ParseImp::tokenPipelineSym() {
foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp));
}
if (!foundp && !m_afterColonColon) { // Check if the symbol can be found in std
// The following keywords from this file are hardcoded for detection in the parser:
// "mailbox", "process", "randomize", "semaphore", "std"
AstPackage* const stdpkgp = v3Global.rootp()->stdPackagep();
if (stdpkgp) {
VSymEnt* const stdsymp = stdpkgp->user4u().toSymEnt();
@ -694,36 +726,11 @@ void V3ParseImp::tokenPipelineSym() {
yylval.scp = scp;
UINFO(7, " tokenPipelineSym: Found " << scp << endl);
if (token == yaID__LEX) { // i.e. not yaID__CC
if (VN_IS(scp, Typedef)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, TypedefFwd)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Class)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Package)) {
token = yaID__ETC;
} else {
token = yaID__ETC;
}
token = yaID__ETC;
}
} else { // Not found
yylval.scp = nullptr;
if (token == yaID__CC) {
if (!m_afterColonColon && !v3Global.opt.bboxUnsup()) {
// IEEE does require this, but we may relax this as UVM breaks it, so allow
// bbox for today
// We'll get a parser error eventually but might not be obvious
// is missing package, and this confuses people
static int warned = false;
if (!warned++) {
yylval.fl->v3warn(PKGNODECL, "Package/class '" + *yylval.strp
+ "' not found, and needs to be "
"predeclared (IEEE 1800-2023 26.3)");
}
}
} else if (token == yaID__LEX) {
token = yaID__ETC;
}
if (token == yaID__LEX) token = yaID__ETC;
}
}
m_afterColonColon = token == yP_COLONCOLON;

View File

@ -316,6 +316,7 @@ private:
int tokenPipelineId(int token) VL_MT_DISABLED;
void tokenPipelineSym() VL_MT_DISABLED;
size_t tokenPipeScanIdInst(size_t depth) VL_MT_DISABLED;
size_t tokenPipeScanIdType(size_t depth) VL_MT_DISABLED;
size_t tokenPipeScanBracket(size_t depth) VL_MT_DISABLED;
size_t tokenPipeScanParam(size_t depth, bool forInst) VL_MT_DISABLED;
size_t tokenPipeScanTypeEq(size_t depth) VL_MT_DISABLED;

View File

@ -968,7 +968,31 @@ def write_ast_impl(filename):
emitBlock("));\n")
# Node's broken rules can be specialized by declaring broken()
emitBlock(" return Ast{t}::broken();\n", t=node.name)
emitBlock("}}\n", t=node.name)
emitBlock("}}\n")
emitBlock(
"bool Ast{t}::wouldBreakGen(const AstNode* const oldp, const AstNode* const newp) const {{\n",
t=node.name)
for i in range(1, 5):
op = node.getOp(i)
if op is None:
continue
name, _, _, legals = op
if legals != '':
# 'this' is a parent, where oldp replacing newp as op1p, must follow op1p's rules
# Could also be on a list, we don't check for speed reasons and as V3Broken doesn't
emitBlock(" if (oldp == op{i}p() && !(", i=i)
eor = ""
for legal in legals.split('|'):
emitBlock("{eor}privateTypeTest<Ast{legal}>(newp)",
eor=eor,
name=name,
legal=legal)
eor = " || "
emitBlock(")) return true;\n")
# Node's broken rules can be specialized by declaring broken()
emitBlock(" return false;\n")
emitBlock("}}\n")
emitBlock("void Ast{t}::cloneRelinkGen() {{\n", t=node.name)
if node.superClass.name != 'Node':
@ -1042,6 +1066,7 @@ def write_ast_macros(filename):
Ast{t}* clonep() const {{ return static_cast<Ast{t}*>(AstNode::clonep()); }}
Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast<Ast{t}*>(AstNode::addNext(this, nodep)); }}
const char* brokenGen() const override;
bool wouldBreakGen(const AstNode* const oldp, const AstNode* const newp) const override;
void cloneRelinkGen() override;
void dumpTreeJsonOpGen(std::ostream& str, const string& indent) const override;
void dumpJsonGen(std::ostream& str) const;

View File

@ -1552,15 +1552,11 @@ port<nodep>: // ==IEEE: port
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
// // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation
portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE
{ // VAR for now, but V3LinkCells may call setIfcaeRef on it later
$$ = $3; VARDECL(VAR); VARIO(NONE);
// Although know it's an interface, use AstRefDType for forward compatibility
// with future parser. V3LinkCells will convert to AstIfaceRefDType.
AstNodeDType* const dtp = new AstRefDType{$<fl>2, *$2};
VARDTYPE(dtp);
addNextNull($$, VARDONEP($$, $4, $5)); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE
//
// // Looks identical to variable_declaration, so V3LinkDot must resolve when ID known
// // NO: portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE
//
portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE
{ // VAR for now, but V3LinkCells may call setIfcaeRef on it later
$$ = $5; VARDECL(VAR); VARIO(NONE);
AstNodeDType* const dtp = new AstIfaceRefDType{$<fl>2, $<fl>4, "", *$2, *$4};
@ -1615,17 +1611,20 @@ port<nodep>: // ==IEEE: port
// // IEEE: portDirNetE data_type '.' portSig -> handled with AstDot in expr.
//
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
{ $$ = $3; VARDTYPE($2); VARIOANSI(); addNextNull($$, VARDONEP($$, $4, $5)); }
{ $$ = $3; VARDTYPE($2); VARIOANSI();
addNextNull($$, VARDONEP($$, $4, $5)); }
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
{ $$ = $3; VARDTYPE($2); VARIOANSI();
if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
{ $$ = $4; VARDTYPE($3); VARIOANSI();
addNextNull($$, VARDONEP($$, $5, $6)); }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
{ $$ = $4; VARDTYPE($3); VARIOANSI();
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
{ $$ = $4; VARDTYPE($3); VARIOANSI();
addNextNull($$, VARDONEP($$, $5, $6)); }
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
{ $$ = $4; VARDTYPE($3); VARIOANSI();
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
@ -2105,13 +2104,10 @@ port_declaration<nodep>: // ==IEEE: port_declaration
//
// // IEEE: interface_port_declaration
// // IEEE: interface_identifier list_of_interface_identifiers
| id/*interface*/
/*mid*/ { VARRESET_NONLIST(VVarType::IFACEREF);
AstIfaceRefDType* const dtp = new AstIfaceRefDType{$<fl>1, "", *$1};
dtp->isPortDecl(true);
VARDTYPE(dtp); }
/*cont*/ mpInstnameList
{ $$ = VARDONEP($3, nullptr, nullptr); }
//
// // Identical to variable_declaration, resolve in V3LinkDot when id known
// // NO: id/*interface*/ mpInstnameList
//
// // IEEE: interface_port_declaration
// // IEEE: interface_identifier '.' modport_identifier list_of_interface_identifiers
| id/*interface*/ '.' idAny/*modport*/
@ -4585,9 +4581,10 @@ exprOrDataType<nodep>: // expr | data_type: combined to prevent conflic
// // data_type includes id that overlaps expr, so special flavor
// // data_type expanded:
| data_typeNoRef { $$ = $1; }
| packageClassScopeE idType packed_dimensionListE
{ AstRefDType* const refp = new AstRefDType{$<fl>2, *$2, $1, nullptr};
$$ = GRAMMARP->createArray(refp, $3, true); }
//
// // Conflicts with non-type id, resolved in V3LinkDot
// // NO: packageClassScopeE idType packed_dimensionListE
//
| packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE
{ AstRefDType* const refp = new AstRefDType{$<fl>2, *$2, $1, $3};
$$ = GRAMMARP->createArray(refp, $4, true); }
@ -5153,8 +5150,8 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
{ $$ = new AstCast{$2, $4, VFlagChildDType{}, $1}; }
// // expanded from simple_type ps_type_identifier (part of simple_type)
// // expanded from simple_type ps_parameter_identifier (part of simple_type)
| packageClassScopeE idType yP_TICK '(' expr ')'
{ $$ = new AstCastParse{$3, $5, new AstRefDType{$<fl>2, *$2, $1, nullptr}}; }
// // Causes conflict, so handled post-parse
// // NO: packageClassScopeE idType yP_TICK '(' expr ')'
//
| yTYPE__ETC '(' exprOrDataType ')' yP_TICK '(' expr ')'
{ $$ = new AstCast{$1, $7, VFlagChildDType{},

View File

@ -405,11 +405,8 @@
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:18: Ignoring unsupported: covergroup within class
164 | covergroup cov1 @m_z;
| ^~~~
%Error: t/t_covergroup_unsup.v:169:28: syntax error, unexpected '=', expecting IDENTIFIER or do or final or randomize
%Error: t/t_covergroup_unsup.v:169:23: Can't find definition of variable: 'cov1'
169 | function new(); cov1 = new; endfunction
| ^
| ^~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Internal Error: t/t_covergroup_unsup.v:160:4: ../V3ParseSym.h:#: Symbols suggest ending FUNC 'new' but parser thinks ending CLASS 'CgCls'
160 | class CgCls;
| ^~~~~
... This fatal error may be caused by the earlier error(s); resolve those first.
%Error: Exiting due to

View File

@ -53,11 +53,14 @@ for s in [
'Illegal +: or -: select; type already selected, or bad dimension: ',
'Illegal bit or array select; type already selected, or bad dimension: ',
'Illegal range select; type already selected, or bad dimension: ',
'Interface port ',
'Interface port declaration ',
'Modport item is not a function/task: ',
'Modport item is not a variable: ',
'Modport item not found: ',
'Modport not referenced as <interface>.',
'Modport not referenced from underneath an interface: ',
'Non-interface used as an interface: ',
'Parameter type pin value isn\'t a type: Param ',
'Parameter type variable isn\'t a type: Param ',
'Pattern replication value of 0 is not legal.',

View File

@ -1,8 +1,3 @@
%Error: t/t_inst_paren_bad.v:11:4: Non-interface used as an interface: 'sub'
: ... Perhaps intended an instantiation but are missing parenthesis (IEEE 1800-2023 23.3.2)?
11 | sub sub_inst;
| ^~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Warning-MULTITOP: t/t_inst_paren_bad.v:10:8: Multiple top level modules
: ... Suggest see manual; fix the duplicates, or use --top-module to select top.
... For warning description see https://verilator.org/warn/MULTITOP?v=latest
@ -13,4 +8,8 @@
: ... Top module 't'
10 | module t( );
| ^
%Error: t/t_inst_paren_bad.v:11:4: Can't find typedef/interface: 'sub'
11 | sub sub_inst;
| ^~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -1,17 +1,11 @@
%Error: t/t_interface_missing_bad.v:14:13: Pin is not an in/out/inout/interface: 'foo'
14 | foo_intf foo
| ^~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_interface_missing_bad.v:14:4: Can't find typedef/interface: 'foo_intf'
14 | foo_intf foo
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_interface_missing_bad.v:20:4: Cannot find file containing interface: 'foo_intf'
20 | foo_intf the_foo ();
| ^~~~~~~~
%Error: t/t_interface_missing_bad.v:25:15: Found definition of 'the_foo' as a CELL but expected a variable
25 | .foo (the_foo)
| ^~~~~~~
%Error: t/t_interface_missing_bad.v:25:10: Instance attempts to connect to 'foo', but it is a variable
25 | .foo (the_foo)
| ^~~
%Error: Exiting due to

View File

@ -1,6 +1,6 @@
%Error: t/t_interface_paren_missing_bad.v:13:9: Interface port declaration 'intf_i' doesn't have corresponding port
%Error: t/t_interface_paren_missing_bad.v:13:4: Parent instance's interface is not found: 'intf'
: ... Perhaps intended an interface instantiation but are missing parenthesis (IEEE 1800-2023 25.3)?
13 | intf intf_i;
| ^~~~~~
| ^~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -3,6 +3,7 @@
| ^~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_top_bad.v:17:4: Parent instance's interface is not found: 'ifc'
: ... Perhaps intended an interface instantiation but are missing parenthesis (IEEE 1800-2023 25.3)?
17 | ifc.counter_mp c_data
| ^~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.

View File

@ -2,8 +2,4 @@
46 | typedef ifc_if.struct_t struct_t;
| ^~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_interface_typedef.v:51:16: syntax error, unexpected IDENTIFIER
51 | struct_t substruct;
| ^~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -1,4 +1,5 @@
%Error: t/t_interface_typo_bad.v:14:4: Parent instance's interface is not found: 'foo_intf'
: ... Perhaps intended an interface instantiation but are missing parenthesis (IEEE 1800-2023 25.3)?
14 | foo_intf foo
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.

View File

@ -1,5 +1,11 @@
%Error: t/t_lint_implicit_type_bad.v:15:11: syntax error, unexpected IDENTIFIER-for-type
%Error: t/t_lint_implicit_type_bad.v:15:11: Data type used where a non-data type is expected: 'imp_typedef_conflict'
15 | assign imp_typedef_conflict = 1'b1;
| ^~~~~~~~~~~~~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_lint_implicit_type_bad.v:16:11: Data type used where a non-data type is expected: 'imp_Cls_conflict'
16 | assign imp_Cls_conflict = 1'b1;
| ^~~~~~~~~~~~~~~~
%Error: t/t_lint_implicit_type_bad.v:17:11: Data type used where a non-data type is expected: 'imp_PARAM_conflict'
17 | assign imp_PARAM_conflict = 1'b1;
| ^~~~~~~~~~~~~~~~~~
%Error: Exiting due to

View File

@ -12,7 +12,7 @@ import vltest_bootstrap
test.scenarios('vlt')
# --debug-check adds extra internal message, otherwise golden log would vary
test.lint(verilator_flags2=["--lint-only --debug-check -Wall -Wno-DECLFILENAME"],
test.lint(verilator_flags2=["--lint-only --no-debug-check -Wall -Wno-DECLFILENAME"],
fails=True,
expect_filename=test.golden_filename)

View File

@ -1,7 +1,3 @@
%Error-PKGNODECL: t/t_lint_import_name2_bad.v:7:8: Package/class 'missing' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
7 | import missing::sigs;
| ^~~~~~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
%Error: t/t_lint_import_name2_bad.v:7:8: Importing from missing package 'missing'
7 | import missing::sigs;
| ^~~~~~~

View File

@ -1,9 +1,5 @@
%Error-PKGNODECL: t/t_lint_pkg_colon_bad.v:7:17: Package/class 'mispkg' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
7 | module t (input mispkg::foo_t a);
| ^~~~~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
%Error: t/t_lint_pkg_colon_bad.v:7:25: syntax error, unexpected IDENTIFIER, expecting IDENTIFIER-for-type
7 | module t (input mispkg::foo_t a);
| ^~~~~
%Error: t/t_lint_pkg_colon_bad.v:8:8: syntax error, unexpected IDENTIFIER-::, expecting IDENTIFIER or do or final or randomize
8 | reg mispkgb::bar_t b;
| ^~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -1,5 +0,0 @@
%Error-PKGNODECL: t/t_lint_pkgnodecl_bad.v:8:12: Package/class 'Pkg' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
8 | initial Pkg::hello();
| ^~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
%Error: Exiting due to

View File

@ -1,29 +0,0 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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
import vltest_bootstrap
test.scenarios('linter')
root = ".."
if not os.path.exists(root + "/.git"):
test.skip("Not in a git repository")
test.lint(fails=True, expect_filename=test.golden_filename)
test.extract(in_filename=test.top_filename,
out_filename=root + "/docs/gen/ex_PKGNODECL_faulty.rst",
lines="7-12")
test.extract(in_filename=test.golden_filename,
out_filename=root + "/docs/gen/ex_PKGNODECL_msg.rst",
lines="1")
test.passes()

View File

@ -1,12 +0,0 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2012 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t;
initial Pkg::hello(); //<--- Warning
endmodule
package Pkg;
function void hello(); endfunction
endpackage

View File

@ -1,7 +1,3 @@
%Error-PKGNODECL: t/t_no_std_bad.v:9:11: Package/class 'std' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
9 | import std::*;
| ^~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
%Error: t/t_no_std_bad.v:9:11: Importing from missing package 'std'
9 | import std::*;
| ^~~

View File

@ -1,5 +1,5 @@
%Error-PKGNODECL: t/t_package_alone_bad.v:7:8: Package/class 'pkg' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
%Error: t/t_package_alone_bad.v:7:13: Export package not found: 'pkg'
7 | export pkg::something;
| ^~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
| ^~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -1,8 +1,24 @@
%Error: t/t_parse_sync_bad2.v:17:16: syntax error, unexpected IDENTIFIER
17 | Invalid1 invalid1;
| ^~~~~~~~
%Error: t/t_parse_sync_bad2.v:9:15: Can't find typedef/interface: 'unknown'
9 | typedef unknown defu;
| ^~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_parse_sync_bad2.v:20:16: syntax error, unexpected IDENTIFIER
%Error: t/t_parse_sync_bad2.v:17:7: Can't find typedef/interface: 'Invalid1'
17 | Invalid1 invalid1;
| ^~~~~~~~
%Error-UNSUPPORTED: t/t_parse_sync_bad2.v:18:12: Unsupported: Multiple '::' package/class reference
18 | pkg::cls::defi valid1;
| ^~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_parse_sync_bad2.v:18:17: Can't find typedef/interface: 'defi'
18 | pkg::cls::defi valid1;
| ^~~~
%Error-UNSUPPORTED: t/t_parse_sync_bad2.v:19:12: Unsupported: Multiple '::' package/class reference
19 | pkg::cls::defu valid2;
| ^~~
%Error: t/t_parse_sync_bad2.v:19:17: Can't find typedef/interface: 'defu'
19 | pkg::cls::defu valid2;
| ^~~~
%Error: t/t_parse_sync_bad2.v:20:7: Can't find typedef/interface: 'Invalid2'
20 | Invalid2 invalid2;
| ^~~~~~~~
| ^~~~~~~~
%Error: Exiting due to

View File

@ -1,4 +1,4 @@
%Error: t/t_pp_circ_subst_bad.v:8:80001: Too many preprocessor tokens on a line (>40000); perhaps recursive `define
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_pp_circ_subst_bad.v:8:1: syntax error, unexpected IDENTIFIER
%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type, expecting IDENTIFIER or do or final or randomize
%Error: Exiting due to

View File

@ -1,4 +1,4 @@
%Error: t/t_pp_circ_subst_bad.v:8:40002: Too many preprocessor tokens on a line (>20000); perhaps recursive `define
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_pp_circ_subst_bad.v:8:1: syntax error, unexpected IDENTIFIER
%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type, expecting IDENTIFIER or do or final or randomize
%Error: Exiting due to

View File

@ -1,4 +1,4 @@
%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize
%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting '('
11 | endmodule
| ^~~~~~~~~
t/t_preproc_inc_bad.v:10:1: ... note: In file included from 't_preproc_inc_bad.v'

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,49 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Use this file as a template for submitting bugs, etc.
// This module takes a single clock input, and should either
// $write("*-* All Finished *-*\n");
// $finish;
// on success, or $stop.
//
// The code as shown applies a random vector to the Test
// module, then calculates a CRC on the Test module's outputs.
//
// **If you do not wish for your code to be released to the public
// please note it here, otherwise:**
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls;
endclass
package Pkg;
// Issue #2956
typedef string STYPE;
typedef string line;
task automatic testf;
inout STYPE line;
endtask
endpackage
module t;
localparam type T = Cls;
// Issue #2412
typedef T this_thing; // this_thing now a type
function T newer();
T this_thing; // this_thing now a class reference
this_thing = new;
return this_thing;
endfunction
initial begin
Cls c;
c = newer();
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -2,7 +2,7 @@
12 | int above;
| ^~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting IDENTIFIER or randomize
%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting '('
12 | int above;
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.