diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 30c5298c9..597e5ad85 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1139,6 +1139,15 @@ public: , m_refDTypep(NULL) , m_name(name) , m_packagep(NULL) {} + AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) + : ASTGEN_SUPER(fl) + , m_typedefp(NULL) + , m_refDTypep(NULL) + , m_name(name) + , m_packagep(NULL) { + setNOp3p(classOrPackagep); + addNOp4p(paramsp); + } class FlagTypeOfExpr {}; // type(expr) for parser only AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) : ASTGEN_SUPER(fl) @@ -1216,6 +1225,8 @@ public: AstNodeModule* packagep() const { return m_packagep; } void packagep(AstNodeModule* nodep) { m_packagep = nodep; } AstNode* typeofp() const { return op2p(); } + AstNode* classOrPackagep() const { return op3p(); } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; class AstStructDType : public AstNodeUOrStructDType { @@ -2893,15 +2904,20 @@ public: class AstClassOrPackageRef : public AstNode { private: + string m_name; AstNode* m_classOrPackagep; // Package hierarchy public: - AstClassOrPackageRef(FileLine* fl, AstNode* classOrPackagep) + AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackagep, + AstNode* paramsp) : ASTGEN_SUPER(fl) - , m_classOrPackagep(classOrPackagep) {} + , m_name(name) + , m_classOrPackagep(classOrPackagep) { + addNOp4p(paramsp); + } ASTNODE_NODE_FUNCS(ClassOrPackageRef) // METHODS virtual const char* broken() const { - BROKEN_RTN(!m_classOrPackagep || !m_classOrPackagep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); return NULL; } virtual void cloneRelink() { @@ -2915,9 +2931,11 @@ public: } virtual V3Hash sameHash() const { return V3Hash(m_classOrPackagep); } virtual void dump(std::ostream& str = std::cout) const; + virtual string name() const { return m_name; } // * = Var name AstNode* classOrPackagep() const { return m_classOrPackagep; } AstPackage* packagep() const { return VN_CAST(classOrPackagep(), Package); } void classOrPackagep(AstNode* nodep) { m_classOrPackagep = nodep; } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; class AstDot : public AstNode { @@ -2933,9 +2951,9 @@ public: } ASTNODE_NODE_FUNCS(Dot) // For parser, make only if non-null package - static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) { - if (!packagep) return rhsp; - return new AstDot(fl, true, new AstClassOrPackageRef(fl, packagep), rhsp); + static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { + if (!packageOrClassp) return rhsp; + return new AstDot(fl, true, packageOrClassp, rhsp); } virtual void dump(std::ostream& str) const; virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index fe6b40018..b697f67d3 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2049,7 +2049,14 @@ private: allowVar = true; UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); - packagep = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(); + AstClassOrPackageRef* cpackagerefp + = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); + packagep = cpackagerefp->packagep(); + if (!packagep && cpackagerefp->classOrPackagep()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Class '::' references: " + << AstNode::prettyNameQ(cpackagerefp->name())); + } UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); m_ds.m_dotSymp = m_statep->getNodeSym(packagep); m_ds.m_dotPos = DP_SCOPE; @@ -2401,6 +2408,14 @@ private: if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); + AstClassOrPackageRef* cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); + if (cpackagerefp->name() == "process" || cpackagerefp->name() == "local") { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); + } + if (cpackagerefp->paramsp()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + } UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), m_ds.m_dotp->lhsp(), "Bad package link"); nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); @@ -2667,6 +2682,22 @@ private: virtual void visit(AstRefDType* nodep) VL_OVERRIDE { // Resolve its reference if (nodep->user3SetOnce()) return; + if (AstNode* cpackagep = nodep->classOrPackagep()) { + if (AstClassOrPackageRef* cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { + if (cpackagerefp->packagep()) { + nodep->packagep(cpackagerefp->packagep()); + } else { + cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference"); + // if (cpackagerefp->paramsp()) { + // nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + // } + } + } else { + cpackagep->v3warn(E_UNSUPPORTED, + "Unsupported: Multiple '::' package/class reference"); + } + VL_DO_DANGLING(cpackagep->unlinkFrBack()->deleteTree(), cpackagep); + } if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); diff --git a/src/verilog.y b/src/verilog.y index 455f17dce..23659e757 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -264,17 +264,6 @@ int V3ParseGrammar::s_modTypeImpNum = 0; GRAMMARP->m_instParamp = paramsp; \ } -static AstPackage* CAST_PACKAGE_CLASS(AstNode* nodep) { - if (!nodep) { - return NULL; - } else if (AstPackage* pkgp = VN_CAST(nodep, Package)) { - return pkgp; - } else { - BBUNSUP(nodep->fileline(), "Unsupported class :: reference"); - return NULL; - } -} - #define DEL(nodep) \ { \ if (nodep) nodep->deleteTree(); \ @@ -1783,8 +1772,8 @@ simple_type: // ==IEEE: simple_type // // Even though we looked up the type and have a AstNode* to it, // // we can't fully resolve it because it may have been just a forward definition. | packageClassScopeE idType - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); $$ = refp; } + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); + $$ = refp; } // // // { generate_block_identifer ... } '.' // // Need to determine if generate_block_identifier can be lex-detected @@ -1801,12 +1790,10 @@ data_type: // ==IEEE: data_type // // IEEE: ps_covergroup_identifier // // Don't distinguish between types and classes so all these combined | packageClassScopeE idType packed_dimensionListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); $$ = GRAMMARP->createArray(refp, $3, true); } | packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, $3); BBUNSUP($3->fileline(), "Unsupported: Parameter classes"); $$ = GRAMMARP->createArray(refp, $4, true); } ; @@ -1851,7 +1838,8 @@ var_data_type: // ==IEEE: var_data_type ; type_reference: // ==IEEE: type_reference - yTYPE '(' exprOrDataType ')' { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } + yTYPE '(' exprOrDataType ')' + { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } ; struct_unionDecl: // IEEE: part of data_type @@ -2021,8 +2009,7 @@ enum_base_typeE: // IEEE: enum_base_type | idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2, true); } | packageClassScope idAny rangeListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); $$ = GRAMMARP->createArray(refp, $3, true); } ; @@ -2526,7 +2513,7 @@ delay_control: //== IEEE: delay_control delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier - packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), $2); } + packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($2, $1, $2); } | yaINTNUM { $$ = new AstConst($1, *$1); } | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } | timeNumAdjusted { $$ = $1; } @@ -3412,7 +3399,7 @@ taskRef: // IEEE: part of tf_call id { $$ = new AstTaskRef($1,*$1,NULL); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstTaskRef($2, *$2, $4)); } + { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2, *$2, $4)); } ; funcRef: // IEEE: part of tf_call @@ -3428,7 +3415,7 @@ funcRef: // IEEE: part of tf_call id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($1, *$1, $3); } | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstFuncRef($2, *$2, $4)); } + { $$ = AstDot::newIfPkg($2, $1, new AstFuncRef($2, *$2, $4)); } //UNSUP list_of_argumentE should be pev_list_of_argumentE //UNSUP: idDotted is really just id to allow dotted method calls ; @@ -4263,7 +4250,7 @@ exprScope: // scope and variable for use to inside an expression yTHIS { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "this"); } | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } | idArrayed { $$ = $1; } - | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), CAST_PACKAGE_CLASS($1), $2); } + | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } | ~l~expr '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } // // expr below must be a "yTHIS" | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } @@ -5912,11 +5899,11 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p //=== Below rules assume special scoping per above -packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID +packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID packageClassScope { $$ = $1; $$ = $1; SYMP->nextId(NULL); } ; -packageClassScopeE: // IEEE: [package_scope] +packageClassScopeE: // IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // TODO: To support classes should return generic type, not packagep @@ -5925,7 +5912,7 @@ packageClassScopeE: // IEEE: [package_scope] | packageClassScope { $$ = $1; $$ = $1; } ; -packageClassScope: // IEEE: class_scope + type +packageClassScope: // IEEE: class_scope // // IEEE: "class_type yP_COLONCOLON" // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId @@ -5934,10 +5921,11 @@ packageClassScope: // IEEE: class_scope + type packageClassScopeList { $$ = $1; $$ = $1; } | localNextId yP_COLONCOLON { $$ = $1; $$ = $1; } | dollarUnitNextId yP_COLONCOLON { $$ = $1; $$ = $1; } - | dollarUnitNextId yP_COLONCOLON packageClassScopeList { $$ = $3; $$ = $3; } + | dollarUnitNextId yP_COLONCOLON packageClassScopeList + { $$ = new AstDot($2, true, $1, $3); $$ = $3; } ; -packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE +packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE // // Or IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId @@ -5945,10 +5933,10 @@ packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assi // // If you follow the rules down, class_type is really a list via ps_class_identifier packageClassScopeItem { $$ = $1; $$ = $1; } | packageClassScopeList packageClassScopeItem - { $$ = $2; $$ = $2; BBUNSUP($2, "Unsupported: Nested :: references"); } + { $$ = new AstDot($2, true, $1, $2); $$ = $2; } ; -packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] +packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE @@ -5956,29 +5944,30 @@ packageClassScopeItem: // IEEE: package_scope or [package_scope]::[cla idCC /*mid*/ { SYMP->nextId($1); } /*cont*/ yP_COLONCOLON - { $$ = VN_CAST($1, Package); $$ = $1; } // UNSUP classes + { $$ = new AstClassOrPackageRef($1, *$1, $1, NULL); $$ = $1; } // | idCC parameter_value_assignment /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before /*cont*/ yP_COLONCOLON - { $$ = VN_CAST($1, Package); $$ = $1; // UNSUP classes - if ($2) BBUNSUP($2->fileline(), "Unsupported: Parameterized classes"); } + { $$ = new AstClassOrPackageRef($1, *$1, $1, $2); $$ = $1; } ; -dollarUnitNextId: // $unit +dollarUnitNextId: // $unit // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // Must call nextId without any additional tokens following yD_UNIT - { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); } + { $$ = new AstClassOrPackageRef($1, "$unit", GRAMMARP->unitPackage($1), NULL); + SYMP->nextId(PARSEP->rootp()); } ; -localNextId: // local +localNextId: // local // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // Must call nextId without any additional tokens following yLOCAL__COLONCOLON - { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); + { $$ = new AstClassOrPackageRef($1, "local::", GRAMMARP->unitPackage($1), NULL); + SYMP->nextId(PARSEP->rootp()); BBUNSUP($1, "Unsupported: Randomize 'local::'"); } ; diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out index 3444da0d9..25f82f892 100644 --- a/test_regress/t/t_class2.out +++ b/test_regress/t/t_class2.out @@ -1,4 +1,7 @@ -%Error: t/t_class2.v:35:16: Can't find definition of variable: 'ENUM_VAL' +%Error-UNSUPPORTED: t/t_class2.v:35:16: Unsupported: Class '::' references: 'Cls' 35 | if (Cls::ENUM_VAL != 22) $stop; | ^~~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_class2.v:35:11: ../V3LinkDot.cpp:#: Bad package link + 35 | if (Cls::ENUM_VAL != 22) $stop; + | ^~~ + ... See the manual and https://verilator.org for more assistance. diff --git a/test_regress/t/t_class_typedef.out b/test_regress/t/t_class_typedef.out index bc468849c..4979a037a 100644 --- a/test_regress/t/t_class_typedef.out +++ b/test_regress/t/t_class_typedef.out @@ -1,4 +1,13 @@ -%Error-UNSUPPORTED: t/t_class_typedef.v:14:24: Unsupported: Parameterized classes +%Error-UNSUPPORTED: t/t_class_typedef.v:12:4: Unsupported: Class '::' reference + 12 | uvm_resource_types::rsrc_q_t rtab [string]; + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_class_typedef.v:12:24: Can't find typedef: 'rsrc_q_t' + 12 | uvm_resource_types::rsrc_q_t rtab [string]; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_class_typedef.v:14:4: Unsupported: Class '::' reference 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^ + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_class_typedef.v:14:32: Can't find typedef: 'rsrc_q_t' + 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; + | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out index c024cca10..7f135af7b 100644 --- a/test_regress/t/t_process.out +++ b/test_regress/t/t_process.out @@ -1,22 +1,9 @@ %Error: t/t_process.v:22:4: Can't find typedef: 'process' 22 | process p; | ^~~~~~~ -%Error: t/t_process.v:26:20: Can't find definition of task/function: 'self' +%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' 26 | p = process::self(); | ^~~~ -%Error: t/t_process.v:27:34: Can't find definition of variable: 'RUNNING' - 27 | if (p.status() != process::RUNNING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:28:34: Can't find definition of variable: 'WAITING' - 28 | if (p.status() == process::WAITING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:29:34: Can't find definition of variable: 'SUSPENDED' - 29 | if (p.status() == process::SUSPENDED) $stop; - | ^~~~~~~~~ -%Error: t/t_process.v:30:34: Can't find definition of variable: 'KILLED' - 30 | if (p.status() == process::KILLED) $stop; - | ^~~~~~ -%Error: t/t_process.v:31:34: Can't find definition of variable: 'FINISHED' - 31 | if (p.status() == process::FINISHED) $stop; - | ^~~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link + 26 | p = process::self(); + | ^~~~~~~