Merge pull request #825 from larsclausen/typed-constructor

Add support for typed constructor calls
This commit is contained in:
Stephen Williams 2022-12-24 17:36:01 -08:00 committed by GitHub
commit cc2ba4f8cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 197 additions and 4 deletions

View File

@ -488,8 +488,8 @@ PENewClass::PENewClass(void)
{
}
PENewClass::PENewClass(const list<PExpr*>&p)
: parms_(p.size())
PENewClass::PENewClass(const list<PExpr*>&p, data_type_t *class_type)
: parms_(p.size()), class_type_(class_type)
{
size_t tmp_idx = 0;
for (list<PExpr*>::const_iterator cur = p.begin()

View File

@ -555,7 +555,8 @@ class PENewClass : public PExpr {
// New without (or with default) constructor
explicit PENewClass ();
// New with constructor arguments
explicit PENewClass (const std::list<PExpr*>&p);
explicit PENewClass (const std::list<PExpr*>&p,
data_type_t *class_type = nullptr);
~PENewClass();
@ -577,6 +578,7 @@ class PENewClass : public PExpr {
private:
std::vector<PExpr*>parms_;
data_type_t *class_type_;
};
class PENewCopy : public PExpr {

View File

@ -6662,6 +6662,32 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
if (class_type_) {
ivl_type_t elab_class_type = class_type_->elaborate_type(des,
scope);
ctype = dynamic_cast<const netclass_t*> (elab_class_type);
if (!ctype) {
cerr << get_fileline() << ": error: Incompatible type in"
<< " typed constructor call.\n"
<< get_fileline() << ": : Constructor type `"
<< *elab_class_type << "` is not a class type."
<< endl;
des->errors++;
return nullptr;
}
if (!ntype->type_compatible(ctype)) {
cerr << get_fileline() << ": error: Incompatible type in"
<< " typed constructor call.\n"
<< get_fileline() << ": : Constructor type `"
<< *ctype
<< "` is not compatible with the target type `"
<< *ntype << "`." << endl;
des->errors++;
return nullptr;
}
}
if (ctype->is_virtual()) {
cerr << get_fileline() << ": error: "
<< "Can not create object of virtual class `"
@ -6670,7 +6696,7 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
NetExpr*obj = new NetENew(ntype);
NetExpr*obj = new NetENew(ctype);
obj->set_line(*this);
obj = elaborate_expr_constructor_(des, scope, ctype, obj, flags);

View File

@ -0,0 +1,16 @@
// Check that typed constructor calls are supported.
module test;
class C;
function new;
$display("PASSED");
endfunction
endclass
initial begin
C c;
c = C::new;
end
endmodule

View File

@ -0,0 +1,30 @@
// Check that typed constructor calls are supported when assigning to an
// variable of a base class type.
module test;
class B;
int x = 0;
task check;
if (x === 10) begin
$display("PASSED");
end else begin
$display("FAILED");
end
endtask
endclass
class C extends B;
function new;
x = 10;
endfunction
endclass
initial begin
B b;
b = C::new;
b.check;
end
endmodule

View File

@ -0,0 +1,19 @@
// Check that typed constructor calls are supported when the type is a typedef
// of a class type.
module test;
class C;
function new;
$display("PASSED");
endfunction
endclass
typedef C T;
initial begin
T c;
c = T::new;
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that an error is reported when using a typed constructor call to assign
// to a class that is not a base class.
module test;
class B;
endclass
class C;
endclass
initial begin
B b;
b = C::new; // This should fail, B is not a base class of C
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,19 @@
// Check that an error is reported when using a typed constructor call to assign
// to a class that is an inherited class.
module test;
class B;
endclass
class C extends B;
endclass
initial begin
C c;
c = B::new; // This should fail, B is a base class of C, but C is not a
// base class of B.
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,22 @@
// Check that an error is reported when using a typed constructor call to assign
// to a class that has a common base class, but is not directly related.
module test;
class B;
endclass
class C extends B;
endclass
class D extends B;
endclass
initial begin
D d;
d = C::new; // This should fail, C and D share a common base class, but are
// not compatible
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,17 @@
// Check that an error is reported when trying to use a typed constructor call
// with a type that is not a class.
module test;
class C;
endclass
typedef int T;
initial begin
C c;
c = T::new; // This should fail, T is not a class
$display("FAILED");
end
endmodule

View File

@ -561,6 +561,13 @@ sv_class_localparam normal,-g2009 ivltests
sv_class_new_fail1 CE,-g2009 ivltests
sv_class_new_fail2 CE,-g2009 ivltests
sv_class_new_init normal,-g2009 ivltests
sv_class_new_typed1 normal,-g2009 ivltests
sv_class_new_typed2 normal,-g2009 ivltests
sv_class_new_typed3 normal,-g2009 ivltests
sv_class_new_typed_fail1 CE,-g2009 ivltests
sv_class_new_typed_fail2 CE,-g2009 ivltests
sv_class_new_typed_fail3 CE,-g2009 ivltests
sv_class_new_typed_fail4 CE,-g2009 ivltests
sv_class_in_module_decl normal,-g2009 ivltests
sv_class_method_call_void normal,-g2009 ivltests
sv_class_method_default1 normal,-g2009 ivltests

View File

@ -416,6 +416,9 @@ sv_class_empty_item CE,-g2009 ivltests
sv_class_extends_scoped CE,-g2009 ivltests
sv_class_localparam CE,-g2009 ivltests
sv_class_new_init CE,-g2009 ivltests
sv_class_new_typed1 CE,-g2009 ivltests
sv_class_new_typed2 CE,-g2009 ivltests
sv_class_new_typed3 CE,-g2009 ivltests
sv_class_in_module_decl CE,-g2009 ivltests
sv_class_method_call_void CE,-g2009 ivltests
sv_class_method_default1 CE,-g2009 ivltests

14
parse.y
View File

@ -652,6 +652,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <data_type> packed_array_data_type
%type <data_type> ps_type_identifier
%type <data_type> simple_packed_type
%type <data_type> class_scope
%type <struct_member> struct_union_member
%type <struct_members> struct_union_member_list
%type <struct_type> struct_data_type
@ -978,6 +979,9 @@ class_item_qualifier_opt
| { $$ = property_qualifier_t::make_none(); }
;
class_scope
: ps_type_identifier K_SCOPE_RES { $$ = $1; }
class_new /* IEEE1800-2005 A.2.4 */
: K_new argument_list_parens_opt
{ std::list<PExpr*>*expr_list = $2;
@ -987,6 +991,16 @@ class_new /* IEEE1800-2005 A.2.4 */
delete $2;
$$ = tmp;
}
// This can't be a class_scope_opt because it will lead to shift/reduce
// conflicts with array_new
| class_scope K_new argument_list_parens_opt
{ std::list<PExpr*>*expr_list = $3;
strip_tail_items(expr_list);
PENewClass *new_expr = new PENewClass(*expr_list, $1);
FILE_NAME(new_expr, @2);
delete $3;
$$ = new_expr;
}
| K_new hierarchy_identifier
{ PEIdent*tmpi = new PEIdent(*$2);
FILE_NAME(tmpi, @2);