This patch by Chris Manghane ignores erroneous trees in the flatten
pass.  This avoids various compiler crashes on invalid input, and
fixes https://golang.org/issue/11536 , https://golang.org/issue/11558
, and https://golang.org/issue/11559 .  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 226825)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-5fc38e74d132cd6f4e7b56e6bcf9fe57031ab203
+fc9da313b4f5c13b4ac3bdddd98e699fd1c89613
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 226596)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -3101,6 +3101,12 @@ Expression*
 Type_conversion_expression::do_flatten(Gogo*, Named_object*,
                                        Statement_inserter* inserter)
 {
+  if (this->type()->is_error_type() || this->expr_->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(this->location());
+    }
+
   if (((this->type()->is_string_type()
         && this->expr_->type()->is_slice_type())
        || this->expr_->type()->interface_type() != NULL)
@@ -3585,8 +3591,13 @@ Expression*
 Unary_expression::do_flatten(Gogo* gogo, Named_object*,
                              Statement_inserter* inserter)
 {
-  if (this->is_error_expression() || this->expr_->is_error_expression())
-    return Expression::make_error(this->location());
+  if (this->is_error_expression()
+      || this->expr_->is_error_expression()
+      || this->expr_->type()->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(this->location());
+    }
 
   Location location = this->location();
   if (this->op_ == OPERATOR_MULT
@@ -5062,10 +5073,16 @@ Expression*
 Binary_expression::do_flatten(Gogo* gogo, Named_object*,
                               Statement_inserter* inserter)
 {
-  if (this->classification() == EXPRESSION_ERROR)
-    return this;
-
   Location loc = this->location();
+  if (this->left_->type()->is_error_type()
+      || this->right_->type()->is_error_type()
+      || this->left_->is_error_expression()
+      || this->right_->is_error_expression())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(loc);
+    }
+
   Temporary_statement* temp;
   if (this->left_->type()->is_string_type()
       && this->op_ == OPERATOR_PLUS)
@@ -6806,6 +6823,11 @@ Builtin_call_expression::do_flatten(Gogo
                                     Statement_inserter* inserter)
 {
   Location loc = this->location();
+  if (this->is_erroneous_call())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(loc);
+    }
 
   switch (this->code_)
     {
@@ -8733,8 +8755,11 @@ Expression*
 Call_expression::do_flatten(Gogo* gogo, Named_object*,
                            Statement_inserter* inserter)
 {
-  if (this->classification() == EXPRESSION_ERROR)
-    return this;
+  if (this->is_erroneous_call())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(this->location());
+    }
 
   if (this->is_flattened_)
     return this;
@@ -8902,6 +8927,27 @@ Call_expression::issue_error()
     }
 }
 
+// Whether or not this call contains errors, either in the call or the
+// arguments to the call.
+
+bool
+Call_expression::is_erroneous_call()
+{
+  if (this->is_error_expression() || this->fn()->is_error_expression())
+    return true;
+
+  if (this->args() == NULL)
+    return false;
+  for (Expression_list::iterator pa = this->args()->begin();
+       pa != this->args()->end();
+       ++pa)
+    {
+      if ((*pa)->type()->is_error_type() || (*pa)->is_error_expression())
+        return true;
+    }
+  return false;
+}
+
 // Get the type.
 
 Type*
@@ -9848,30 +9894,47 @@ Array_index_expression::do_flatten(Gogo*
                                    Statement_inserter* inserter)
 {
   Location loc = this->location();
+  Expression* array = this->array_;
+  Expression* start = this->start_;
+  Expression* end = this->end_;
+  Expression* cap = this->cap_;
+  if (array->is_error_expression()
+      || array->type()->is_error_type()
+      || start->is_error_expression()
+      || start->type()->is_error_type()
+      || (end != NULL
+          && (end->is_error_expression() || end->type()->is_error_type()))
+      || (cap != NULL
+          && (cap->is_error_expression() || cap->type()->is_error_type())))
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(loc);
+    }
+
   Temporary_statement* temp;
-  if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
+  if (array->type()->is_slice_type() && !array->is_variable())
     {
-      temp = Statement::make_temporary(NULL, this->array_, loc);
+      temp = Statement::make_temporary(NULL, array, loc);
       inserter->insert(temp);
       this->array_ = Expression::make_temporary_reference(temp, loc);
     }
-  if (!this->start_->is_variable())
+  if (!start->is_variable())
     {
-      temp = Statement::make_temporary(NULL, this->start_, loc);
+      temp = Statement::make_temporary(NULL, start, loc);
       inserter->insert(temp);
       this->start_ = Expression::make_temporary_reference(temp, loc);
     }
-  if (this->end_ != NULL
-      && !this->end_->is_nil_expression()
-      && !this->end_->is_variable())
+  if (end != NULL
+      && !end->is_nil_expression()
+      && !end->is_variable())
     {
-      temp = Statement::make_temporary(NULL, this->end_, loc);
+      temp = Statement::make_temporary(NULL, end, loc);
       inserter->insert(temp);
       this->end_ = Expression::make_temporary_reference(temp, loc);
     }
-  if (this->cap_ != NULL && !this->cap_->is_variable())
+  if (cap!= NULL && !cap->is_variable())
     {
-      temp = Statement::make_temporary(NULL, this->cap_, loc);
+      temp = Statement::make_temporary(NULL, cap, loc);
       inserter->insert(temp);
       this->cap_ = Expression::make_temporary_reference(temp, loc);
     }
@@ -10179,8 +10242,22 @@ Expression*
 String_index_expression::do_flatten(Gogo*, Named_object*,
                                     Statement_inserter* inserter)
 {
-  Temporary_statement* temp;
   Location loc = this->location();
+  Expression* string = this->string_;
+  Expression* start = this->start_;
+  Expression* end = this->end_;
+  if (string->is_error_expression()
+      || string->type()->is_error_type()
+      || start->is_error_expression()
+      || start->type()->is_error_type()
+      || (end != NULL
+          && (end->is_error_expression() || end->type()->is_error_type())))
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(loc);
+    }
+
+  Temporary_statement* temp;
   if (!this->string_->is_variable())
     {
       temp = Statement::make_temporary(NULL, this->string_, loc);
@@ -10419,6 +10496,14 @@ Map_index_expression::do_flatten(Gogo* g
 {
   Location loc = this->location();
   Map_type* mt = this->get_map_type();
+  if (this->index()->is_error_expression()
+      || this->index()->type()->is_error_type()
+      || mt->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(loc);
+    }
+
   if (!Type::are_identical(mt->key_type(), this->index_->type(), false, NULL))
     {
       if (this->index_->type()->interface_type() != NULL
@@ -10443,6 +10528,9 @@ Map_index_expression::do_flatten(Gogo* g
 
   if (this->value_pointer_ == NULL)
     this->get_value_pointer(this->is_lvalue_);
+  if (this->value_pointer_->is_error_expression()
+      || this->value_pointer_->type()->is_error_type())
+    return Expression::make_error(loc);
   if (!this->value_pointer_->is_variable())
     {
       Temporary_statement* temp =
@@ -10819,6 +10907,13 @@ Expression*
 Interface_field_reference_expression::do_flatten(Gogo*, Named_object*,
                                                 Statement_inserter* inserter)
 {
+  if (this->expr_->is_error_expression()
+      || this->expr_->type()->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(this->location());
+    }
+
   if (!this->expr_->is_variable())
     {
       Temporary_statement* temp =
@@ -11598,6 +11693,11 @@ Struct_construction_expression::do_flatt
     {
       if (*pv != NULL)
        {
+          if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
+            {
+              go_assert(saw_errors());
+              return Expression::make_error(loc);
+            }
          if (!(*pv)->is_variable())
            {
              Temporary_statement* temp =
@@ -11809,6 +11909,11 @@ Array_construction_expression::do_flatte
     {
       if (*pv != NULL)
        {
+          if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
+            {
+              go_assert(saw_errors());
+              return Expression::make_error(loc);
+            }
          if (!(*pv)->is_variable())
            {
              Temporary_statement* temp =
@@ -12124,6 +12229,11 @@ Map_construction_expression::do_flatten(
         {
           Expression_list* key_value_pair = new Expression_list();
           Expression* key = *pv;
+          if (key->is_error_expression() || key->type()->is_error_type())
+            {
+              go_assert(saw_errors());
+              return Expression::make_error(loc);
+            }
          if (key->type()->interface_type() != NULL && !key->is_variable())
            {
              Temporary_statement* temp =
@@ -12135,6 +12245,11 @@ Map_construction_expression::do_flatten(
 
           ++pv;
           Expression* val = *pv;
+          if (val->is_error_expression() || val->type()->is_error_type())
+            {
+              go_assert(saw_errors());
+              return Expression::make_error(loc);
+            }
          if (val->type()->interface_type() != NULL && !val->is_variable())
            {
              Temporary_statement* temp =
@@ -13103,6 +13218,13 @@ Expression*
 Type_guard_expression::do_flatten(Gogo*, Named_object*,
                                   Statement_inserter* inserter)
 {
+  if (this->expr_->is_error_expression()
+      || this->expr_->type()->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Expression::make_error(this->location());
+    }
+
   if (!this->expr_->is_variable())
     {
       Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
@@ -13297,6 +13419,11 @@ Receive_expression::do_flatten(Gogo*, Na
       go_assert(saw_errors());
       return this;
     }
+  else if (this->channel_->is_error_expression())
+   {
+     go_assert(saw_errors());
+     return Expression::make_error(this->location());
+   }
 
   Type* element_type = channel_type->element_type();
   if (this->temp_receiver_ == NULL)
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h     (revision 226510)
+++ gcc/go/gofrontend/expressions.h     (working copy)
@@ -1958,6 +1958,11 @@ class Call_expression : public Expressio
   bool
   issue_error();
 
+  // Whether or not this call contains errors, either in the call or the
+  // arguments to the call.
+  bool
+  is_erroneous_call();
+
   // Whether this call returns multiple results that are used as an
   // multi-valued argument.
   bool
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc     (revision 226788)
+++ gcc/go/gofrontend/statements.cc     (working copy)
@@ -253,6 +253,14 @@ Statement*
 Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
                                            Block*, Statement_inserter* 
inserter)
 {
+  Variable* var = this->var_->var_value();
+  if (var->type()->is_error_type()
+      || (var->init() != NULL
+          && var->init()->is_error_expression()))
+    {
+      go_assert(saw_errors());
+      return Statement::make_error_statement(this->location());
+    }
   this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
   return this;
 }
@@ -437,6 +445,14 @@ Statement*
 Temporary_statement::do_flatten(Gogo*, Named_object*, Block*,
                                Statement_inserter* inserter)
 {
+  if (this->type()->is_error_type()
+      || (this->init_ != NULL
+          && this->init_->is_error_expression()))
+    {
+      go_assert(saw_errors());
+      return Statement::make_error_statement(this->location());
+    }
+
   if (this->type_ != NULL
       && this->init_ != NULL
       && !Type::are_identical(this->type_, this->init_->type(), false, NULL)
@@ -610,6 +626,15 @@ Statement*
 Assignment_statement::do_flatten(Gogo*, Named_object*, Block*,
                                 Statement_inserter* inserter)
 {
+  if (this->lhs_->is_error_expression()
+      || this->lhs_->type()->is_error_type()
+      || this->rhs_->is_error_expression()
+      || this->rhs_->type()->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Statement::make_error_statement(this->location());
+    }
+
   if (!this->lhs_->is_sink_expression()
       && !Type::are_identical(this->lhs_->type(), this->rhs_->type(),
                              false, NULL)
@@ -4397,6 +4422,13 @@ Statement*
 Send_statement::do_flatten(Gogo*, Named_object*, Block*,
                           Statement_inserter* inserter)
 {
+  if (this->channel_->is_error_expression()
+      || this->channel_->type()->is_error_type())
+    {
+      go_assert(saw_errors());
+      return Statement::make_error_statement(this->location());
+    }
+
   Type* element_type = this->channel_->type()->channel_type()->element_type();
   if (!Type::are_identical(element_type, this->val_->type(), false, NULL)
       && this->val_->type()->interface_type() != NULL

Reply via email to