diff --git a/configure.ac b/configure.ac index 1aa353ed7..9315730f4 100644 --- a/configure.ac +++ b/configure.ac @@ -474,6 +474,7 @@ AC_SUBST(CFG_LDFLAGS_VERILATED) # pthreads is harmless otherwise. CFG_LIBS="$LIBS $CFG_LIBS" _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread) +_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic) # Check libraries for MingW _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index b68dc0c83..aedd96a91 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -248,16 +248,18 @@ public: return nullptr; } - void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, bool& firstr) { + void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, std::set &doneClassesr) { for (const AstClassExtends* extp = classp->extendsp(); extp; extp = VN_AS(extp->nextp(), ClassExtends)) { if (extp->classp()->useVirtualPublic()) { // It's a c++ virtual class (diamond relation) // Must get the subclasses initialized first - putConstructorSubinit(extp->classp(), cfuncp, false, firstr); + putConstructorSubinit(extp->classp(), cfuncp, false, doneClassesr); } - puts(firstr ? "" : "\n, "); - firstr = false; + // Diamond pattern with same base class twice? + if (doneClassesr.find(extp->classp()) != doneClassesr.end()) continue; + puts(doneClassesr.empty() ? "" : "\n , "); + doneClassesr.emplace(extp->classp()); puts(prefixNameProtect(extp->classp())); if (constructorNeedsProcess(extp->classp())) { puts("(vlProcess, vlSymsp"); @@ -295,8 +297,8 @@ public: const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class); if (nodep->isConstructor() && classp && classp->extendsp()) { puts("\n : "); - bool first = true; - putConstructorSubinit(classp, nodep, true, first /*ref*/); + std::set doneClasses; + putConstructorSubinit(classp, nodep, true, doneClasses /*ref*/); } } puts(" {\n"); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2d0887306..a8f6a58a7 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2030,7 +2030,7 @@ class LinkDotResolveVisitor final : public VNVisitor { AstNodeFTask* m_ftaskp = nullptr; // Current function/task int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem - std::set m_ifClassImpNames; // Names imported from interface class + std::map m_ifClassImpNames; // Names imported from interface class std::set m_extendsParam; // Classes that have a parameterized super class // (except the default instances) // They are added to the set only in linkDotPrimary. @@ -2235,9 +2235,9 @@ class LinkDotResolveVisitor final : public VNVisitor { << "... Location of interface class's function\n" << interfaceSubp->warnContextSecondary()); } - if (!existsInChild - && m_ifClassImpNames.find(interfaceSubp->name()) - != m_ifClassImpNames.end()) { + const auto it = m_ifClassImpNames.find(interfaceSubp->name()); + if (!existsInChild && it != m_ifClassImpNames.end() + && it->second != interfaceSubp) { // Not exact same function from diamond implementsClassp->v3error( "Class " << implementsClassp->prettyNameQ() << " implements " << interfaceClassp->prettyNameQ() @@ -2249,7 +2249,7 @@ class LinkDotResolveVisitor final : public VNVisitor { << "... Location of interface class's function\n" << interfaceSubp->warnContextSecondary()); } - m_ifClassImpNames.emplace(interfaceSubp->name()); + m_ifClassImpNames.emplace(interfaceSubp->name(), interfaceSubp); } } } diff --git a/test_regress/t/t_class_diamond.pl b/test_regress/t/t_class_diamond.pl new file mode 100755 index 000000000..e64ab41be --- /dev/null +++ b/test_regress/t/t_class_diamond.pl @@ -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 2024 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; diff --git a/test_regress/t/t_class_diamond.v b/test_regress/t/t_class_diamond.v new file mode 100644 index 000000000..b4af229af --- /dev/null +++ b/test_regress/t/t_class_diamond.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module class_tb (); +interface class Ibase; + pure virtual function int fn(); +endclass + +interface class Ic1 extends Ibase; + pure virtual function int fn1(); +endclass + +interface class Ic2 extends Ibase; + pure virtual function int fn2(); +endclass + +interface class Ic3 extends Ic1, Ic2; +endclass + +class Cls implements Ic3; + virtual function int fn(); + return 10; + endfunction + virtual function int fn1(); + return 1; + endfunction + virtual function int fn2(); + return 2; + endfunction +endclass + + initial begin + Cls cls; + Ibase ibase; + Ic1 ic1; + Ic2 ic2; + Ic3 ic3; + cls = new; + if (cls.fn() != 10) $stop; + if (cls.fn1() != 1) $stop; + if (cls.fn2() != 2) $stop; + ibase = cls; + ic1 = cls; + ic2 = cls; + ic3 = cls; + if (ibase.fn() != 10) $stop; + if (ic1.fn() != 10) $stop; + if (ic2.fn() != 10) $stop; + if (ic3.fn() != 10) $stop; + if (ic1.fn1() != 1) $stop; + if (ic2.fn2() != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_implements_collision_bad.v b/test_regress/t/t_implements_collision_bad.v index d457be661..9767d8677 100644 --- a/test_regress/t/t_implements_collision_bad.v +++ b/test_regress/t/t_implements_collision_bad.v @@ -19,6 +19,24 @@ endclass class Cls implements IclsBoth; endclass + +// This is not a collision - diamond +interface class Ibase; + pure virtual function int fn(); +endclass + +interface class Ic1 extends Ibase; + pure virtual function int fn1(); +endclass + +interface class Ic2 extends Ibase; + pure virtual function int fn2(); +endclass + +interface class Ic3 extends Ic1, Ic2; +endclass + + module t (/*AUTOARG*/); Cls c; endmodule