From 5bbb054173dec1300add7090a143e7da7d9192da Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 20:39:54 +0000 Subject: [PATCH] Add check for explicit lifetime when initialising static variables. If a static variable declared in a task, function, or block has an initialisation expression, SystemVerilog requires the declaration to have an explicit static lifetime. This is supposed to be a compile error, but for now just output a warning. Implementing this required adding support in the parser for explicit lifetimes in variable declarations. For now, just output an error if the user asks for a lifetime that isn't the default for that scope. (cherry picked from commit 9538c81d342c7bdf2ad81ad22966f179dd290bfd) --- PScope.cc | 6 +++++- PScope.h | 7 +++++-- PTask.cc | 5 +++++ PTask.h | 2 ++ Statement.cc | 5 +++++ Statement.h | 2 ++ parse.y | 45 +++++++++++++++++++++++++++++++++++++++++---- pform.cc | 1 + 8 files changed, 66 insertions(+), 7 deletions(-) diff --git a/PScope.cc b/PScope.cc index 377142bf9..9add20a1b 100644 --- a/PScope.cc +++ b/PScope.cc @@ -19,6 +19,11 @@ # include "PScope.h" +bool LexicalScope::var_init_needs_explicit_lifetime() const +{ + return false; +} + PScope::PScope(perm_string n, LexicalScope*parent) : LexicalScope(parent), name_(n) { @@ -58,4 +63,3 @@ PScopeExtra::PScopeExtra(perm_string n) PScopeExtra::~PScopeExtra() { } - diff --git a/PScope.h b/PScope.h index 081d9fb58..ce6f94afb 100644 --- a/PScope.h +++ b/PScope.h @@ -53,11 +53,12 @@ class NetScope; class LexicalScope { public: - explicit LexicalScope(LexicalScope*parent) : parent_(parent) { } + enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; + + explicit LexicalScope(LexicalScope*parent) : default_lifetime(INHERITED), parent_(parent) { } // A virtual destructor is so that dynamic_cast can work. virtual ~LexicalScope() { } - enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; lifetime_t default_lifetime; struct range_t { @@ -124,6 +125,8 @@ class LexicalScope { LexicalScope* parent_scope() const { return parent_; } + virtual bool var_init_needs_explicit_lifetime() const; + protected: void dump_typedefs_(ostream&out, unsigned indent) const; diff --git a/PTask.cc b/PTask.cc index 034f38da6..93f8ba10f 100644 --- a/PTask.cc +++ b/PTask.cc @@ -30,6 +30,11 @@ PTaskFunc::~PTaskFunc() { } +bool PTaskFunc::var_init_needs_explicit_lifetime() const +{ + return default_lifetime == STATIC; +} + void PTaskFunc::set_ports(vector*p) { assert(ports_ == 0); diff --git a/PTask.h b/PTask.h index 1b636d05a..4c1899d04 100644 --- a/PTask.h +++ b/PTask.h @@ -41,6 +41,8 @@ class PTaskFunc : public PScope, public LineInfo { PTaskFunc(perm_string name, LexicalScope*parent); ~PTaskFunc(); + bool var_init_needs_explicit_lifetime() const; + void set_ports(std::vector*p); void set_this(class_type_t*use_type, PWire*this_wire); diff --git a/Statement.cc b/Statement.cc index e0ed46d24..942558107 100644 --- a/Statement.cc +++ b/Statement.cc @@ -115,6 +115,11 @@ PBlock::~PBlock() delete list_[idx]; } +bool PBlock::var_init_needs_explicit_lifetime() const +{ + return default_lifetime == STATIC; +} + PChainConstructor* PBlock::extract_chain_constructor() { if (list_.empty()) diff --git a/Statement.h b/Statement.h index cc7214194..18e4c0f9a 100644 --- a/Statement.h +++ b/Statement.h @@ -183,6 +183,8 @@ class PBlock : public PScope, public Statement { BL_TYPE bl_type() const { return bl_type_; } + bool var_init_needs_explicit_lifetime() const; + // This is only used if this block is the statement list for a // constructor. We look for a PChainConstructor as the first // statement, and if it is there, extract it. diff --git a/parse.y b/parse.y index 1b0fec636..b9f90933e 100644 --- a/parse.y +++ b/parse.y @@ -65,6 +65,10 @@ static PTask* current_task = 0; static PFunction* current_function = 0; static stack current_block_stack; +/* The variable declaration rules need to know if a lifetime has been + specified. */ +static LexicalScope::lifetime_t var_lifetime; + static pform_name_t* pform_create_this(void) { name_component_t name (perm_string::literal("@")); @@ -667,7 +671,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type atom2_type %type module_start module_end -%type lifetime_opt +%type lifetime lifetime_opt %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -1369,10 +1373,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */ } ; -lifetime_opt /* IEEE1800-2005: A.2.1.3 */ +lifetime /* IEEE1800-2005: A.2.1.3 */ : K_automatic { $$ = LexicalScope::AUTOMATIC; } | K_static { $$ = LexicalScope::STATIC; } - | { $$ = LexicalScope::INHERITED; } + ; + +lifetime_opt /* IEEE1800-2005: A.2.1.3 */ + : lifetime { $$ = $1; } + | { $$ = LexicalScope::INHERITED; } ; /* Loop statements are kinds of statements. */ @@ -2254,6 +2262,19 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ } ; +variable_lifetime + : lifetime + { if (!gn_system_verilog()) { + yyerror(@1, "error: overriding the default variable lifetime " + "requires SystemVerilog."); + } else if ($1 != pform_peek_scope()->default_lifetime) { + yyerror(@1, "sorry: overriding the default variable lifetime " + "is not yet supported."); + } + var_lifetime = $1; + } + ; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -2328,10 +2349,20 @@ block_item_decl { if ($1) pform_set_data_type(@1, $1, $2, NetNet::REG, attributes_in_context); } + | variable_lifetime data_type register_variable_list ';' + { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context); + var_lifetime = LexicalScope::INHERITED; + } + | K_reg data_type register_variable_list ';' { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context); } + | variable_lifetime K_reg data_type register_variable_list ';' + { if ($3) pform_set_data_type(@3, $3, $4, NetNet::REG, attributes_in_context); + var_lifetime = LexicalScope::INHERITED; + } + | K_event event_variable_list ';' { if ($2) pform_make_events($2, @1.text, @1.first_line); } @@ -5492,7 +5523,13 @@ register_variable $$ = $1; } | IDENTIFIER dimensions_opt '=' expression - { perm_string name = lex_strings.make($1); + { if (pform_peek_scope()->var_init_needs_explicit_lifetime() + && (var_lifetime == LexicalScope::INHERITED)) { + cerr << @3 << ": warning: Static variable initialization requires " + "explicit lifetime in this context." << endl; + warn_count += 1; + } + perm_string name = lex_strings.make($1); pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); pform_set_reg_idx(name, $2); diff --git a/pform.cc b/pform.cc index 34a5eb638..95f0d5191 100644 --- a/pform.cc +++ b/pform.cc @@ -513,6 +513,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) } PBlock*block = new PBlock(block_name, lexical_scope, bt); + block->default_lifetime = find_lifetime(LexicalScope::INHERITED); lexical_scope = block; return block;