Add error on missing forward declarations (#6207).
This commit is contained in:
parent
d8dbb08a95
commit
f3560837ec
1
Changes
1
Changes
|
@ -17,6 +17,7 @@ Verilator 5.039 devel
|
|||
* Add NOEFFECT warning, replacing previous `foreach` error.
|
||||
* Add SPECIFYIGN warning for specify constructs that were previously silently ignored.
|
||||
* Add enum base data type, and wire data type checking per IEEE.
|
||||
* Add error on missing forward declarations (#6207). [Alex Solomatnikov]
|
||||
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
||||
* Support disabling a fork in additional contexts (#5432 partial) (#6174) (#6183). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.]
|
||||
|
|
|
@ -58,6 +58,27 @@ const VNTypeInfo VNType::typeInfoTable[] = {
|
|||
|
||||
std::ostream& operator<<(std::ostream& os, VNType rhs);
|
||||
|
||||
//######################################################################
|
||||
// VFwdType
|
||||
|
||||
bool VFwdType::isNodeCompatible(const AstNode* nodep) const {
|
||||
const AstNode* defp = nodep;
|
||||
if (const AstTypedef* const adefp = VN_CAST(defp, Typedef)) defp = adefp->subDTypep();
|
||||
if (const AstNodeDType* const adefp = VN_CAST(defp, NodeDType))
|
||||
defp = adefp->skipRefToNonRefp();
|
||||
switch (m_e) {
|
||||
case VFwdType::NONE: return true; break;
|
||||
case VFwdType::ENUM: return VN_IS(defp, EnumDType); break;
|
||||
case VFwdType::STRUCT: return VN_IS(defp, StructDType); break;
|
||||
case VFwdType::UNION: return VN_IS(defp, UnionDType); break;
|
||||
case VFwdType::INTERFACE_CLASS: // FALLTHRU // TODO: Over permissive for now
|
||||
case VFwdType::CLASS: return VN_IS(defp, ClassRefDType) || VN_IS(defp, Class); break;
|
||||
default: v3fatalSrc("Bad case");
|
||||
}
|
||||
VL_UNREACHABLE;
|
||||
return false; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// VSelfPointerText
|
||||
|
||||
|
|
|
@ -304,6 +304,8 @@ public:
|
|||
explicit VFwdType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
// Is a node type compatible with the declaration
|
||||
bool isNodeCompatible(const AstNode* nodep) const;
|
||||
};
|
||||
constexpr bool operator==(const VFwdType& lhs, const VFwdType& rhs) { return lhs.m_e == rhs.m_e; }
|
||||
constexpr bool operator==(const VFwdType& lhs, VFwdType::en rhs) { return lhs.m_e == rhs; }
|
||||
|
@ -2236,6 +2238,8 @@ public:
|
|||
}
|
||||
virtual void tag(const string& text) {}
|
||||
virtual string tag() const { return ""; }
|
||||
virtual uint32_t declTokenNum() const { return 0; }
|
||||
virtual void declTokenNumSetMin(uint32_t tokenNum) {}
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied
|
||||
string origNameProtect() const; // origName with --protect-id applied
|
||||
|
|
|
@ -1829,6 +1829,7 @@ class AstTypedef final : public AstNode {
|
|||
|
||||
string m_name;
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
uint32_t m_declTokenNum; // Declaration token number
|
||||
bool m_attrPublic = false;
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
|
@ -1838,6 +1839,7 @@ public:
|
|||
AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_Typedef(fl)
|
||||
, m_name{name}
|
||||
, m_declTokenNum{fl->tokenNum()}
|
||||
, m_isHideLocal{false}
|
||||
, m_isHideProtected{false} {
|
||||
childDTypep(dtp); // Only for parser
|
||||
|
@ -1852,6 +1854,10 @@ public:
|
|||
return dtypep() ? dtypep() : childDTypep();
|
||||
}
|
||||
// METHODS
|
||||
uint32_t declTokenNum() const override { return m_declTokenNum; }
|
||||
void declTokenNumSetMin(uint32_t tokenNum) override {
|
||||
m_declTokenNum = std::min(m_declTokenNum, tokenNum);
|
||||
}
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
|
@ -1868,15 +1874,20 @@ public:
|
|||
class AstTypedefFwd final : public AstNode {
|
||||
// Forward declaration of a type; stripped after netlist parsing is complete
|
||||
string m_name;
|
||||
const VFwdType m_fwdType; // Forward type for lint check
|
||||
|
||||
public:
|
||||
AstTypedefFwd(FileLine* fl, const string& name)
|
||||
AstTypedefFwd(FileLine* fl, const string& name, const VFwdType& fwdType)
|
||||
: ASTGEN_SUPER_TypedefFwd(fl)
|
||||
, m_name{name} {}
|
||||
, m_name{name}
|
||||
, m_fwdType{fwdType} {}
|
||||
ASTGEN_MEMBERS_AstTypedefFwd;
|
||||
// METHODS
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
VFwdType fwdType() const { return m_fwdType; }
|
||||
};
|
||||
class AstUdpTable final : public AstNode {
|
||||
// @astgen op1 := linesp : List[AstUdpTableLine]
|
||||
|
@ -2505,6 +2516,7 @@ class AstClass final : public AstNodeModule {
|
|||
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||
// MEMBERS
|
||||
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
|
||||
uint32_t m_declTokenNum; // Declaration token number
|
||||
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
||||
bool m_extended = false; // Is extension or extended by other classes
|
||||
bool m_interfaceClass = false; // Interface class
|
||||
|
@ -2514,7 +2526,8 @@ class AstClass final : public AstNodeModule {
|
|||
|
||||
public:
|
||||
AstClass(FileLine* fl, const string& name, const string& libname)
|
||||
: ASTGEN_SUPER_Class(fl, name, libname) {}
|
||||
: ASTGEN_SUPER_Class(fl, name, libname)
|
||||
, m_declTokenNum{fl->tokenNum()} {}
|
||||
ASTGEN_MEMBERS_AstClass;
|
||||
string verilogKwd() const override { return "class"; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
|
@ -2538,6 +2551,10 @@ public:
|
|||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
uint32_t declTokenNum() const override { return m_declTokenNum; }
|
||||
void declTokenNumSetMin(uint32_t tokenNum) override {
|
||||
m_declTokenNum = std::min(m_declTokenNum, tokenNum);
|
||||
}
|
||||
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
|
||||
VBaseOverride baseOverride() const { return m_baseOverride; }
|
||||
// Return the lowest class extended from, or this class
|
||||
|
|
|
@ -1771,6 +1771,7 @@ void AstClass::dump(std::ostream& str) const {
|
|||
if (useVirtualPublic()) str << " [VIRPUB]";
|
||||
}
|
||||
void AstClass::dumpJson(std::ostream& str) const {
|
||||
// dumpJsonNumFunc(str, declTokenNum); // Not dumped as adding token changes whole file
|
||||
dumpJsonBoolFunc(str, isExtended);
|
||||
dumpJsonBoolFunc(str, isInterfaceClass);
|
||||
dumpJsonBoolFunc(str, isVirtual);
|
||||
|
@ -2161,9 +2162,18 @@ void AstTypedef::dump(std::ostream& str) const {
|
|||
}
|
||||
}
|
||||
void AstTypedef::dumpJson(std::ostream& str) const {
|
||||
// dumpJsonNumFunc(str, declTokenNum); // Not dumped as adding token changes whole file
|
||||
dumpJsonBoolFunc(str, attrPublic);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstTypedefFwd::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << fwdType().ascii() << "]";
|
||||
}
|
||||
void AstTypedefFwd::dumpJson(std::ostream& str) const {
|
||||
dumpJsonStr(str, "fwdType", fwdType().ascii());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstNodeRange::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
void AstRange::dump(std::ostream& str) const {
|
||||
|
|
|
@ -293,6 +293,8 @@ void FileLine::lineDirectiveParse(const char* textp, string& filenameRef, int& l
|
|||
}
|
||||
|
||||
void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) {
|
||||
static int s_tokenNum = 1;
|
||||
m_tokenNum = s_tokenNum++;
|
||||
for (const char* sp = textp; size && *sp; ++sp, --size) {
|
||||
if (*sp == '\n') {
|
||||
if (trackLines) linenoInc();
|
||||
|
|
|
@ -146,7 +146,7 @@ class FileLine final {
|
|||
bool m_waive : 1; // Waive warning - pack next to the line number to save 8 bytes of storage
|
||||
unsigned m_contentLineno : 31; // Line number within source stream
|
||||
// 64-bit word # 1
|
||||
uint32_t m_pad = 0; // space for project coming soon
|
||||
uint32_t m_tokenNum = 0; // Token number in processing order
|
||||
int m_firstLineno = 0; // `line corrected token's first line number
|
||||
// 64-bit word # 2
|
||||
uint32_t m_firstColumn : 24; // `line corrected token's first column number
|
||||
|
@ -197,6 +197,7 @@ public:
|
|||
, m_filenameno{from.m_filenameno}
|
||||
, m_waive{from.m_waive}
|
||||
, m_contentLineno{from.m_contentLineno}
|
||||
, m_tokenNum{from.m_tokenNum}
|
||||
, m_firstLineno{from.m_firstLineno}
|
||||
, m_firstColumn{from.m_firstColumn}
|
||||
, m_lastColumn{from.m_lastColumn}
|
||||
|
@ -210,6 +211,7 @@ public:
|
|||
, m_filenameno{fromp->m_filenameno}
|
||||
, m_waive{fromp->m_waive}
|
||||
, m_contentLineno{fromp->m_contentLineno}
|
||||
, m_tokenNum{fromp->m_tokenNum}
|
||||
, m_firstLineno{fromp->m_firstLineno}
|
||||
, m_firstColumn{fromp->m_firstColumn}
|
||||
, m_lastColumn{fromp->m_lastColumn}
|
||||
|
@ -272,6 +274,7 @@ public:
|
|||
}
|
||||
// Advance last line/column based on given text
|
||||
void forwardToken(const char* textp, size_t size, bool trackLines = true);
|
||||
uint32_t tokenNum() const VL_MT_SAFE { return m_tokenNum; }
|
||||
int firstLineno() const VL_MT_SAFE { return m_firstLineno; }
|
||||
int firstColumn() const VL_MT_SAFE { return static_cast<int>(m_firstColumn); }
|
||||
int lastLineno() const VL_MT_SAFE { return m_firstLineno + m_lastLinenoAdder; }
|
||||
|
@ -386,9 +389,10 @@ public:
|
|||
/// Simplified information vs warnContextPrimary() to make dump clearer
|
||||
string warnContextSecondary() const { return warnContext(); }
|
||||
bool operator==(const FileLine& rhs) const {
|
||||
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
||||
&& m_lastLinenoAdder == rhs.m_lastLinenoAdder && m_lastColumn == rhs.m_lastColumn
|
||||
&& m_filenameno == rhs.m_filenameno && m_msgEnIdx == rhs.m_msgEnIdx);
|
||||
return (m_tokenNum == rhs.m_tokenNum && m_firstLineno == rhs.m_firstLineno
|
||||
&& m_firstColumn == rhs.m_firstColumn && m_lastLinenoAdder == rhs.m_lastLinenoAdder
|
||||
&& m_lastColumn == rhs.m_lastColumn && m_filenameno == rhs.m_filenameno
|
||||
&& m_msgEnIdx == rhs.m_msgEnIdx);
|
||||
}
|
||||
bool equalFirstLineCol(const FileLine& rhs) const {
|
||||
return (m_filenameno == rhs.m_filenameno && m_firstLineno == rhs.m_firstLineno
|
||||
|
@ -408,6 +412,8 @@ public:
|
|||
for (size_t i = 0; i < msgEn().size(); ++i) {
|
||||
if (msgEn().test(i) != rhs.msgEn().test(i)) return rhs.msgEn().test(i) ? -1 : 1;
|
||||
}
|
||||
// TokenNum is compared last as makes more logical sort order by file/line first
|
||||
if (m_tokenNum != rhs.m_tokenNum) return (m_tokenNum < rhs.m_tokenNum) ? -1 : 1;
|
||||
return 0; // (*this) and rhs are equivalent
|
||||
}
|
||||
|
||||
|
|
|
@ -310,6 +310,8 @@ public:
|
|||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< fnodep->warnOther() << "... Location of original declaration\n"
|
||||
<< fnodep->warnContextSecondary());
|
||||
nodep->declTokenNumSetMin(0); // Disable checking forward typedefs
|
||||
fnodep->declTokenNumSetMin(0); // Disable checking forward typedefs
|
||||
} else {
|
||||
nodep->v3error("Unsupported in C: "
|
||||
<< ucfirst(nodeTextType(nodep)) << " has the same name as "
|
||||
|
@ -2063,8 +2065,13 @@ class LinkDotParamVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstTypedefFwd* nodep) override { // ParamVisitor::
|
||||
VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name());
|
||||
if (!foundp && v3Global.opt.pedantic()
|
||||
&& nodep->name() != "process") { // Process is dangling as isn't implemented yet
|
||||
if (foundp) {
|
||||
// If the typedef was earlier in source order (tokenNum), then remember that earlier
|
||||
// point to avoid error something wasn't declared
|
||||
// Might be forward declaring something odd (with declTokenNumSetMin not implemented,
|
||||
// but should be harmless to ignore as this is just for error detection
|
||||
foundp->nodep()->declTokenNumSetMin(nodep->fileline()->tokenNum());
|
||||
} else if (v3Global.opt.pedantic()) {
|
||||
// We only check it was ever really defined in pedantic mode, as it
|
||||
// might have been in a header file referring to a module we never
|
||||
// needed so there are false positives
|
||||
|
@ -2645,6 +2652,23 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
symIterateNull(nodep, m_statep->getNodeSym(nodep));
|
||||
}
|
||||
|
||||
void checkDeclOrder(AstNode* nodep, AstNode* declp) {
|
||||
uint32_t declTokenNum = declp->declTokenNum();
|
||||
if (!declTokenNum) return; // Not implemented/valid on this object
|
||||
if (nodep->fileline()->tokenNum() < declTokenNum) {
|
||||
UINFO(1, "Related node " << nodep->fileline()->tokenNum() << " " << nodep);
|
||||
UINFO(1, "Related decl " << declTokenNum << " " << declp);
|
||||
nodep->v3error("Reference to "
|
||||
<< nodep->prettyNameQ() << " before declaration (IEEE 1800-2023 6.18)\n"
|
||||
<< nodep->warnMore()
|
||||
<< "... Suggest move the declaration before the reference, or use a "
|
||||
"forward typedef\n"
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< declp->warnOther() << "... Location of original declaration\n"
|
||||
<< declp->warnContextSecondary());
|
||||
}
|
||||
}
|
||||
|
||||
void replaceWithCheckBreak(AstNode* oldp, AstNodeDType* newp) {
|
||||
// Flag now to avoid V3Broken throwing an internal error
|
||||
if (oldp->wouldBreak(newp)) {
|
||||
|
@ -3505,6 +3529,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
ok = m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE;
|
||||
if (ok) {
|
||||
AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()};
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be
|
||||
// resolved yet
|
||||
if (m_ds.m_dotPos == DP_NONE) checkDeclOrder(nodep, defp);
|
||||
refp->typedefp(defp);
|
||||
if (VN_IS(nodep->backp(), SelExtract)) {
|
||||
m_packedArrayDtp = refp;
|
||||
|
@ -4551,6 +4578,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
foundp = m_curSymp->findIdFlat(nodep->name());
|
||||
}
|
||||
if (AstTypedef* const defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be resolved
|
||||
// yet
|
||||
if (!nodep->classOrPackagep()) checkDeclOrder(nodep, defp);
|
||||
nodep->typedefp(defp);
|
||||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
} else if (AstParamTypeDType* const defp
|
||||
|
@ -4566,6 +4596,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
}
|
||||
} else if (AstClass* const defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be resolved
|
||||
// yet
|
||||
if (!nodep->classOrPackagep()) checkDeclOrder(nodep, defp);
|
||||
AstPin* const paramsp = nodep->paramsp();
|
||||
if (paramsp) paramsp->unlinkFrBackWithNext();
|
||||
AstClassRefDType* const newp
|
||||
|
|
|
@ -782,19 +782,7 @@ class ParamProcessor final {
|
|||
// Constify may have caused pinp->exprp to change
|
||||
rawTypep = VN_AS(pinp->exprp(), NodeDType);
|
||||
exprp = rawTypep->skipRefToNonRefp();
|
||||
bool ok = true;
|
||||
switch (modvarp->fwdType()) {
|
||||
case VFwdType::NONE: ok = true; break;
|
||||
case VFwdType::ENUM: ok = VN_IS(exprp, EnumDType); break;
|
||||
case VFwdType::STRUCT: ok = VN_IS(exprp, StructDType); break;
|
||||
case VFwdType::UNION: ok = VN_IS(exprp, UnionDType); break;
|
||||
case VFwdType::CLASS: ok = VN_IS(exprp, ClassRefDType); break;
|
||||
case VFwdType::INTERFACE_CLASS: // TODO: Over permissive for now:
|
||||
ok = VN_IS(exprp, ClassRefDType);
|
||||
break;
|
||||
default: modvarp->v3fatalSrc("Bad case");
|
||||
}
|
||||
if (!ok) {
|
||||
if (!modvarp->fwdType().isNodeCompatible(exprp)) {
|
||||
pinp->v3error("Parameter type expression type "
|
||||
<< exprp->prettyDTypeNameQ()
|
||||
<< " violates parameter's forwarding type '"
|
||||
|
|
|
@ -260,7 +260,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
|||
}
|
||||
if (VN_IS(dtypep, ParseTypeDType)) {
|
||||
// Parser needs to know what is a type
|
||||
AstNode* const newp = new AstTypedefFwd{fileline, name};
|
||||
AstNode* const newp = new AstTypedefFwd{fileline, name, VFwdType::NONE};
|
||||
AstNode::addNext<AstNode, AstNode>(nodep, newp);
|
||||
}
|
||||
// Don't set dtypep in the ranging;
|
||||
|
|
|
@ -183,8 +183,8 @@ public:
|
|||
PARSEP->tagNodep(nodep);
|
||||
return nodep;
|
||||
}
|
||||
AstNode* createTypedefFwd(FileLine* fl, const string& name) {
|
||||
AstTypedefFwd* const nodep = new AstTypedefFwd{fl, name};
|
||||
AstNode* createTypedefFwd(FileLine* fl, const string& name, const VFwdType& fwdType) {
|
||||
AstTypedefFwd* const nodep = new AstTypedefFwd{fl, name, fwdType};
|
||||
PARSEP->tagNodep(nodep);
|
||||
return nodep;
|
||||
}
|
||||
|
@ -2695,15 +2695,15 @@ type_declaration<nodep>: // ==IEEE: type_declaration
|
|||
| yTYPEDEF idAny/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';'
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); }
|
||||
// // idAny as also allows redeclaring same typedef again
|
||||
| yTYPEDEF idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>2, *$2); }
|
||||
| yTYPEDEF idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>2, *$2, VFwdType::NONE); }
|
||||
// // IEEE: expanded forward_type to prevent conflict
|
||||
| yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
|
||||
| yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
|
||||
| yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
|
||||
| yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
|
||||
| yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>4, *$4); }
|
||||
| yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3, VFwdType::ENUM); }
|
||||
| yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3, VFwdType::STRUCT); }
|
||||
| yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3, VFwdType::UNION); }
|
||||
| yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3, VFwdType::CLASS); }
|
||||
| yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>4, *$4, VFwdType::INTERFACE_CLASS); }
|
||||
//
|
||||
| yTYPEDEF error idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
|
||||
| yTYPEDEF error idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3, VFwdType::NONE); }
|
||||
;
|
||||
|
||||
dtypeAttrListE<nodep>:
|
||||
|
|
|
@ -534,7 +534,7 @@
|
|||
"childDTypep": [
|
||||
{"type":"PARSETYPEDTYPE","name":"","addr":"(PI)","loc":"d,32:20,32:24","dtypep":"UNLINKED","generic":false}
|
||||
],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"TYPEDEFFWD","name":"T","addr":"(QI)","loc":"d,32:25,32:26"},
|
||||
{"type":"TYPEDEFFWD","name":"T","addr":"(QI)","loc":"d,32:25,32:26","fwdType":"none"},
|
||||
{"type":"VAR","name":"m_bound","addr":"(RI)","loc":"d,33:21,33:28","dtypep":"UNLINKED","origName":"m_bound","isSc":false,"isPrimaryIO":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isUsedClock":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"attrClocker":"UNKNOWN","lifetime":"NONE","varType":"VAR","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED",
|
||||
"childDTypep": [
|
||||
{"type":"BASICDTYPE","name":"int","addr":"(SI)","loc":"d,33:17,33:20","dtypep":"(SI)","keyword":"int","range":"31:0","generic":false,"rangep": []}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/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('linter')
|
||||
|
||||
test.lint()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,42 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// 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
|
||||
|
||||
package P;
|
||||
`ifndef TEST_NO_TYPEDEFS
|
||||
typedef enum enum_t;
|
||||
typedef struct struct_t;
|
||||
typedef union union_t;
|
||||
typedef class ClsB;
|
||||
typedef interface class IfC;
|
||||
typedef generic_t;
|
||||
`endif
|
||||
|
||||
class ClsA;
|
||||
enum_t m_e; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
struct_t m_s; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
union_t m_u; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
ClsB m_b; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
IfC m_i; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
generic_t m_g; // <--- Error need forward decl (if TEST_NO_TYPEDEFS)
|
||||
endclass
|
||||
|
||||
typedef enum {N = 0} enum_t;
|
||||
|
||||
typedef struct packed {int s;} struct_t;
|
||||
typedef union packed {int s;} union_t;
|
||||
|
||||
class ClsB;
|
||||
endclass
|
||||
|
||||
interface class IfC;
|
||||
endclass
|
||||
|
||||
typedef int generic_t;
|
||||
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
endmodule
|
|
@ -0,0 +1,44 @@
|
|||
%Error: t/t_typedef_fwd.v:18:5: Reference to 'enum_t' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
18 | enum_t m_e;
|
||||
| ^~~~~~
|
||||
t/t_typedef_fwd.v:26:24: ... Location of original declaration
|
||||
26 | typedef enum {N = 0} enum_t;
|
||||
| ^~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_typedef_fwd.v:19:5: Reference to 'struct_t' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
19 | struct_t m_s;
|
||||
| ^~~~~~~~
|
||||
t/t_typedef_fwd.v:28:34: ... Location of original declaration
|
||||
28 | typedef struct packed {int s;} struct_t;
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_typedef_fwd.v:20:5: Reference to 'union_t' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
20 | union_t m_u;
|
||||
| ^~~~~~~
|
||||
t/t_typedef_fwd.v:29:33: ... Location of original declaration
|
||||
29 | typedef union packed {int s;} union_t;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_typedef_fwd.v:21:5: Reference to 'ClsB' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
21 | ClsB m_b;
|
||||
| ^~~~
|
||||
t/t_typedef_fwd.v:31:3: ... Location of original declaration
|
||||
31 | class ClsB;
|
||||
| ^~~~~
|
||||
%Error: t/t_typedef_fwd.v:22:5: Reference to 'IfC' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
22 | IfC m_i;
|
||||
| ^~~
|
||||
t/t_typedef_fwd.v:34:13: ... Location of original declaration
|
||||
34 | interface class IfC;
|
||||
| ^~~~~
|
||||
%Error: t/t_typedef_fwd.v:23:5: Reference to 'generic_t' before declaration (IEEE 1800-2023 6.18)
|
||||
: ... Suggest move the declaration before the reference, or use a forward typedef
|
||||
23 | generic_t m_g;
|
||||
| ^~~~~~~~~
|
||||
t/t_typedef_fwd.v:37:15: ... Location of original declaration
|
||||
37 | typedef int generic_t;
|
||||
| ^~~~~~~~~
|
||||
%Error: Exiting due to
|
|
@ -0,0 +1,17 @@
|
|||
#!/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('linter')
|
||||
test.top_filename = 't/t_typedef_fwd.v'
|
||||
|
||||
test.lint(v_flags2=['+define+TEST_NO_TYPEDEFS'], fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
Loading…
Reference in New Issue