mirror of
https://github.com/verilator/verilator.git
synced 2025-04-04 19:52:39 +00:00
This commit is contained in:
parent
28b9216f8a
commit
1ed5557d2d
4
Changes
4
Changes
@ -16,16 +16,18 @@ Verilator 5.023 devel
|
||||
* Add printing summary reports, use `--quiet` or `+verilator+quiet` to suppress (#4909).
|
||||
* Support 1800-2023 keywords, and parsing with UNDEFINED warnings.
|
||||
* Support 1800-2023 preprocessor ifdef expressions.
|
||||
* Support 1800-2023 DPI headers, svGetTime/svgGetTimeUnit/svGetTimePrecision methods.
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Change 1800-2023 to be default language version.
|
||||
* Add DFG 'regularize' pass, and improve variable removal (#4937). [Geza Lore]
|
||||
* Add error when pass net to function argument (#4132) (#4966). [Fuad Ismail]
|
||||
* Add `UNUSEDLOOP` when unused loop is removed (#4926). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Add custom version for verilator --version packaging (#4954). [Nolan Poe]
|
||||
* Add error on missing pure virtual functions (#4961).
|
||||
* Add error on calling static function without object (#4962).
|
||||
* Support 1800-2023 DPI headers, svGetTime/svgGetTimeUnit/svGetTimePrecision methods.
|
||||
* Support 1800-2023 class and function :initial, :extends, :final virtual overrides (#5025).
|
||||
* Support public packed struct / union (#860) (#4878). [Kefa Chen]
|
||||
* Support implicitly-typed variable definitions in for-loop initializers (#4945) (#4986). [Kevin Nygaard]
|
||||
* Improve installation to be relocatable (#4927). [Geza Lore]
|
||||
|
45
src/V3Ast.h
45
src/V3Ast.h
@ -242,6 +242,51 @@ inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return o
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VBaseOverride final {
|
||||
bool m_extends : 1;
|
||||
bool m_final : 1;
|
||||
bool m_initial : 1;
|
||||
|
||||
public:
|
||||
VBaseOverride()
|
||||
: m_extends{false}
|
||||
, m_final{false}
|
||||
, m_initial{false} {}
|
||||
class Extends {};
|
||||
VBaseOverride(Extends)
|
||||
: m_extends{true}
|
||||
, m_final{false}
|
||||
, m_initial{false} {}
|
||||
class Final {};
|
||||
VBaseOverride(Final)
|
||||
: m_extends{false}
|
||||
, m_final{true}
|
||||
, m_initial{false} {}
|
||||
class Initial {};
|
||||
VBaseOverride(Initial)
|
||||
: m_extends{false}
|
||||
, m_final{false}
|
||||
, m_initial{true} {}
|
||||
void combine(const VBaseOverride& other) {
|
||||
m_extends |= other.m_extends;
|
||||
m_final |= other.m_final;
|
||||
m_initial |= other.m_initial;
|
||||
}
|
||||
bool isAny() const { return m_extends | m_final | m_initial; }
|
||||
bool isExtends() const { return m_extends; }
|
||||
bool isFinal() const { return m_final; }
|
||||
bool isInitial() const { return m_initial; }
|
||||
string ascii() const {
|
||||
string out;
|
||||
if (m_initial) out = VString::dot(out, " ", "initial");
|
||||
if (m_extends) out = VString::dot(out, " ", "extends");
|
||||
if (m_final) out = VString::dot(out, " ", "final");
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VSigning final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
|
@ -87,6 +87,7 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode {
|
||||
bool m_underGenerate : 1; // Under generate (for warning)
|
||||
bool m_virtual : 1; // Virtual method in class
|
||||
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
||||
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
||||
VLifetime m_lifetime; // Default lifetime of local vars
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
@ -183,6 +184,8 @@ public:
|
||||
bool isVirtual() const { return m_virtual; }
|
||||
void setNeedProcess() { m_needProcess = true; }
|
||||
bool needProcess() const { return m_needProcess; }
|
||||
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
|
||||
VBaseOverride baseOverride() const { return m_baseOverride; }
|
||||
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
||||
VLifetime lifetime() const { return m_lifetime; }
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
@ -2272,6 +2275,7 @@ class AstClass final : public AstNodeModule {
|
||||
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||
// MEMBERS
|
||||
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
|
||||
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
||||
bool m_extended = false; // Is extension or extended by other classes
|
||||
bool m_interfaceClass = false; // Interface class
|
||||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
@ -2307,6 +2311,8 @@ public:
|
||||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
|
||||
VBaseOverride baseOverride() const { return m_baseOverride; }
|
||||
// Return the lowest class extended from, or this class
|
||||
AstClass* baseMostClassp();
|
||||
static bool isCacheableChild(const AstNode* nodep);
|
||||
|
@ -1539,6 +1539,7 @@ void AstClass::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFunc(str, isExtended);
|
||||
dumpJsonBoolFunc(str, isInterfaceClass);
|
||||
dumpJsonBoolFunc(str, isVirtual);
|
||||
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstClassExtends::dump(std::ostream& str) const {
|
||||
@ -2488,6 +2489,7 @@ void AstNodeFTask::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFunc(str, prototype);
|
||||
dumpJsonBoolFunc(str, recursive);
|
||||
dumpJsonBoolFunc(str, taskPublic);
|
||||
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
||||
dumpJsonStrFunc(str, cname);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ struct V3ParseBisonYYSType final {
|
||||
FileLine* fl;
|
||||
AstNode* scp; // Symbol table scope for future lookups
|
||||
int token; // Read token, aka tok
|
||||
VBaseOverride baseOverride;
|
||||
union {
|
||||
V3Number* nump;
|
||||
string* strp;
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include "V3WidthCommit.h"
|
||||
|
||||
#include "V3MemberMap.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
@ -40,6 +42,7 @@ class WidthCommitVisitor final : public VNVisitor {
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr;
|
||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
@ -73,7 +76,7 @@ private:
|
||||
return nodep;
|
||||
}
|
||||
void classEncapCheck(AstNode* nodep, AstNode* defp, AstClass* defClassp) {
|
||||
// Call on non-local class to check local/protected status and complain
|
||||
// Check local/protected status and complain
|
||||
bool local = false;
|
||||
bool prot = false;
|
||||
if (const auto varp = VN_CAST(defp, Var)) {
|
||||
@ -110,10 +113,23 @@ private:
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
{
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
editDType(nodep);
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
editDType(nodep);
|
||||
if (AstClass* const classp = VN_CAST(nodep, Class)) {
|
||||
for (AstClassExtends* extendsp = classp->extendsp(); extendsp;
|
||||
extendsp = extendsp->classp()->extendsp()) {
|
||||
const AstClass* const ebasep = extendsp->classp();
|
||||
if (ebasep->baseOverride().isFinal()) {
|
||||
extendsp->v3error("Class " << nodep->prettyNameQ()
|
||||
<< " is being extended from class marked ':final'"
|
||||
" (IEEE 1800-2023 8.20)\n"
|
||||
<< extendsp->warnContextPrimary() << "\n"
|
||||
<< ebasep->warnOther()
|
||||
<< "... Location of ':final' class being extended\n"
|
||||
<< ebasep->warnContextSecondary());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void visit(AstConst* nodep) override {
|
||||
@ -177,6 +193,45 @@ private:
|
||||
nodep->v3error(
|
||||
"Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2023 8.21)");
|
||||
}
|
||||
bool extended = false;
|
||||
if (const AstClass* const classp = VN_CAST(m_modp, Class)) {
|
||||
for (AstClassExtends* extendsp = classp->extendsp(); extendsp;
|
||||
extendsp = extendsp->classp()->extendsp()) {
|
||||
const AstClass* const eclassp = extendsp->classp();
|
||||
if (AstNodeFTask* const fbasep
|
||||
= VN_CAST(m_memberMap.findMember(eclassp, nodep->name()), NodeFTask)) {
|
||||
if (fbasep != nodep) {
|
||||
extended = true;
|
||||
if (nodep->baseOverride().isInitial()) {
|
||||
nodep->v3error("Member "
|
||||
<< nodep->prettyNameQ()
|
||||
<< " is marked ':initial' but is being extended"
|
||||
" (IEEE 1800-2023 8.20)\n"
|
||||
<< nodep->warnContextPrimary() << "\n"
|
||||
<< fbasep->warnOther()
|
||||
<< "... Location of declaration being extended\n"
|
||||
<< fbasep->warnContextSecondary());
|
||||
}
|
||||
if (fbasep->baseOverride().isFinal()) {
|
||||
nodep->v3error(
|
||||
"Member "
|
||||
<< nodep->prettyNameQ()
|
||||
<< " is being extended from member marked ':final'"
|
||||
" (IEEE 1800-2023 8.20)\n"
|
||||
<< nodep->warnContextPrimary() << "\n"
|
||||
<< fbasep->warnOther()
|
||||
<< "... Location of ':final' declaration being extended\n"
|
||||
<< fbasep->warnContextSecondary());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!extended && nodep->baseOverride().isExtends()) {
|
||||
nodep->v3error("Member " << nodep->prettyNameQ()
|
||||
<< " marked ':extends' but no base class function is"
|
||||
" being extend (IEEE 1800-2023 8.20)");
|
||||
}
|
||||
}
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
@ -4458,6 +4458,7 @@ list_of_argumentsE<nodeExprp>: // IEEE: [list_of_arguments]
|
||||
task_declaration<nodeFTaskp>: // ==IEEE: task_declaration
|
||||
yTASK dynamic_override_specifiersE lifetimeE taskId tfGuts yENDTASK endLabelE
|
||||
{ $$ = $4; $$->addStmtsp($5); SYMP->popScope($$);
|
||||
$$->baseOverride($2);
|
||||
$$->lifetime($3);
|
||||
GRAMMARP->endLabel($<fl>7, $$, $7); }
|
||||
;
|
||||
@ -4472,11 +4473,13 @@ task_prototype<nodeFTaskp>: // ==IEEE: task_prototype
|
||||
function_declaration<nodeFTaskp>: // IEEE: function_declaration + function_body_declaration
|
||||
yFUNCTION dynamic_override_specifiersE lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE
|
||||
{ $$ = $4; $4->attrIsolateAssign($5); $$->addStmtsp($6);
|
||||
$$->baseOverride($2);
|
||||
$$->lifetime($3);
|
||||
SYMP->popScope($$);
|
||||
GRAMMARP->endLabel($<fl>8, $$, $8); }
|
||||
| yFUNCTION dynamic_override_specifiersE lifetimeE funcIdNew funcIsolateE tfNewGuts yENDFUNCTION endLabelE
|
||||
{ $$ = $4; $4->attrIsolateAssign($5); $$->addStmtsp($6);
|
||||
$$->baseOverride($2);
|
||||
$$->lifetime($3);
|
||||
SYMP->popScope($$);
|
||||
GRAMMARP->endLabel($<fl>8, $$, $8); }
|
||||
@ -7011,6 +7014,7 @@ classFront<classp>: // IEEE: part of class_declaration
|
||||
// // IEEE 1800-2023: lifetimeE replaced with final_specifierE
|
||||
classVirtualE yCLASS final_specifierE lifetimeE idAny/*class_identifier*/
|
||||
{ $$ = new AstClass{$2, *$5};
|
||||
$$->baseOverride($3);
|
||||
$$->isVirtual($1);
|
||||
SYMP->pushNew($<classp>$);
|
||||
v3Global.setHasClasses(); }
|
||||
@ -7223,20 +7227,22 @@ class_method<nodep>: // ==IEEE: class_method
|
||||
{ $$ = $3; $2.applyToNodes($3); $3->isExternProto(true); }
|
||||
;
|
||||
|
||||
dynamic_override_specifiersE: // IEEE: dynamic_override_specifiers or empty
|
||||
/* empty */ { /* UNSUP-2023-ignored */ }
|
||||
dynamic_override_specifiersE<baseOverride>: // IEEE: dynamic_override_specifiers or empty
|
||||
/* empty */ { $$ = VBaseOverride{}; }
|
||||
// // IEEE: Expanded [ initial_or_extends_specifier ] [ final_specifier ]
|
||||
// // Note lifetime used by members is instead under memberQual
|
||||
| ':' yINITIAL { /* UNSUP-2023-ignored */ }
|
||||
| ':' yEXTENDS { /* UNSUP-2023-ignored */ }
|
||||
| ':' yINITIAL ':' yFINAL { /* UNSUP-2023-ignored */ }
|
||||
| ':' yEXTENDS ':' yFINAL { /* UNSUP-2023-ignored */ }
|
||||
| ':' yFINAL { /* UNSUP-2023-ignored */ }
|
||||
| ':' yINITIAL { $$ = VBaseOverride{VBaseOverride::Initial{}}; }
|
||||
| ':' yEXTENDS { $$ = VBaseOverride{VBaseOverride::Extends{}}; }
|
||||
| ':' yINITIAL ':' yFINAL { $$ = VBaseOverride{VBaseOverride::Initial{}};
|
||||
$$.combine(VBaseOverride{VBaseOverride::Final{}}); }
|
||||
| ':' yEXTENDS ':' yFINAL { $$ = VBaseOverride{VBaseOverride::Extends{}};
|
||||
$$.combine(VBaseOverride{VBaseOverride::Final{}}); }
|
||||
| ':' yFINAL { $$ = VBaseOverride{VBaseOverride::Final{}}; }
|
||||
;
|
||||
|
||||
final_specifierE: // ==IEEE: final_specifier (similar to dynamic_override_specifiers)
|
||||
/* empty */ { }
|
||||
| ':' yFINAL { /* UNSUP-2023-ignored */ }
|
||||
final_specifierE<baseOverride>: // ==IEEE: final_specifier (similar to dynamic_override_specifiers)
|
||||
/* empty */ { $$ = VBaseOverride{}; }
|
||||
| ':' yFINAL { $$ = VBaseOverride{VBaseOverride::Final{}}; }
|
||||
;
|
||||
|
||||
// IEEE: class_constructor_prototype
|
||||
|
21
test_regress/t/t_class_override.pl
Executable file
21
test_regress/t/t_class_override.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
113
test_regress/t/t_class_override.v
Normal file
113
test_regress/t/t_class_override.v
Normal file
@ -0,0 +1,113 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Function names correspond to how the function is declared in the base class,
|
||||
// then the extend class, with letters:
|
||||
// Does-not-exist(x), Nothing(n), :initial(i), :extends(e), :final(f)
|
||||
|
||||
class Base;
|
||||
// _X = non-existant
|
||||
// _n = None
|
||||
function int get_n; return 1; endfunction
|
||||
function int get_n_n; return 1; endfunction
|
||||
function int get_n_e; return 1; endfunction
|
||||
function int get_n_ef; return 1; endfunction
|
||||
function int get_n_i; return 1; endfunction
|
||||
function int get_n_if; return 1; endfunction
|
||||
function int get_n_f; return 1; endfunction
|
||||
// _e = :extends
|
||||
// function :extends int get_e; return 1; endfunction // Bad
|
||||
// _ef = :extends :final
|
||||
// function :extends :final int get_ef; return 1; endfunction // Bad
|
||||
// _i = :initial
|
||||
function :initial int get_i; return 1; endfunction
|
||||
function :initial int get_i_n; return 1; endfunction
|
||||
function :initial int get_i_e; return 1; endfunction
|
||||
function :initial int get_i_ef; return 1; endfunction
|
||||
function :initial int get_i_i; return 1; endfunction
|
||||
function :initial int get_i_if; return 1; endfunction
|
||||
function :initial int get_i_f; return 1; endfunction
|
||||
// _if = :initial :final
|
||||
function :initial :final int get_if; return 1; endfunction
|
||||
function :initial :final int get_if_n; return 1; endfunction
|
||||
function :initial :final int get_if_e; return 1; endfunction
|
||||
function :initial :final int get_if_ef; return 1; endfunction
|
||||
function :initial :final int get_if_i; return 1; endfunction
|
||||
function :initial :final int get_if_if; return 1; endfunction
|
||||
function :initial :final int get_if_f; return 1; endfunction
|
||||
// _f = :final
|
||||
function :final int get_f; return 1; endfunction
|
||||
function :final int get_f_n; return 1; endfunction
|
||||
function :final int get_f_e; return 1; endfunction
|
||||
function :final int get_f_ef; return 1; endfunction
|
||||
function :final int get_f_i; return 1; endfunction
|
||||
function :final int get_f_if; return 1; endfunction
|
||||
function :final int get_f_f; return 1; endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class Cls extends Base;
|
||||
// _X = non-existant
|
||||
function int get_x_n; return 1; endfunction
|
||||
// function :extends int get_x_e; return 1; endfunction // Bad
|
||||
// function :extends :final int get_x_ef; return 1; endfunction // Bad
|
||||
function :initial int get_x_i; return 1; endfunction
|
||||
function :initial :final int get_x_if; return 1; endfunction
|
||||
function :final int get_x_f; return 1; endfunction
|
||||
// _n = None
|
||||
function int get_n_n; return 1; endfunction
|
||||
function :extends int get_n_e; return 1; endfunction
|
||||
function :extends :final int get_n_ef; return 1; endfunction
|
||||
// function :initial int get_n_i; return 1; endfunction // Bad
|
||||
// function :initial :final int get_n_if; return 1; endfunction // Bad
|
||||
function :final int get_n_f; return 1; endfunction
|
||||
// _e = :extends
|
||||
// _ef = :extends :final
|
||||
// _i = :initial
|
||||
function int get_i_n; return 1; endfunction
|
||||
function :extends int get_i_e; return 1; endfunction
|
||||
function :extends :final int get_i_ef; return 1; endfunction
|
||||
// function :initial int get_i_i; return 1; endfunction // Bad
|
||||
// function :initial :final int get_i_if; return 1; endfunction // Bad
|
||||
function :final int get_i_f; return 1; endfunction
|
||||
// _if = :initial :final
|
||||
// function int get_if_n; return 1; endfunction // Bad
|
||||
// function :extends int get_if_e; return 1; endfunction // Bad
|
||||
// function :extends :final int get_if_ef; return 1; endfunction // Bad
|
||||
// function :initial int get_if_i; return 1; endfunction // Bad
|
||||
// function :initial :final int get_if_if; return 1; endfunction // Bad
|
||||
// function :final int get_if_f; return 1; endfunction // Bad
|
||||
// _f = :final
|
||||
// function int get_f_n; return 1; endfunction // Bad
|
||||
// function :extends int get_f_e; return 1; endfunction // Bad
|
||||
// function :extends :final int get_f_ef; return 1; endfunction // Bad
|
||||
// function :initial int get_f_i; return 1; endfunction // Bad
|
||||
// function :initial :final int get_f_if; return 1; endfunction // Bad
|
||||
// function :final int get_f_f; return 1; endfunction // Bad
|
||||
endclass
|
||||
|
||||
class CBase;
|
||||
endclass
|
||||
|
||||
class CClsN extends CBase;
|
||||
endclass
|
||||
|
||||
class :final CClsF extends CBase;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
Cls c;
|
||||
CClsF cc;
|
||||
|
||||
if (c != null) $stop;
|
||||
c = new;
|
||||
cc = new;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
164
test_regress/t/t_class_override_bad.out
Normal file
164
test_regress/t/t_class_override_bad.out
Normal file
@ -0,0 +1,164 @@
|
||||
%Error: t/t_class_override_bad.v:22:26: Member 'get_e' marked ':extends' but no base class function is being extend (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
22 | function :extends int get_e; return 1; endfunction
|
||||
| ^~~~~
|
||||
%Error: t/t_class_override_bad.v:24:33: Member 'get_ef' marked ':extends' but no base class function is being extend (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
24 | function :extends :final int get_ef; return 1; endfunction
|
||||
| ^~~~~~
|
||||
%Error: t/t_class_override_bad.v:55:26: Member 'get_x_e' marked ':extends' but no base class function is being extend (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
55 | function :extends int get_x_e; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:56:33: Member 'get_x_ef' marked ':extends' but no base class function is being extend (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
56 | function :extends :final int get_x_ef; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:64:26: Member 'get_n_i' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
64 | function :initial int get_n_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:18:17: ... Location of declaration being extended
|
||||
18 | function int get_n_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:65:33: Member 'get_n_if' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
65 | function :initial :final int get_n_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:19:17: ... Location of declaration being extended
|
||||
19 | function int get_n_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:73:26: Member 'get_i_i' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
73 | function :initial int get_i_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:30:26: ... Location of declaration being extended
|
||||
30 | function :initial int get_i_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:74:33: Member 'get_i_if' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
74 | function :initial :final int get_i_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:31:26: ... Location of declaration being extended
|
||||
31 | function :initial int get_i_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:77:17: Member 'get_if_n' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
77 | function int get_if_n; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:35:33: ... Location of ':final' declaration being extended
|
||||
35 | function :initial :final int get_if_n; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:78:26: Member 'get_if_e' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
78 | function :extends int get_if_e; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:36:33: ... Location of ':final' declaration being extended
|
||||
36 | function :initial :final int get_if_e; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:79:33: Member 'get_if_ef' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
79 | function :extends :final int get_if_ef; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
t/t_class_override_bad.v:37:33: ... Location of ':final' declaration being extended
|
||||
37 | function :initial :final int get_if_ef; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:80:26: Member 'get_if_i' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
80 | function :initial int get_if_i; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:38:33: ... Location of declaration being extended
|
||||
38 | function :initial :final int get_if_i; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:80:26: Member 'get_if_i' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
80 | function :initial int get_if_i; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:38:33: ... Location of ':final' declaration being extended
|
||||
38 | function :initial :final int get_if_i; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:81:33: Member 'get_if_if' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
81 | function :initial :final int get_if_if; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
t/t_class_override_bad.v:39:33: ... Location of declaration being extended
|
||||
39 | function :initial :final int get_if_if; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:81:33: Member 'get_if_if' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
81 | function :initial :final int get_if_if; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
t/t_class_override_bad.v:39:33: ... Location of ':final' declaration being extended
|
||||
39 | function :initial :final int get_if_if; return 1; endfunction
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:82:24: Member 'get_if_f' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
82 | function :final int get_if_f; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:40:33: ... Location of ':final' declaration being extended
|
||||
40 | function :initial :final int get_if_f; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:84:17: Member 'get_f_n' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
84 | function int get_f_n; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:43:24: ... Location of ':final' declaration being extended
|
||||
43 | function :final int get_f_n; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:85:26: Member 'get_f_e' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
85 | function :extends int get_f_e; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:44:24: ... Location of ':final' declaration being extended
|
||||
44 | function :final int get_f_e; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:86:33: Member 'get_f_ef' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
86 | function :extends :final int get_f_ef; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:45:24: ... Location of ':final' declaration being extended
|
||||
45 | function :final int get_f_ef; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:87:26: Member 'get_f_i' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
87 | function :initial int get_f_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:46:24: ... Location of declaration being extended
|
||||
46 | function :final int get_f_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:87:26: Member 'get_f_i' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
87 | function :initial int get_f_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:46:24: ... Location of ':final' declaration being extended
|
||||
46 | function :final int get_f_i; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:88:33: Member 'get_f_if' is marked ':initial' but is being extended (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
88 | function :initial :final int get_f_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:47:24: ... Location of declaration being extended
|
||||
47 | function :final int get_f_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:88:33: Member 'get_f_if' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
88 | function :initial :final int get_f_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
t/t_class_override_bad.v:47:24: ... Location of ':final' declaration being extended
|
||||
47 | function :final int get_f_if; return 1; endfunction
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_class_override_bad.v:89:24: Member 'get_f_f' is being extended from member marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
89 | function :final int get_f_f; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
t/t_class_override_bad.v:48:24: ... Location of ':final' declaration being extended
|
||||
48 | function :final int get_f_f; return 1; endfunction
|
||||
| ^~~~~~~
|
||||
%Error: t/t_class_override_bad.v:101:42: Class 'CClsBadExtendsFinal' is being extended from class marked ':final' (IEEE 1800-2023 8.20)
|
||||
: ... note: In instance 't'
|
||||
101 | class :final CClsBadExtendsFinal extends CClsF;
|
||||
| ^~~~~
|
||||
t/t_class_override_bad.v:98:1: ... Location of ':final' class being extended
|
||||
98 | class :final CClsF extends CBase;
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_class_override_bad.pl
Executable file
19
test_regress/t/t_class_override_bad.pl
Executable 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 2020 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;
|
116
test_regress/t/t_class_override_bad.v
Normal file
116
test_regress/t/t_class_override_bad.v
Normal file
@ -0,0 +1,116 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Function names correspond to how the function is declared in the base class,
|
||||
// then the extend class, with letters:
|
||||
// Does-not-exist(x), Nothing(n), :initial(i), :extends(e), :final(f)
|
||||
|
||||
class Base;
|
||||
// _X = non-existant
|
||||
// _n = None
|
||||
function int get_n; return 1; endfunction
|
||||
function int get_n_n; return 1; endfunction
|
||||
function int get_n_e; return 1; endfunction
|
||||
function int get_n_ef; return 1; endfunction
|
||||
function int get_n_i; return 1; endfunction
|
||||
function int get_n_if; return 1; endfunction
|
||||
function int get_n_f; return 1; endfunction
|
||||
// _e = :extends
|
||||
function :extends int get_e; return 1; endfunction // Bad
|
||||
// _ef = :extends :final
|
||||
function :extends :final int get_ef; return 1; endfunction // Bad
|
||||
// _i = :initial
|
||||
function :initial int get_i; return 1; endfunction
|
||||
function :initial int get_i_n; return 1; endfunction
|
||||
function :initial int get_i_e; return 1; endfunction
|
||||
function :initial int get_i_ef; return 1; endfunction
|
||||
function :initial int get_i_i; return 1; endfunction
|
||||
function :initial int get_i_if; return 1; endfunction
|
||||
function :initial int get_i_f; return 1; endfunction
|
||||
// _if = :initial :final
|
||||
function :initial :final int get_if; return 1; endfunction
|
||||
function :initial :final int get_if_n; return 1; endfunction
|
||||
function :initial :final int get_if_e; return 1; endfunction
|
||||
function :initial :final int get_if_ef; return 1; endfunction
|
||||
function :initial :final int get_if_i; return 1; endfunction
|
||||
function :initial :final int get_if_if; return 1; endfunction
|
||||
function :initial :final int get_if_f; return 1; endfunction
|
||||
// _f = :final
|
||||
function :final int get_f; return 1; endfunction
|
||||
function :final int get_f_n; return 1; endfunction
|
||||
function :final int get_f_e; return 1; endfunction
|
||||
function :final int get_f_ef; return 1; endfunction
|
||||
function :final int get_f_i; return 1; endfunction
|
||||
function :final int get_f_if; return 1; endfunction
|
||||
function :final int get_f_f; return 1; endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class Cls extends Base;
|
||||
// _X = non-existant
|
||||
function int get_x_n; return 1; endfunction
|
||||
function :extends int get_x_e; return 1; endfunction // Bad
|
||||
function :extends :final int get_x_ef; return 1; endfunction // Bad
|
||||
function :initial int get_x_i; return 1; endfunction
|
||||
function :initial :final int get_x_if; return 1; endfunction
|
||||
function :final int get_x_f; return 1; endfunction
|
||||
// _n = None
|
||||
function int get_n_n; return 1; endfunction
|
||||
function :extends int get_n_e; return 1; endfunction
|
||||
function :extends :final int get_n_ef; return 1; endfunction
|
||||
function :initial int get_n_i; return 1; endfunction // Bad
|
||||
function :initial :final int get_n_if; return 1; endfunction // Bad
|
||||
function :final int get_n_f; return 1; endfunction
|
||||
// _e = :extends
|
||||
// _ef = :extends :final
|
||||
// _i = :initial
|
||||
function int get_i_n; return 1; endfunction
|
||||
function :extends int get_i_e; return 1; endfunction
|
||||
function :extends :final int get_i_ef; return 1; endfunction
|
||||
function :initial int get_i_i; return 1; endfunction // Bad
|
||||
function :initial :final int get_i_if; return 1; endfunction // Bad
|
||||
function :final int get_i_f; return 1; endfunction
|
||||
// _if = :initial :final
|
||||
function int get_if_n; return 1; endfunction // Bad
|
||||
function :extends int get_if_e; return 1; endfunction // Bad
|
||||
function :extends :final int get_if_ef; return 1; endfunction // Bad
|
||||
function :initial int get_if_i; return 1; endfunction // Bad
|
||||
function :initial :final int get_if_if; return 1; endfunction // Bad
|
||||
function :final int get_if_f; return 1; endfunction // Bad
|
||||
// _f = :final
|
||||
function int get_f_n; return 1; endfunction // Bad
|
||||
function :extends int get_f_e; return 1; endfunction // Bad
|
||||
function :extends :final int get_f_ef; return 1; endfunction // Bad
|
||||
function :initial int get_f_i; return 1; endfunction // Bad
|
||||
function :initial :final int get_f_if; return 1; endfunction // Bad
|
||||
function :final int get_f_f; return 1; endfunction // Bad
|
||||
endclass
|
||||
|
||||
class CBase;
|
||||
endclass
|
||||
|
||||
class CClsN extends CBase;
|
||||
endclass
|
||||
|
||||
class :final CClsF extends CBase;
|
||||
endclass
|
||||
|
||||
class :final CClsBadExtendsFinal extends CClsF;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
Cls c;
|
||||
CClsF cc;
|
||||
|
||||
if (c != null) $stop;
|
||||
c = new;
|
||||
cc = new;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user