From 60cbbf0ec1d4b4c6faad3ff0c66d2497768131dc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 11 Aug 2025 19:50:47 -0400 Subject: [PATCH] Add error on mismatching prototypes (#6207). --- Changes | 2 +- docs/guide/warnings.rst | 13 +++ src/V3Ast.h | 4 + src/V3AstNodeDType.h | 2 +- src/V3AstNodeExpr.h | 4 +- src/V3AstNodeOther.h | 4 + src/V3Error.cpp | 4 +- src/V3Error.h | 22 ++--- src/V3LinkDot.cpp | 25 ++++-- src/V3Width.cpp | 99 +++++++++++++++++++++- src/V3WidthCommit.cpp | 11 +++ test_regress/t/t_class_extern_args.py | 17 ++++ test_regress/t/t_class_extern_args_bad.out | 75 ++++++++++++++++ test_regress/t/t_class_extern_args_bad.py | 16 ++++ test_regress/t/t_class_extern_args_bad.v | 46 ++++++++++ test_regress/t/t_class_extern_bad.out | 25 +++--- test_regress/t/t_class_extern_bad.v | 8 +- test_regress/t/t_constraint_extern_bad.out | 5 +- 18 files changed, 340 insertions(+), 42 deletions(-) create mode 100755 test_regress/t/t_class_extern_args.py create mode 100644 test_regress/t/t_class_extern_args_bad.out create mode 100755 test_regress/t/t_class_extern_args_bad.py create mode 100644 test_regress/t/t_class_extern_args_bad.v diff --git a/Changes b/Changes index 8c0734804..3711067e3 100644 --- a/Changes +++ b/Changes @@ -18,7 +18,7 @@ Verilator 5.039 devel * Add SPECIFYIGN warning for specify constructs that were previously silently ignored. * Add PARAMNODEFAULT error, for parameters without defaults. * Add enum base data type, wire data type, and I/O versus data declaration checking per IEEE. -* Add error on missing forward declarations (#6206). [Alex Solomatnikov] +* Add error on missing and mismatching prototypes (#6206) (#6207). [Alex Solomatnikov] * Add error when trying to assign class object to variable of non-class types (#6237). [Igor Zaworski, Antmicro Ltd.] * Add error on class 'function static'. * Add `-DVERILATOR=1` definition to compiler flags when using verilated.mk. diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 22e61d582..24bfd9a56 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1612,6 +1612,19 @@ List Of Warnings accepts the protected code. +.. option:: PROTOTYPEMIS + + Error that a function prototype does not match in some respects the + out-of-block declaration of that function. IEEE requires this error. + + The typical solution is to fix the prototype to match the declaration + exactly, including in number of arguments, name of arguments, argument + data types, and return data type (for functions). + + Disabling this error will cause Verilator to ignore the prototype and + may make the code illegal in other tools. + + .. option:: RANDC Historical, never issued since version 5.018, when :code:`randc` became diff --git a/src/V3Ast.h b/src/V3Ast.h index f0528a961..f4a2842bc 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -508,6 +508,9 @@ public: ENUM_NAME, // V3Width processes ENUM_VALID, // V3Width processes // + FUNC_ARG_PROTO, // V3WidthCommit processes + FUNC_RETURN_PROTO, // V3WidthCommit processes + // TYPEID, // V3Width processes TYPENAME, // V3Width processes // @@ -538,6 +541,7 @@ public: "DT_PUBLIC", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID", + "FUNC_ARG_PROTO", "FUNC_RETURN_PROTO", "TYPEID", "TYPENAME", "VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 53c28d404..f16fc7fa2 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -1336,7 +1336,7 @@ public: AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; } AstNodeDType* virtRefDTypep() const override { return nullptr; } void virtRefDTypep(AstNodeDType* nodep) override {} - bool similarDTypeNode(const AstNodeDType* samep) const override { return this == samep; } + bool similarDTypeNode(const AstNodeDType* samep) const override { return true; } AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } int widthAlignBytes() const override { return 1; } int widthTotalBytes() const override { return 1; } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 1e06fd10c..5b5c17f6d 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -594,6 +594,7 @@ class AstAttrOf final : public AstNodeExpr { // @astgen op1 := fromp : Optional[AstNode] // @astgen op2 := dimp : Optional[AstNodeExpr] VAttrType m_attrType; // What sort of extraction + string m_name; // Name for some attributes public: AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNodeExpr* dimp = nullptr) @@ -603,10 +604,11 @@ public: m_attrType = attrtype; } ASTGEN_MEMBERS_AstAttrOf; + string name() const override VL_MT_STABLE { return m_name; } // * = Var name + void name(const string& name) override { m_name = name; } VAttrType attrType() const { return m_attrType; } void dump(std::ostream& str = std::cout) const override; void dumpJson(std::ostream& str = std::cout) const override; - string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { V3ERROR_NA_RETURN(true); } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index af7d445d4..7b55b7ce9 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -69,6 +69,7 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode { bool m_taskPublic : 1; // Public task bool m_attrIsolateAssign : 1; // User isolate_assignments attribute bool m_classMethod : 1; // Class method + bool m_didProto : 1; // Did prototype processing bool m_prototype : 1; // Just a prototype bool m_dpiExport : 1; // DPI exported bool m_dpiImport : 1; // DPI imported @@ -98,6 +99,7 @@ protected: , m_taskPublic{false} , m_attrIsolateAssign{false} , m_classMethod{false} + , m_didProto{false} , m_prototype{false} , m_dpiExport{false} , m_dpiImport{false} @@ -145,6 +147,8 @@ public: void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } bool classMethod() const { return m_classMethod; } void classMethod(bool flag) { m_classMethod = flag; } + bool didProto() const { return m_didProto; } + void didProto(bool flag) { m_didProto = flag; } bool isExternProto() const { return m_isExternProto; } void isExternProto(bool flag) { m_isExternProto = flag; } bool isExternDef() const { return m_isExternDef; } diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 0ef6e50fb..67c7566bf 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -300,8 +300,8 @@ void V3Error::init() { describedEachWarn(static_cast(i), false); pretendError(static_cast(i), V3ErrorCode{i}.pretendError()); } - UASSERT(std::string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} == " MAX", - "Enum table in V3ErrorCode::EC_ascii() is munged"); + // Not an UASSERT as failure would call V3Error and it's broken due to this + assert(std::string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} == " MAX"); } string V3Error::lineStr(const char* filename, int lineno) VL_PURE { diff --git a/src/V3Error.h b/src/V3Error.h index ebb8e3fa5..224f6f987 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -139,7 +139,8 @@ public: PROCASSINIT, // Procedural assignment versus initialization PROCASSWIRE, // Procedural assignment on wire PROFOUTOFDATE, // Profile data out of date - PROTECTED, // detected `pragma protected + PROTECTED, // Detected `pragma protected + PROTOTYPEMIS, // Prototype mismatch or related RANDC, // Unsupported: 'randc' converted to 'rand' REALCVT, // Real conversion REDEFMACRO, // Redefining existing define macro @@ -213,14 +214,14 @@ public: "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING", "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT", "PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", - "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", - "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SIDEEFFECT", - "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", - "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", - "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL", - "USERERROR", "USERFATAL", "USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH", - "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", - " MAX"}; + "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", + "PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE", + "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY", + "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", + "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP", + "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", + "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", + "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"}; return names[m_e]; } // Warnings that default to off @@ -249,7 +250,8 @@ public: || m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED || m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == IMPURE || m_e == MODMISSING || m_e == PARAMNODEFAULT || m_e == PINNOTFOUND - || m_e == PKGNODECL || m_e == PROCASSWIRE || m_e == ZEROREPL // Says IEEE + || m_e == PKGNODECL || m_e == PROCASSWIRE || m_e == PROTOTYPEMIS + || m_e == ZEROREPL // Says IEEE ); } // Warnings to mention manual diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index fa3a765bb..6a53003d4 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3717,8 +3717,8 @@ class LinkDotResolveVisitor final : public VNVisitor { } if (nodep->isExternProto()) { if (!m_curSymp->findIdFallback(nodep->name()) && nodep->isExternExplicit()) { - nodep->v3error("Definition not found for extern prototype " - + nodep->prettyNameQ()); + nodep->v3warn(PROTOTYPEMIS, "Definition not found for extern prototype " + << nodep->prettyNameQ()); } } VL_RESTORER(m_curSymp); @@ -4270,7 +4270,8 @@ class LinkDotResolveVisitor final : public VNVisitor { LINKDOT_VISIT_START(); UINFO(5, indent() << "visit " << nodep); checkNoDot(nodep); - if (nodep->isExternDef()) { + if (nodep->isExternDef() && !nodep->didProto()) { + nodep->didProto(true); if (const VSymEnt* const foundp = m_curSymp->findIdFallback("extern " + nodep->name())) { const AstNodeFTask* const protop = VN_AS(foundp->nodep(), NodeFTask); @@ -4281,14 +4282,28 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->isStatic(protop->isStatic()); nodep->isVirtual(protop->isVirtual()); nodep->lifetime(protop->lifetime()); + // Always add an FUNC_RETURN_PROTO even if task, so we can locate the prototype + nodep->addStmtsp(new AstAttrOf{protop->fileline(), VAttrType::FUNC_RETURN_PROTO, + protop->fvarp() + ? protop->fvarp()->cloneTree(false) + : new AstVoidDType{protop->fileline()}}); + for (AstNode* stmtp = protop->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstVar* const portp = VN_CAST(stmtp, Var)) { + AstAttrOf* const attrp + = new AstAttrOf{protop->fileline(), VAttrType::FUNC_ARG_PROTO, + portp->subDTypep()->cloneTree(false)}; + attrp->name(portp->name()); + nodep->addStmtsp(attrp); + } + } } else { nodep->v3error("extern not found that declares " + nodep->prettyNameQ()); } } if (nodep->isExternProto()) { if (!m_curSymp->findIdFallback(nodep->name())) { - nodep->v3error("Definition not found for extern prototype " - + nodep->prettyNameQ()); + nodep->v3warn(PROTOTYPEMIS, + "Definition not found for extern prototype " + nodep->prettyNameQ()); } } VL_RESTORER(m_curSymp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 22a7c78b8..9af0997ad 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -911,7 +911,7 @@ class WidthVisitor final : public VNVisitor { } void visit(AstNodeStream* nodep) override { VL_RESTORER(m_streamConcat); - UINFOTREE(1, nodep, "stream-in vup" << m_vup, "stream-in "); + // UINFOTREE(1, nodep, "stream-in vup" << m_vup, "stream-in "); if (m_vup->prelim()) { m_streamConcat = true; iterateCheckSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -1669,9 +1669,6 @@ class WidthVisitor final : public VNVisitor { if (nodep->dimp()) userIterateAndNext(nodep->dimp(), WidthVP{SELF, BOTH}.p()); // Don't iterate children, don't want to lose VarRef. switch (nodep->attrType()) { - case VAttrType::VAR_BASE: - // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf - break; case VAttrType::DIM_DIMENSIONS: case VAttrType::DIM_UNPK_DIMENSIONS: { UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); @@ -1795,6 +1792,36 @@ class WidthVisitor final : public VNVisitor { } break; } + case VAttrType::FUNC_ARG_PROTO: + // Created by V3LinkDot only to check that the prototype was correct when we got here + // Checked at bottom of visit(AstNodeFTask) + // V3WidthCommit::visit(AstAttrOf) will delete nodep + break; + case VAttrType::FUNC_RETURN_PROTO: { + // Created by V3LinkDot only to check that the prototype was correct when we got here + UASSERT_OBJ(m_ftaskp, nodep, "FUNC attr not under function"); + AstNodeDType* const protoDtp = nodep->fromp()->dtypep(); + AstNodeDType* const declDtp = m_ftaskp->fvarp() + ? m_ftaskp->fvarp()->dtypep() + : new AstVoidDType{m_ftaskp->fileline()}; + if (!similarDTypeRecurse(protoDtp, declDtp)) { + protoDtp->v3warn( + PROTOTYPEMIS, + "In prototype for " + << m_ftaskp->prettyNameQ() + << ", return data type does not match out-of-block" + " declaration data-type (IEEE 1800-2023 8.24)\n" + << protoDtp->warnMore() + << "... Prototype data type: " << protoDtp->prettyDTypeNameQ() << '\n' + << protoDtp->warnMore() + << "... Declaration data type: " << declDtp->prettyDTypeNameQ() << '\n' + << protoDtp->warnContextPrimary() << '\n' + << declDtp->warnOther() << "... Location of out-of-block declaration\n" + << declDtp->warnContextSecondary()); + } + // V3WidthCommit::visit(AstAttrOf) will delete nodep + break; + } case VAttrType::TYPENAME: { UASSERT_OBJ(nodep->fromp(), nodep, "Unprovided expression"); const string result = nodep->fromp()->dtypep()->prettyDTypeName(true); @@ -1808,6 +1835,9 @@ class WidthVisitor final : public VNVisitor { // Soon to be handled in AstEqT nodep->dtypeSetSigned32(); break; + case VAttrType::VAR_BASE: + // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf + break; default: { // Everything else resolved earlier nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // Approximation, unsized 32 @@ -6076,6 +6106,67 @@ class WidthVisitor final : public VNVisitor { nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling // func } + + std::vector ports; + std::vector protos; + AstAttrOf* protop = nullptr; // Base prototype + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstVar* const portp = VN_CAST(stmtp, Var)) { + if (portp->isIO() && !portp->isFuncReturn()) { ports.emplace_back(portp); } + } else if (AstAttrOf* const attrp = VN_CAST(stmtp, AttrOf)) { + if (attrp->attrType() == VAttrType::FUNC_ARG_PROTO) { protos.emplace_back(attrp); } + if (attrp->attrType() == VAttrType::FUNC_RETURN_PROTO) { protop = attrp; } + } + } + if (protop) { + for (size_t i = 0; i < std::max(ports.size(), protos.size()); ++i) { + if (i >= ports.size() || i >= protos.size()) { + protop->v3warn( + PROTOTYPEMIS, + "In prototype for " + << nodep->prettyNameQ() + << ", the argumement counts do not match the out-of-block declaration" + << " (IEEE 1800-2023 8.24)\n" + << protop->warnContextPrimary() << '\n' + << nodep->warnOther() << "... Location of out-of-block declaration\n" + << nodep->warnContextSecondary()); + break; + } else { + AstVar* const portp = ports[i]; + AstAttrOf* const protop = protos[i]; + AstNodeDType* const declDtp = portp->dtypep(); + AstNodeDType* const protoDtp = protop->fromp()->dtypep(); + if (portp->name() != protop->name()) { + protoDtp->v3warn(PROTOTYPEMIS, + "In prototype for " + << nodep->prettyNameQ() << ", argument " << (i + 1) + << " named " << protop->prettyNameQ() + << " mismatches out-of-block argument name " + << portp->prettyNameQ() << " (IEEE 1800-2023 8.24)\n" + << protoDtp->warnContextPrimary() << '\n' + << declDtp->warnOther() + << "... Location of out-of-block declaration\n" + << declDtp->warnContextSecondary()); + } else if (!similarDTypeRecurse(protoDtp, declDtp)) { + protoDtp->v3warn( + PROTOTYPEMIS, + "In prototype for " + << nodep->prettyNameQ() << ", argument " << portp->prettyNameQ() + << " data-type does not match out-of-block" + " declaration's data-type (IEEE 1800-2023 8.24)\n" + << protoDtp->warnMore() << "... Prototype data type: " + << protoDtp->prettyDTypeNameQ() << '\n' + << protoDtp->warnMore() << "... Declaration data type: " + << declDtp->prettyDTypeNameQ() << '\n' + << protoDtp->warnContextPrimary() << '\n' + << declDtp->warnOther() + << "... Location of out-of-block declaration\n" + << declDtp->warnContextSecondary()); + } + } + } + // V3WidthCommit::visit(AstAttrOf) will delete nodep + } } void visit(AstConstraint* nodep) override { if (nodep->didWidth()) return; diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp index f94eb0788..64e35b3ea 100644 --- a/src/V3WidthCommit.cpp +++ b/src/V3WidthCommit.cpp @@ -168,6 +168,17 @@ private: } } } + void visit(AstAttrOf* nodep) override { + switch (nodep->attrType()) { + case VAttrType::FUNC_ARG_PROTO: // FALLTHRU + case VAttrType::FUNC_RETURN_PROTO: + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + default:; + } + iterateChildren(nodep); + editDType(nodep); + } void visit(AstClassExtends* nodep) override { if (nodep->user1SetOnce()) return; // Process once // Extend arguments were converted to super.new arguments in V3LinkDot diff --git a/test_regress/t/t_class_extern_args.py b/test_regress/t/t_class_extern_args.py new file mode 100755 index 000000000..3d49093ba --- /dev/null +++ b/test_regress/t/t_class_extern_args.py @@ -0,0 +1,17 @@ +#!/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('vlt') +test.top_filename = 't/t_class_extern_args_bad.v' + +test.lint(verilator_flags2=['-Wno-PROTOTYPEMIS']) + +test.passes() diff --git a/test_regress/t/t_class_extern_args_bad.out b/test_regress/t/t_class_extern_args_bad.out new file mode 100644 index 000000000..facf52cdb --- /dev/null +++ b/test_regress/t/t_class_extern_args_bad.out @@ -0,0 +1,75 @@ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:8:15: In prototype for 'func_bad', return data type does not match out-of-block declaration data-type (IEEE 1800-2023 8.24) + : ... note: In instance 't' + : ... Prototype data type: 'VOIDDTYPE' + : ... Declaration data type: 'bit' + 8 | extern task func_bad(); + | ^~~~~~~~ + t/t_class_extern_args_bad.v:19:10: ... Location of out-of-block declaration + 19 | function bit Cls::func_bad(); + | ^~~ + ... For error description see https://verilator.org/warn/PROTOTYPEMIS?v=latest +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:9:19: In prototype for 'f1_bad', return data type does not match out-of-block declaration data-type (IEEE 1800-2023 8.24) + : ... note: In instance 't' + : ... Prototype data type: 'int' + : ... Declaration data type: 'bit' + 9 | extern function int f1_bad(); + | ^~~ + t/t_class_extern_args_bad.v:22:10: ... Location of out-of-block declaration + 22 | function bit Cls::f1_bad(); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:10:19: In prototype for 'f2_bad', return data type does not match out-of-block declaration data-type (IEEE 1800-2023 8.24) + : ... note: In instance 't' + : ... Prototype data type: 'int' + : ... Declaration data type: 'VOIDDTYPE' + 10 | extern function int f2_bad(); + | ^~~ + t/t_class_extern_args_bad.v:24:15: ... Location of out-of-block declaration + 24 | function void Cls::f2_bad(); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:11:24: In prototype for 'f3_bad', return data type does not match out-of-block declaration data-type (IEEE 1800-2023 8.24) + : ... note: In instance 't' + : ... Prototype data type: 'VOIDDTYPE' + : ... Declaration data type: 'bit' + 11 | extern function void f3_bad(); + | ^~~~~~ + t/t_class_extern_args_bad.v:26:10: ... Location of out-of-block declaration + 26 | function bit Cls::f3_bad(); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:12:34: In prototype for 'f1bit_bad', argument 'a' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24) + : ... note: In instance 't' + : ... Prototype data type: 'int' + : ... Declaration data type: 'bit' + 12 | extern function void f1bit_bad(int a); + | ^~~ + t/t_class_extern_args_bad.v:29:30: ... Location of out-of-block declaration + 29 | function void Cls::f1bit_bad(bit a); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:13:24: In prototype for 'f2args1_bad', the argumement counts do not match the out-of-block declaration (IEEE 1800-2023 8.24) + : ... note: In instance 't' + 13 | extern function void f2args1_bad(bit a); + | ^~~~~~~~~~~ + t/t_class_extern_args_bad.v:32:15: ... Location of out-of-block declaration + 32 | function void Cls::f2args1_bad(bit a, bit b); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:14:24: In prototype for 'f2args2', the argumement counts do not match the out-of-block declaration (IEEE 1800-2023 8.24) + : ... note: In instance 't' + 14 | extern function void f2args2(bit a); + | ^~~~~~~ + t/t_class_extern_args_bad.v:35:15: ... Location of out-of-block declaration + 35 | function void Cls::f2args2(bit a, bit b); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:15:24: In prototype for 'f2args3_bad', the argumement counts do not match the out-of-block declaration (IEEE 1800-2023 8.24) + : ... note: In instance 't' + 15 | extern function void f2args3_bad(bit a, bit b, bit c); + | ^~~~~~~~~~~ + t/t_class_extern_args_bad.v:38:15: ... Location of out-of-block declaration + 38 | function void Cls::f2args3_bad(bit a, bit b); + | ^~~ +%Error-PROTOTYPEMIS: t/t_class_extern_args_bad.v:16:38: In prototype for 'farg_name_bad', argument 1 named 'declnamebad' mismatches out-of-block argument name 'declname' (IEEE 1800-2023 8.24) + : ... note: In instance 't' + 16 | extern function void farg_name_bad(bit declnamebad); + | ^~~ + t/t_class_extern_args_bad.v:41:34: ... Location of out-of-block declaration + 41 | function void Cls::farg_name_bad(bit declname); + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extern_args_bad.py b/test_regress/t/t_class_extern_args_bad.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_class_extern_args_bad.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_extern_args_bad.v b/test_regress/t/t_class_extern_args_bad.v new file mode 100644 index 000000000..a969abb06 --- /dev/null +++ b/test_regress/t/t_class_extern_args_bad.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + extern task func_bad(); //<--- Error (mismatch func) + extern function int f1_bad(); //<--- Error (mismatch func type) + extern function int f2_bad(); //<--- Error (mismatch func type) + extern function void f3_bad(); //<--- Error (mismatch func type) + extern function void f1bit_bad(int a); //<--- Error (mismatch arg type) + extern function void f2args1_bad(bit a); //<--- Error (missing arg) + extern function void f2args2(bit a); // ok + extern function void f2args3_bad(bit a, bit b, bit c); //<--- Error (missing arg) + extern function void farg_name_bad(bit declnamebad); //<--- Error (declname arg) +endclass + +function bit Cls::func_bad(); +endfunction + +function bit Cls::f1_bad(); +endfunction +function void Cls::f2_bad(); +endfunction +function bit Cls::f3_bad(); +endfunction + +function void Cls::f1bit_bad(bit a); +endfunction + +function void Cls::f2args1_bad(bit a, bit b); +endfunction + +function void Cls::f2args2(bit a, bit b); +endfunction + +function void Cls::f2args3_bad(bit a, bit b); +endfunction + +function void Cls::farg_name_bad(bit declname); +endfunction + +module t; + initial $stop; +endmodule diff --git a/test_regress/t/t_class_extern_bad.out b/test_regress/t/t_class_extern_bad.out index 785b44d9e..d83e39a43 100644 --- a/test_regress/t/t_class_extern_bad.out +++ b/test_regress/t/t_class_extern_bad.out @@ -1,16 +1,17 @@ -%Error: t/t_class_extern_bad.v:9:16: Duplicate declaration of task: 'extern nodef' - 9 | extern task nodef(); - | ^~~~~ - t/t_class_extern_bad.v:8:16: ... Location of original declaration - 8 | extern task nodef(); - | ^~~~~ +%Error: t/t_class_extern_bad.v:9:15: Duplicate declaration of task: 'extern nodef' + 9 | extern task nodef(); + | ^~~~~ + t/t_class_extern_bad.v:8:15: ... Location of original declaration + 8 | extern task nodef(); + | ^~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_class_extern_bad.v:8:16: Definition not found for extern prototype 'nodef' - 8 | extern task nodef(); - | ^~~~~ -%Error: t/t_class_extern_bad.v:9:16: Definition not found for extern prototype 'nodef' - 9 | extern task nodef(); - | ^~~~~ +%Error-PROTOTYPEMIS: t/t_class_extern_bad.v:8:15: Definition not found for extern prototype 'nodef' + 8 | extern task nodef(); + | ^~~~~ + ... For error description see https://verilator.org/warn/PROTOTYPEMIS?v=latest +%Error-PROTOTYPEMIS: t/t_class_extern_bad.v:9:15: Definition not found for extern prototype 'nodef' + 9 | extern task nodef(); + | ^~~~~ %Error: t/t_class_extern_bad.v:12:6: extern not found that declares 'noproto' 12 | task Base1::noproto(); | ^~~~~ diff --git a/test_regress/t/t_class_extern_bad.v b/test_regress/t/t_class_extern_bad.v index 86b921820..58d6dbbdb 100644 --- a/test_regress/t/t_class_extern_bad.v +++ b/test_regress/t/t_class_extern_bad.v @@ -5,12 +5,12 @@ // SPDX-License-Identifier: CC0-1.0 class Base1; - extern task nodef(); - extern task nodef(); // duplicate + extern task nodef(); + extern task nodef(); // <--- Error: duplicate endclass -task Base1::noproto(); // no such prototype +task Base1::noproto(); // <--- Error: Missing prototype endtask -module t (/*AUTOARG*/); +module t; endmodule diff --git a/test_regress/t/t_constraint_extern_bad.out b/test_regress/t/t_constraint_extern_bad.out index 2e6c8787f..c47d59249 100644 --- a/test_regress/t/t_constraint_extern_bad.out +++ b/test_regress/t/t_constraint_extern_bad.out @@ -1,8 +1,9 @@ -%Error: t/t_constraint_extern_bad.v:8:22: Definition not found for extern prototype 'missing_bad' +%Error-PROTOTYPEMIS: t/t_constraint_extern_bad.v:8:22: Definition not found for extern prototype 'missing_bad' 8 | extern constraint missing_bad; | ^~~~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. + ... For error description see https://verilator.org/warn/PROTOTYPEMIS?v=latest %Error: t/t_constraint_extern_bad.v:11:20: extern not found that declares 'missing_extern' 11 | constraint Packet::missing_extern { } | ^~~~~~~~~~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to