Change type definition error to show type chain with source context (#7151)

This commit is contained in:
em2machine 2026-02-25 14:47:13 -05:00 committed by GitHub
parent 8d34bc786a
commit d658517715
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 109 additions and 2 deletions

View File

@ -941,12 +941,21 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
bool assertOn) const VL_MT_STABLE {
static constexpr int MAX_TYPEDEF_DEPTH = 1000;
static constexpr int MAX_CHAIN_DISPLAY = 10;
const AstNodeDType* nodep = this;
std::unordered_set<const AstNodeDType*> visited;
std::vector<const AstNodeDType*> chain;
bool isCycle = false;
for (int depth = 0; depth < MAX_TYPEDEF_DEPTH; ++depth) {
if (VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType) || VN_IS(nodep, RefDType) //
|| VN_IS(nodep, RequireDType) //
|| (VN_IS(nodep, ConstDType) && skipConst) //
|| (VN_IS(nodep, EnumDType) && skipEnum)) {
if (!visited.emplace(nodep).second) {
isCycle = true;
break;
}
if (chain.size() < static_cast<size_t>(MAX_CHAIN_DISPLAY)) chain.push_back(nodep);
if (const AstNodeDType* subp = nodep->subDTypep()) {
nodep = subp;
continue;
@ -957,7 +966,33 @@ const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
}
return nodep;
}
nodep->v3error("Recursive type definition, or over " << MAX_TYPEDEF_DEPTH << " types deep");
// Build user-facing error with type chain
V3Error::v3errorPrep(V3ErrorCode::EC_ERROR);
{
std::ostringstream& os = V3Error::v3errorStr();
if (isCycle) {
os << "Recursive type definition";
} else {
os << "Type definition over " << MAX_TYPEDEF_DEPTH << " types deep";
}
bool first = true;
for (const AstNodeDType* chainp : chain) {
// Skip internal scaffolding nodes (e.g. REQUIREDTYPE) with no user-visible name
if (chainp->name().empty()) continue;
os << '\n'
<< chainp->fileline()->warnOther() << "... Type chain: " << chainp->prettyTypeName()
<< '\n'
<< (first ? chainp->fileline()->warnContextPrimary()
: chainp->fileline()->warnContextSecondary());
first = false;
}
if (visited.size() > static_cast<size_t>(MAX_CHAIN_DISPLAY)) {
os << '\n'
<< this->fileline()->warnMore() << "... and "
<< (visited.size() - MAX_CHAIN_DISPLAY) << " more";
}
}
this->v3errorEnd(V3Error::v3errorStr());
return nullptr;
}

View File

@ -0,0 +1,30 @@
%Error: t/t_recursive_typedef_bad.v:11:30: Recursive type definition
: ... note: In instance 't.u_circ'
t/t_recursive_typedef_bad.v:11:30: ... Type chain: PARAMTYPEDTYPE 'A'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:34: ... Type chain: REFDTYPE 'B'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:52: ... Type chain: PARAMTYPEDTYPE 'B'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:56: ... Type chain: REFDTYPE 'A'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_recursive_typedef_bad.v:11:52: Recursive type definition
: ... note: In instance 't.u_circ'
t/t_recursive_typedef_bad.v:11:52: ... Type chain: PARAMTYPEDTYPE 'B'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:56: ... Type chain: REFDTYPE 'A'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:30: ... Type chain: PARAMTYPEDTYPE 'A'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
t/t_recursive_typedef_bad.v:11:34: ... Type chain: REFDTYPE 'B'
11 | module circ #(parameter type A = B, parameter type B = A)
| ^
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2025 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('linter')
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,22 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2025 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
//
// Recursive type definition via circular parameter type defaults
// should produce a clear error with type chain display.
// Circular: A defaults to B, B defaults to A
module circ #(parameter type A = B, parameter type B = A)
(input A ai, output B bo);
assign bo = ai;
endmodule
module t();
logic [7:0] x, y;
circ u_circ(.ai(x), .bo(y));
initial begin
$finish;
end
endmodule

View File

@ -1,6 +1,10 @@
%Error: t/t_type_param_circ_bad.v:14:22: Recursive type definition, or over 1000 types deep
%Error: t/t_type_param_circ_bad.v:14:22: Recursive type definition
: ... note: In instance 't'
t/t_type_param_circ_bad.v:14:22: ... Type chain: PARAMTYPEDTYPE 'SZ'
14 | # (parameter type SZ = SZ)
| ^~
t/t_type_param_circ_bad.v:14:27: ... Type chain: REFDTYPE 'SZ'
14 | # (parameter type SZ = SZ)
| ^~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to