From aff501f5c4aba93842a77789c01a32225cc1e6f4 Mon Sep 17 00:00:00 2001 From: em2machine <92717390+em2machine@users.noreply.github.com> Date: Fri, 12 Dec 2025 21:20:15 +0100 Subject: [PATCH] Fix resolution of specialized typedefs (#6754) (#6808) --- src/V3Param.cpp | 19 +++++++++ test_regress/t/t_class_param_typedef5.py | 18 +++++++++ test_regress/t/t_class_param_typedef5.v | 44 +++++++++++++++++++++ test_regress/t/t_class_param_typedef6.py | 18 +++++++++ test_regress/t/t_class_param_typedef6.v | 49 ++++++++++++++++++++++++ 5 files changed, 148 insertions(+) create mode 100755 test_regress/t/t_class_param_typedef5.py create mode 100644 test_regress/t/t_class_param_typedef5.v create mode 100755 test_regress/t/t_class_param_typedef6.py create mode 100644 test_regress/t/t_class_param_typedef6.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 69bedbdbb..0687fb103 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1240,6 +1240,25 @@ class ParamProcessor final { = nodeDeparamCommon(nodep, srcModp, nodep->paramsp(), nullptr, false); if (!newModp) return nullptr; nodep->classOrPackagep(newModp); // Might be unchanged if not cloned (newModp == srcModp) + + // If this ClassOrPackageRef is a child of a RefDType (e.g., typedef class#(T)::member_t), + // resolve the RefDType's typedef to point to the typedef inside the specialized class + AstRefDType* const refDTypep = VN_CAST(nodep->backp(), RefDType); + AstClass* const newClassp = refDTypep ? VN_CAST(newModp, Class) : nullptr; + if (newClassp && !refDTypep->typedefp() && !refDTypep->subDTypep()) { + for (AstNode* itemp = newClassp->membersp(); itemp; itemp = itemp->nextp()) { + if (AstTypedef* const typedefp = VN_CAST(itemp, Typedef)) { + if (typedefp->name() == refDTypep->name()) { + refDTypep->typedefp(typedefp); + refDTypep->classOrPackagep(newClassp); + UINFO(9, "Resolved parameterized class typedef: " + << refDTypep->name() << " -> " << typedefp << " in " + << newClassp->name()); + break; + } + } + } + } return newModp; } AstNodeModule* classRefDeparam(AstClassRefDType* nodep, AstNodeModule* srcModp) { diff --git a/test_regress/t/t_class_param_typedef5.py b/test_regress/t/t_class_param_typedef5.py new file mode 100755 index 000000000..c53b55262 --- /dev/null +++ b/test_regress/t/t_class_param_typedef5.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_param_typedef5.v b/test_regress/t/t_class_param_typedef5.v new file mode 100644 index 000000000..fb3fdbe92 --- /dev/null +++ b/test_regress/t/t_class_param_typedef5.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// SPDX-License-Identifier: CC0-1.0 + +class func_c #(parameter p_width=4); + typedef struct packed { + logic[p_width-1:0] data; + } my_type_t; + static function my_type_t func( + input logic[p_width-1:0] inb + ); + func.data = inb; + endfunction +endclass + +module modA #(parameter p_width = 7)( + input func_c#(p_width)::my_type_t sig_a + ,output func_c#(p_width)::my_type_t sig_b +); + assign sig_b.data = func_c#(p_width)::func(sig_a); +endmodule + +module the_top(); + localparam int Size = 3; + + func_c#(Size)::my_type_t sig_a, sig_b, sig_c; + + modA #(.p_width(Size)) modA( + .sig_a(sig_a) + ,.sig_b(sig_b) + ); + + initial begin + sig_a.data = 'h3; + sig_c.data = func_c#(Size)::func('h5); + #1; + if(sig_b.data != 'h3) $stop; + if(sig_c.data != 'h5) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_typedef6.py b/test_regress/t/t_class_param_typedef6.py new file mode 100755 index 000000000..c53b55262 --- /dev/null +++ b/test_regress/t/t_class_param_typedef6.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_param_typedef6.v b/test_regress/t/t_class_param_typedef6.v new file mode 100644 index 000000000..1be0a302f --- /dev/null +++ b/test_regress/t/t_class_param_typedef6.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// SPDX-License-Identifier: CC0-1.0 + + +`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); + +class pipeline_class #( + parameter type XWORD = logic +); + + typedef struct packed { + XWORD pc; + } if_id_t; + +endclass + +module pipe_reg #( + parameter type T = logic +)(); + initial begin + #1; + `checkd($bits(T), 8); + end +endmodule + +module the_top #() (); + + typedef logic [7:0] my_t; + typedef pipeline_class #(my_t)::if_id_t if_id_t; + pipe_reg #(if_id_t) if_id_reg(); + + initial begin + #1; + #1; + `checkd($bits(if_id_t), 8); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule