Commit d4157849 by Ian Lance Taylor

compiler: Better handling of erroneous function signatures.

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