diff --git a/src/verilog.y b/src/verilog.y index 2a93acad9..29e18999c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5342,7 +5342,14 @@ exprScope: // scope and variable for use to inside an e | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } | ~l~expr '.' idArrayed { $$ = new AstDot{$2, false, $1, $3}; } // // expr below must be a "yTHIS" - | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } + | ~l~expr '.' ySUPER + { AstParseRef* const anodep = VN_CAST($1, ParseRef); + if (anodep && anodep->name() == "this") { + $$ = new AstParseRef{$1, VParseRefExp::PX_ROOT, "super"}; + } else { + $$ = $1; $$->v3error("Syntax error: 'super' must be first name component, or after 'this.'"); + } + } // // Part of implicit_class_handle | ySUPER { $$ = new AstParseRef{$1, VParseRefExp::PX_ROOT, "super"}; } ; @@ -6093,7 +6100,8 @@ idClass: // Misc Ref to dotted, and/or arrayed, and/or bi { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "this"}, $3}; } | ySUPER '.' idDotted { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "super"}, $3}; } - | yTHIS '.' ySUPER '.' idDotted { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + | yTHIS '.' ySUPER '.' idDotted + { $$ = new AstDot{$4, false, new AstParseRef{$3, VParseRefExp::PX_ROOT, "super"}, $5}; } // // Expanded: package_scope idDottedSel | packageClassScope idDotted { $$ = new AstDot{$2, true, $1, $2}; } ; @@ -6105,7 +6113,8 @@ idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bi { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "this"}, $3}; } | ySUPER '.' idDottedSel { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "super"}, $3}; } - | yTHIS '.' ySUPER '.' idDottedSel { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + | yTHIS '.' ySUPER '.' idDottedSel + { $$ = new AstDot{$4, false, new AstParseRef{$3, VParseRefExp::PX_ROOT, "super"}, $5}; } // // Expanded: package_scope idDottedSel | packageClassScope idDottedSel { $$ = new AstDot{$2, true, $1, $2}; } ; @@ -6117,7 +6126,8 @@ idClassSelForeach: { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "this"}, $3}; } | ySUPER '.' idDottedForeach { $$ = new AstDot{$2, false, new AstParseRef{$1, VParseRefExp::PX_ROOT, "super"}, $3}; } - | yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + | yTHIS '.' ySUPER '.' idDottedForeach + { $$ = new AstDot{$4, false, new AstParseRef{$3, VParseRefExp::PX_ROOT, "super"}, $5}; } // // Expanded: package_scope idForeach | packageClassScope idDottedForeach { $$ = new AstDot{$2, true, $1, $2}; } ; diff --git a/test_regress/t/t_class_super_bad3.out b/test_regress/t/t_class_super_bad3.out new file mode 100644 index 000000000..8f4a075c6 --- /dev/null +++ b/test_regress/t/t_class_super_bad3.out @@ -0,0 +1,5 @@ +%Error: t/t_class_super_bad3.v:10:5: Syntax error: 'super' must be first name component, or after 'this.' + 10 | i.super.i = 1; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_class_super_bad3.py b/test_regress/t/t_class_super_bad3.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_class_super_bad3.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_class_super_bad3.v b/test_regress/t/t_class_super_bad3.v new file mode 100644 index 000000000..e50fd51fe --- /dev/null +++ b/test_regress/t/t_class_super_bad3.v @@ -0,0 +1,12 @@ +// 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 Cls; + task t; + i.super.i = 1; // <--- BAD: cannot dot a reference to get super + endtask +endclass diff --git a/test_regress/t/t_class_this_super.py b/test_regress/t/t_class_this_super.py new file mode 100755 index 000000000..f989a35fb --- /dev/null +++ b/test_regress/t/t_class_this_super.py @@ -0,0 +1,18 @@ +#!/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.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_this_super.v b/test_regress/t/t_class_this_super.v new file mode 100644 index 000000000..bfb325783 --- /dev/null +++ b/test_regress/t/t_class_this_super.v @@ -0,0 +1,52 @@ +// 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 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// Based on icarus/ivtest/ivltests/sv_class_super6.v + +class B; + int m_x, m_y; + + task set_y; + m_y = 2000; + endtask + + function void check_x; + `checkd(m_x, 1000); + endfunction +endclass + +class C extends B; + byte m_x, m_y; + task set_x; + m_x = 6; + this.m_y = 7; + this.super.m_x = 1000; + endtask + + function void check_y; + `checkd(m_x, 6); + `checkd(this.m_y, 7); + `checkd(this.super.m_y, 2000); + endfunction +endclass + +module test; + C c; + + initial begin + c = new; + c.set_x(); + c.set_y(); + c.check_x(); + c.check_y(); + $finish; + end +endmodule