Fix missing class forward declarations (#4151)

This commit is contained in:
Krzysztof Boroński 2023-05-22 14:29:01 +02:00 committed by GitHub
parent 8e0682f442
commit de3095e3b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 120 additions and 23 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -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);

View File

@ -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)) {

View File

@ -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;

View File

@ -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