From ac4f9f013e5328dc135f4143e0f646893f5d8891 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 18 Jan 2026 19:58:33 -0500 Subject: [PATCH] Fix static call after covergroup (#6916 repair) --- src/V3Ast.cpp | 7 ++++++ src/V3Ast.h | 1 + src/V3Width.cpp | 6 ++--- test_regress/t/t_class_static_after_cg.py | 16 ++++++++++++++ test_regress/t/t_class_static_after_cg.v | 27 +++++++++++++++++++++++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_class_static_after_cg.py create mode 100644 test_regress/t/t_class_static_after_cg.v diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 156f4bf5b..82277db58 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -139,6 +139,13 @@ AstNode* AstNode::abovep() const { const AstNode* const firstp = firstAbovep() ? this : m_headtailp; return firstp->backp(); } +AstNode* AstNode::aboveLoopp() const { + // Returns parent node. Avoid using this, may have performance issues. + const AstNode* nodep = this; + // Backwards over peers (versus parents) + while (nodep->backp() && nodep->backp()->nextp() == nodep) nodep = nodep->backp(); + return nodep->backp(); +} string AstNode::encodeName(const string& namein) { // Encode signal name raw from parser, then not called again on same signal diff --git a/src/V3Ast.h b/src/V3Ast.h index bb1a57f8b..5005ee8d4 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -540,6 +540,7 @@ public: AstNode* nextp() const VL_MT_STABLE { return m_nextp; } AstNode* backp() const VL_MT_STABLE { return m_backp; } AstNode* abovep() const; // Get parent node above, only for list head and tail + AstNode* aboveLoopp() const; // Get parent node above, may have performance issues as loops AstNode* op1p() const VL_MT_STABLE { return m_op1p; } AstNode* op2p() const VL_MT_STABLE { return m_op2p; } AstNode* op3p() const VL_MT_STABLE { return m_op3p; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 54f5ada1e..8fdbfc5a8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6654,7 +6654,7 @@ 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 + // abovep 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)) { @@ -6663,8 +6663,8 @@ class WidthVisitor final : public VNVisitor { if (m_containingClassp.find(nodep) != m_containingClassp.end()) { return m_containingClassp[nodep]; } - if (nodep->backp()) { - return m_containingClassp[nodep] = containingClass(nodep->backp()); + if (AstNode* const abovep = nodep->aboveLoopp()) { + return m_containingClassp[nodep] = containingClass(abovep); } else { return m_containingClassp[nodep] = nullptr; } diff --git a/test_regress/t/t_class_static_after_cg.py b/test_regress/t/t_class_static_after_cg.py new file mode 100755 index 000000000..7dcbd6ae6 --- /dev/null +++ b/test_regress/t/t_class_static_after_cg.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.lint() + +test.passes() diff --git a/test_regress/t/t_class_static_after_cg.v b/test_regress/t/t_class_static_after_cg.v new file mode 100644 index 000000000..10085988a --- /dev/null +++ b/test_regress/t/t_class_static_after_cg.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + class Cls; + // verilator lint_off COVERIGN + covergroup cov_trans; + option.per_instance = 1; + endgroup + + virtual function void perform_transfer_checks(); + check_transfer_size(); + endfunction + virtual function void check_transfer_size(); + endfunction + endclass + + initial begin + Cls c; + c = new; + c.perform_transfer_checks(); + $finish; + end +endmodule