Internals: Add RequireDType and check for recursive data types, in prep for future parser.
This commit is contained in:
parent
640339ec36
commit
3b632739a8
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(" ");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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, ',
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue