From 4a439beae5ccdfc0fff5cfd56d01e25d180f38a2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 11 Mar 2024 18:56:30 -0400 Subject: [PATCH] Add error on missing pure virtual functions (#4961). --- Changes | 1 + src/V3AstNodes.cpp | 1 + src/V3LinkDot.cpp | 21 +++++++++++++-------- test_regress/t/t_class_mispure_bad.out | 7 +++++++ test_regress/t/t_class_mispure_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_class_mispure_bad.v | 21 +++++++++++++++++++++ 6 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 test_regress/t/t_class_mispure_bad.out create mode 100755 test_regress/t/t_class_mispure_bad.pl create mode 100644 test_regress/t/t_class_mispure_bad.v diff --git a/Changes b/Changes index df9fab7bd..d007f2117 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,7 @@ Verilator 5.023 devel **Minor:** * Add DFG 'regularize' pass, and improve variable removal (#4937). [Geza Lore] +* Add error on missing pure virtual functions (#4961). * Add error on calling static function without object (#4962). * Support public packed struct / union (#860) (#4878). [Kefa Chen] * Change installation to be relocatable (#4927). [Geza Lore] diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 1a4cf75ea..322a8793d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2449,6 +2449,7 @@ void AstNodeFTask::dump(std::ostream& str) const { if (dpiOpenChild()) str << " [DPIOPENCHILD]"; if (dpiOpenParent()) str << " [DPIOPENPARENT]"; if (prototype()) str << " [PROTOTYPE]"; + if (pureVirtual()) str << " [PUREVIRTUAL]"; if (recursive()) str << " [RECURSIVE]"; if (taskPublic()) str << " [PUBLIC]"; if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]"; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 98abcfac0..1a0375bc4 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2214,20 +2214,25 @@ class LinkDotResolveVisitor final : public VNVisitor { return classSymp; } void importImplementsClass(AstClass* implementsClassp, VSymEnt* interfaceSymp, - AstClass* interfaceClassp) { - UINFO(8, "importImplementsClass to " << implementsClassp << " from " << interfaceClassp - << endl); + AstClass* baseClassp) { + // Also used for standard 'extends' from a base class + UINFO(8, + "importImplementsClass to " << implementsClassp << " from " << baseClassp << endl); for (VSymEnt::const_iterator it = interfaceSymp->begin(); it != interfaceSymp->end(); ++it) { if (AstNode* interfaceSubp = it->second->nodep()) { UINFO(8, " SymFunc " << interfaceSubp << endl); if (VN_IS(interfaceSubp, NodeFTask)) { const VSymEnt* const foundp = m_curSymp->findIdFlat(interfaceSubp->name()); + const AstNodeFTask* const interfaceFuncp = VN_CAST(interfaceSubp, NodeFTask); + if (!interfaceFuncp || !interfaceFuncp->pureVirtual()) continue; bool existsInChild = foundp && !foundp->imported(); + const string impOrExtends + = baseClassp->isInterfaceClass() ? " implements " : " extends "; if (!existsInChild && !implementsClassp->isInterfaceClass()) { implementsClassp->v3error( - "Class " << implementsClassp->prettyNameQ() << " implements " - << interfaceClassp->prettyNameQ() + "Class " << implementsClassp->prettyNameQ() << impOrExtends + << baseClassp->prettyNameQ() << " but is missing implementation for " << interfaceSubp->prettyNameQ() << " (IEEE 1800-2023 8.26)\n" << implementsClassp->warnContextPrimary() << '\n' @@ -2239,8 +2244,8 @@ class LinkDotResolveVisitor final : public VNVisitor { if (!existsInChild && it != m_ifClassImpNames.end() && it->second != interfaceSubp) { // Not exact same function from diamond implementsClassp->v3error( - "Class " << implementsClassp->prettyNameQ() << " implements " - << interfaceClassp->prettyNameQ() + "Class " << implementsClassp->prettyNameQ() << impOrExtends + << baseClassp->prettyNameQ() << " but missing inheritance conflict resolution for " << interfaceSubp->prettyNameQ() << " (IEEE 1800-2023 8.26.6.2)\n" @@ -2257,7 +2262,7 @@ class LinkDotResolveVisitor final : public VNVisitor { void importSymbolsFromExtended(AstClass* const nodep, AstClassExtends* const cextp) { AstClass* const baseClassp = cextp->classp(); VSymEnt* const srcp = m_statep->getNodeSym(baseClassp); - if (baseClassp->isInterfaceClass()) importImplementsClass(nodep, srcp, baseClassp); + importImplementsClass(nodep, srcp, baseClassp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } void classExtendImport(AstClass* nodep) { diff --git a/test_regress/t/t_class_mispure_bad.out b/test_regress/t/t_class_mispure_bad.out new file mode 100644 index 000000000..b5cc6f091 --- /dev/null +++ b/test_regress/t/t_class_mispure_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_class_mispure_bad.v:11:1: Class 'Bar' extends 'Base' but is missing implementation for 'pvfunc' (IEEE 1800-2023 8.26) + 11 | class Bar extends Base; + | ^~~~~ + t/t_class_mispure_bad.v:8:31: ... Location of interface class's function + 8 | pure virtual function void pvfunc(); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_mispure_bad.pl b/test_regress/t/t_class_mispure_bad.pl new file mode 100755 index 000000000..9c9fb65a0 --- /dev/null +++ b/test_regress/t/t_class_mispure_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_mispure_bad.v b/test_regress/t/t_class_mispure_bad.v new file mode 100644 index 000000000..438361a93 --- /dev/null +++ b/test_regress/t/t_class_mispure_bad.v @@ -0,0 +1,21 @@ +// 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 + +virtual class Base; + pure virtual function void pvfunc(); +endclass + +class Bar extends Base; + // Bad, no implementation of pvfunc +endclass + +module t; + initial begin + Bar obj = new(); + obj.pvfunc(); + $stop; + end +endmodule