Detect and complain about some constructor chain errors

This.new is not allowed.

super.new beyond the first statement is not allowed.

And while I'm at it, clean up the use of "@" and "#" in
the code as tokens for this and super.
This commit is contained in:
Stephen Williams 2020-11-22 13:42:28 -08:00
parent 292d174cad
commit 156644d91e
7 changed files with 44 additions and 14 deletions

View File

@ -2601,7 +2601,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
/* Add the implicit this reference when requested. */
if (add_this_flag) {
assert(use_path.empty());
use_path.push_front(name_component_t(perm_string::literal("@")));
use_path.push_front(name_component_t(perm_string::literal(THIS_TOKEN)));
}
// If there is no object to the left of the method name, then
@ -3906,7 +3906,7 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
NetScope*scope_method = find_method_containing_scope(*this, scope);
ivl_assert(*this, scope_method);
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
NetNet*this_net = scope_method->find_signal(perm_string::literal(THIS_TOKEN));
if (this_net == 0) {
cerr << get_fileline() << ": internal error: "
<< "Unable to find 'this' port of " << scope_path(scope_method)
@ -5766,7 +5766,7 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
// The return value of the initializer is the "this"
// variable, instead of the "new&" scope name.
NetNet*res1 = new1_scope->find_signal(perm_string::literal("@"));
NetNet*res1 = new1_scope->find_signal(perm_string::literal(THIS_TOKEN));
ivl_assert(*this, res1);
NetESignal*eres = new NetESignal(res1);
@ -5853,7 +5853,7 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
// The return value for the constructor is actually the "this"
// variable, instead of the "new" scope name.
NetNet*res = new_scope->find_signal(perm_string::literal("@"));
NetNet*res = new_scope->find_signal(perm_string::literal(THIS_TOKEN));
ivl_assert(*this, res);
NetESignal*eres = new NetESignal(res);

View File

@ -378,7 +378,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
NetScope*scope_method = find_method_containing_scope(*this, scope);
ivl_assert(*this, scope_method);
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
NetNet*this_net = scope_method->find_signal(perm_string::literal(THIS_TOKEN));
if (this_net == 0) {
cerr << get_fileline() << ": internal error: "
<< "Unable to find 'this' port of " << scope_path(scope_method)

View File

@ -578,10 +578,10 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
// source code for the definition may be:
// function new(...);
// endfunction
// In this case, the "@" port is the synthetic "this"
// argument and we also use it as a return value at the
// same time.
ret_sig = scope->find_signal(perm_string::literal("@"));
// In this case, the "@" port (THIS_TOKEN) is the synthetic
// "this" argument and we also use it as a return value at
// the same time.
ret_sig = scope->find_signal(perm_string::literal(THIS_TOKEN));
ivl_assert(*this, ret_sig);
if (debug_elaborate)

View File

@ -3002,6 +3002,25 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
assert(list_[idx]);
// Detect the error that a super.new() statement is in the
// midst of a block. Report the error. Continue on with the
// elaboration so that other errors might be found.
if (PChainConstructor*supernew = dynamic_cast<PChainConstructor*> (list_[idx])) {
if (debug_elaborate) {
cerr << get_fileline() << ": PBlock::elaborate: "
<< "Found super.new statement, idx=" << idx << ", "
<< " at " << supernew->get_fileline() << "."
<< endl;
}
if (idx > 0) {
des->errors += 1;
cerr << supernew->get_fileline() << ": error: "
<< "super.new(...) must be the first statement in a block."
<< endl;
}
}
NetProc*tmp = list_[idx]->elaborate(des, nscope);
// If the statement fails to elaborate, then simply
// ignore it. Presumably, the elaborate for the
@ -3266,7 +3285,7 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const
// Need the "this" variable for the current constructor. We're
// going to pass this to the chained constructor.
NetNet*var_this = scope->find_signal(perm_string::literal("@"));
NetNet*var_this = scope->find_signal(perm_string::literal(THIS_TOKEN));
// If super.new is an implicit constructor, then there are no
// arguments (other than "this" to worry about, so make a
@ -3728,7 +3747,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
/* Add the implicit this reference when requested. */
if (add_this_flag) {
assert(use_path.empty());
use_path.push_front(name_component_t(perm_string::literal("@")));
use_path.push_front(name_component_t(perm_string::literal(THIS_TOKEN)));
}
// There is no signal to search for so this cannot be a method.

View File

@ -68,7 +68,7 @@ static LexicalScope::lifetime_t var_lifetime;
static pform_name_t* pform_create_this(void)
{
name_component_t name (perm_string::literal("@"));
name_component_t name (perm_string::literal(THIS_TOKEN));
pform_name_t*res = new pform_name_t;
res->push_back(name);
return res;
@ -76,7 +76,7 @@ static pform_name_t* pform_create_this(void)
static pform_name_t* pform_create_super(void)
{
name_component_t name (perm_string::literal("#"));
name_component_t name (perm_string::literal(SUPER_TOKEN));
pform_name_t*res = new pform_name_t;
res->push_back(name);
return res;
@ -6897,6 +6897,9 @@ statement_item /* This is roughly statement_item in the LRM */
| implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';'
{ PChainConstructor*tmp = new PChainConstructor(*$5);
FILE_NAME(tmp, @3);
if (peek_head_name(*$1) == THIS_TOKEN) {
yyerror(@1, "error: this.new is invalid syntax. Did you mean super.new?");
}
delete $1;
$$ = tmp;
}

View File

@ -109,7 +109,7 @@ void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net)
return;
list<perm_string>*this_name = new list<perm_string>;
this_name->push_back(perm_string::literal("@"));
this_name->push_back(perm_string::literal(THIS_TOKEN));
vector<pform_tf_port_t>*this_port = pform_make_task_ports(loc,
NetNet::PINPUT,
pform_cur_class->type,

View File

@ -381,6 +381,14 @@ inline perm_string peek_tail_name(const pform_name_t&that)
return that.back().name;
}
/*
* In pform names, the "super" and "this" keywords are converted to
* These tokens so that they don't interfere with the namespace and
* are handled specially.
*/
# define SUPER_TOKEN "#"
# define THIS_TOKEN "@"
extern std::ostream& operator<< (std::ostream&out, const pform_name_t&);
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);