Add SUPERNFIRST error on super.new on non-first statement (#6784).

This commit is contained in:
Wilson Snyder 2025-12-09 19:22:59 -05:00
parent d467fda7c6
commit 075d624b29
9 changed files with 129 additions and 7 deletions

View File

@ -18,6 +18,7 @@ Verilator 5.043 devel
* Add `-param`/`-port` options to `public_flat*` control directives (#6685). [Geza Lore, Fractile Ltd.]
* Add `--top` specifying `config` name (#6710). [Dan Ruelas-Petrisko]
* Add `sc_biguint` pragma (#6712). [Jakub Wasilewski, Antmicro Ltd.]
* Add SUPERNFIRST error on super.new on non-first statement (#6784). [Artur Bieniek]
* Support `std::randomize(){...}` (#4706) (#6573). [Yilou Wang]
* Support `config` instance clauses (#5891 partial) (#6745). [Dan Ruelas-Petrisko]
* Support unpacked struct in localparam (#6053 partial) (#6708). [Jonathan Drolet]

View File

@ -0,0 +1,8 @@
.. comment: generated by t_class_new_supernfirst_bad
.. code-block:: sv
:linenos:
:emphasize-lines: 3
function new();
int x = $random();
super.new(build_coverage(x), x); // <--- BAD, must be first statement

View File

@ -0,0 +1,4 @@
.. comment: generated by t_class_new_supernfirst_bad
.. code-block::
%Error-SUPERNFIRST: example.v:1:11 'super.new' must be first statement in a 'function new' (IEEE 1800-2023 8.15)

View File

@ -2003,6 +2003,24 @@ List Of Warnings
* Run Verilator with :vlopt:`--timing`.
.. option:: SUPERNFIRST
An error that a `super.new` is not the first statement in a `function
new`.
IEEE requires this error. Ignoring this warning may cause other errors
or initialization ordering surprises, as described in IEEE 1800-2023
8.15.
Faulty example:
.. include:: ../../docs/gen/ex_SUPERNFIRST_faulty.rst
Results in:
.. include:: ../../docs/gen/ex_SUPERNFIRST_msg.rst
.. option:: SYMRSVDWORD
Warning that a symbol matches a C++ reserved word, and using this as a

View File

@ -158,6 +158,7 @@ public:
SPLITVAR, // Cannot split the variable
STATICVAR, // Static variable declared in a loop with a declaration assignment
STMTDLY, // Delayed statement
SUPERNFIRST, // Super.new must be first statement
SYMRSVDWORD, // Symbol is Reserved Word
SYNCASYNCNET, // Mixed sync + async reset
TICKCOUNT, // Too large tick count
@ -224,11 +225,12 @@ public:
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT",
"PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "PROTOTYPEMIS", "RANDC", "REALCVT",
"REDEFMACRO", "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN",
"SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT",
"TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED",
"UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR",
"USERFATAL", "USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT",
"WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"};
"SPLITVAR", "STATICVAR", "STMTDLY", "SUPERNFIRST", "SYMRSVDWORD", "SYNCASYNCNET",
"TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
"UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL",
"USERERROR", "USERFATAL", "USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH",
"WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL",
" MAX"};
return names[m_e];
}
// Warnings that default to off
@ -258,8 +260,8 @@ public:
|| m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == HIERPARAM
|| m_e == FUNCTIMECTL || m_e == IMPURE || m_e == MODMISSING
|| m_e == PARAMNODEFAULT || m_e == PINNOTFOUND || m_e == PKGNODECL
|| m_e == PROCASSWIRE || m_e == PROTOTYPEMIS || m_e == ZEROREPL // Says IEEE
);
|| m_e == PROCASSWIRE || m_e == PROTOTYPEMIS || m_e == SUPERNFIRST
|| m_e == ZEROREPL);
}
// Warnings to mention manual
bool mentionManual() const VL_MT_SAFE {

View File

@ -6337,6 +6337,33 @@ class WidthVisitor final : public VNVisitor {
nodep->v3error("class 'new()' cannot be virual (IEEE 1800-2023 18.3)");
if (nodep->isStatic())
nodep->v3error("class 'new()' cannot be static (IEEE 1800-2023 18.3)");
AstNode* firstp = nullptr;
for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstStmtExpr* const sep = VN_CAST(itemp, StmtExpr)) {
if (AstNew* const newp = VN_CAST(sep->exprp(), New)) {
if (firstp) {
UINFOTREE(1, firstp, "", "-earlier");
newp->v3warn(SUPERNFIRST,
"'super.new' must be first statement in a 'function "
"new' (IEEE 1800-2023 8.15)\n"
<< newp->warnContextPrimary() << '\n'
<< firstp->warnOther()
<< "... Location of earlier statement\n"
<< firstp->warnContextSecondary());
break;
}
}
continue;
}
if (AstVar* const varp = VN_CAST(itemp, Var)) {
if (!varp->valuep() || VN_CAST(varp->valuep(), Const) || varp->isIO())
continue;
}
if (AstAssign* const aitemp = VN_CAST(itemp, Assign)) {
if (VN_IS(aitemp->rhsp(), Const)) continue;
}
firstp = itemp;
}
}
// Function hasn't been widthed, so make it so.
// Would use user1 etc, but V3Width called from too many places to spend a user

View File

@ -0,0 +1,9 @@
%Error-SUPERNFIRST: t/t_class_new_supernfirst_bad.v:20:11: 'super.new' must be first statement in a 'function new' (IEEE 1800-2023 8.15)
: ... note: In instance 't'
20 | super.new(build_coverage(x), x);
| ^~~
t/t_class_new_supernfirst_bad.v:19:13: ... Location of earlier statement
19 | int x = $random();
| ^~~~~~~
... For error description see https://verilator.org/warn/SUPERNFIRST?v=latest
%Error: Exiting due to

View File

@ -0,0 +1,24 @@
#!/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('linter')
test.lint(verilator_flags2=['--timing'], fails=True, expect_filename=test.golden_filename)
test.extract(in_filename=test.top_filename,
out_filename=test.root + "/docs/gen/ex_SUPERNFIRST_faulty.rst",
lines="18-20")
test.extract(in_filename=test.golden_filename,
out_filename=test.root + "/docs/gen/ex_SUPERNFIRST_msg.rst",
regexp=r'SUPERNFIRST:')
test.passes()

View File

@ -0,0 +1,29 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class base_reg_block;
function new(string name, int x);
if (name == x) $finish;
endfunction
function string build_coverage(int x);
return $sformatf("%0d", x);
endfunction
endclass
class spi_reg_block extends base_reg_block;
function new();
int x = $random();
super.new(build_coverage(x), x); // <--- BAD, must be first statement
endfunction
endclass
module t;
initial begin
spi_reg_block test = new;
$finish;
end
endmodule