compiler: Flatten erroneous subtrees into errors.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 13 Aug 2015 01:04:42 +0000 (01:04 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 13 Aug 2015 01:04:42 +0000 (01:04 +0000)
    Between the lowering and flattening passes of the compiler, there are
    several passes that modify the lowered Go parse tree and as errors are
    discovered, several nodes transform into error nodes.  However, for a
    higher level node such as a construction expression, the erroneous
    nodes in the subtrees might not propagate their error.  The flatten
    phase for a node now looks for errors in the subtree and flattens the
    node into an error node if any are found.

    Fixes golang/go#11559, golang/go#11536, golang/go#11558.

    Reviewed-on: https://go-review.googlesource.com/13097

From-SVN: r226845

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/statements.cc

index c9e63002c9937a7a44c474e852411d7f85def89a..1961c7ea6ff56353ddd57ffc64bf47935aa8294a 100644 (file)
@@ -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 3aabbaba4c53c35b8ad54ff56dd6cdfbd13b469d..9f757a2aa26540a059cf75c5030f813539f0e987 100644 (file)
@@ -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*, Named_object*,
                                     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*, Named_object*,
                                    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* gogo, Named_object*,
 {
   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* gogo, Named_object*,
 
   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_flatten(Gogo*, Named_object*,
     {
       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_flatten(Gogo*, Named_object*,
     {
       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(Gogo* gogo, Named_object*,
         {
           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(Gogo* gogo, Named_object*,
 
           ++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*, Named_object*,
       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 6d0f6a4c0118e4afb22c6c81aed4ca7df113a2d3..5358b021339da740803023acfbdeafe9eb40895d 100644 (file)
@@ -1958,6 +1958,11 @@ class Call_expression : public Expression
   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 40b437382f020ef74a2f5e751fcfb3905f455d4e..72b41cb09a35cacecd4b48ece57bcc7e77dac4a8 100644 (file)
@@ -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