From 4563501192bc60b07ae96e24bea21ab1fc15948e Mon Sep 17 00:00:00 2001 From: Artur Bieniek Date: Wed, 14 Jan 2026 14:40:57 +0100 Subject: [PATCH] Fix error when calling non-static method (#6916) --- src/V3Width.cpp | 42 +++++++++++++++++++++--- test_regress/t/t_class_misstatic_bad.out | 26 ++++++++++----- test_regress/t/t_class_misstatic_bad.v | 7 ++++ 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0e0a64867..9830d6737 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -237,6 +237,8 @@ class WidthVisitor final : public VNVisitor { TableMap m_tableMap; // Created tables so can remove duplicates std::map m_queueDTypeIndexed; // Queues with given index type + std::map + m_containingClassp; // Containing class cache for containingClass() function std::unordered_set m_aliasedVars; // Variables referenced in alias static constexpr int ENUM_LOOKUP_BITS = 16; // Maximum # bits to make enum lookup table @@ -6582,6 +6584,22 @@ class WidthVisitor final : public VNVisitor { } return VN_CAST(pkgItemp->backp(), Package); } + const AstClass* containingClass(AstNode* nodep) { + // backp is still needed, m_containingClassp is just a cache + if (const AstClass* const classp = VN_CAST(nodep, Class)) + return m_containingClassp[nodep] = classp; + if (const AstClassPackage* const packagep = VN_CAST(nodep, ClassPackage)) { + return m_containingClassp[nodep] = packagep->classp(); + } + if (m_containingClassp.find(nodep) != m_containingClassp.end()) { + return m_containingClassp[nodep]; + } + if (nodep->backp()) { + return m_containingClassp[nodep] = containingClass(nodep->backp()); + } else { + return m_containingClassp[nodep] = nullptr; + } + } void visit(AstFuncRef* nodep) override { visit(static_cast(nodep)); if (nodep->taskp() && VN_IS(nodep->taskp(), Task)) { @@ -6889,10 +6907,26 @@ class WidthVisitor final : public VNVisitor { return; } if ((nodep->taskp()->classMethod() && !nodep->taskp()->isStatic()) - && !VN_IS(m_procedurep, InitialAutomatic) - && (!m_ftaskp || !m_ftaskp->classMethod() || m_ftaskp->isStatic()) && !m_constraintp) { - nodep->v3error("Cannot call non-static member function " - << nodep->prettyNameQ() << " without object (IEEE 1800-2023 8.10)"); + && !VN_IS(m_procedurep, InitialAutomatic) && !m_constraintp) { + bool allow = false; + if (m_ftaskp && m_ftaskp->classMethod() && !m_ftaskp->isStatic()) { + if (const AstFuncRef* const funcRefp = VN_CAST(nodep, FuncRef)) { + allow = funcRefp->superReference(); + } else if (const AstTaskRef* const taskRefp = VN_CAST(nodep, TaskRef)) { + allow = taskRefp->superReference(); + } + if (!allow) { + const AstClass* callerClassp = containingClass(m_ftaskp); + if (!callerClassp) callerClassp = containingClass(m_ftaskp->classOrPackagep()); + const AstClass* calleeClassp = VN_CAST(nodep->classOrPackagep(), Class); + if (!calleeClassp) calleeClassp = containingClass(nodep->taskp()); + allow = AstClass::isClassExtendedFrom(callerClassp, calleeClassp); + } + } + if (!allow) { + nodep->v3error("Cannot call non-static member function " + << nodep->prettyNameQ() << " without object (IEEE 1800-2023 8.10)"); + } } if (nodep->taskp() && !nodep->scopeNamep() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) { diff --git a/test_regress/t/t_class_misstatic_bad.out b/test_regress/t/t_class_misstatic_bad.out index 368cfffae..171d60fed 100644 --- a/test_regress/t/t_class_misstatic_bad.out +++ b/test_regress/t/t_class_misstatic_bad.out @@ -1,14 +1,22 @@ -%Error: t/t_class_misstatic_bad.v:31:5: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) - : ... note: In instance 't' - 31 | nonstatic(); - | ^~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_class_misstatic_bad.v:38:10: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) +%Error: t/t_class_misstatic_bad.v:23:10: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) : ... note: In instance 't' - 38 | Cls::nonstatic(); + 23 | Cls::nonstatic(); | ^~~~~~~~~ -%Error: t/t_class_misstatic_bad.v:44:10: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_class_misstatic_bad.v:24:10: Cannot call non-static member function 'nonstatic_retcls' without object (IEEE 1800-2023 8.10) : ... note: In instance 't' - 44 | Cls::nonstatic(); + 24 | Cls::nonstatic_retcls(); + | ^~~~~~~~~~~~~~~~ +%Error: t/t_class_misstatic_bad.v:35:5: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) + : ... note: In instance 't' + 35 | nonstatic(); + | ^~~~~~~~~ +%Error: t/t_class_misstatic_bad.v:45:10: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) + : ... note: In instance 't' + 45 | Cls::nonstatic(); + | ^~~~~~~~~ +%Error: t/t_class_misstatic_bad.v:51:10: Cannot call non-static member function 'nonstatic' without object (IEEE 1800-2023 8.10) + : ... note: In instance 't' + 51 | Cls::nonstatic(); | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_misstatic_bad.v b/test_regress/t/t_class_misstatic_bad.v index 3f0cbca1c..e71fb8696 100644 --- a/test_regress/t/t_class_misstatic_bad.v +++ b/test_regress/t/t_class_misstatic_bad.v @@ -11,6 +11,9 @@ class Cls; endfunction function void nonstatic(); endfunction + function Cls nonstatic_retcls(); + return null; + endfunction static function void isst(); endfunction endclass @@ -18,6 +21,7 @@ endclass class Bar; function void bar(); Cls::nonstatic(); // <--- bad static ref + Cls::nonstatic_retcls(); // <--- bad static ref Cls::isst(); endfunction endclass @@ -31,6 +35,9 @@ class Extends extends Cls; nonstatic(); // <--- bad static ref isst(); endfunction + function new(); + Cls c = super.nonstatic_retcls(); + endfunction endclass module t;