Fix circular class inheritance hang (#8324) (#8545)

This commit is contained in:
Saqib Khan
2026-09-30 18:42:58 -04:00
committed by GitHub
parent 61289bc80b
commit 5458bd2e77
4 changed files with 92 additions and 0 deletions
+23
View File
@@ -3463,6 +3463,24 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
defParamPins.emplace(nodep->paramPath(), nodep);
}
static bool extendsClass(const AstClass* classp, const AstClass* targetp) {
// Return true if classp inherits from targetp through already resolved extends
// If performance of this becomes a problem, use just a counter to check
// exceeds some number of iterations then perform the more expensive analysis
std::set<const AstClass*> visited;
std::vector<const AstClass*> todo{classp};
while (!todo.empty()) {
const AstClass* const currp = todo.back();
todo.pop_back();
if (currp == targetp) return true;
if (!visited.insert(currp).second) continue;
for (const AstClassExtends* cextp = currp->extendsp(); cextp;
cextp = VN_AS(cextp->nextp(), ClassExtends)) {
if (const AstClass* const basep = cextp->classOrNullp()) todo.push_back(basep);
}
}
return false;
}
static AstClocking* sensClockingp(AstNode* nodep) {
// Return the clocking block referenced by nodep, either directly or through a modport
if (AstClocking* const clockingp = VN_CAST(nodep, Clocking)) return clockingp;
@@ -5989,6 +6007,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (baseClassp == nodep) {
cextp->v3error("Attempting to extend class " << nodep->prettyNameQ()
<< " from itself");
} else if (extendsClass(baseClassp, nodep)) {
cextp->v3error("Attempting to extend class "
<< nodep->prettyNameQ() << " from "
<< baseClassp->prettyNameQ()
<< ", which circularly inherits from it");
} else if (cextp->isImplements() && !baseClassp->isInterfaceClass()) {
cextp->v3error("Attempting to implement from non-interface class "
<< baseClassp->prettyNameQ() << '\n'
@@ -0,0 +1,23 @@
%Error: t/t_class_extends_cycle_bad.v:10:21: Attempting to extend class 'Cls2B' from 'Cls2A', which circularly inherits from it
10 | class Cls2B extends Cls2A;
| ^~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_class_extends_cycle_bad.v:8:21: Attempting to extend class 'Cls2A' from 'Cls2B', which circularly inherits from it
8 | class Cls2A extends Cls2B;
| ^~~~~
%Error: t/t_class_extends_cycle_bad.v:16:21: Attempting to extend class 'Cls3B' from 'Cls3A', which circularly inherits from it
16 | class Cls3B extends Cls3A;
| ^~~~~
%Error: t/t_class_extends_cycle_bad.v:18:21: Attempting to extend class 'Cls3C' from 'Cls3B', which circularly inherits from it
18 | class Cls3C extends Cls3B;
| ^~~~~
%Error: t/t_class_extends_cycle_bad.v:14:21: Attempting to extend class 'Cls3A' from 'Cls3C', which circularly inherits from it
14 | class Cls3A extends Cls3C;
| ^~~~~
%Error: t/t_class_extends_cycle_bad.v:24:30: Attempting to extend class 'IfcB' from 'IfcA', which circularly inherits from it
24 | interface class IfcB extends IfcA;
| ^~~~
%Error: t/t_class_extends_cycle_bad.v:22:30: Attempting to extend class 'IfcA' from 'IfcB', which circularly inherits from it
22 | interface class IfcA extends IfcB;
| ^~~~
%Error: Exiting due to
+16
View File
@@ -0,0 +1,16 @@
#!/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('linter')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()
@@ -0,0 +1,30 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Saqib Khan
// SPDX-License-Identifier: CC0-1.0
// Two-class cycle
class Cls2A extends Cls2B;
endclass
class Cls2B extends Cls2A;
endclass
// Three-class cycle
class Cls3A extends Cls3C;
endclass
class Cls3B extends Cls3A;
endclass
class Cls3C extends Cls3B;
endclass
// Interface class cycle
interface class IfcA extends IfcB;
endclass
interface class IfcB extends IfcA;
endclass
module t;
Cls2A c2 = new;
Cls3B c3 = new;
endmodule