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:
parent
292d174cad
commit
156644d91e
|
|
@ -2601,7 +2601,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||||
/* Add the implicit this reference when requested. */
|
/* Add the implicit this reference when requested. */
|
||||||
if (add_this_flag) {
|
if (add_this_flag) {
|
||||||
assert(use_path.empty());
|
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
|
// 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);
|
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||||
ivl_assert(*this, scope_method);
|
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) {
|
if (this_net == 0) {
|
||||||
cerr << get_fileline() << ": internal error: "
|
cerr << get_fileline() << ": internal error: "
|
||||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
<< "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"
|
// The return value of the initializer is the "this"
|
||||||
// variable, instead of the "new&" scope name.
|
// 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);
|
ivl_assert(*this, res1);
|
||||||
|
|
||||||
NetESignal*eres = new NetESignal(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"
|
// The return value for the constructor is actually the "this"
|
||||||
// variable, instead of the "new" scope name.
|
// 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);
|
ivl_assert(*this, res);
|
||||||
|
|
||||||
NetESignal*eres = new NetESignal(res);
|
NetESignal*eres = new NetESignal(res);
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||||
ivl_assert(*this, scope_method);
|
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) {
|
if (this_net == 0) {
|
||||||
cerr << get_fileline() << ": internal error: "
|
cerr << get_fileline() << ": internal error: "
|
||||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||||
|
|
|
||||||
|
|
@ -578,10 +578,10 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
// source code for the definition may be:
|
// source code for the definition may be:
|
||||||
// function new(...);
|
// function new(...);
|
||||||
// endfunction
|
// endfunction
|
||||||
// In this case, the "@" port is the synthetic "this"
|
// In this case, the "@" port (THIS_TOKEN) is the synthetic
|
||||||
// argument and we also use it as a return value at the
|
// "this" argument and we also use it as a return value at
|
||||||
// same time.
|
// the same time.
|
||||||
ret_sig = scope->find_signal(perm_string::literal("@"));
|
ret_sig = scope->find_signal(perm_string::literal(THIS_TOKEN));
|
||||||
ivl_assert(*this, ret_sig);
|
ivl_assert(*this, ret_sig);
|
||||||
|
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
|
|
|
||||||
23
elaborate.cc
23
elaborate.cc
|
|
@ -3002,6 +3002,25 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
|
||||||
assert(list_[idx]);
|
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);
|
NetProc*tmp = list_[idx]->elaborate(des, nscope);
|
||||||
// If the statement fails to elaborate, then simply
|
// If the statement fails to elaborate, then simply
|
||||||
// ignore it. Presumably, the elaborate for the
|
// 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
|
// Need the "this" variable for the current constructor. We're
|
||||||
// going to pass this to the chained constructor.
|
// 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
|
// If super.new is an implicit constructor, then there are no
|
||||||
// arguments (other than "this" to worry about, so make a
|
// 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. */
|
/* Add the implicit this reference when requested. */
|
||||||
if (add_this_flag) {
|
if (add_this_flag) {
|
||||||
assert(use_path.empty());
|
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.
|
// There is no signal to search for so this cannot be a method.
|
||||||
|
|
|
||||||
7
parse.y
7
parse.y
|
|
@ -68,7 +68,7 @@ static LexicalScope::lifetime_t var_lifetime;
|
||||||
|
|
||||||
static pform_name_t* pform_create_this(void)
|
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;
|
pform_name_t*res = new pform_name_t;
|
||||||
res->push_back(name);
|
res->push_back(name);
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -76,7 +76,7 @@ static pform_name_t* pform_create_this(void)
|
||||||
|
|
||||||
static pform_name_t* pform_create_super(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;
|
pform_name_t*res = new pform_name_t;
|
||||||
res->push_back(name);
|
res->push_back(name);
|
||||||
return res;
|
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 ')' ';'
|
| implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';'
|
||||||
{ PChainConstructor*tmp = new PChainConstructor(*$5);
|
{ PChainConstructor*tmp = new PChainConstructor(*$5);
|
||||||
FILE_NAME(tmp, @3);
|
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;
|
delete $1;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list<perm_string>*this_name = new list<perm_string>;
|
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,
|
vector<pform_tf_port_t>*this_port = pform_make_task_ports(loc,
|
||||||
NetNet::PINPUT,
|
NetNet::PINPUT,
|
||||||
pform_cur_class->type,
|
pform_cur_class->type,
|
||||||
|
|
|
||||||
|
|
@ -381,6 +381,14 @@ inline perm_string peek_tail_name(const pform_name_t&that)
|
||||||
return that.back().name;
|
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 pform_name_t&);
|
||||||
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
|
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
|
||||||
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);
|
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue