From 4d5e448664163fb2e73a747a157ff7c4770eda12 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 1 Jul 2020 07:31:53 -0400 Subject: [PATCH] Parser: Move member qualifier unsupporteds out of parser. --- src/V3Ast.h | 6 ++- src/V3LinkDot.cpp | 9 +++- src/V3ParseImp.h | 57 ++++++++++++++++++++ src/V3Width.cpp | 3 ++ src/verilog.y | 69 ++++++++++++------------- test_regress/t/t_class_name.out | 5 +- test_regress/t/t_class_static_order.out | 15 +++--- test_regress/t/t_class_unsup_bad.out | 23 +++------ test_regress/t/t_class_unsup_bad.v | 1 + 9 files changed, 126 insertions(+), 62 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 8daf96a13..b64d67134 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2646,6 +2646,7 @@ private: bool m_dpiTask : 1; // DPI import task (vs. void function) bool m_isConstructor : 1; // Class constructor bool m_pure : 1; // DPI import pure (vs. virtual pure) + bool m_virtual : 1; // Virtual method in class VLifetime m_lifetime; // Lifetime public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) @@ -2662,7 +2663,8 @@ public: , m_dpiOpenChild(false) , m_dpiTask(false) , m_isConstructor(false) - , m_pure(false) { + , m_pure(false) + , m_virtual(false) { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -2711,6 +2713,8 @@ public: bool isConstructor() const { return m_isConstructor; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } + void isVirtual(bool flag) { m_virtual = flag; } + bool isVirtual() const { return m_virtual; } void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index e5591458e..bb1b0bf77 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1041,6 +1041,9 @@ class LinkDotFindVisitor : public AstNVisitor { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } + if (nodep->isClassMember() && nodep->lifetime().isStatic()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class members"); + } if (!m_statep->forScopeCreation()) { // Find under either a task or the module's vars VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name()); @@ -2029,8 +2032,7 @@ private: "ParseRefs should no longer exist"); if (nodep->name() == "this") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: this"); - } - else if (nodep->name() == "super") { + } else if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); } DotStates lastStates = m_ds; @@ -2630,6 +2632,9 @@ private: virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); checkNoDot(nodep); + if (nodep->classMethod() && nodep->lifetime().isStatic()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method"); + } VSymEnt* oldCurSymp = m_curSymp; { m_ftaskp = nodep; diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 0be03568d..c44e759c1 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -41,6 +41,62 @@ typedef enum { uniq_NONE, uniq_UNIQUE, uniq_UNIQUE0, uniq_PRIORITY } V3UniqState typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty; +//============================================================================ +// Member qualifiers + +struct VMemberQualifiers { + union { + uint32_t m_flags; + struct { + uint32_t m_local : 1; // Local class item (ignored until warning implemented) + uint32_t m_protected : 1; // Protected class item (ignored until warning implemented) + uint32_t m_rand : 1; // Rand property/member qualifier (ignored until supported) + uint32_t m_randc : 1; // Randc property/member qualifier (ignored until supported) + uint32_t m_virtual : 1; // Virtual property/method qualifier + uint32_t m_automatic : 1; // Automatic property/method qualifier + uint32_t m_const : 1; // Const property/method qualifier + uint32_t m_static : 1; // Static class method + }; + }; + static VMemberQualifiers none() { + VMemberQualifiers q; + q.m_flags = 0; + return q; + } + static VMemberQualifiers combine(const VMemberQualifiers& a, const VMemberQualifiers& b) { + VMemberQualifiers q; + q.m_flags = a.m_flags | b.m_flags; + return q; + } + void applyToNodes(AstNodeFTask* nodesp) const { + for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), NodeFTask)) { + // Ignored for now: m_local + // Ignored for now: m_protected + if (m_virtual) nodep->isVirtual(true); + if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); + if (m_static) nodep->lifetime(VLifetime::STATIC); + if (m_const || m_rand || m_randc) { + nodep->v3error("Syntax error: 'const'/'rand'/'randc' not allowed before " + "function/task declaration"); + } + } + } + void applyToNodes(AstVar* nodesp) const { + for (AstVar* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), Var)) { + // Ignored for now: m_local + // Ignored for now: m_protected + // Ignored for now: m_rand + // Ignored for now: m_randc + if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); + if (m_static) nodep->lifetime(VLifetime::STATIC); + if (m_const) nodep->isConst(true); + if (m_virtual) { + nodep->v3error("Syntax error: 'virtual' not allowed before var declaration"); + } + } + } +}; + //============================================================================ // Parser YYSType, e.g. for parser's yylval // We can't use bison's %union as we want to pass the fileline with all tokens @@ -55,6 +111,7 @@ struct V3ParseBisonYYSType { int cint; double cdouble; bool cbool; + VMemberQualifiers qualifiers; V3UniqState uniqstate; V3ImportProperty iprop; VSigning::en signstate; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 914e72665..e2222f5d7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3700,6 +3700,9 @@ private: nodep->didWidth(true); return; } + if (nodep->isVirtual()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'virtual' class method"); + } // Function hasn't been widthed, so make it so. // Would use user1 etc, but V3Width called from too many places to spend a user nodep->doingWidth(true); diff --git a/src/verilog.y b/src/verilog.y index 0c37189f7..3f6883559 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1868,6 +1868,7 @@ struct_union_memberList: // IEEE: { struct_union_member } ; struct_union_member: // ==IEEE: struct_union_member + // // UNSUP random_qualifer not propagagted until have randomize support random_qualifierE data_type_or_void /*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. /*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = NULL; } @@ -1904,9 +1905,9 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assignment | '=' class_new { NULL; BBUNSUP($1, "Unsupported: member declaration assignment with new()"); } ; -list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments +list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments variable_decl_assignment { $$ = $1; } - | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = $1->addNextNull($3); } + | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = VN_CAST($1->addNextNull($3), Var); } ; variable_decl_assignment: // ==IEEE: variable_decl_assignment @@ -1970,14 +1971,14 @@ variable_dimension: // ==IEEE: variable_dimension // // '[' '$' ':' expr ']' -- anyrange:expr:$ ; -random_qualifierE: // IEEE: random_qualifier + empty - /*empty*/ { } - | random_qualifier { } +random_qualifierE: // IEEE: random_qualifier + empty + /*empty*/ { $$ = VMemberQualifiers::none(); } + | random_qualifier { $$ = $1; } ; -random_qualifier: // ==IEEE: random_qualifier - yRAND { } // Ignored until we support randomize() - | yRANDC { } // Ignored until we support randomize() +random_qualifier: // ==IEEE: random_qualifier + yRAND { $$ = VMemberQualifiers::none(); $$.m_rand = true; } + | yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; } ; taggedE: @@ -2062,20 +2063,22 @@ data_declaration: // ==IEEE: data_declaration ; class_property: // ==IEEE: class_property, which is {property_qualifier} data_declaration - memberQualResetListE data_declarationVarClass { $$ = $2; } - | memberQualResetListE type_declaration { $$ = $2; } - | memberQualResetListE package_import_declaration { $$ = $2; } + memberQualListE data_declarationVarClass { $$ = $2; $1.applyToNodes($2); } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE type_declaration { $$ = $2; } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE package_import_declaration { $$ = $2; } // // IEEE: virtual_interface_declaration // // "yVIRTUAL yID yID" looks just like a data_declaration // // Therefore the virtual_interface_declaration term isn't used ; -data_declarationVar: // IEEE: part of data_declaration +data_declarationVar: // IEEE: part of data_declaration // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; } ; -data_declarationVarClass: // IEEE: part of data_declaration (for class_property) +data_declarationVarClass: // IEEE: part of data_declaration (for class_property) // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFrontClass list_of_variable_decl_assignments ';' { $$ = $2; } ; @@ -6000,51 +6003,47 @@ class_item: // ==IEEE: class_item ; class_method: // ==IEEE: class_method - memberQualResetListE task_declaration { $$ = $2; } - | memberQualResetListE function_declaration { $$ = $2; } - | yPURE yVIRTUAL__ETC memberQualResetListE method_prototype ';' + memberQualListE task_declaration { $$ = $2; $1.applyToNodes($2); } + | memberQualListE function_declaration { $$ = $2; $1.applyToNodes($2); } + | yPURE yVIRTUAL__ETC memberQualListE method_prototype ';' { $$ = NULL; BBUNSUP($1, "Unsupported: pure virtual class method"); } - | yEXTERN memberQualResetListE method_prototype ';' + | yEXTERN memberQualListE method_prototype ';' { $$ = NULL; BBUNSUP($1, "Unsupported: extern class method prototype"); } // // IEEE: "method_qualifierE class_constructor_declaration" // // part of function_declaration - | yEXTERN memberQualResetListE class_constructor_prototype + | yEXTERN memberQualListE class_constructor_prototype { $$ = NULL; BBUNSUP($1, "Unsupported: extern class"); } ; // IEEE: class_constructor_prototype // See function_declaration -class_item_qualifier: // IEEE: class_item_qualifier minus ySTATIC - // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule - yPROTECTED { $$ = NULL; } // Ignoring protected until warning implemented - | yLOCAL__ETC { $$ = NULL; } // Ignoring local until warning implemented - | ySTATIC__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'static' class item"); } - ; - -memberQualResetListE: // Called from class_property for all qualifiers before yVAR +memberQualListE: // Called from class_property for all qualifiers before yVAR // // Also before method declarations, to prevent grammar conflict // // Thus both types of qualifiers (method/property) are here - /*empty*/ { $$ = NULL; } + /*empty*/ { $$ = VMemberQualifiers::none(); } | memberQualList { $$ = $1; } ; -memberQualList: +memberQualList: memberQualOne { $$ = $1; } - | memberQualList memberQualOne { $$ = AstNode::addNextNull($1, $2); } + | memberQualList memberQualOne { $$ = VMemberQualifiers::combine($1, $2); } ; -memberQualOne: // IEEE: property_qualifier + method_qualifier +memberQualOne: // IEEE: property_qualifier + method_qualifier // // Part of method_qualifier and property_qualifier - class_item_qualifier { $$ = $1; } + // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule + yPROTECTED { $$ = VMemberQualifiers::none(); $$.m_protected = true; } + | yLOCAL__ETC { $$ = VMemberQualifiers::none(); $$.m_local = true; } + | ySTATIC__ETC { $$ = VMemberQualifiers::none(); $$.m_static = true; } // // Part of method_qualifier only - | yVIRTUAL__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: virtual class member qualifier"); } + | yVIRTUAL__ETC { $$ = VMemberQualifiers::none(); $$.m_virtual = true; } // // Part of property_qualifier only - | random_qualifier { $$ = NULL; } + | random_qualifier { $$ = $1; } // // Part of lifetime, but here as ySTATIC can be in different positions - | yAUTOMATIC { $$ = NULL; BBUNSUP($1, "Unsupported: automatic class member qualifier"); } + | yAUTOMATIC { $$ = VMemberQualifiers::none(); $$.m_automatic = true; } // // Part of data_declaration, but not in data_declarationVarFrontClass - | yCONST__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: const class member qualifier"); } + | yCONST__ETC { $$ = VMemberQualifiers::none(); $$.m_const = true; } ; //********************************************************************** diff --git a/test_regress/t/t_class_name.out b/test_regress/t/t_class_name.out index f502aeddb..8f5e19daa 100644 --- a/test_regress/t/t_class_name.out +++ b/test_regress/t/t_class_name.out @@ -1,4 +1,5 @@ -%Error-UNSUPPORTED: t/t_class_name.v:12:4: Unsupported: 'static' class item +%Error-UNSUPPORTED: t/t_class_name.v:12:16: Unsupported: 'static' class method + : ... In instance t 12 | static task static_name; - | ^~~~~~ + | ^~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_static_order.out b/test_regress/t/t_class_static_order.out index 9314c7c1a..9565f5068 100644 --- a/test_regress/t/t_class_static_order.out +++ b/test_regress/t/t_class_static_order.out @@ -1,10 +1,13 @@ -%Error-UNSUPPORTED: t/t_class_static_order.v:23:4: Unsupported: 'static' class item +%Error-UNSUPPORTED: t/t_class_static_order.v:23:16: Unsupported: 'static' class members + : ... In instance t 23 | static ClsZ z = new; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_class_static_order.v:34:4: Unsupported: 'static' class item + | ^ +%Error-UNSUPPORTED: t/t_class_static_order.v:34:16: Unsupported: 'static' class members + : ... In instance t 34 | static ClsA a = new; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_class_static_order.v:35:4: Unsupported: 'static' class item + | ^ +%Error-UNSUPPORTED: t/t_class_static_order.v:35:16: Unsupported: 'static' class members + : ... In instance t 35 | static ClsB b = new; - | ^~~~~~ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_unsup_bad.out b/test_regress/t/t_class_unsup_bad.out index 8adc7beca..23492861e 100644 --- a/test_regress/t/t_class_unsup_bad.out +++ b/test_regress/t/t_class_unsup_bad.out @@ -7,22 +7,13 @@ %Error-UNSUPPORTED: t/t_class_unsup_bad.v:14:26: Unsupported: class parameters 14 | localparam LOCPAR = 10; | ^ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:25:4: Unsupported: virtual class member qualifier - 25 | virtual function void func_virtual; endfunction - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:26:4: Unsupported: pure virtual class method - 26 | pure virtual function void func_pure_virtual; +%Error-UNSUPPORTED: t/t_class_unsup_bad.v:27:4: Unsupported: pure virtual class method + 27 | pure virtual function void func_pure_virtual; | ^~~~ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:27:4: Unsupported: automatic class member qualifier - 27 | automatic function void func_automatic; endfunction - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:28:4: Unsupported: const class member qualifier - 28 | const function void func_const; endfunction - | ^~~~~ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:29:4: Unsupported: extern class method prototype - 29 | extern task exttask; +%Error: t/t_class_unsup_bad.v:29:24: Syntax error: 'const'/'rand'/'randc' not allowed before function/task declaration + 29 | const function void func_const; endfunction + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_class_unsup_bad.v:30:4: Unsupported: extern class method prototype + 30 | extern task exttask; | ^~~~~~ -%Error-UNSUPPORTED: t/t_class_unsup_bad.v:42:4: Unsupported: virtual class member qualifier - 42 | virtual function uvm_root get_root(); - | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_unsup_bad.v b/test_regress/t/t_class_unsup_bad.v index 69d5e9793..dbfdbf310 100644 --- a/test_regress/t/t_class_unsup_bad.v +++ b/test_regress/t/t_class_unsup_bad.v @@ -13,6 +13,7 @@ typedef interface class ic; class C #(parameter P=1); localparam LOCPAR = 10; int imember; + static int istatic; local int loc; protected int prot;