diff --git a/src/V3Ast.h b/src/V3Ast.h index 13790a5cd..f0528a961 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -514,6 +514,7 @@ public: VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes VAR_CLOCK_ENABLE, // Ignored, accepted for compatibility VAR_FORCEABLE, // V3LinkParse moves to AstVar::isForceable + VAR_PORT_DTYPE, // V3LinkDot for V3Width to check port dtype VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic @@ -538,7 +539,7 @@ public: "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID", "TYPEID", "TYPENAME", - "VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC", + "VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER", "VAR_NO_CLOCKER", "VAR_SPLIT_VAR" diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7df735e67..2f85156be 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1512,33 +1512,32 @@ class LinkDotFindVisitor final : public VNVisitor { && !findvarp->subDTypep()->numeric().isSigned()) { findvarp->subDTypep()->numeric(VSigning{true}); } - AstBasicDType* const bdtypep - = VN_CAST(findvarp->childDTypep(), BasicDType); + AstNodeDType* varDtp = findvarp->subDTypep(); + AstNodeDType* otherDtp = nodep->subDTypep(); + AstBasicDType* const bdtypep = VN_CAST(varDtp, BasicDType); if (bdtypep && bdtypep->implicit()) { // Then have "input foo" and "real foo" so the // dtype comes from the other side. - AstNodeDType* const newdtypep = nodep->subDTypep(); - UASSERT_OBJ(newdtypep && nodep->childDTypep(), findvarp, - "No child type?"); + AstNodeDType* const newdtypep = otherDtp; + otherDtp = varDtp; + varDtp = newdtypep; VL_DO_DANGLING(bdtypep->unlinkFrBack()->deleteTree(), bdtypep); newdtypep->unlinkFrBack(); findvarp->childDTypep(newdtypep); } - if (nodep->childDTypep() && findvarp->childDTypep() - && !(VN_IS(nodep->childDTypep(), BasicDType) - && VN_AS(nodep->childDTypep(), BasicDType)->keyword() + if (otherDtp && varDtp + && !(VN_IS(otherDtp, BasicDType) + && VN_AS(otherDtp, BasicDType)->keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) - && !(VN_IS(findvarp->childDTypep(), BasicDType) - && VN_AS(findvarp->childDTypep(), BasicDType)->keyword() - == VBasicDTypeKwd::LOGIC_IMPLICIT) - && !nodep->sameTree(findvarp)) { - nodep->v3error("Non-ANSI I/O declaration of signal " - "conflicts with type declaration: " - << nodep->prettyNameQ() << '\n' - << nodep->warnContextPrimary() << '\n' - << findvarp->warnOther() - << "... Location of other declaration\n" - << findvarp->warnContextSecondary()); + && !(VN_IS(varDtp, BasicDType) + && VN_AS(varDtp, BasicDType)->keyword() + == VBasicDTypeKwd::LOGIC_IMPLICIT)) { + // Can't compare dtypes now as might contain parameters, + // defer to V3Width + AstAttrOf* const newp + = new AstAttrOf{otherDtp->fileline(), VAttrType::VAR_PORT_DTYPE, + otherDtp->unlinkFrBack()}; + findvarp->addAttrsp(newp); } } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 109875ae2..269006aaf 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2356,6 +2356,23 @@ class WidthVisitor final : public VNVisitor { // Make sure dtype is sized nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var"); + if (nodep->attrsp()) { + nodep->attrsp()->foreach([this, nodep](AstAttrOf* attrp) { + if (attrp->attrType() == VAttrType::VAR_PORT_DTYPE) { + V3Const::constifyParamsEdit(attrp->fromp()); // fromp may change + if (!similarDTypeRecurse(nodep->dtypep(), VN_AS(attrp->fromp(), NodeDType))) { + nodep->dtypep()->v3error("Non-ANSI I/O declaration of signal " + "conflicts with type declaration: " + << nodep->prettyNameQ() << '\n' + << nodep->dtypep()->warnContextPrimary() << '\n' + << attrp->warnOther() + << "... Location of other declaration\n" + << attrp->warnContextSecondary()); + } + VL_DO_DANGLING(pushDeletep(attrp->unlinkFrBack()), attrp); + } + }); + } if (m_ftaskp && m_ftaskp->dpiImport()) { AstNodeDType* dtp = nodep->dtypep(); AstNodeDType* np = nullptr; diff --git a/test_regress/t/t_func_nansi_bad.out b/test_regress/t/t_func_nansi_bad.out deleted file mode 100644 index 6ba6f4330..000000000 --- a/test_regress/t/t_func_nansi_bad.out +++ /dev/null @@ -1,44 +0,0 @@ -%Error: t/t_func_nansi_bad.v:13:14: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad1' - 13 | shortint bad1; - | ^~~~ - t/t_func_nansi_bad.v:12:18: ... Location of other declaration - 12 | input [15:0] bad1; - | ^~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_func_nansi_bad.v:18:7: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad2' - 18 | T bad2; - | ^~~~ - t/t_func_nansi_bad.v:17:18: ... Location of other declaration - 17 | input [31:0] bad2; - | ^~~~ -%Error: t/t_func_nansi_bad.v:23:15: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad3' - 23 | reg [3:0] bad3; - | ^~~~ - t/t_func_nansi_bad.v:22:17: ... Location of other declaration - 22 | input [7:0] bad3; - | ^~~~ -%Error: t/t_func_nansi_bad.v:28:9: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad4' - 28 | reg bad4; - | ^~~~ - t/t_func_nansi_bad.v:27:17: ... Location of other declaration - 27 | input [7:0] bad4; - | ^~~~ -%Error: t/t_func_nansi_bad.v:29:9: Duplicate declaration of signal: 'bad4' - 29 | reg bad4; - | ^~~~ - t/t_func_nansi_bad.v:27:17: ... Location of original declaration - 27 | input [7:0] bad4; - | ^~~~ -%Error: t/t_func_nansi_bad.v:34:17: Duplicate declaration of signal: 'bad5' - 34 | input [7:0] bad5; - | ^~~~ - t/t_func_nansi_bad.v:33:17: ... Location of original declaration - 33 | input [7:0] bad5; - | ^~~~ -%Error: t/t_func_nansi_bad.v:35:9: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad5' - 35 | reg bad5; - | ^~~~ - t/t_func_nansi_bad.v:33:17: ... Location of other declaration - 33 | input [7:0] bad5; - | ^~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_func_nansi_dup_bad.out b/test_regress/t/t_func_nansi_dup_bad.out new file mode 100644 index 000000000..cf407f0aa --- /dev/null +++ b/test_regress/t/t_func_nansi_dup_bad.out @@ -0,0 +1,14 @@ +%Error: t/t_func_nansi_dup_bad.v:14:9: Duplicate declaration of signal: 'bad4' + 14 | reg bad4; + | ^~~~ + t/t_func_nansi_dup_bad.v:12:17: ... Location of original declaration + 12 | input [7:0] bad4; + | ^~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_func_nansi_dup_bad.v:19:17: Duplicate declaration of signal: 'bad5' + 19 | input [7:0] bad5; + | ^~~~ + t/t_func_nansi_dup_bad.v:18:17: ... Location of original declaration + 18 | input [7:0] bad5; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_func_nansi_bad.py b/test_regress/t/t_func_nansi_dup_bad.py similarity index 100% rename from test_regress/t/t_func_nansi_bad.py rename to test_regress/t/t_func_nansi_dup_bad.py diff --git a/test_regress/t/t_func_nansi_dup_bad.v b/test_regress/t/t_func_nansi_dup_bad.v new file mode 100644 index 000000000..06efe7e21 --- /dev/null +++ b/test_regress/t/t_func_nansi_dup_bad.v @@ -0,0 +1,23 @@ +// 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 + +typedef int T; + +module test; + + task t4; + input [7:0] bad4; + reg bad4; + reg bad4; // <--- Error (duplicate) + endtask + + task t5; + input [7:0] bad5; + input [7:0] bad5; // <--- Error (duplicate) + reg bad5; + endtask + +endmodule diff --git a/test_regress/t/t_func_nansi_mism_bad.out b/test_regress/t/t_func_nansi_mism_bad.out new file mode 100644 index 000000000..2ccad4f9a --- /dev/null +++ b/test_regress/t/t_func_nansi_mism_bad.out @@ -0,0 +1,20 @@ +%Error: t/t_func_nansi_mism_bad.v:12:11: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad1' + 12 | input [15:0] bad1; + | ^ + t/t_func_nansi_mism_bad.v:13:5: ... Location of other declaration + 13 | shortint bad1; + | ^~~~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_func_nansi_mism_bad.v:17:11: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad2' + 17 | input [31:0] bad2; + | ^ + t/t_func_nansi_mism_bad.v:18:5: ... Location of other declaration + 18 | T bad2; + | ^ +%Error: t/t_func_nansi_mism_bad.v:22:11: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad3' + 22 | input [7:0] bad3; + | ^ + t/t_func_nansi_mism_bad.v:23:5: ... Location of other declaration + 23 | reg [3:0] bad3; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_nansi_bad.py b/test_regress/t/t_func_nansi_mism_bad.py similarity index 100% rename from test_regress/t/t_inst_nansi_bad.py rename to test_regress/t/t_func_nansi_mism_bad.py diff --git a/test_regress/t/t_func_nansi_bad.v b/test_regress/t/t_func_nansi_mism_bad.v similarity index 73% rename from test_regress/t/t_func_nansi_bad.v rename to test_regress/t/t_func_nansi_mism_bad.v index c69df2b8c..b5d0038a3 100644 --- a/test_regress/t/t_func_nansi_bad.v +++ b/test_regress/t/t_func_nansi_mism_bad.v @@ -23,16 +23,4 @@ module test; reg [3:0] bad3; // <--- Error (type doesn't match above) endtask - task t4; - input [7:0] bad4; - reg bad4; - reg bad4; // <--- Error (duplicate) - endtask - - task t5; - input [7:0] bad5; - input [7:0] bad5; // <--- Error (duplicate) - reg bad5; - endtask - endmodule diff --git a/test_regress/t/t_inst_nansi_bad.out b/test_regress/t/t_inst_nansi_bad.out deleted file mode 100644 index 3576c08e5..000000000 --- a/test_regress/t/t_inst_nansi_bad.out +++ /dev/null @@ -1,32 +0,0 @@ -%Error: t/t_inst_nansi_bad.v:14:12: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad1' - 14 | shortint bad1; - | ^~~~ - t/t_inst_nansi_bad.v:13:17: ... Location of other declaration - 13 | output [15:0] bad1; - | ^~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_inst_nansi_bad.v:17:5: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad2' - 17 | T bad2; - | ^~~~ - t/t_inst_nansi_bad.v:16:17: ... Location of other declaration - 16 | output [31:0] bad2; - | ^~~~ -%Error: t/t_inst_nansi_bad.v:20:13: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad3' - 20 | reg [7:0] bad3; - | ^~~~ - t/t_inst_nansi_bad.v:19:16: ... Location of other declaration - 19 | output [3:0] bad3; - | ^~~~ -%Error: t/t_inst_nansi_bad.v:24:7: Duplicate declaration of signal: 'bad4' - 24 | reg bad4; - | ^~~~ - t/t_inst_nansi_bad.v:22:10: ... Location of original declaration - 22 | output bad4; - | ^~~~ -%Error: t/t_inst_nansi_bad.v:27:10: Duplicate declaration of signal: 'bad5' - 27 | output bad5; - | ^~~~ - t/t_inst_nansi_bad.v:26:10: ... Location of original declaration - 26 | output bad5; - | ^~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_inst_nansi_dup_bad.out b/test_regress/t/t_inst_nansi_dup_bad.out new file mode 100644 index 000000000..97999019b --- /dev/null +++ b/test_regress/t/t_inst_nansi_dup_bad.out @@ -0,0 +1,14 @@ +%Error: t/t_inst_nansi_dup_bad.v:16:7: Duplicate declaration of signal: 'bad4' + 16 | reg bad4; + | ^~~~ + t/t_inst_nansi_dup_bad.v:14:10: ... Location of original declaration + 14 | output bad4; + | ^~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_inst_nansi_dup_bad.v:19:10: Duplicate declaration of signal: 'bad5' + 19 | output bad5; + | ^~~~ + t/t_inst_nansi_dup_bad.v:18:10: ... Location of original declaration + 18 | output bad5; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_nansi_dup_bad.py b/test_regress/t/t_inst_nansi_dup_bad.py new file mode 100755 index 000000000..55203b6c9 --- /dev/null +++ b/test_regress/t/t_inst_nansi_dup_bad.py @@ -0,0 +1,16 @@ +#!/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(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_inst_nansi_dup_bad.v b/test_regress/t/t_inst_nansi_dup_bad.v new file mode 100644 index 000000000..386b23154 --- /dev/null +++ b/test_regress/t/t_inst_nansi_dup_bad.v @@ -0,0 +1,22 @@ +// 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 + +typedef int T; + +module test ( /*AUTOARG*/ + // Outputs + bad4, bad5 + ); + + output bad4; + reg bad4; + reg bad4; // <--- Error (duplicate) + + output bad5; + output bad5; // <--- Error (duplicate) + reg bad5; // <--- Error (duplicate) + +endmodule diff --git a/test_regress/t/t_inst_nansi_mism_bad.out b/test_regress/t/t_inst_nansi_mism_bad.out new file mode 100644 index 000000000..690ee8feb --- /dev/null +++ b/test_regress/t/t_inst_nansi_mism_bad.out @@ -0,0 +1,26 @@ +%Error: t/t_inst_nansi_mism_bad.v:13:10: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad1' + 13 | output [15:0] bad1; + | ^ + t/t_inst_nansi_mism_bad.v:14:3: ... Location of other declaration + 14 | shortint bad1; + | ^~~~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_inst_nansi_mism_bad.v:16:10: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad2' + 16 | output [31:0] bad2; + | ^ + t/t_inst_nansi_mism_bad.v:17:3: ... Location of other declaration + 17 | T bad2; + | ^ +%Error: t/t_inst_nansi_mism_bad.v:19:10: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad3' + 19 | output [3:0] bad3; + | ^ + t/t_inst_nansi_mism_bad.v:20:3: ... Location of other declaration + 20 | reg [7:0] bad3; + | ^~~ +%Error: t/t_inst_nansi_mism_bad.v:22:3: Non-ANSI I/O declaration of signal conflicts with type declaration: 'bad4' + 22 | reg [7:0] bad4; + | ^~~ + t/t_inst_nansi_mism_bad.v:23:10: ... Location of other declaration + 23 | output [3:0] bad4; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_nansi_mism_bad.py b/test_regress/t/t_inst_nansi_mism_bad.py new file mode 100755 index 000000000..55203b6c9 --- /dev/null +++ b/test_regress/t/t_inst_nansi_mism_bad.py @@ -0,0 +1,16 @@ +#!/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(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_inst_nansi_bad.v b/test_regress/t/t_inst_nansi_mism_bad.v similarity index 65% rename from test_regress/t/t_inst_nansi_bad.v rename to test_regress/t/t_inst_nansi_mism_bad.v index b87a602a1..d5fbb4f8f 100644 --- a/test_regress/t/t_inst_nansi_bad.v +++ b/test_regress/t/t_inst_nansi_mism_bad.v @@ -8,7 +8,7 @@ typedef int T; module test ( /*AUTOARG*/ // Outputs - bad1, bad2, bad3, bad4, bad5 + bad1, bad2, bad3, bad4 ); output [15:0] bad1; shortint bad1; // <--- Error (type doesn't match above) @@ -17,14 +17,9 @@ module test ( /*AUTOARG*/ T bad2; // <--- Error (type doesn't match above due to range) output [3:0] bad3; - reg [7:0] bad3; // <--- Error (range doesn't match) + reg [7:0] bad3; // <--- Error (range doesn't match) (output-before-reg) - output bad4; - reg bad4; - reg bad4; // <--- Error (duplicate) - - output bad5; - output bad5; // <--- Error (duplicate) - reg bad5; // <--- Error (duplicate) + reg [7:0] bad4; // <--- Error (range doesn't match) (reg-before-output) + output [3:0] bad4; endmodule diff --git a/test_regress/t/t_inst_nansi_param.py b/test_regress/t/t_inst_nansi_param.py new file mode 100755 index 000000000..f2f5d0201 --- /dev/null +++ b/test_regress/t/t_inst_nansi_param.py @@ -0,0 +1,16 @@ +#!/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.compile() + +test.passes() diff --git a/test_regress/t/t_inst_nansi_param.v b/test_regress/t/t_inst_nansi_param.v new file mode 100644 index 000000000..7d4c1baa0 --- /dev/null +++ b/test_regress/t/t_inst_nansi_param.v @@ -0,0 +1,16 @@ +// 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 + +module sub(i); + parameter N = 3; + input [N : 0] i; // Note 3:0 conflicts until parameterize + wire [2:0] i; +endmodule + +module t; + wire [2:0] i; + sub #(.N(2)) sub(.i); +endmodule