OSDN Git Service

Don't crash on invalid parameters/results.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Dec 2010 22:58:23 +0000 (22:58 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Dec 2010 22:58:23 +0000 (22:58 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167820 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h

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