Merge pull request #824 from larsclausen/class-lifetime

Fix variable initialization in class methods
This commit is contained in:
Stephen Williams 2022-12-24 17:33:29 -08:00 committed by GitHub
commit 7b1fad78c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 10 deletions

View File

@ -517,7 +517,14 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
hname_t use_name (cur->first);
NetScope*method_scope = new NetScope(class_scope, use_name, NetScope::TASK);
// Task methods are always automatic...
if (!cur->second->is_auto()) {
cerr << "error: Lifetime of method `"
<< scope_path(method_scope)
<< "` must not be static" << endl;
des->errors += 1;
}
method_scope->is_auto(true);
method_scope->set_line(cur->second);
method_scope->add_imports(&cur->second->explicit_imports);
@ -536,7 +543,14 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
hname_t use_name (cur->first);
NetScope*method_scope = new NetScope(class_scope, use_name, NetScope::FUNC);
// Function methods are always automatic...
if (!cur->second->is_auto()) {
cerr << "error: Lifetime of method `"
<< scope_path(method_scope)
<< "` must not be static" << endl;
des->errors += 1;
}
method_scope->is_auto(true);
method_scope->set_line(cur->second);
method_scope->add_imports(&cur->second->explicit_imports);

View File

@ -0,0 +1,18 @@
// Check that specifing static lifetime for a class method taks results in an
// error.
module test;
class C;
// This should fail, all class methods have automatic lifetime
task static t(int x);
int y;
y = 2 * x;
endtask
endclass
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,19 @@
// Check that specifing static lifetime for a class method function results in
// an error.
module test;
class C;
// This should fail, all class methods have automatic lifetime
function static int t(int x);
int y;
y = 2 * x;
return y;
endfunction
endclass
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,25 @@
// Check that variable initialization as part of the declaration works as
// expected in class methods.
module test;
class C;
task t(bit check);
int x = 10; // The initialization should happen on each invocation
if (check) begin
if (x === 10) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
x = 20;
endtask
endclass
initial begin
C c;
c = new;
c.t(1'b0);
c.t(1'b1);
end
endmodule

View File

@ -565,8 +565,11 @@ sv_class_in_module_decl normal,-g2009 ivltests
sv_class_method_call_void normal,-g2009 ivltests
sv_class_method_default1 normal,-g2009 ivltests
sv_class_method_default2 normal,-g2009 ivltests
sv_class_method_lt_static1 CE,-g2009 ivltests
sv_class_method_lt_static2 CE,-g2009 ivltests
sv_class_method_signed1 normal,-g2009 ivltests
sv_class_method_signed2 normal,-g2009 ivltests
sv_class_method_var_init normal,-g2009 ivltests
sv_class_property_signed1 normal,-g2009 ivltests
sv_class_property_signed2 normal,-g2009 ivltests
sv_class_property_signed3 normal,-g2009 ivltests

View File

@ -422,6 +422,7 @@ sv_class_method_default1 CE,-g2009 ivltests
sv_class_method_default2 CE,-g2009 ivltests
sv_class_method_signed1 CE,-g2009,-pallowsigned=1 ivltests
sv_class_method_signed2 CE,-g2009,-pallowsigned=1 ivltests
sv_class_method_var_init CE,-g2009,-pallowsigned=1 ivltests
sv_class_property_signed1 CE,-g2009,-pallowsigned=1 ivltests
sv_class_property_signed2 CE,-g2009,-pallowsigned=1 ivltests
sv_class_property_signed3 CE,-g2009,-pallowsigned=1 ivltests

14
parse.y
View File

@ -796,12 +796,22 @@ block_identifier_opt /* */
class_declaration /* IEEE1800-2005: A.1.2 */
: K_virtual_opt K_class lifetime_opt identifier_name class_declaration_extends_opt ';'
{
{ /* Up to 1800-2017 the grammar in the LRM allowed an optional lifetime
* qualifier for class declarations. But the LRM never specified what
* this qualifier should do. Starting with 1800-2023 the qualifier has
* been removed from the grammar. Allow it for backwards compatibility,
* but print a warning.
*/
if ($3 != LexicalScope::INHERITED) {
cerr << @1 << ": warning: Class lifetime qualifier is deprecated "
"and has no effect." << endl;
warn_count += 1;
}
perm_string name = lex_strings.make($4);
class_type_t *class_type= new class_type_t(name);
FILE_NAME(class_type, @4);
pform_set_typedef(@4, name, class_type, nullptr);
pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $3, $1);
pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $1);
}
class_items_opt K_endclass
{ // Process a class.

View File

@ -602,11 +602,10 @@ static void pform_set_scope_timescale(PScope*scope, const PScope*parent)
scope->time_prec_is_default = parent->time_prec_is_default;
}
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime)
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
{
PClass*class_scope = new PClass(name, lexical_scope);
class_scope->default_lifetime = find_lifetime(lifetime);
class_scope->default_lifetime = LexicalScope::AUTOMATIC;
FILE_NAME(class_scope, loc);
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);

View File

@ -173,7 +173,6 @@ extern void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
std::list<PExpr*>*base_exprs,
LexicalScope::lifetime_t lifetime,
bool virtual_class);
extern void pform_class_property(const struct vlltype&loc,
property_qualifier_t pq,
@ -241,8 +240,7 @@ extern void pform_pop_scope();
*/
extern LexicalScope* pform_peek_scope();
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime);
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name);
extern PFunction*pform_push_constructor_scope(const struct vlltype&loc);

View File

@ -43,10 +43,9 @@ void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
list<PExpr*>*base_exprs,
LexicalScope::lifetime_t lifetime,
bool virtual_class)
{
PClass*class_scope = pform_push_class_scope(loc, type->name, lifetime);
PClass*class_scope = pform_push_class_scope(loc, type->name);
class_scope->type = type;
assert(pform_cur_class == 0);
pform_cur_class = class_scope;