Support parameterized class references in extends statement (#4146)
This commit is contained in:
parent
621b7e63cf
commit
ee5c0a2902
|
|
@ -3287,7 +3287,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstClass* nodep) override {
|
||||
nodep->user3SetOnce();
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(5, " " << nodep << endl);
|
||||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_curSymp);
|
||||
|
|
@ -3300,117 +3300,116 @@ private:
|
|||
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
|
||||
m_modp = nodep;
|
||||
int next = 0;
|
||||
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstClassExtends* const cextp = VN_CAST(itemp, ClassExtends)) {
|
||||
// Replace abstract reference with hard pointer
|
||||
// Will need later resolution when deal with parameters
|
||||
if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) {
|
||||
cextp->v3error("Multiple inheritance illegal on non-interface classes"
|
||||
" (IEEE 1800-2017 8.13)");
|
||||
}
|
||||
if (cextp->childDTypep() || cextp->dtypep()) {
|
||||
// Already converted. Update symbol table to link unlinked members
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
continue;
|
||||
}
|
||||
AstNode* cprp = cextp->classOrPkgsp();
|
||||
VSymEnt* lookSymp = m_curSymp;
|
||||
if (AstDot* const dotp = VN_CAST(cextp->classOrPkgsp(), Dot)) {
|
||||
dotp->user3(true);
|
||||
if (AstClassOrPackageRef* lookNodep
|
||||
= VN_CAST(dotp->lhsp(), ClassOrPackageRef)) {
|
||||
iterate(lookNodep);
|
||||
cprp = dotp->rhsp();
|
||||
lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep());
|
||||
} else {
|
||||
dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE
|
||||
" using non-class under dot");
|
||||
}
|
||||
}
|
||||
AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef);
|
||||
if (VL_UNCOVERABLE(!cpackagerefp)) {
|
||||
// Linking the extend gives an error before this is hit
|
||||
cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE
|
||||
for (AstClassExtends* cextp = nodep->extendsp(); cextp;
|
||||
cextp = VN_AS(cextp->nextp(), ClassExtends)) {
|
||||
// Replace abstract reference with hard pointer
|
||||
// Will need later resolution when deal with parameters
|
||||
if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) {
|
||||
cextp->v3error("Multiple inheritance illegal on non-interface classes"
|
||||
" (IEEE 1800-2017 8.13)");
|
||||
}
|
||||
if (cextp->childDTypep() || cextp->dtypep()) {
|
||||
// Already converted. Update symbol table to link unlinked members.
|
||||
// Base class has to be visited in a case if its extends statement
|
||||
// needs to be handled. Recursive inheritance was already checked.
|
||||
iterate(cextp->classp());
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
continue;
|
||||
}
|
||||
AstNode* cprp = cextp->classOrPkgsp();
|
||||
VSymEnt* lookSymp = m_curSymp;
|
||||
if (AstDot* const dotp = VN_CAST(cprp, Dot)) {
|
||||
dotp->user3(true);
|
||||
if (AstClassOrPackageRef* lookNodep
|
||||
= VN_CAST(dotp->lhsp(), ClassOrPackageRef)) {
|
||||
iterate(lookNodep);
|
||||
cprp = dotp->rhsp();
|
||||
lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep());
|
||||
} else {
|
||||
VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name());
|
||||
if (foundp) {
|
||||
AstClassRefDType* classRefDtypep = nullptr;
|
||||
AstClass* classp = VN_CAST(foundp->nodep(), Class);
|
||||
if (classp) {
|
||||
if (classp != nodep) {
|
||||
// Case with recursive inheritance is handled later in this
|
||||
// function
|
||||
iterate(classp);
|
||||
}
|
||||
if (m_statep->forPrimary()
|
||||
&& m_extendsParam.find(classp) != m_extendsParam.end()) {
|
||||
// Has a parameter as its base class
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
}
|
||||
AstPin* paramsp = cpackagerefp->paramsp();
|
||||
if (paramsp) paramsp = paramsp->cloneTree(true);
|
||||
classRefDtypep
|
||||
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
|
||||
} else if (AstParamTypeDType* const paramp
|
||||
= VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
||||
if (m_statep->forPrimary()) {
|
||||
// Extending has to be handled after V3Param.cpp
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
continue;
|
||||
} else {
|
||||
AstNodeDType* const paramTypep = paramp->subDTypep();
|
||||
classRefDtypep
|
||||
= VN_CAST(paramTypep->cloneTree(false), ClassRefDType);
|
||||
if (!classRefDtypep) {
|
||||
paramTypep->v3error(
|
||||
"Attempting to extend using non-class");
|
||||
} else {
|
||||
classp = classRefDtypep->classp();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cextp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: " << foundp->nodep()->prettyTypeName()
|
||||
<< " in AstClassExtends");
|
||||
dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE
|
||||
" using non-class under dot");
|
||||
}
|
||||
}
|
||||
AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef);
|
||||
if (VL_UNCOVERABLE(!cpackagerefp)) {
|
||||
// Linking the extend gives an error before this is hit
|
||||
cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name());
|
||||
if (foundp) {
|
||||
AstClassRefDType* classRefDtypep = nullptr;
|
||||
AstClass* classp = VN_CAST(foundp->nodep(), Class);
|
||||
if (classp) {
|
||||
if (classp != nodep) {
|
||||
// Case with recursive inheritance is handled later in this
|
||||
// function
|
||||
iterate(classp);
|
||||
}
|
||||
|
||||
if (classp) {
|
||||
UINFO(8, "Import to " << nodep << " from export class " << classp
|
||||
<< endl);
|
||||
if (classp == nodep) {
|
||||
cextp->v3error("Attempting to extend class "
|
||||
<< nodep->prettyNameQ() << " from itself");
|
||||
} else if (cextp->isImplements() && !classp->isInterfaceClass()) {
|
||||
cextp->v3error(
|
||||
"Attempting to implement from non-interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'extends'");
|
||||
} else if (!cextp->isImplements() && !nodep->isInterfaceClass()
|
||||
&& classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to extend from interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'implements'");
|
||||
if (m_statep->forPrimary()
|
||||
&& m_extendsParam.find(classp) != m_extendsParam.end()) {
|
||||
// Has a parameter as its base class
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
}
|
||||
AstPin* paramsp = cpackagerefp->paramsp();
|
||||
if (paramsp) paramsp = paramsp->cloneTree(true);
|
||||
classRefDtypep
|
||||
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
|
||||
} else if (AstParamTypeDType* const paramp
|
||||
= VN_CAST(foundp->nodep(), ParamTypeDType)) {
|
||||
if (m_statep->forPrimary()) {
|
||||
// Extending has to be handled after V3Param.cpp
|
||||
m_extendsParam.insert(nodep);
|
||||
m_insideClassExtParam = true;
|
||||
continue;
|
||||
} else {
|
||||
AstNodeDType* const paramTypep = paramp->subDTypep();
|
||||
classRefDtypep
|
||||
= VN_CAST(paramTypep->cloneTree(false), ClassRefDType);
|
||||
if (!classRefDtypep) {
|
||||
paramTypep->v3error("Attempting to extend using non-class");
|
||||
} else {
|
||||
cextp->childDTypep(classRefDtypep);
|
||||
classp->isExtended(true);
|
||||
nodep->isExtended(true);
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
VL_DO_DANGLING(
|
||||
cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(),
|
||||
cpackagerefp);
|
||||
classp = classRefDtypep->classp();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const string suggest = m_statep->suggestSymFallback(
|
||||
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
|
||||
cpackagerefp->v3error(
|
||||
"Class for '"
|
||||
<< cextp->verilogKwd() // extends/implements
|
||||
<< "' not found: " << cpackagerefp->prettyNameQ() << '\n'
|
||||
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
|
||||
cextp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: " << foundp->nodep()->prettyTypeName()
|
||||
<< " in AstClassExtends");
|
||||
}
|
||||
|
||||
if (classp) {
|
||||
UINFO(8, "Import to " << nodep << " from export class " << classp
|
||||
<< endl);
|
||||
if (classp == nodep) {
|
||||
cextp->v3error("Attempting to extend class "
|
||||
<< nodep->prettyNameQ() << " from itself");
|
||||
} else if (cextp->isImplements() && !classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to implement from non-interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'extends'");
|
||||
} else if (!cextp->isImplements() && !nodep->isInterfaceClass()
|
||||
&& classp->isInterfaceClass()) {
|
||||
cextp->v3error("Attempting to extend from interface class "
|
||||
<< classp->prettyNameQ() << '\n'
|
||||
<< "... Suggest use 'implements'");
|
||||
} else {
|
||||
cextp->childDTypep(classRefDtypep);
|
||||
classp->isExtended(true);
|
||||
nodep->isExtended(true);
|
||||
importSymbolsFromExtended(nodep, cextp);
|
||||
VL_DO_DANGLING(cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(),
|
||||
cpackagerefp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const string suggest = m_statep->suggestSymFallback(
|
||||
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
|
||||
cpackagerefp->v3error(
|
||||
"Class for '"
|
||||
<< cextp->verilogKwd() // extends/implements
|
||||
<< "' not found: " << cpackagerefp->prettyNameQ() << '\n'
|
||||
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,17 +39,51 @@ module t (/*AUTOARG*/
|
|||
endfunction
|
||||
endclass
|
||||
|
||||
class ExtendBar1 extends Bar #(Foo);
|
||||
function int get_x;
|
||||
return super.get_x();
|
||||
endfunction
|
||||
function int get_6;
|
||||
return 2 * get_3();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class ExtendBarBaz extends Bar #(Baz);
|
||||
function int get_x;
|
||||
return super.get_x();
|
||||
endfunction
|
||||
function int get_8;
|
||||
return 2 * get_4();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class ExtendExtendBar extends ExtendBar;
|
||||
function int get_12;
|
||||
return 4 * get_3();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
Bar #() bar_foo_i;
|
||||
Bar #(Baz) bar_baz_i;
|
||||
ExtendBar extend_bar_i;
|
||||
ExtendBar1 extend_bar1_i;
|
||||
ExtendBarBaz extend_bar_baz_i;
|
||||
ExtendExtendBar extend_extend_bar_i;
|
||||
|
||||
initial begin
|
||||
bar_foo_i = new;
|
||||
bar_baz_i = new;
|
||||
extend_bar_i = new;
|
||||
extend_bar1_i = new;
|
||||
extend_bar_baz_i = new;
|
||||
extend_extend_bar_i = new;
|
||||
if (bar_foo_i.get_x() == 1 && bar_foo_i.get_3() == 3 &&
|
||||
bar_baz_i.get_x() == 2 && bar_baz_i.get_4() == 4 &&
|
||||
extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6) begin
|
||||
extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 &&
|
||||
extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 &&
|
||||
extend_bar1_i.get_x() == 1 && extend_bar1_i.get_6() == 6 &&
|
||||
extend_bar_baz_i.get_x() == 2 && extend_bar_baz_i.get_8() == 8 &&
|
||||
extend_extend_bar_i.get_x() == 1 && extend_extend_bar_i.get_12() == 12) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue