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 9538c81d34)
This commit is contained in:
Martin Whitaker 2016-03-19 20:39:54 +00:00
parent 7d2eeb0137
commit 5bbb054173
8 changed files with 66 additions and 7 deletions

View File

@ -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()
{
}

View File

@ -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;

View File

@ -30,6 +30,11 @@ PTaskFunc::~PTaskFunc()
{
}
bool PTaskFunc::var_init_needs_explicit_lifetime() const
{
return default_lifetime == STATIC;
}
void PTaskFunc::set_ports(vector<pform_tf_port_t>*p)
{
assert(ports_ == 0);

View File

@ -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<pform_tf_port_t>*p);
void set_this(class_type_t*use_type, PWire*this_wire);

View File

@ -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())

View File

@ -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.

43
parse.y
View File

@ -65,6 +65,10 @@ static PTask* current_task = 0;
static PFunction* current_function = 0;
static stack<PBlock*> 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<Statement*>
%type <int_val> atom2_type
%type <int_val> module_start module_end
%type <lifetime> lifetime_opt
%type <lifetime> 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,9 +1373,13 @@ 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; }
;
lifetime_opt /* IEEE1800-2005: A.2.1.3 */
: lifetime { $$ = $1; }
| { $$ = LexicalScope::INHERITED; }
;
@ -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);

View File

@ -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;