compiler: Better handling of erroneous function signatures.
From-SVN: r183479
This commit is contained in:
parent
00a42fb364
commit
d4157849c9
7 changed files with 140 additions and 26 deletions
|
@ -1455,8 +1455,9 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
|||
{
|
||||
if (this->is_composite_literal_key_)
|
||||
return this;
|
||||
error_at(location, "reference to undefined name %qs",
|
||||
this->named_object_->message_name().c_str());
|
||||
if (!this->no_error_message_)
|
||||
error_at(location, "reference to undefined name %qs",
|
||||
this->named_object_->message_name().c_str());
|
||||
return Expression::make_error(location);
|
||||
}
|
||||
}
|
||||
|
@ -1469,8 +1470,9 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
|||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||
if (this->is_composite_literal_key_)
|
||||
return this;
|
||||
error_at(location, "reference to undefined type %qs",
|
||||
real->message_name().c_str());
|
||||
if (!this->no_error_message_)
|
||||
error_at(location, "reference to undefined type %qs",
|
||||
real->message_name().c_str());
|
||||
return Expression::make_error(location);
|
||||
case Named_object::NAMED_OBJECT_VAR:
|
||||
real->var_value()->set_is_used();
|
||||
|
@ -1481,7 +1483,8 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
|||
case Named_object::NAMED_OBJECT_PACKAGE:
|
||||
if (this->is_composite_literal_key_)
|
||||
return this;
|
||||
error_at(location, "unexpected reference to package");
|
||||
if (!this->no_error_message_)
|
||||
error_at(location, "unexpected reference to package");
|
||||
return Expression::make_error(location);
|
||||
default:
|
||||
go_unreachable();
|
||||
|
@ -1499,7 +1502,7 @@ Unknown_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
|
|||
|
||||
// Make a reference to an unknown name.
|
||||
|
||||
Expression*
|
||||
Unknown_expression*
|
||||
Expression::make_unknown_reference(Named_object* no, Location location)
|
||||
{
|
||||
return new Unknown_expression(no, location);
|
||||
|
@ -8483,6 +8486,11 @@ Builtin_call_expression::do_check_types(Gogo*)
|
|||
|| type->function_type() != NULL
|
||||
|| type->is_slice_type())
|
||||
;
|
||||
else if ((*p)->is_type_expression())
|
||||
{
|
||||
// If this is a type expression it's going to give
|
||||
// an error anyhow, so we don't need one here.
|
||||
}
|
||||
else
|
||||
this->report_error(_("unsupported argument type to "
|
||||
"builtin function"));
|
||||
|
|
|
@ -153,7 +153,7 @@ class Expression
|
|||
|
||||
// Make a reference to an unknown name. In a correct program this
|
||||
// will always be lowered to a real const/var/func reference.
|
||||
static Expression*
|
||||
static Unknown_expression*
|
||||
make_unknown_reference(Named_object*, Location);
|
||||
|
||||
// Make a constant bool expression.
|
||||
|
@ -1554,7 +1554,8 @@ class Unknown_expression : public Parser_expression
|
|||
public:
|
||||
Unknown_expression(Named_object* named_object, Location location)
|
||||
: Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location),
|
||||
named_object_(named_object), is_composite_literal_key_(false)
|
||||
named_object_(named_object), no_error_message_(false),
|
||||
is_composite_literal_key_(false)
|
||||
{ }
|
||||
|
||||
// The associated named object.
|
||||
|
@ -1566,6 +1567,13 @@ class Unknown_expression : public Parser_expression
|
|||
const std::string&
|
||||
name() const;
|
||||
|
||||
// Call this to indicate that we should not give an error if this
|
||||
// name is never defined. This is used to avoid knock-on errors
|
||||
// during an erroneous parse.
|
||||
void
|
||||
set_no_error_message()
|
||||
{ this->no_error_message_ = true; }
|
||||
|
||||
// Note that this expression is being used as the key in a composite
|
||||
// literal, so it may be OK if it is not resolved.
|
||||
void
|
||||
|
@ -1592,6 +1600,9 @@ class Unknown_expression : public Parser_expression
|
|||
private:
|
||||
// The unknown name.
|
||||
Named_object* named_object_;
|
||||
// True if we should not give errors if this is undefined. This is
|
||||
// used if there was a parse failure.
|
||||
bool no_error_message_;
|
||||
// True if this is the key in a composite literal.
|
||||
bool is_composite_literal_key_;
|
||||
};
|
||||
|
|
|
@ -1108,6 +1108,10 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
|||
}
|
||||
break;
|
||||
|
||||
case NAMED_OBJECT_ERRONEOUS:
|
||||
decl = error_mark_node;
|
||||
break;
|
||||
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
|
|
|
@ -626,8 +626,8 @@ Gogo::start_function(const std::string& name, Function_type* type,
|
|||
const Typed_identifier* receiver = type->receiver();
|
||||
Variable* this_param = new Variable(receiver->type(), NULL, false,
|
||||
true, true, location);
|
||||
std::string name = receiver->name();
|
||||
if (name.empty())
|
||||
std::string rname = receiver->name();
|
||||
if (rname.empty())
|
||||
{
|
||||
// We need to give receivers a name since they wind up in
|
||||
// DECL_ARGUMENTS. FIXME.
|
||||
|
@ -635,10 +635,10 @@ Gogo::start_function(const std::string& name, Function_type* type,
|
|||
char buf[50];
|
||||
snprintf(buf, sizeof buf, "r.%u", count);
|
||||
++count;
|
||||
name = buf;
|
||||
rname = buf;
|
||||
}
|
||||
if (!Gogo::is_sink_name(name))
|
||||
block->bindings()->add_variable(name, NULL, this_param);
|
||||
if (!Gogo::is_sink_name(rname))
|
||||
block->bindings()->add_variable(rname, NULL, this_param);
|
||||
}
|
||||
|
||||
const Typed_identifier_list* parameters = type->parameters();
|
||||
|
@ -654,8 +654,8 @@ Gogo::start_function(const std::string& name, Function_type* type,
|
|||
if (is_varargs && p + 1 == parameters->end())
|
||||
param->set_is_varargs_parameter();
|
||||
|
||||
std::string name = p->name();
|
||||
if (name.empty() || Gogo::is_sink_name(name))
|
||||
std::string pname = p->name();
|
||||
if (pname.empty() || Gogo::is_sink_name(pname))
|
||||
{
|
||||
// We need to give parameters a name since they wind up
|
||||
// in DECL_ARGUMENTS. FIXME.
|
||||
|
@ -663,9 +663,9 @@ Gogo::start_function(const std::string& name, Function_type* type,
|
|||
char buf[50];
|
||||
snprintf(buf, sizeof buf, "p.%u", count);
|
||||
++count;
|
||||
name = buf;
|
||||
pname = buf;
|
||||
}
|
||||
block->bindings()->add_variable(name, NULL, param);
|
||||
block->bindings()->add_variable(pname, NULL, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -834,6 +834,14 @@ Gogo::finish_block(Location location)
|
|||
return block;
|
||||
}
|
||||
|
||||
// Add an erroneous name.
|
||||
|
||||
Named_object*
|
||||
Gogo::add_erroneous_name(const std::string& name)
|
||||
{
|
||||
return this->package_->bindings()->add_erroneous_name(name);
|
||||
}
|
||||
|
||||
// Add an unknown name.
|
||||
|
||||
Named_object*
|
||||
|
@ -3522,6 +3530,7 @@ Block::traverse(Traverse* traverse)
|
|||
|
||||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||
case Named_object::NAMED_OBJECT_UNKNOWN:
|
||||
case Named_object::NAMED_OBJECT_ERRONEOUS:
|
||||
break;
|
||||
|
||||
case Named_object::NAMED_OBJECT_PACKAGE:
|
||||
|
@ -4521,6 +4530,9 @@ Named_object::location() const
|
|||
case NAMED_OBJECT_UNINITIALIZED:
|
||||
go_unreachable();
|
||||
|
||||
case NAMED_OBJECT_ERRONEOUS:
|
||||
return Linemap::unknown_location();
|
||||
|
||||
case NAMED_OBJECT_UNKNOWN:
|
||||
return this->unknown_value()->location();
|
||||
|
||||
|
@ -4565,6 +4577,9 @@ Named_object::export_named_object(Export* exp) const
|
|||
case NAMED_OBJECT_UNKNOWN:
|
||||
go_unreachable();
|
||||
|
||||
case NAMED_OBJECT_ERRONEOUS:
|
||||
break;
|
||||
|
||||
case NAMED_OBJECT_CONST:
|
||||
this->const_value()->export_const(exp, this->name_);
|
||||
break;
|
||||
|
@ -4751,6 +4766,9 @@ Bindings::add_named_object_to_contour(Contour* contour,
|
|||
Named_object*
|
||||
Bindings::new_definition(Named_object* old_object, Named_object* new_object)
|
||||
{
|
||||
if (new_object->is_erroneous() && !old_object->is_erroneous())
|
||||
return new_object;
|
||||
|
||||
std::string reason;
|
||||
switch (old_object->classification())
|
||||
{
|
||||
|
@ -4758,6 +4776,9 @@ Bindings::new_definition(Named_object* old_object, Named_object* new_object)
|
|||
case Named_object::NAMED_OBJECT_UNINITIALIZED:
|
||||
go_unreachable();
|
||||
|
||||
case Named_object::NAMED_OBJECT_ERRONEOUS:
|
||||
return old_object;
|
||||
|
||||
case Named_object::NAMED_OBJECT_UNKNOWN:
|
||||
{
|
||||
Named_object* real = old_object->unknown_value()->real_named_object();
|
||||
|
@ -5003,6 +5024,7 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
|||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||
case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
|
||||
case Named_object::NAMED_OBJECT_UNKNOWN:
|
||||
case Named_object::NAMED_OBJECT_ERRONEOUS:
|
||||
break;
|
||||
|
||||
case Named_object::NAMED_OBJECT_SINK:
|
||||
|
|
|
@ -267,6 +267,11 @@ class Gogo
|
|||
Block*
|
||||
finish_block(Location);
|
||||
|
||||
// Declare an erroneous name. This is used to avoid knock-on errors
|
||||
// after a parsing error.
|
||||
Named_object*
|
||||
add_erroneous_name(const std::string& name);
|
||||
|
||||
// Declare an unknown name. This is used while parsing. The name
|
||||
// must be resolved by the end of the parse. Unknown names are
|
||||
// always added at the package level.
|
||||
|
@ -1688,6 +1693,9 @@ class Named_object
|
|||
{
|
||||
// An uninitialized Named_object. We should never see this.
|
||||
NAMED_OBJECT_UNINITIALIZED,
|
||||
// An erroneous name. This indicates a parse error, to avoid
|
||||
// later errors about undefined references.
|
||||
NAMED_OBJECT_ERRONEOUS,
|
||||
// An unknown name. This is used for forward references. In a
|
||||
// correct program, these will all be resolved by the end of the
|
||||
// parse.
|
||||
|
@ -1719,6 +1727,10 @@ class Named_object
|
|||
|
||||
// Classifiers.
|
||||
|
||||
bool
|
||||
is_erroneous() const
|
||||
{ return this->classification_ == NAMED_OBJECT_ERRONEOUS; }
|
||||
|
||||
bool
|
||||
is_unknown() const
|
||||
{ return this->classification_ == NAMED_OBJECT_UNKNOWN; }
|
||||
|
@ -1761,6 +1773,10 @@ class Named_object
|
|||
|
||||
// Creators.
|
||||
|
||||
static Named_object*
|
||||
make_erroneous_name(const std::string& name)
|
||||
{ return new Named_object(name, NULL, NAMED_OBJECT_ERRONEOUS); }
|
||||
|
||||
static Named_object*
|
||||
make_unknown_name(const std::string& name, Location);
|
||||
|
||||
|
@ -2032,6 +2048,11 @@ class Bindings
|
|||
|
||||
Bindings(Bindings* enclosing);
|
||||
|
||||
// Add an erroneous name.
|
||||
Named_object*
|
||||
add_erroneous_name(const std::string& name)
|
||||
{ return this->add_named_object(Named_object::make_erroneous_name(name)); }
|
||||
|
||||
// Add an unknown name.
|
||||
Named_object*
|
||||
add_unknown_name(const std::string& name, Location location)
|
||||
|
|
|
@ -45,6 +45,7 @@ Parse::Parse(Lex* lex, Gogo* gogo)
|
|||
token_(Token::make_invalid_token(Linemap::unknown_location())),
|
||||
unget_token_(Token::make_invalid_token(Linemap::unknown_location())),
|
||||
unget_token_valid_(false),
|
||||
is_erroneous_function_(false),
|
||||
gogo_(gogo),
|
||||
break_stack_(NULL),
|
||||
continue_stack_(NULL),
|
||||
|
@ -2123,8 +2124,6 @@ Parse::function_decl()
|
|||
this->advance_token();
|
||||
|
||||
Function_type* fntype = this->signature(rec, this->location());
|
||||
if (fntype == NULL)
|
||||
return;
|
||||
|
||||
Named_object* named_object = NULL;
|
||||
|
||||
|
@ -2171,13 +2170,28 @@ Parse::function_decl()
|
|||
if (!this->peek_token()->is_op(OPERATOR_LCURLY))
|
||||
{
|
||||
if (named_object == NULL && !Gogo::is_sink_name(name))
|
||||
this->gogo_->declare_function(name, fntype, location);
|
||||
{
|
||||
if (fntype != NULL)
|
||||
this->gogo_->declare_function(name, fntype, location);
|
||||
else
|
||||
this->gogo_->add_erroneous_name(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hold_is_erroneous_function = this->is_erroneous_function_;
|
||||
if (fntype == NULL)
|
||||
{
|
||||
fntype = Type::make_function_type(NULL, NULL, NULL, location);
|
||||
this->is_erroneous_function_ = true;
|
||||
if (!Gogo::is_sink_name(name))
|
||||
this->gogo_->add_erroneous_name(name);
|
||||
name = this->gogo_->pack_hidden_name("_", false);
|
||||
}
|
||||
this->gogo_->start_function(name, fntype, true, location);
|
||||
Location end_loc = this->block();
|
||||
this->gogo_->finish_function(end_loc);
|
||||
this->is_erroneous_function_ = hold_is_erroneous_function;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2392,7 +2406,15 @@ Parse::operand(bool may_be_sink)
|
|||
return Expression::make_func_reference(named_object, NULL,
|
||||
location);
|
||||
case Named_object::NAMED_OBJECT_UNKNOWN:
|
||||
return Expression::make_unknown_reference(named_object, location);
|
||||
{
|
||||
Unknown_expression* ue =
|
||||
Expression::make_unknown_reference(named_object, location);
|
||||
if (this->is_erroneous_function_)
|
||||
ue->set_no_error_message();
|
||||
return ue;
|
||||
}
|
||||
case Named_object::NAMED_OBJECT_ERRONEOUS:
|
||||
return Expression::make_error(location);
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
|
@ -2698,14 +2720,22 @@ Parse::function_lit()
|
|||
hold_enclosing_vars.swap(this->enclosing_vars_);
|
||||
|
||||
Function_type* type = this->signature(NULL, location);
|
||||
bool fntype_is_error = false;
|
||||
if (type == NULL)
|
||||
type = Type::make_function_type(NULL, NULL, NULL, location);
|
||||
{
|
||||
type = Type::make_function_type(NULL, NULL, NULL, location);
|
||||
fntype_is_error = true;
|
||||
}
|
||||
|
||||
// For a function literal, the next token must be a '{'. If we
|
||||
// don't see that, then we may have a type expression.
|
||||
if (!this->peek_token()->is_op(OPERATOR_LCURLY))
|
||||
return Expression::make_type(type, location);
|
||||
|
||||
bool hold_is_erroneous_function = this->is_erroneous_function_;
|
||||
if (fntype_is_error)
|
||||
this->is_erroneous_function_ = true;
|
||||
|
||||
Bc_stack* hold_break_stack = this->break_stack_;
|
||||
Bc_stack* hold_continue_stack = this->continue_stack_;
|
||||
this->break_stack_ = NULL;
|
||||
|
@ -2724,6 +2754,8 @@ Parse::function_lit()
|
|||
this->break_stack_ = hold_break_stack;
|
||||
this->continue_stack_ = hold_continue_stack;
|
||||
|
||||
this->is_erroneous_function_ = hold_is_erroneous_function;
|
||||
|
||||
hold_enclosing_vars.swap(this->enclosing_vars_);
|
||||
|
||||
Expression* closure = this->create_closure(no, &hold_enclosing_vars,
|
||||
|
@ -3043,13 +3075,27 @@ Parse::id_to_expression(const std::string& name, Location location)
|
|||
case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
|
||||
return Expression::make_func_reference(named_object, NULL, location);
|
||||
case Named_object::NAMED_OBJECT_UNKNOWN:
|
||||
return Expression::make_unknown_reference(named_object, location);
|
||||
{
|
||||
Unknown_expression* ue =
|
||||
Expression::make_unknown_reference(named_object, location);
|
||||
if (this->is_erroneous_function_)
|
||||
ue->set_no_error_message();
|
||||
return ue;
|
||||
}
|
||||
case Named_object::NAMED_OBJECT_PACKAGE:
|
||||
case Named_object::NAMED_OBJECT_TYPE:
|
||||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||
// These cases can arise for a field name in a composite
|
||||
// literal.
|
||||
return Expression::make_unknown_reference(named_object, location);
|
||||
{
|
||||
// These cases can arise for a field name in a composite
|
||||
// literal.
|
||||
Unknown_expression* ue =
|
||||
Expression::make_unknown_reference(named_object, location);
|
||||
if (this->is_erroneous_function_)
|
||||
ue->set_no_error_message();
|
||||
return ue;
|
||||
}
|
||||
case Named_object::NAMED_OBJECT_ERRONEOUS:
|
||||
return Expression::make_error(location);
|
||||
default:
|
||||
error_at(this->location(), "unexpected type of identifier");
|
||||
return Expression::make_error(location);
|
||||
|
|
|
@ -305,6 +305,8 @@ class Parse
|
|||
Token unget_token_;
|
||||
// Whether unget_token_ is valid.
|
||||
bool unget_token_valid_;
|
||||
// Whether the function we are parsing had errors in the signature.
|
||||
bool is_erroneous_function_;
|
||||
// The code we are generating.
|
||||
Gogo* gogo_;
|
||||
// A stack of statements for which break may be used.
|
||||
|
|
Loading…
Add table
Reference in a new issue