Add warning on missing class reference #()

This commit is contained in:
Wilson Snyder 2023-03-03 21:06:52 -05:00
parent ab502c5196
commit e21198cb2d
8 changed files with 85 additions and 17 deletions

View File

@ -210,6 +210,7 @@ private:
bool m_modTrace : 1; // Tracing this module
bool m_inLibrary : 1; // From a library, no error if not used, never top level
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
bool m_hasGParam : 1; // Has global parameter (for link)
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
bool m_internal : 1; // Internally created
bool m_recursive : 1; // Recursive module
@ -223,6 +224,7 @@ protected:
, m_modTrace{false}
, m_inLibrary{false}
, m_dead{false}
, m_hasGParam{false}
, m_hierBlock{false}
, m_internal{false}
, m_recursive{false}
@ -250,6 +252,8 @@ public:
bool modTrace() const { return m_modTrace; }
void dead(bool flag) { m_dead = flag; }
bool dead() const { return m_dead; }
void hasGParam(bool flag) { m_hasGParam = flag; }
bool hasGParam() const { return m_hasGParam; }
void hierBlock(bool flag) { m_hierBlock = flag; }
bool hierBlock() const { return m_hierBlock; }
void internal(bool flag) { m_internal = flag; }

View File

@ -2227,6 +2227,7 @@ private:
}
}
}
// VISITs
void visit(AstNetlist* nodep) override {
// Recurse..., backward as must do packages before using packages
@ -2822,8 +2823,15 @@ private:
UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl);
iterateChildren(nodep);
}
if (m_statep->forPrimary() && VN_IS(nodep->classOrPackagep(), Class) && !nodep->paramsp()
&& nodep->classOrPackagep()->hasGParam()
// Don't warn on typedefs, which are hard to know if there's a param somewhere buried
&& VN_IS(nodep->classOrPackageNodep(), Class)) {
nodep->v3error("Reference to parameterized class without #() (IEEE 1800-2017 8.25.1)\n"
<< nodep->warnMore() << "... Suggest use '"
<< nodep->classOrPackageNodep()->prettyName() << "#()'");
}
}
void visit(AstVarRef* nodep) override {
// VarRef: Resolve its reference
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find

View File

@ -225,6 +225,7 @@ private:
if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) {
nodep->lifetime(m_lifetime);
}
if (nodep->isGParam() && m_modp) m_modp->hasGParam(true);
if (nodep->isParam() && !nodep->valuep()
&& nodep->fileline()->language() < V3LangCode::L1800_2009) {
nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later.");

View File

@ -1394,7 +1394,7 @@ parameter_value_assignmentE<pinp>: // IEEE: [ parameter_value_assignment ]
;
parameter_value_assignment<pinp>: // IEEE: parameter_value_assignment
'#' '(' cellparamList ')' { $$ = $3; }
'#' '(' cellparamListE ')' { $$ = $3; }
// // Parentheses are optional around a single parameter
| '#' yaINTNUM { $$ = new AstPin{$<fl>2, 1, "", new AstConst{$<fl>2, *$2}}; }
| '#' yaFLOATNUM { $$ = new AstPin{$<fl>2, 1, "",
@ -1408,7 +1408,7 @@ parameter_value_assignment<pinp>: // IEEE: parameter_value_assignment
parameter_value_assignmentClass<pinp>: // IEEE: [ parameter_value_assignment ] (for classes)
// // Like parameter_value_assignment, but for classes only, which always have #()
'#' '(' cellparamList ')' { $$ = $3; }
'#' '(' cellparamListE ')' { $$ = $3; }
;
parameter_port_listE<nodep>: // IEEE: parameter_port_list + empty == parameter_value_assignment
@ -3160,11 +3160,11 @@ instnameList<nodep>:
;
instnameParen<nodep>:
id instRangeListE '(' cellpinList ')'
id instRangeListE '(' cellpinListE ')'
{ $$ = GRAMMARP->createCellOrIfaceRef($<fl>1, *$1, $4, $2); }
| id instRangeListE
{ $$ = GRAMMARP->createCellOrIfaceRef($<fl>1, *$1, nullptr, $2); }
//UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP
//UNSUP instRangeListE '(' cellpinListE ')' { UNSUP } // UDP
// // Adding above and switching to the Verilog-Perl syntax
// // causes a shift conflict due to use of idClassSel inside exprScope.
// // It also breaks allowing "id foo;" instantiation syntax.
@ -3187,22 +3187,22 @@ instRange<nodeRangep>:
{ $$ = new AstRange{$1, $2, $4}; }
;
cellparamList<pinp>:
{ GRAMMARP->pinPush(); } cellparamItList { $$ = $2; GRAMMARP->pinPop(CRELINE()); }
cellparamListE<pinp>:
{ GRAMMARP->pinPush(); } cellparamItListE { $$ = $2; GRAMMARP->pinPop(CRELINE()); }
;
cellpinList<pinp>:
{VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); }
cellpinListE<pinp>:
{ VARRESET_LIST(UNKNOWN); } cellpinItListE { $$ = $2; VARRESET_NONLIST(UNKNOWN); }
;
cellparamItList<pinp>: // IEEE: list_of_parameter_assignmente
cellparamItListE<pinp>: // IEEE: list_of_parameter_assignmente
cellparamItemE { $$ = $1; }
| cellparamItList ',' cellparamItemE { $$ = addNextNull($1, $3); }
| cellparamItListE ',' cellparamItemE { $$ = addNextNull($1, $3); }
;
cellpinItList<pinp>: // IEEE: list_of_port_connections
cellpinItListE<pinp>: // IEEE: list_of_port_connections
cellpinItemE { $$ = $1; }
| cellpinItList ',' cellpinItemE { $$ = addNextNull($1, $3); }
| cellpinItListE ',' cellpinItemE { $$ = addNextNull($1, $3); }
;
cellparamItemE<pinp>: // IEEE: named_parameter_assignment + empty
@ -6602,8 +6602,8 @@ checker_generate_item<nodep>: // ==IEEE: checker_generate_item
//UNSUPchecker_instantiation<nodep>:
//UNSUP // // Only used for procedural_assertion_item's
//UNSUP // // Version in concurrent_assertion_item looks like etcInst
//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinList
//UNSUP id/*checker_identifier*/ id '(' cellpinList ')' ';' { }
//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinListE
//UNSUP id/*checker_identifier*/ id '(' cellpinListE ')' ';' { }
//UNSUP ;
//**********************************************************************

View File

@ -210,11 +210,11 @@ module t (/*AUTOARG*/);
if(dict_op.get("abcd") != 1) $stop;
if (getter1.get_1() != 1) $stop;
if (Getter1::get_1() != 1) $stop;
if (Getter1#()::get_1() != 1) $stop;
if (getter1_param_1.get_1() != 1) $stop;
if (getter2.get_2() != 2) $stop;
if (Getter2::get_2() != 2) $stop;
if (Getter2#()::get_2() != 2) $stop;
if (Getter2#(2)::get_2() != 2) $stop;
$write("*-* All Finished *-*\n");

View File

@ -0,0 +1,5 @@
%Error: t/t_class_param_bad_paren.v:28:11: Reference to parameterized class without #() (IEEE 1800-2017 8.25.1)
: ... Suggest use 'Cls#()'
28 | if (Cls::OTHER != 12) $stop;
| ^~~
%Error: Exiting due to

View File

@ -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 2022 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;

View File

@ -0,0 +1,31 @@
// 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 Cls #(int PARAM = 1);
parameter OTHER = 12;
endclass
class Other extends Cls#(); // Ok
endclass
class OtherMaybe extends Cls; // Questionable but others do not warn
endclass
module t (/*AUTOARG*/);
typedef Cls#(2) Cls2_t; // Ok
typedef Cls ClsNone_t; // Ok
Cls c; // Ok
initial begin
if (Cls#()::OTHER != 12) $stop; // Ok
if (Cls2_t::OTHER != 12) $stop; // ok
if (Cls::OTHER != 12) $stop; // Bad #() required
end
endmodule