diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 05440ea5b..28ba20462 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2534,12 +2534,14 @@ private: string expectWhat; bool allowScope = false; bool allowVar = false; + bool staticAccess = false; if (m_ds.m_dotPos == DP_PACKAGE) { // {package}::{a} AstNodeModule* classOrPackagep = nullptr; expectWhat = "scope/variable"; allowScope = true; allowVar = true; + staticAccess = true; UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); AstClassOrPackageRef* const cpackagerefp @@ -2667,6 +2669,10 @@ private: newp = refp; } } else { + if (staticAccess && !varp->lifetime().isStatic() && !varp->isParam()) { + nodep->v3error("Static access to non-static member variable " + << varp->prettyNameQ() << endl); + } AstVarRef* const refp = new AstVarRef{ nodep->fileline(), varp, VAccess::READ}; // lvalue'ness computed later refp->classOrPackagep(foundp->classOrPackagep()); @@ -2980,6 +2986,7 @@ private: iterateChildren(nodep); } + bool staticAccess = false; if (m_ds.m_unresolvedClass) { // Unable to link before V3Param return; @@ -2995,6 +3002,7 @@ private: } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); + staticAccess = true; AstClassOrPackageRef* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef); if (cpackagerefp->name() == "local") { @@ -3066,6 +3074,10 @@ private: AstNodeFTask* const taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr if (taskp) { + if (staticAccess && !taskp->lifetime().isStatic()) { + nodep->v3error("Static access to non-static task/function " + << taskp->prettyNameQ() << endl); + } nodep->taskp(taskp); nodep->classOrPackagep(foundp->classOrPackagep()); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp diff --git a/test_regress/t/t_class_fwd_cc.v b/test_regress/t/t_class_fwd_cc.v index dce477fdf..cfb6c3696 100644 --- a/test_regress/t/t_class_fwd_cc.v +++ b/test_regress/t/t_class_fwd_cc.v @@ -15,7 +15,7 @@ package Pkg; endfunction endclass class Fwd; - function Fwd m_uvm_get_root(); + static function Fwd m_uvm_get_root(); return null; endfunction endclass diff --git a/test_regress/t/t_class_member_bad3.out b/test_regress/t/t_class_member_bad3.out new file mode 100644 index 000000000..4712e0838 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.out @@ -0,0 +1,7 @@ +%Error: t/t_class_member_bad3.v:16:12: Static access to non-static member variable 'member' + 16 | Foo::member = 1; + | ^~~~~~ +%Error: t/t_class_member_bad3.v:17:12: Static access to non-static task/function 'method' + 17 | Foo::method(); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_member_bad3.pl b/test_regress/t/t_class_member_bad3.pl new file mode 100755 index 000000000..9c3b25c46 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.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 2023 by Antmicro Ltd. 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_member_bad3.v b/test_regress/t/t_class_member_bad3.v new file mode 100644 index 000000000..ccde97456 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + int member; + + task method; endtask +endclass + +module t; + initial begin + Foo foo = new; + Foo::member = 1; + Foo::method(); + end +endmodule