diff --git a/src/V3Ast.h b/src/V3Ast.h
index c2ab16559..8daf96a13 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -1809,6 +1809,8 @@ public:
virtual bool hasDType() const { return false; }
// Iff has a non-null childDTypep(), as generic node function
virtual AstNodeDType* getChildDTypep() const { return NULL; }
+ // Iff has a non-null child2DTypep(), as generic node function
+ virtual AstNodeDType* getChild2DTypep() const { return NULL; }
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool maybePointedTo() const { return false; }
virtual const char* broken() const { return NULL; }
diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h
index 7b1691737..200a6c877 100644
--- a/src/V3AstNodes.h
+++ b/src/V3AstNodes.h
@@ -541,8 +541,9 @@ public:
virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
+ virtual AstNodeDType* getChildDTypep() const { return childDTypep(); }
+ virtual AstNodeDType* getChild2DTypep() const { return keyChildDTypep(); }
virtual bool isHeavy() const { return true; }
- AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
@@ -5619,6 +5620,7 @@ public:
AstNode* lhsp() const { return op1p(); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); }
+ virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastDynamic : public AstNodeBiop {
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index 72d0c4d5c..b00a52ec1 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -1332,9 +1332,8 @@ private:
// DTYPES
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// Cleanup array size
userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
nodep->dtypep(nodep); // The array itself, not subDtype
@@ -1349,29 +1348,23 @@ private:
}
virtual void visit(AstAssocArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
- if (nodep->keyChildDTypep()) {
- nodep->keyDTypep(moveDTypeEdit(nodep, nodep->keyChildDTypep()));
- }
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
- nodep->keyDTypep(iterateEditDTypep(nodep, nodep->keyDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
+ nodep->keyDTypep(iterateEditMoveDTypep(nodep, nodep->keyDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
}
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
}
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
if (VN_IS(nodep->boundp(), Unbounded)) {
nodep->boundp()->unlinkFrBack()->deleteTree(); // NULL will represent unbounded
@@ -1380,9 +1373,8 @@ private:
}
virtual void visit(AstUnsizedArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// Cleanup array size
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
@@ -1412,12 +1404,8 @@ private:
}
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- // Move any childDTypep to instead be in global AstTypeTable.
- // This way if this node gets deleted and some other dtype points to it
- // it won't become a dead pointer. This doesn't change the object pointed to.
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
nodep->dtypep(nodep); // Should already be set, but be clear it's not the subDType
nodep->widthFromSub(nodep->subDTypep());
@@ -1444,8 +1432,10 @@ private:
}
userIterateChildren(nodep, NULL);
if (nodep->subDTypep()) {
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->typedefp(NULL); // Note until line above subDTypep() may have followed this
+ // Widths are resolved, but special iterate to check for recurstion
+ userIterate(nodep->subDTypep(), NULL);
}
// Effectively nodep->dtypeFrom(nodep->dtypeSkipRefp());
// But might be recursive, so instead manually recurse into the referenced type
@@ -1457,15 +1447,13 @@ private:
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
+ nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
- nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep()));
}
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
+ nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
- nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->widthFromSub(nodep->subDTypep());
}
virtual void visit(AstCastDynamic* nodep) VL_OVERRIDE {
@@ -1494,8 +1482,7 @@ private:
}
}
virtual void visit(AstCast* nodep) VL_OVERRIDE {
- if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
- nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
+ nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// if (debug()) nodep->dumpTree(cout, " CastPre: ");
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
// When more general casts are supported, the cast elimination will be done later.
@@ -1602,8 +1589,7 @@ private:
}
nodep->doingWidth(true);
// Make sure dtype is sized
- if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
- nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
+ nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
if (!(m_ftaskp && m_ftaskp->dpiImport())) {
@@ -1733,8 +1719,7 @@ private:
virtual void visit(AstEnumDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5, " ENUMDTYPE " << nodep << endl);
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep);
nodep->widthFromSub(nodep->subDTypep());
// Assign widths
@@ -1937,20 +1922,23 @@ private:
userIterateChildren(nodep, NULL); // First size all members
nodep->repairCache();
}
+ virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
+ if (nodep->didWidthAndSet()) return;
+ // TODO this maybe eventually required to properly resolve members,
+ // though causes problems with t_class_forward.v, so for now avoided
+ // userIterateChildren(nodep->classp(), NULL);
+ }
virtual void visit(AstClassExtends* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
nodep->v3error("Unsupported: class extends"); // Member/meth access breaks
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
- // if (nodep->childDTypep()) {
- // nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
- // }
+ // nodep->dtypep(iterateEditMoveDTypep(nodep)); // data_type '{ pattern }
// userIterateChildren(nodep, NULL);
}
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
- if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
- nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
+ nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The member itself, not subDtype
nodep->widthFromSub(nodep->subDTypep());
}
@@ -2680,8 +2668,9 @@ private:
virtual void visit(AstPattern* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
UINFO(9, "PATTERN " << nodep << endl);
- if (nodep->childDTypep())
- nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
+ if (nodep->childDTypep()) { // data_type '{ pattern }
+ nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
+ }
if (!nodep->dtypep() && m_vup->dtypeNullp()) { // Get it from parent assignment/pin/etc
nodep->dtypep(m_vup->dtypep());
}
@@ -4957,32 +4946,45 @@ private:
//----------------------------------------------------------------------
// METHODS - data types
- AstNodeDType* moveDTypeEdit(AstNode* nodep, AstNodeDType* dtnodep) {
- // DTypes at parse time get added as a e.g. childDType to some node types such as AstVars.
- // Move type to global scope, so removing/changing a variable won't lose the dtype.
- UASSERT_OBJ(dtnodep, nodep, "Caller should check for NULL before calling moveDTypeEdit");
- UINFO(9, "moveDTypeEdit " << dtnodep << endl);
- dtnodep->unlinkFrBack(); // Make non-child
- v3Global.rootp()->typeTablep()->addTypesp(dtnodep);
+ AstNodeDType* iterateEditMoveDTypep(AstNode* parentp, AstNodeDType* dtnodep) {
+ UASSERT_OBJ(dtnodep, parentp, "Caller should check for NULL before computing dtype");
+ // Iterate into a data type to resolve that type.
+ // The data type may either:
+ // 1. Be a child (typically getChildDTypep() returns it)
+ // DTypes at parse time get added as these to some node types
+ // such as AstVars.
+ // This function will move it to global scope (that is #2
+ // will now apply).
+ // 2. Be under the Netlist and pointed to by an Ast member variable
+ // (typically refDTypep() or dtypep() returns it)
+ // so removing/changing a variable won't lose the dtype
+
+ // Case #1 above applies?
+ bool child1 = (parentp->getChildDTypep() == dtnodep);
+ bool child2 = (parentp->getChild2DTypep() == dtnodep);
+ if (child1 || child2) {
+ UINFO(9, "iterateEditMoveDTypep child iterating " << dtnodep << endl);
+ // Iterate, this might edit the dtypes which means dtnodep now lost
+ VL_DO_DANGLING(userIterate(dtnodep, NULL), dtnodep);
+ // Figure out the new dtnodep, remained a child of parent so find it there
+ dtnodep = child1 ? parentp->getChildDTypep() : parentp->getChild2DTypep();
+ UASSERT_OBJ(dtnodep, parentp, "iterateEditMoveDTypep lost pointer to child");
+ UASSERT_OBJ(dtnodep->didWidth(), parentp,
+ "iterateEditMoveDTypep didn't get width resolution of "
+ << dtnodep->prettyTypeName());
+ // Move to under netlist
+ UINFO(9, "iterateEditMoveDTypep child moving " << dtnodep << endl);
+ dtnodep->unlinkFrBack();
+ v3Global.rootp()->typeTablep()->addTypesp(dtnodep);
+ }
+ if (!dtnodep->didWidth()) {
+ UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl);
+ userIterate(dtnodep, NULL);
+ UASSERT_OBJ(dtnodep->didWidth(), parentp,
+ "iterateEditMoveDTypep didn't get width resolution");
+ }
return dtnodep;
}
- AstNodeDType* moveChildDTypeEdit(AstNode* nodep) {
- return moveDTypeEdit(nodep, nodep->getChildDTypep());
- }
- AstNodeDType* iterateEditDTypep(AstNode* parentp, AstNodeDType* nodep) {
- // Iterate into a data type to resolve that type. This process
- // may eventually create a new data type, but not today
- // it may make a new datatype, need subChildDType() to point to it;
- // maybe we have user5p indicate a "replace me with" pointer.
- // Need to be careful with "implicit" types though.
- //
- // Alternative is to have WidthVP return information.
- // or have a call outside of normal visitor land.
- // or have a m_return type (but need to return if width called multiple times)
- UASSERT_OBJ(nodep, parentp, "Null dtype when widthing dtype");
- userIterate(nodep, NULL);
- return nodep;
- }
AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType,
int dim) {
diff --git a/test_regress/t/t_metacmt_onoff.out b/test_regress/t/t_metacmt_onoff.out
index d1233b4d7..5de179f75 100644
--- a/test_regress/t/t_metacmt_onoff.out
+++ b/test_regress/t/t_metacmt_onoff.out
@@ -1,8 +1,10 @@
%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:8: Little bit endian vector: MSB < LSB of bit range: 0:1
+ : ... In instance t
8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3;
| ^
... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message.
%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:109: Little bit endian vector: MSB < LSB of bit range: 0:3
+ : ... In instance t
8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3;
| ^
%Error: Exiting due to
diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out
index 98533f4d2..f31c7e096 100644
--- a/test_regress/t/t_select_bad_msb.out
+++ b/test_regress/t/t_select_bad_msb.out
@@ -1,4 +1,5 @@
%Warning-LITENDIAN: t/t_select_bad_msb.v:12:8: Little bit endian vector: MSB < LSB of bit range: 0:22
+ : ... In instance t
12 | reg [0:22] backwd;
| ^
... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message.
diff --git a/test_regress/t/t_struct_unpacked2.out b/test_regress/t/t_struct_unpacked2.out
index 3d938df82..aa812216b 100644
--- a/test_regress/t/t_struct_unpacked2.out
+++ b/test_regress/t/t_struct_unpacked2.out
@@ -3,6 +3,7 @@
| ^
... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message.
%Warning-UNPACKED: t/t_struct_unpacked2.v:9:12: Unsupported: Unpacked struct/union
+ : ... In instance x
9 | typedef struct {
| ^~~~~~
%Error: Exiting due to
diff --git a/test_regress/t/t_struct_unpacked_bad.out b/test_regress/t/t_struct_unpacked_bad.out
index 96bc2b963..6e9356b6d 100644
--- a/test_regress/t/t_struct_unpacked_bad.out
+++ b/test_regress/t/t_struct_unpacked_bad.out
@@ -1,4 +1,5 @@
%Warning-UNPACKED: t/t_struct_unpacked_bad.v:9:12: Unsupported: Unpacked struct/union
+ : ... In instance x
9 | typedef struct {
| ^~~~~~
... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message.
diff --git a/test_regress/t/t_xml_tag.out b/test_regress/t/t_xml_tag.out
index 30f20a7ca..0dac9c752 100644
--- a/test_regress/t/t_xml_tag.out
+++ b/test_regress/t/t_xml_tag.out
@@ -58,24 +58,24 @@
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
-