Fix selects of static members (#4326)
This commit is contained in:
parent
32019d2bc4
commit
242f661644
|
|
@ -1428,6 +1428,7 @@ class AstMemberSel final : public AstNodeExpr {
|
||||||
// @astgen op1 := fromp : AstNodeExpr
|
// @astgen op1 := fromp : AstNodeExpr
|
||||||
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
||||||
string m_name;
|
string m_name;
|
||||||
|
VAccess m_access; // Read or write, as in AstNodeVarRef
|
||||||
AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection
|
AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection
|
||||||
public:
|
public:
|
||||||
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name)
|
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name)
|
||||||
|
|
@ -1448,10 +1449,12 @@ public:
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
void name(const string& name) override { m_name = name; }
|
void name(const string& name) override { m_name = name; }
|
||||||
|
VAccess access() const { return m_access; }
|
||||||
|
void access(const VAccess& flag) { m_access = flag; }
|
||||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
bool cleanOut() const override { return true; }
|
bool cleanOut() const override { return true; }
|
||||||
bool same(const AstNode* samep) const override { return true; } // dtype comparison does it
|
bool same(const AstNode* samep) const override;
|
||||||
int instrCount() const override { return widthInstrs(); }
|
int instrCount() const override { return widthInstrs(); }
|
||||||
AstVar* varp() const { return m_varp; }
|
AstVar* varp() const { return m_varp; }
|
||||||
void varp(AstVar* nodep) { m_varp = nodep; }
|
void varp(AstVar* nodep) { m_varp = nodep; }
|
||||||
|
|
|
||||||
|
|
@ -1676,6 +1676,12 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
|
||||||
return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr
|
return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AstMemberSel::same(const AstNode* samep) const {
|
||||||
|
const AstMemberSel* const sp = static_cast<const AstMemberSel*>(samep);
|
||||||
|
return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
|
||||||
|
&& name() == sp->name() && varp()->same(sp->varp());
|
||||||
|
}
|
||||||
|
|
||||||
void AstMemberSel::dump(std::ostream& str) const {
|
void AstMemberSel::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,16 @@ private:
|
||||||
iterateAndNextNull(nodep->thsp());
|
iterateAndNextNull(nodep->thsp());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void visit(AstMemberSel* nodep) override {
|
||||||
|
if (m_setRefLvalue != VAccess::NOCHANGE) {
|
||||||
|
nodep->access(m_setRefLvalue);
|
||||||
|
} else {
|
||||||
|
// It is the only place where the access is set to member select nodes.
|
||||||
|
// If it doesn't have to be set to WRITE, it means that it is READ.
|
||||||
|
nodep->access(VAccess::READ);
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
VL_RESTORER(m_ftaskp);
|
VL_RESTORER(m_ftaskp);
|
||||||
m_ftaskp = nodep;
|
m_ftaskp = nodep;
|
||||||
|
|
|
||||||
|
|
@ -2710,31 +2710,7 @@ private:
|
||||||
if (AstNodeUOrStructDType* const adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) {
|
if (AstNodeUOrStructDType* const adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) {
|
||||||
if (memberSelStruct(nodep, adtypep)) return;
|
if (memberSelStruct(nodep, adtypep)) return;
|
||||||
} else if (AstClassRefDType* const adtypep = VN_CAST(fromDtp, ClassRefDType)) {
|
} else if (AstClassRefDType* const adtypep = VN_CAST(fromDtp, ClassRefDType)) {
|
||||||
if (AstNode* const foundp = memberSelClass(nodep, adtypep)) {
|
if (memberSelClass(nodep, adtypep)) return;
|
||||||
if (AstVar* const varp = VN_CAST(foundp, Var)) {
|
|
||||||
if (!varp->didWidth()) userIterate(varp, nullptr);
|
|
||||||
nodep->dtypep(foundp->dtypep());
|
|
||||||
nodep->varp(varp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) {
|
|
||||||
nodep->replaceWith(adfoundp->cloneTree(false));
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) {
|
|
||||||
nodep->replaceWith(new AstMethodCall{nodep->fileline(),
|
|
||||||
nodep->fromp()->unlinkFrBack(),
|
|
||||||
nodep->name(), nullptr});
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UINFO(1, "found object " << foundp << endl);
|
|
||||||
nodep->v3fatalSrc("MemberSel of non-variable\n"
|
|
||||||
<< nodep->warnContextPrimary() << '\n'
|
|
||||||
<< foundp->warnOther() << "... Location of found object\n"
|
|
||||||
<< foundp->warnContextSecondary());
|
|
||||||
}
|
|
||||||
} else if (AstIfaceRefDType* const adtypep = VN_CAST(fromDtp, IfaceRefDType)) {
|
} else if (AstIfaceRefDType* const adtypep = VN_CAST(fromDtp, IfaceRefDType)) {
|
||||||
if (AstNode* const foundp = memberSelIface(nodep, adtypep)) {
|
if (AstNode* const foundp = memberSelIface(nodep, adtypep)) {
|
||||||
if (AstVar* const varp = VN_CAST(foundp, Var)) {
|
if (AstVar* const varp = VN_CAST(foundp, Var)) {
|
||||||
|
|
@ -2773,15 +2749,50 @@ private:
|
||||||
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
}
|
}
|
||||||
AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) {
|
bool memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) {
|
||||||
// Returns node if ok
|
// Returns true if ok
|
||||||
// No need to width-resolve the class, as it was done when we did the child
|
// No need to width-resolve the class, as it was done when we did the child
|
||||||
AstClass* const first_classp = adtypep->classp();
|
AstClass* const first_classp = adtypep->classp();
|
||||||
UASSERT_OBJ(first_classp, nodep, "Unlinked");
|
UASSERT_OBJ(first_classp, nodep, "Unlinked");
|
||||||
for (AstClass* classp = first_classp; classp;) {
|
for (AstClass* classp = first_classp; classp;) {
|
||||||
if (AstNode* const foundp = classp->findMember(nodep->name())) return foundp;
|
if (AstNode* const foundp = classp->findMember(nodep->name())) {
|
||||||
|
if (AstVar* const varp = VN_CAST(foundp, Var)) {
|
||||||
|
if (!varp->didWidth()) userIterate(varp, nullptr);
|
||||||
|
if (varp->lifetime().isStatic()) {
|
||||||
|
// Static fiels are moved outside the class, so they shouldn't be accessed
|
||||||
|
// by member select on a class object
|
||||||
|
AstVarRef* const varRefp
|
||||||
|
= new AstVarRef{nodep->fileline(), varp, nodep->access()};
|
||||||
|
varRefp->classOrPackagep(classp);
|
||||||
|
nodep->replaceWith(varRefp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
nodep->dtypep(foundp->dtypep());
|
||||||
|
nodep->varp(varp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) {
|
||||||
|
nodep->replaceWith(adfoundp->cloneTree(false));
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) {
|
||||||
|
nodep->replaceWith(new AstMethodCall{nodep->fileline(),
|
||||||
|
nodep->fromp()->unlinkFrBack(),
|
||||||
|
nodep->name(), nullptr});
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
UINFO(1, "found object " << foundp << endl);
|
||||||
|
nodep->v3fatalSrc("MemberSel of non-variable\n"
|
||||||
|
<< nodep->warnContextPrimary() << '\n'
|
||||||
|
<< foundp->warnOther() << "... Location of found object\n"
|
||||||
|
<< foundp->warnContextSecondary());
|
||||||
|
}
|
||||||
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
|
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VSpellCheck speller;
|
VSpellCheck speller;
|
||||||
for (AstClass* classp = first_classp; classp;) {
|
for (AstClass* classp = first_classp; classp;) {
|
||||||
for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
|
for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
|
||||||
|
|
@ -2796,7 +2807,7 @@ private:
|
||||||
"Member " << nodep->prettyNameQ() << " not found in class "
|
"Member " << nodep->prettyNameQ() << " not found in class "
|
||||||
<< first_classp->prettyNameQ() << "\n"
|
<< first_classp->prettyNameQ() << "\n"
|
||||||
<< (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
|
<< (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
|
||||||
return nullptr; // Caller handles error
|
return false; // Caller handles error
|
||||||
}
|
}
|
||||||
AstNode* memberSelIface(AstMemberSel* nodep, AstIfaceRefDType* adtypep) {
|
AstNode* memberSelIface(AstMemberSel* nodep, AstIfaceRefDType* adtypep) {
|
||||||
// Returns node if ok
|
// Returns node if ok
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
static int x = 1;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
Foo f;
|
||||||
|
function new;
|
||||||
|
f = new;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Baz;
|
||||||
|
function static Bar get_bar;
|
||||||
|
Bar b = new;
|
||||||
|
return b;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class IntWrapper;
|
||||||
|
int x;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
static IntWrapper iw;
|
||||||
|
function new;
|
||||||
|
if (iw == null) iw = new;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class ExtendCls extends Cls;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Getter1;
|
||||||
|
function static int get_1;
|
||||||
|
return 1;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Foo foo = new;
|
||||||
|
Bar bar = new;
|
||||||
|
Baz baz = new;
|
||||||
|
ExtendCls ec = new;
|
||||||
|
Getter1 getter1 = new;
|
||||||
|
|
||||||
|
if (foo.x != 1) $stop;
|
||||||
|
|
||||||
|
foo.x = 2;
|
||||||
|
if (foo.x != 2) $stop;
|
||||||
|
|
||||||
|
bar.f.x = 3;
|
||||||
|
if (bar.f.x != 3) $stop;
|
||||||
|
|
||||||
|
baz.get_bar().f.x = 4;
|
||||||
|
if (baz.get_bar().f.x != 4) $stop;
|
||||||
|
|
||||||
|
ec.iw.x = 5;
|
||||||
|
if (ec.iw.x != 5) $stop;
|
||||||
|
|
||||||
|
if (getter1.get_1 != 1) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue