From 91c44d7830a300d59a95ce3fb9fdc41e46f752e8 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 26 Jan 2023 02:33:18 +0100 Subject: [PATCH] Support class extending its parameter (#3904) --- src/V3LinkDot.cpp | 44 +++++++++++++---- .../t/t_class_extends_alias_unsup.out | 5 ++ test_regress/t/t_class_extends_alias_unsup.pl | 19 ++++++++ test_regress/t/t_class_extends_alias_unsup.v | 38 +++++++++++++++ .../t/t_class_extends_aliased_real_bad.out | 5 ++ .../t/t_class_extends_aliased_real_bad.pl | 19 ++++++++ .../t/t_class_extends_aliased_real_bad.v | 19 ++++++++ .../t/t_class_extends_int_param_bad.out | 5 ++ .../t/t_class_extends_int_param_bad.pl | 19 ++++++++ .../t/t_class_extends_int_param_bad.v | 15 ++++++ test_regress/t/t_class_extends_param.pl | 20 ++++++++ test_regress/t/t_class_extends_param.v | 48 +++++++++++++++++++ 12 files changed, 246 insertions(+), 10 deletions(-) create mode 100644 test_regress/t/t_class_extends_alias_unsup.out create mode 100755 test_regress/t/t_class_extends_alias_unsup.pl create mode 100644 test_regress/t/t_class_extends_alias_unsup.v create mode 100644 test_regress/t/t_class_extends_aliased_real_bad.out create mode 100755 test_regress/t/t_class_extends_aliased_real_bad.pl create mode 100644 test_regress/t/t_class_extends_aliased_real_bad.v create mode 100644 test_regress/t/t_class_extends_int_param_bad.out create mode 100755 test_regress/t/t_class_extends_int_param_bad.pl create mode 100644 test_regress/t/t_class_extends_int_param_bad.v create mode 100755 test_regress/t/t_class_extends_param.pl create mode 100644 test_regress/t/t_class_extends_param.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 332f585bb..5301de451 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3174,20 +3174,46 @@ private: cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE } else { VSymEnt* const foundp = m_curSymp->findIdFallback(cpackagerefp->name()); - bool ok = false; if (foundp) { - if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) { + AstClassRefDType* classRefDtypep = nullptr; + AstClass* classp = VN_CAST(foundp->nodep(), Class); + if (classp) { + AstPin* paramsp = cpackagerefp->paramsp(); + if (paramsp) paramsp = paramsp->cloneTree(true); + classRefDtypep + = new AstClassRefDType{nodep->fileline(), classp, paramsp}; + } else if (AstParamTypeDType* const paramp + = VN_CAST(foundp->nodep(), ParamTypeDType)) { + if (m_statep->forPrimary()) { + // Extending has to be handled after V3Param.cpp, but the type + // reference has to be visited + iterate(paramp); + return; + } else { + AstNodeDType* const paramTypep = paramp->getChildDTypep(); + classRefDtypep + = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); + if (!classRefDtypep) { + paramTypep->v3error( + "Attempting to extend using non-class"); + } else { + classp = classRefDtypep->classp(); + } + } + } else { + cextp->v3warn(E_UNSUPPORTED, + "Unsupported: " << foundp->nodep()->prettyTypeName() + << " in AstClassExtends"); + } + + if (classp) { UINFO(8, "Import to " << nodep << " from export class " << classp << endl); if (classp == nodep) { cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() << " from itself"); } else { - AstPin* paramsp = cpackagerefp->paramsp(); - if (paramsp) paramsp = paramsp->cloneTree(true); - const auto newp - = new AstClassRefDType{nodep->fileline(), classp, paramsp}; - cextp->childDTypep(newp); + cextp->childDTypep(classRefDtypep); classp->isExtended(true); nodep->isExtended(true); VSymEnt* const srcp = m_statep->getNodeSym(classp); @@ -3195,10 +3221,8 @@ private: VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), cpackagerefp); } - ok = true; } - } - if (!ok) { + } else { const string suggest = m_statep->suggestSymFallback( m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); cpackagerefp->v3error( diff --git a/test_regress/t/t_class_extends_alias_unsup.out b/test_regress/t/t_class_extends_alias_unsup.out new file mode 100644 index 000000000..ff50572f7 --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_class_extends_alias_unsup.v:22:22: Unsupported: TYPEDEF 'foo_t' in AstClassExtends + 22 | class bar extends foo_t; + | ^~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_alias_unsup.pl b/test_regress/t/t_class_extends_alias_unsup.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.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 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; diff --git a/test_regress/t/t_class_extends_alias_unsup.v b/test_regress/t/t_class_extends_alias_unsup.v new file mode 100644 index 000000000..a0a8f7197 --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.v @@ -0,0 +1,38 @@ +// 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 + +module t (/*AUTOARG*/ + ); + + class foo; + int x = 1; + function int get_x; + return x; + endfunction + function int get_3; + return 3; + endfunction + endclass + + typedef foo foo_t; + + class bar extends foo_t; + endclass + + + bar bar_foo_t_i; + + initial begin + bar_foo_t_i = new; + if (bar_foo_t_i.get_x() == 1 && bar_foo_t_i.get_3() == 3) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_class_extends_aliased_real_bad.out b/test_regress/t/t_class_extends_aliased_real_bad.out new file mode 100644 index 000000000..ce714742d --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_extends_aliased_real_bad.v:14:10: Attempting to extend using non-class + : ... In instance t + 14 | bar #(real_t) bar_real_t; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_aliased_real_bad.pl b/test_regress/t/t_class_extends_aliased_real_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.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 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; diff --git a/test_regress/t/t_class_extends_aliased_real_bad.v b/test_regress/t/t_class_extends_aliased_real_bad.v new file mode 100644 index 000000000..a03f8bc93 --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.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 + +module t (/*AUTOARG*/); + + class bar #(type T) extends T; + endclass + + typedef real real_t; + + bar #(real_t) bar_real_t; + + initial begin + $stop; + end +endmodule diff --git a/test_regress/t/t_class_extends_int_param_bad.out b/test_regress/t/t_class_extends_int_param_bad.out new file mode 100644 index 000000000..8f75bf3af --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class + : ... In instance t + 9 | class bar #(type T=int) extends T; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_int_param_bad.pl b/test_regress/t/t_class_extends_int_param_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.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 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; diff --git a/test_regress/t/t_class_extends_int_param_bad.v b/test_regress/t/t_class_extends_int_param_bad.v new file mode 100644 index 000000000..f5ee566eb --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.v @@ -0,0 +1,15 @@ +// 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 + +module t (/*AUTOARG*/); + + class bar #(type T=int) extends T; + endclass + + initial begin + $stop; + end +endmodule diff --git a/test_regress/t/t_class_extends_param.pl b/test_regress/t/t_class_extends_param.pl new file mode 100755 index 000000000..e191e87f4 --- /dev/null +++ b/test_regress/t/t_class_extends_param.pl @@ -0,0 +1,20 @@ +#!/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 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; diff --git a/test_regress/t/t_class_extends_param.v b/test_regress/t/t_class_extends_param.v new file mode 100644 index 000000000..056985bc5 --- /dev/null +++ b/test_regress/t/t_class_extends_param.v @@ -0,0 +1,48 @@ +// 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 + +module t (/*AUTOARG*/ + ); + + class foo; + int x = 1; + function int get_x; + return x; + endfunction + function int get_3; + return 3; + endfunction + endclass + + class bar #(type T=foo) extends T; + endclass + + class baz; + int x = 2; + function int get_x; + return x; + endfunction + function int get_4; + return 4; + endfunction + endclass + + bar bar_foo_i; + bar #(baz) bar_baz_i; + + initial begin + bar_foo_i = new; + bar_baz_i = new; + if (bar_foo_i.get_x() == 1 && bar_foo_i.get_3() == 3 && + bar_baz_i.get_x() == 2 && bar_baz_i.get_4() == 4) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $stop; + end + end +endmodule