Fix functions in generate block resulting in "Broken link in node" (#7236) (#7367)

Fixes #7236
This commit is contained in:
em2machine 2026-04-03 11:19:17 -04:00 committed by GitHub
parent 56ed47ee7c
commit e7a644a3fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 77 additions and 0 deletions

View File

@ -233,6 +233,7 @@ private:
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
bool m_pli = false; // Pli system call ($name)
bool m_containsGenBlock = false; // Contains gen block reference
VIsCached m_purity; // Pure state
protected:
@ -259,6 +260,8 @@ public:
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
bool containsGenBlock() const { return m_containsGenBlock; }
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
bool isPure() override;
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }

View File

@ -3111,6 +3111,7 @@ void AstActive::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
if (containsGenBlock()) str << " [GENBLK]";
str << " -> ";
if (dotted() != "") str << ".=" << dotted() << " ";
if (taskp()) {
@ -3121,6 +3122,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
}
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
dumpJsonStrFunc(str, dotted);
dumpJsonBoolFuncIf(str, containsGenBlock);
dumpJsonGen(str);
}
void AstNodeFTask::dump(std::ostream& str) const {

View File

@ -5067,6 +5067,17 @@ class LinkDotResolveVisitor final : public VNVisitor {
m_ds.m_dotPos = DP_MEMBER;
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
nodep->dotted(m_ds.m_dotText); // Maybe ""
// Only flag FTaskRefs under generate-if/case blocks that may be
// pruned. GenFor and plain begin-blocks won't be pruned by V3Param.
// VarXRef uses the broader m_genBlk flag (set for all GenBlocks)
// because genfor unrolling also removes variables.
if (m_ds.m_genBlk && m_ds.m_dotSymp) {
const AstNode* const blkp = m_ds.m_dotSymp->nodep();
if (VN_IS(blkp, GenBlock)
&& (VN_IS(blkp->backp(), GenIf) || VN_IS(blkp->backp(), GenCase))) {
nodep->containsGenBlock(true);
}
}
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is method call.
// {scope}.{var}.HERE {method} ( ARGS )

View File

@ -2529,6 +2529,14 @@ class ParamVisitor final : public VNVisitor {
}
return false;
}
void visit(AstNodeFTaskRef* nodep) override {
if (nodep->containsGenBlock()) {
// Needs relink, as may remove pointed-to task/func
nodep->taskp(nullptr);
return;
}
iterateChildren(nodep);
}
void visit(AstVarXRef* nodep) override {
if (nodep->containsGenBlock()) {
// Needs relink, as may remove pointed-to var

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,35 @@
// DESCRIPTION: Verilator: Verify function calls through generate-if block references
//
// When a function is defined inside a generate-if block and called via a
// dotted reference (e.g. defs.foo()), the FUNCREF must survive generate
// pruning. Previously the FUNCREF could point to the deleted else-branch
// function, causing a broken-link internal error.
//
// 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-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
module t(/*AUTOARG*/);
generate
if (1) begin : defs
function automatic logic foo;
foo = 1'b1;
endfunction
end else begin : defs
function automatic logic foo;
foo = 1'b0;
endfunction
end
endgenerate
initial begin
if (defs.foo() !== 1'b1) begin
$display("%%Error: defs.foo() returned wrong value");
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule