Internals: Add RequireDType and check for recursive data types, in prep for future parser.

This commit is contained in:
Wilson Snyder 2025-05-17 20:40:03 -04:00
parent 640339ec36
commit 3b632739a8
8 changed files with 72 additions and 12 deletions

View File

@ -123,6 +123,7 @@ public:
bool similarDType(const AstNodeDType* samep) const;
// Iff has a non-null subDTypep(), as generic node function
virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return nullptr; }
virtual AstNodeDType* subDType2p() const VL_MT_STABLE { return nullptr; }
virtual bool isFourstate() const;
// Ideally an IEEE $typename
virtual string prettyDTypeName(bool) const { return prettyTypeName(); }
@ -362,6 +363,9 @@ public:
AstNodeDType* subDTypep() const override VL_MT_STABLE {
return m_refDTypep ? m_refDTypep : childDTypep();
}
AstNodeDType* subDType2p() const override VL_MT_STABLE {
return m_keyDTypep ? m_keyDTypep : keyChildDTypep();
}
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
@ -1174,6 +1178,33 @@ public:
return false;
}
};
class AstRequireDType final : public AstNodeDType {
// @astgen op1 := lhsp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
//
// Require a generic node type (typically AstParseRef become a type.
public:
AstRequireDType(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER_RequireDType(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstRequireDType;
// METHODS
bool similarDTypeNode(const AstNodeDType* samep) const override {
const AstRequireDType* const asamep = VN_DBG_AS(samep, RequireDType);
return subDTypep()->similarDType(asamep->subDTypep());
}
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
AstNodeDType* subDTypep() const override VL_MT_STABLE {
// Used for recursive definition checking
if (AstNodeDType* const dtp = VN_CAST(lhsp(), NodeDType))
return dtp;
else
return nullptr;
}
int widthAlignBytes() const override { V3ERROR_NA_RETURN(1); }
int widthTotalBytes() const override { V3ERROR_NA_RETURN(1); }
bool isCompound() const override { V3ERROR_NA_RETURN(false); }
};
class AstSampleQueueDType final : public AstNodeDType {
// @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width
//

View File

@ -830,12 +830,13 @@ 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;
const AstNodeDType* nodep = this;
while (true) {
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType)
|| VN_IS(nodep, RefDType) //
|| (VN_IS(nodep, ConstDType) && skipConst) //
|| (VN_IS(nodep, EnumDType) && skipEnum))) {
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 (const AstNodeDType* subp = nodep->subDTypep()) {
nodep = subp;
continue;
@ -846,6 +847,8 @@ const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
}
return nodep;
}
nodep->v3error("Recursive type definition, or over " << MAX_TYPEDEF_DEPTH << " types deep");
return nullptr;
}
bool AstNodeDType::similarDType(const AstNodeDType* samep) const {

View File

@ -779,6 +779,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
puts("\n???? // "s + nodep->prettyTypeName() + " -> UNLINKED\n");
}
}
void visit(AstRequireDType* nodep) override { iterateConst(nodep->lhsp()); }
void visit(AstModport* nodep) override {
puts(nodep->verilogKwd());
puts(" ");

View File

@ -4218,8 +4218,17 @@ class LinkDotResolveVisitor final : public VNVisitor {
// Get the value of type parameter passed to the class instance,
// to print the helpful error message.
const AstNodeDType* typep = refp->refDTypep();
if (const AstParamTypeDType* const paramp = VN_CAST(typep, ParamTypeDType)) {
typep = paramp->subDTypep();
while (true) {
if (const AstParamTypeDType* const atypep
= VN_CAST(typep, ParamTypeDType)) {
typep = atypep->subDTypep();
continue;
}
if (const AstRequireDType* const atypep = VN_CAST(typep, RequireDType)) {
typep = atypep->subDTypep();
continue;
}
break;
}
typep->v3error("Attempting to extend using non-class");
}

View File

@ -324,14 +324,15 @@ class LinkParseVisitor final : public VNVisitor {
}
if (VN_IS(nodep->subDTypep(), ParseTypeDType)) {
// It's a parameter type. Use a different node type for this.
AstNodeDType* dtypep = VN_CAST(nodep->valuep(), NodeDType);
AstNode* dtypep = nodep->valuep();
if (dtypep) {
dtypep->unlinkFrBack();
} else {
dtypep = new AstVoidDType{nodep->fileline()};
}
AstNode* const newp = new AstParamTypeDType{nodep->fileline(), nodep->varType(),
nodep->name(), VFlagChildDType{}, dtypep};
AstNode* const newp = new AstParamTypeDType{
nodep->fileline(), nodep->varType(), nodep->name(), VFlagChildDType{},
new AstRequireDType{nodep->fileline(), dtypep}};
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;

View File

@ -2026,6 +2026,18 @@ class WidthVisitor final : public VNVisitor {
userIterateChildren(nodep, nullptr);
nodep->widthFromSub(nodep->subDTypep());
}
void visit(AstRequireDType* nodep) override {
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
if (AstNodeDType* const dtp = VN_CAST(nodep->lhsp(), NodeDType)) {
nodep->replaceWith(dtp->unlinkFrBack());
} else {
if (nodep->lhsp())
nodep->lhsp()->v3error("Expected data type, not a "
<< nodep->lhsp()->prettyTypeName());
nodep->replaceWith(new AstVoidDType{nodep->fileline()});
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstCastDynamic* nodep) override {
nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());

View File

@ -45,6 +45,7 @@ for s in [
'Can\'t read annotation file: ',
'Can\'t resolve module reference: \'',
'Can\'t write file: ',
'Expected data type, not a ',
'Extern declaration\'s scope is not a defined class',
'File not found: ',
'Format to $display-like function must have constant format string',
@ -60,6 +61,7 @@ for s in [
'Parameter type pin value isn\'t a type: Param ',
'Parameter type variable isn\'t a type: Param ',
'Pattern replication value of 0 is not legal.',
'Reference to \'',
'Signals inside functions/tasks cannot be marked forceable',
'Slice size cannot be zero.',
'Slices of arrays in assignments have different unpacked dimensions, ',

View File

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