Skip to content

Commit

Permalink
Add check for explicit lifetime when initialising static variables.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
martinwhitaker committed Mar 19, 2016
1 parent 6e718c2 commit 9538c81
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 7 deletions.
6 changes: 5 additions & 1 deletion PScope.cc
Expand Up @@ -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)
{
Expand Down Expand Up @@ -58,4 +63,3 @@ PScopeExtra::PScopeExtra(perm_string n)
PScopeExtra::~PScopeExtra()
{
}

7 changes: 5 additions & 2 deletions PScope.h
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions PTask.cc
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions PTask.h
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions Statement.cc
Expand Up @@ -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())
Expand Down
2 changes: 2 additions & 0 deletions Statement.h
Expand Up @@ -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.
Expand Down
45 changes: 41 additions & 4 deletions parse.y
Expand Up @@ -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("@"));
Expand Down Expand Up @@ -666,7 +670,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
Expand Down Expand Up @@ -1368,10 +1372,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. */
Expand Down Expand Up @@ -2262,6 +2270,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. */
Expand Down Expand Up @@ -2336,10 +2357,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);
}
Expand Down Expand Up @@ -5496,7 +5527,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);
Expand Down
1 change: 1 addition & 0 deletions pform.cc
Expand Up @@ -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;
Expand Down

0 comments on commit 9538c81

Please sign in to comment.