Commit cad51bed by Ian Lance Taylor

Don't crash on invalid parameters/results.

From-SVN: r167820
parent 86137e81
...@@ -8662,8 +8662,7 @@ Call_result_expression::do_check_types(Gogo*) ...@@ -8662,8 +8662,7 @@ Call_result_expression::do_check_types(Gogo*)
ok = false; ok = false;
} }
if (!ok) if (!ok)
error_at(this->location(), this->report_error(_("number of results does not match number of values"));
"number of results does not match number of values");
} }
// Determine the type. We have nothing to do here, but the 0 result // Determine the type. We have nothing to do here, but the 0 result
......
...@@ -244,7 +244,10 @@ Parse::type() ...@@ -244,7 +244,10 @@ Parse::type()
{ {
source_location location = token->location(); source_location location = token->location();
this->advance_token(); this->advance_token();
return this->signature(NULL, location); Type* type = this->signature(NULL, location);
if (type == NULL)
return Type::make_error_type();
return type;
} }
else if (token->is_keyword(KEYWORD_MAP)) else if (token->is_keyword(KEYWORD_MAP))
return this->map_type(); return this->map_type();
...@@ -662,16 +665,25 @@ Parse::channel_type() ...@@ -662,16 +665,25 @@ Parse::channel_type()
// RECEIVER is the receiver if there is one, or NULL. LOCATION is the // RECEIVER is the receiver if there is one, or NULL. LOCATION is the
// location of the start of the type. // location of the start of the type.
// This returns NULL on a parse error.
Function_type* Function_type*
Parse::signature(Typed_identifier* receiver, source_location location) Parse::signature(Typed_identifier* receiver, source_location location)
{ {
bool is_varargs = false; bool is_varargs = false;
Typed_identifier_list* params = this->parameters(&is_varargs); Typed_identifier_list* params;
bool params_ok = this->parameters(&params, &is_varargs);
Typed_identifier_list* result = NULL; Typed_identifier_list* result = NULL;
if (this->peek_token()->is_op(OPERATOR_LPAREN) if (this->peek_token()->is_op(OPERATOR_LPAREN)
|| this->type_may_start_here()) || this->type_may_start_here())
result = this->result(); {
if (!this->result(&result))
return NULL;
}
if (!params_ok)
return NULL;
Function_type* ret = Type::make_function_type(receiver, params, result, Function_type* ret = Type::make_function_type(receiver, params, result,
location); location);
...@@ -682,21 +694,28 @@ Parse::signature(Typed_identifier* receiver, source_location location) ...@@ -682,21 +694,28 @@ Parse::signature(Typed_identifier* receiver, source_location location)
// Parameters = "(" [ ParameterList [ "," ] ] ")" . // Parameters = "(" [ ParameterList [ "," ] ] ")" .
Typed_identifier_list* // This returns false on a parse error.
Parse::parameters(bool* is_varargs)
bool
Parse::parameters(Typed_identifier_list** pparams, bool* is_varargs)
{ {
*pparams = NULL;
if (!this->peek_token()->is_op(OPERATOR_LPAREN)) if (!this->peek_token()->is_op(OPERATOR_LPAREN))
{ {
error_at(this->location(), "expected %<(%>"); error_at(this->location(), "expected %<(%>");
return NULL; return false;
} }
Typed_identifier_list* params = NULL; Typed_identifier_list* params = NULL;
bool saw_error = false;
const Token* token = this->advance_token(); const Token* token = this->advance_token();
if (!token->is_op(OPERATOR_RPAREN)) if (!token->is_op(OPERATOR_RPAREN))
{ {
params = this->parameter_list(is_varargs); params = this->parameter_list(is_varargs);
if (params == NULL)
saw_error = true;
token = this->peek_token(); token = this->peek_token();
} }
...@@ -707,7 +726,11 @@ Parse::parameters(bool* is_varargs) ...@@ -707,7 +726,11 @@ Parse::parameters(bool* is_varargs)
else else
this->advance_token(); this->advance_token();
return params; if (saw_error)
return false;
*pparams = params;
return true;
} }
// ParameterList = ParameterDecl { "," ParameterDecl } . // ParameterList = ParameterDecl { "," ParameterDecl } .
...@@ -717,12 +740,16 @@ Parse::parameters(bool* is_varargs) ...@@ -717,12 +740,16 @@ Parse::parameters(bool* is_varargs)
// We pick up an optional trailing comma. // We pick up an optional trailing comma.
// This returns NULL if some error is seen.
Typed_identifier_list* Typed_identifier_list*
Parse::parameter_list(bool* is_varargs) Parse::parameter_list(bool* is_varargs)
{ {
source_location location = this->location(); source_location location = this->location();
Typed_identifier_list* ret = new Typed_identifier_list(); Typed_identifier_list* ret = new Typed_identifier_list();
bool saw_error = false;
// If we see an identifier and then a comma, then we don't know // If we see an identifier and then a comma, then we don't know
// whether we are looking at a list of identifiers followed by a // whether we are looking at a list of identifiers followed by a
// type, or a list of types given by name. We have to do an // type, or a list of types given by name. We have to do an
...@@ -834,15 +861,16 @@ Parse::parameter_list(bool* is_varargs) ...@@ -834,15 +861,16 @@ Parse::parameter_list(bool* is_varargs)
else else
{ {
error_at(this->location(), "%<...%> only permits one name"); error_at(this->location(), "%<...%> only permits one name");
saw_error = true;
this->advance_token(); this->advance_token();
type = this->type(); type = this->type();
} }
for (size_t i = 0; i < ret->size(); ++i) for (size_t i = 0; i < ret->size(); ++i)
ret->set_type(i, type); ret->set_type(i, type);
if (!this->peek_token()->is_op(OPERATOR_COMMA)) if (!this->peek_token()->is_op(OPERATOR_COMMA))
return ret; return saw_error ? NULL : ret;
if (this->advance_token()->is_op(OPERATOR_RPAREN)) if (this->advance_token()->is_op(OPERATOR_RPAREN))
return ret; return saw_error ? NULL : ret;
} }
else else
{ {
...@@ -865,6 +893,7 @@ Parse::parameter_list(bool* is_varargs) ...@@ -865,6 +893,7 @@ Parse::parameter_list(bool* is_varargs)
{ {
error_at(p->location(), "expected %<%s%> to be a type", error_at(p->location(), "expected %<%s%> to be a type",
Gogo::message_name(p->name()).c_str()); Gogo::message_name(p->name()).c_str());
saw_error = true;
type = Type::make_error_type(); type = Type::make_error_type();
} }
tret->push_back(Typed_identifier("", type, p->location())); tret->push_back(Typed_identifier("", type, p->location()));
...@@ -873,7 +902,7 @@ Parse::parameter_list(bool* is_varargs) ...@@ -873,7 +902,7 @@ Parse::parameter_list(bool* is_varargs)
ret = tret; ret = tret;
if (!just_saw_comma if (!just_saw_comma
|| this->peek_token()->is_op(OPERATOR_RPAREN)) || this->peek_token()->is_op(OPERATOR_RPAREN))
return ret; return saw_error ? NULL : ret;
} }
} }
} }
...@@ -883,13 +912,24 @@ Parse::parameter_list(bool* is_varargs) ...@@ -883,13 +912,24 @@ Parse::parameter_list(bool* is_varargs)
while (this->peek_token()->is_op(OPERATOR_COMMA)) while (this->peek_token()->is_op(OPERATOR_COMMA))
{ {
if (is_varargs != NULL && *is_varargs) if (is_varargs != NULL && *is_varargs)
{
error_at(this->location(), "%<...%> must be last parameter"); error_at(this->location(), "%<...%> must be last parameter");
saw_error = true;
}
if (this->advance_token()->is_op(OPERATOR_RPAREN)) if (this->advance_token()->is_op(OPERATOR_RPAREN))
break; break;
this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error); this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error);
} }
if (mix_error) if (mix_error)
{
error_at(location, "invalid named/anonymous mix"); error_at(location, "invalid named/anonymous mix");
saw_error = true;
}
if (saw_error)
{
delete ret;
return NULL;
}
return ret; return ret;
} }
...@@ -973,18 +1013,26 @@ Parse::parameter_decl(bool parameters_have_names, ...@@ -973,18 +1013,26 @@ Parse::parameter_decl(bool parameters_have_names,
// Result = Parameters | Type . // Result = Parameters | Type .
Typed_identifier_list* // This returns false on a parse error.
Parse::result()
bool
Parse::result(Typed_identifier_list** presults)
{ {
if (this->peek_token()->is_op(OPERATOR_LPAREN)) if (this->peek_token()->is_op(OPERATOR_LPAREN))
return this->parameters(NULL); return this->parameters(presults, NULL);
else else
{ {
source_location location = this->location(); source_location location = this->location();
Typed_identifier_list* til = new Typed_identifier_list();
Type* type = this->type(); Type* type = this->type();
if (type->is_error_type())
{
*presults = NULL;
return false;
}
Typed_identifier_list* til = new Typed_identifier_list();
til->push_back(Typed_identifier("", type, location)); til->push_back(Typed_identifier("", type, location));
return til; *presults = til;
return true;
} }
} }
...@@ -1108,14 +1156,14 @@ Parse::interface_type() ...@@ -1108,14 +1156,14 @@ Parse::interface_type()
// MethodName = identifier . // MethodName = identifier .
// InterfaceTypeName = TypeName . // InterfaceTypeName = TypeName .
bool void
Parse::method_spec(Typed_identifier_list* methods) Parse::method_spec(Typed_identifier_list* methods)
{ {
const Token* token = this->peek_token(); const Token* token = this->peek_token();
if (!token->is_identifier()) if (!token->is_identifier())
{ {
error_at(this->location(), "expected identifier"); error_at(this->location(), "expected identifier");
return false; return;
} }
std::string name = token->identifier(); std::string name = token->identifier();
...@@ -1126,7 +1174,9 @@ Parse::method_spec(Typed_identifier_list* methods) ...@@ -1126,7 +1174,9 @@ Parse::method_spec(Typed_identifier_list* methods)
{ {
// This is a MethodName. // This is a MethodName.
name = this->gogo_->pack_hidden_name(name, is_exported); name = this->gogo_->pack_hidden_name(name, is_exported);
Function_type* type = this->signature(NULL, location); Type* type = this->signature(NULL, location);
if (type == NULL)
return;
methods->push_back(Typed_identifier(name, type, location)); methods->push_back(Typed_identifier(name, type, location));
} }
else else
...@@ -1148,15 +1198,13 @@ Parse::method_spec(Typed_identifier_list* methods) ...@@ -1148,15 +1198,13 @@ Parse::method_spec(Typed_identifier_list* methods)
&& !token->is_op(OPERATOR_SEMICOLON) && !token->is_op(OPERATOR_SEMICOLON)
&& !token->is_op(OPERATOR_RCURLY)) && !token->is_op(OPERATOR_RCURLY))
token = this->advance_token(); token = this->advance_token();
return false; return;
} }
// This must be an interface type, but we can't check that now. // This must be an interface type, but we can't check that now.
// We check it and pull out the methods in // We check it and pull out the methods in
// Interface_type::do_verify. // Interface_type::do_verify.
methods->push_back(Typed_identifier("", type, location)); methods->push_back(Typed_identifier("", type, location));
} }
return false;
} }
// Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl . // Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .
...@@ -1933,6 +1981,8 @@ Parse::function_decl() ...@@ -1933,6 +1981,8 @@ 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;
...@@ -2462,6 +2512,11 @@ Parse::function_lit() ...@@ -2462,6 +2512,11 @@ 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);
if (type == NULL)
{
this->block();
return Expression::make_error(location);
}
// 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.
......
...@@ -167,13 +167,13 @@ class Parse ...@@ -167,13 +167,13 @@ class Parse
Type* pointer_type(); Type* pointer_type();
Type* channel_type(); Type* channel_type();
Function_type* signature(Typed_identifier*, source_location); Function_type* signature(Typed_identifier*, source_location);
Typed_identifier_list* parameters(bool* is_varargs); bool parameters(Typed_identifier_list**, bool* is_varargs);
Typed_identifier_list* parameter_list(bool* is_varargs); Typed_identifier_list* parameter_list(bool* is_varargs);
void parameter_decl(bool, Typed_identifier_list*, bool*, bool*); void parameter_decl(bool, Typed_identifier_list*, bool*, bool*);
Typed_identifier_list* result(); bool result(Typed_identifier_list**);
source_location block(); source_location block();
Type* interface_type(); Type* interface_type();
bool method_spec(Typed_identifier_list*); void method_spec(Typed_identifier_list*);
void declaration(); void declaration();
bool declaration_may_start_here(); bool declaration_may_start_here();
void decl(void (Parse::*)(void*), void*); void decl(void (Parse::*)(void*), void*);
......
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