Support local and protected on typedef (#5460).

This commit is contained in:
Wilson Snyder 2024-10-06 18:08:40 -04:00
parent bc8a332ee8
commit 28ecd8e908
12 changed files with 104 additions and 22 deletions

View File

@ -30,6 +30,7 @@ Verilator 5.029 devel
* Support inside array constraints (#5448). [Arkadiusz Kozdra, Antmicro Ltd.]
* Support DPI imports and exports with double underscores (#5481).
* Support ccache when compiling Verilated files with cmake.
* Support `local` and `protected` on `typedef` (#5460).
* Add error on misused genvar (#408). [Alex Solomatnikov]
* Add error on instances without parenthesis.
* Add Docker pre-commit hook (#5238) (#5452). [Chris Bachhuber]

View File

@ -1714,12 +1714,16 @@ class AstTypedef final : public AstNode {
string m_name;
string m_tag; // Holds the string of the verilator tag -- used in XML output.
bool m_attrPublic = false;
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
public:
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType,
AstNodeDType* dtp)
: ASTGEN_SUPER_Typedef(fl)
, m_name{name} {
, m_name{name}
, m_isHideLocal{false}
, m_isHideProtected{false} {
childDTypep(dtp); // Only for parser
addAttrsp(attrsp);
dtypep(nullptr); // V3Width will resolve
@ -1738,6 +1742,10 @@ public:
void name(const string& flag) override { m_name = flag; }
bool attrPublic() const { return m_attrPublic; }
void attrPublic(bool flag) { m_attrPublic = flag; }
bool isHideLocal() const { return m_isHideLocal; }
void isHideLocal(bool flag) { m_isHideLocal = flag; }
bool isHideProtected() const { return m_isHideProtected; }
void isHideProtected(bool flag) { m_isHideProtected = flag; }
void tag(const string& text) override { m_tag = text; }
string tag() const override { return m_tag; }
};

View File

@ -2031,9 +2031,10 @@ void AstRefDType::dump(std::ostream& str) const {
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
str << " -> ";
if (const auto subp = typedefp()) {
if (const auto subp = subDTypep()) {
if (typedefp()) str << "typedef=" << static_cast<void*>(typedefp())<< " -> ";
subp->dump(str);
} else if (const auto subp = subDTypep()) {
} else if (const auto subp = typedefp()) {
subp->dump(str);
}
s_recursing = false;

View File

@ -74,11 +74,19 @@ struct VMemberQualifiers final {
if (m_static) nodep->isStatic(true);
if (m_virtual) nodep->isVirtual(true);
if (m_const || m_rand || m_randc) {
nodep->v3error("Syntax error: 'const'/'rand'/'randc' not allowed before "
"function/task declaration");
nodep->v3error("Syntax error: 'const'/'rand'/'randc' not allowed "
"before function/task declaration");
}
}
}
void applyToNodes(AstTypedef* nodep) const {
if (m_local) nodep->isHideLocal(true);
if (m_protected) nodep->isHideProtected(true);
if (m_static || m_virtual || m_rand || m_randc) {
nodep->v3error("Syntax error: 'static'/'virtual'/'rand'/'randc' not allowed "
"before typedef declaration");
}
}
void applyToNodes(AstVar* nodesp) const {
for (AstVar* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), Var)) {
if (m_rand) nodep->rand(VRandAttr::RAND);

View File

@ -1853,13 +1853,11 @@ class WidthVisitor final : public VNVisitor {
if (AstNodeDType* typeofDtp = VN_CAST(nodep->typeofp(), NodeDType)) {
// It's directly a type, e.g. "type(int)"
typeofDtp = iterateEditMoveDTypep(nodep, typeofDtp); // Changes typeofp
nodep->typedefp(nullptr);
nodep->refDTypep(typeofDtp);
} else {
// Type comes from expression's type, e.g. "type(variable)"
userIterateAndNext(nodep->typeofp(), WidthVP{SELF, BOTH}.p());
AstNode* const typeofp = nodep->typeofp();
nodep->typedefp(nullptr);
nodep->refDTypep(typeofp->dtypep());
VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp);
}
@ -1873,7 +1871,6 @@ class WidthVisitor final : public VNVisitor {
// this node's childDTypep
userIterate(nodep->subDTypep(), nullptr);
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->typedefp(nullptr); // Note until line above subDTypep() may have followed this
// Widths are resolved, but special iterate to check for recursion
userIterate(nodep->subDTypep(), nullptr);
}
@ -1883,6 +1880,7 @@ class WidthVisitor final : public VNVisitor {
nodep->dtypeFrom(nodep->subDTypep());
nodep->widthFromSub(nodep->subDTypep());
UINFO(4, "dtWidthed " << nodep << endl);
// No nodep->typedefp(nullptr) for now; V3WidthCommit needs to check accesses
nodep->doingWidth(false);
}
void visit(AstTypedef* nodep) override {

View File

@ -85,12 +85,15 @@ private:
"Only rand_mode() and constraint_mode() can have no def");
return;
}
if (const auto varp = VN_CAST(defp, Var)) {
local = varp->isHideLocal();
prot = varp->isHideProtected();
} else if (const auto ftaskp = VN_CAST(defp, NodeFTask)) {
local = ftaskp->isHideLocal();
prot = ftaskp->isHideProtected();
if (const auto anodep = VN_CAST(defp, Var)) {
local = anodep->isHideLocal();
prot = anodep->isHideProtected();
} else if (const auto anodep = VN_CAST(defp, NodeFTask)) {
local = anodep->isHideLocal();
prot = anodep->isHideProtected();
} else if (const auto anodep = VN_CAST(defp, Typedef)) {
local = anodep->isHideLocal();
prot = anodep->isHideProtected();
} else {
nodep->v3fatalSrc("ref to unhandled definition type " << defp->prettyTypeName());
}
@ -178,6 +181,12 @@ private:
nodep->unlinkFrBack(); // Make non-child
v3Global.rootp()->typeTablep()->addTypesp(nodep);
}
void visit(AstRefDType* nodep) override {
visitIterateNodeDType(nodep);
if (!nodep->typedefp()) return; // Already checked and cleared
classEncapCheck(nodep, nodep->typedefp(), VN_CAST(nodep->classOrPackagep(), Class));
nodep->typedefp(nullptr); // No longer needed
}
void visitIterateNodeDType(AstNodeDType* nodep) {
// Rather than use dtypeChg which may make new nodes, we edit in place,
// as we don't need to preserve any widthMin's, and every dtype with the same width

View File

@ -186,14 +186,14 @@ public:
}
AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep,
AstNodeRange* rangep) {
AstNode* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{},
AstTypedef* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{},
GRAMMARP->createArray(basep, rangep, false)};
SYMP->reinsert(nodep);
PARSEP->tagNodep(nodep);
return nodep;
}
AstNode* createTypedefFwd(FileLine* fl, const string& name) {
AstNode* const nodep = new AstTypedefFwd{fl, name};
AstTypedefFwd* const nodep = new AstTypedefFwd{fl, name};
SYMP->reinsert(nodep);
PARSEP->tagNodep(nodep);
return nodep;
@ -2479,11 +2479,13 @@ data_declaration<nodep>: // ==IEEE: data_declaration
;
class_property<nodep>: // ==IEEE: class_property, which is {property_qualifier} data_declaration
memberQualListE data_declarationVarClass { $$ = $2; $1.applyToNodes($2); }
memberQualListE data_declarationVarClass
{ $$ = $2; $1.applyToNodes($2); }
| memberQualListE type_declaration
{ $$ = $2; if (VN_IS($2, Typedef)) $1.applyToNodes(VN_AS($2, Typedef)); }
// // UNSUP: Import needs to apply local/protected from memberQualList, and error on others
| memberQualListE type_declaration { $$ = $2; }
// // UNSUP: Import needs to apply local/protected from memberQualList, and error on others
| memberQualListE package_import_declaration { $$ = $2; }
| memberQualListE package_import_declaration
{ $$ = $2; }
// // IEEE: virtual_interface_declaration
// // "yVIRTUAL yID yID" looks just like a data_declaration
// // Therefore the virtual_interface_declaration term isn't used

View File

@ -0,0 +1,14 @@
%Error-ENCAPSULATED: t/t_class_local_typedef_bad.v:13:8: 't1' is hidden as 'local' within this context (IEEE 1800-2023 8.18)
13 | Cls::t1 var1;
| ^~
t/t_class_local_typedef_bad.v:13:8: ... Location of definition
9 | local typedef bit t1;
| ^~
... For error description see https://verilator.org/warn/ENCAPSULATED?v=latest
%Error-ENCAPSULATED: t/t_class_local_typedef_bad.v:14:8: 't2' is hidden as 'protected' within this context (IEEE 1800-2023 8.18)
14 | Cls::t2 var2;
| ^~
t/t_class_local_typedef_bad.v:14:8: ... Location of definition
10 | protected typedef bit t2;
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/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')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,16 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t;
class Cls;
local typedef bit t1;
protected typedef bit t2;
endclass
Cls::t1 var1; // BAD: access error expected
Cls::t2 var2; // BAD: access error expected
endmodule

View File

@ -1,4 +1,10 @@
%Error: t/t_class_unsup_bad.v:28:24: Syntax error: 'const'/'rand'/'randc' not allowed before function/task declaration
28 | const function void func_const; endfunction
%Error: t/t_class_unsup_bad.v:24:21: Syntax error: 'static'/'virtual'/'rand'/'randc' not allowed before typedef declaration
24 | rand typedef int irand_t;
| ^~~~~~~
%Error: t/t_class_unsup_bad.v:25:22: Syntax error: 'static'/'virtual'/'rand'/'randc' not allowed before typedef declaration
25 | randc typedef int icrand_t;
| ^~~~~~~~
%Error: t/t_class_unsup_bad.v:31:24: Syntax error: 'const'/'rand'/'randc' not allowed before function/task declaration
31 | const function void func_const; endfunction
| ^~~~~~~~~~
%Error: Exiting due to

View File

@ -21,6 +21,9 @@ class C #(parameter P=1);
rand int irand;
randc int icrand;
rand typedef int irand_t;
randc typedef int icrand_t;
task classtask; endtask
function int classfunc; endfunction
virtual function void func_virtual; endfunction