Add support for typed constructor calls

By default when creating a new class object the type of the object is
determined by the type of the target.

SystemVerilog also allows to explicitly specify the type of the object to
be created. The specified class still needs to be assignment compatible
with the target. This is e.g. useful to construct an object of a derived
class of the target. E.g.

```
class B; ... endclass
class C extends B; ... endclass
B b;
b = C::new;
```

Add support for this to the parser as well as handling it during
elaboration.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-09-18 12:39:18 +02:00
parent 580d79eae3
commit df82410a37
4 changed files with 46 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);

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
@ -968,6 +969,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;
@ -977,6 +981,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);