Fix missing class forward declarations (#4151)
This commit is contained in:
parent
8e0682f442
commit
de3095e3b4
|
|
@ -45,12 +45,16 @@ class CUseVisitor final : public VNVisitor {
|
|||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// MEMBERS
|
||||
bool m_impOnly = false; // In details needed only for implementation
|
||||
AstNodeModule* const m_modp; // Current module
|
||||
std::set<std::pair<VUseType, std::string>> m_didUse; // What we already used
|
||||
bool m_dtypesImplOnly = false;
|
||||
|
||||
// METHODS
|
||||
void addNewUse(AstNode* nodep, VUseType useType, const string& name) {
|
||||
if (m_dtypesImplOnly
|
||||
&& (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS))
|
||||
return;
|
||||
|
||||
if (m_didUse.emplace(useType, name).second) {
|
||||
AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name};
|
||||
m_modp->addStmtsp(newp);
|
||||
|
|
@ -61,12 +65,29 @@ class CUseVisitor final : public VNVisitor {
|
|||
// VISITORS
|
||||
void visit(AstClassRefDType* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
|
||||
// Need to include extends() when we implement, but no need for pointers to know
|
||||
VL_RESTORER(m_impOnly);
|
||||
addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateAndNextNull(nodep->argsp());
|
||||
|
||||
{
|
||||
m_impOnly = true;
|
||||
iterateChildren(nodep->classp()); // This also gets all extend classes
|
||||
VL_RESTORER(m_dtypesImplOnly);
|
||||
m_dtypesImplOnly = true;
|
||||
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(nodep->finalsp());
|
||||
}
|
||||
}
|
||||
void visit(AstCReturn* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
if (m_dtypesImplOnly) {
|
||||
for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) {
|
||||
if (exprp->dtypep()) iterate(exprp->dtypep());
|
||||
}
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeDType* nodep) override {
|
||||
|
|
@ -79,6 +100,8 @@ class CUseVisitor final : public VNVisitor {
|
|||
if (stypep && stypep->classOrPackagep()) {
|
||||
addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name());
|
||||
iterateChildren(stypep);
|
||||
} else if (AstClassRefDType* const classp = VN_CAST(nodep->skipRefp(), ClassRefDType)) {
|
||||
addNewUse(nodep, VUseType::INT_FWD_CLASS, classp->name());
|
||||
}
|
||||
}
|
||||
void visit(AstNode* nodep) override {
|
||||
|
|
|
|||
|
|
@ -224,21 +224,12 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) {
|
|||
}
|
||||
|
||||
void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) {
|
||||
string nl;
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
if (usep->useType() == useType) {
|
||||
if (usep->useType().isInclude()) {
|
||||
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
|
||||
}
|
||||
if (usep->useType().isFwdClass()) {
|
||||
puts("class " + prefixNameProtect(usep) + ";\n");
|
||||
}
|
||||
nl = "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
puts(nl);
|
||||
bool nl = false;
|
||||
forModCUse(modp, useType, [&](string entry) {
|
||||
puts(entry);
|
||||
nl = true;
|
||||
});
|
||||
if (nl) puts("\n");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,21 @@ public:
|
|||
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
|
||||
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
|
||||
void emitVarDecl(const AstVar* nodep, bool asRef = false);
|
||||
template <typename F>
|
||||
static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) {
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
if (usep->useType() == useType) {
|
||||
if (usep->useType().isInclude()) {
|
||||
action("#include \"" + prefixNameProtect(usep) + ".h\"\n");
|
||||
}
|
||||
if (usep->useType().isFwdClass()) {
|
||||
action("class " + prefixNameProtect(usep) + ";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void emitModCUse(const AstNodeModule* modp, VUseType useType);
|
||||
void emitTextSection(const AstNodeModule* modp, VNType type);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
|
@ -287,11 +288,9 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
+ ".h\"\n");
|
||||
}
|
||||
}
|
||||
emitModCUse(modp, VUseType::INT_INCLUDE);
|
||||
|
||||
// Forward declarations required by this AstNodeModule
|
||||
puts("\nclass " + symClassName() + ";\n");
|
||||
emitModCUse(modp, VUseType::INT_FWD_CLASS);
|
||||
|
||||
// From `systemc_header
|
||||
emitTextSection(modp, VNType::atScHdr);
|
||||
|
|
@ -361,6 +360,19 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n");
|
||||
if (v3Global.usesTiming()) puts("#include \"verilated_timing.h\"\n");
|
||||
|
||||
std::set<string> cuse_set;
|
||||
auto add_to_cuse_set = [&](string s) { cuse_set.insert(s); };
|
||||
|
||||
forModCUse(modp, VUseType::INT_INCLUDE, add_to_cuse_set);
|
||||
forModCUse(modp, VUseType::INT_FWD_CLASS, add_to_cuse_set);
|
||||
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
|
||||
forModCUse(packagep->classp(), VUseType::INT_INCLUDE, add_to_cuse_set);
|
||||
forModCUse(packagep->classp(), VUseType::INT_FWD_CLASS, add_to_cuse_set);
|
||||
}
|
||||
|
||||
for (const string& s : cuse_set) puts(s);
|
||||
puts("\n");
|
||||
|
||||
emitAll(modp);
|
||||
|
||||
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2023 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(vlt => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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 Baz;
|
||||
endclass
|
||||
|
||||
class Bar#(type T) extends T;
|
||||
endclass
|
||||
|
||||
class Foo;
|
||||
typedef struct {
|
||||
int field;
|
||||
} Zee;
|
||||
|
||||
task t1();
|
||||
// Refer to Baz CLASSREFDTYPE node in implementation (via CLASSEXTENDS)
|
||||
Bar#(Baz) b = new;
|
||||
endtask
|
||||
// Refer to the very same Baz CLASSREFDTYPE node again, this time within interface
|
||||
task t2(Bar#(Baz)::T b);
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class Moo;
|
||||
// Use Foo::Zee to cause inclusion of Foo's header file
|
||||
Foo::Zee z;
|
||||
endclass
|
||||
|
||||
module t();
|
||||
initial begin
|
||||
// Use Moo in top module to add Moo to root, causing inclusion of Foo header into
|
||||
// root header.
|
||||
Moo moo;
|
||||
moo = new;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue