compiler: in range, evaluate array if it has receives or calls
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 5 Feb 2018 01:50:22 +0000 (01:50 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 5 Feb 2018 01:50:22 +0000 (01:50 +0000)
    The last change was incomplete, in that it did not evaluate the array
    argument in some cases where it had to be evaluated.  This reuses the
    existing code for checking whether len/cap is constant.

    Also clean up the use of _ as the second variable in a for/range,
    which was previously inconsistent depending on whether the statement
    used = or :=.

    Updates golang/go#22313

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

From-SVN: r257377

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

index edfec3911d9a5cde6f272905efde3f230261e6e9..575756eae5a3ec55a35b8bec3393080040cc7e04 100644 (file)
@@ -1,4 +1,4 @@
-312af623f48633989e9eb6e559ede84a23998ece
+5031f878a761bf83f5f96710d62f83e2dc5ecf04
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 715f6255d48283d9d3634ca1334fc3cf9f171ac2..3bcc5ae1471c1d270c71f9035f505a7ee586ba25 100644 (file)
@@ -7957,8 +7957,10 @@ class Find_call_expression : public Traverse
 int
 Find_call_expression::expression(Expression** pexpr)
 {
-  if ((*pexpr)->call_expression() != NULL
-      || (*pexpr)->receive_expression() != NULL)
+  Expression* expr = *pexpr;
+  if (!expr->is_constant()
+      && (expr->call_expression() != NULL
+         || expr->receive_expression() != NULL))
     {
       this->found_ = true;
       return TRAVERSE_EXIT;
@@ -7966,6 +7968,24 @@ Find_call_expression::expression(Expression** pexpr)
   return TRAVERSE_CONTINUE;
 }
 
+// Return whether calling len or cap on EXPR, of array type, is a
+// constant.  The language spec says "the expressions len(s) and
+// cap(s) are constants if the type of s is an array or pointer to an
+// array and the expression s does not contain channel receives or
+// (non-constant) function calls."
+
+bool
+Builtin_call_expression::array_len_is_constant(Expression* expr)
+{
+  go_assert(expr->type()->deref()->array_type() != NULL
+           && !expr->type()->deref()->is_slice_type());
+  if (expr->is_constant())
+    return true;
+  Find_call_expression find_call;
+  Expression::traverse(&expr, &find_call);
+  return !find_call.found();
+}
+
 // Return whether this is constant: len of a string constant, or len
 // or cap of an array, or unsafe.Sizeof, unsafe.Offsetof,
 // unsafe.Alignof.
@@ -7993,19 +8013,9 @@ Builtin_call_expression::do_is_constant() const
            && !arg_type->points_to()->is_slice_type())
          arg_type = arg_type->points_to();
 
-       // The len and cap functions are only constant if there are no
-       // function calls or channel operations in the arguments.
-       // Otherwise we have to make the call.
-       if (!arg->is_constant())
-         {
-           Find_call_expression find_call;
-           Expression::traverse(&arg, &find_call);
-           if (find_call.found())
-             return false;
-         }
-
        if (arg_type->array_type() != NULL
-           && arg_type->array_type()->length() != NULL)
+           && arg_type->array_type()->length() != NULL
+           && Builtin_call_expression::array_len_is_constant(arg))
          return true;
 
        if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
index 6b00cab92e39337725377460ac2c1008cde96206..18fd91b054fff1790c65613f3eea8a0f31379aa3 100644 (file)
@@ -2406,6 +2406,11 @@ class Builtin_call_expression : public Call_expression
   is_builtin()
   { return true; }
 
+  // Return whether EXPR, of array type, is a constant if passed to
+  // len or cap.
+  static bool
+  array_len_is_constant(Expression* expr);
+
  protected:
   // This overrides Call_expression::do_lower.
   Expression*
index 86d3510475e089fde5da570bcf5c96a73f71e482..9700cc34363a34303303d2493802acd1ff5d308e 100644 (file)
@@ -5459,8 +5459,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
        no->var_value()->set_type_from_range_value();
       if (is_new)
        any_new = true;
-      if (!Gogo::is_sink_name(pti->name()))
-        p_range_clause->value = Expression::make_var_reference(no, location);
+      p_range_clause->value = Expression::make_var_reference(no, location);
     }
 
   if (!any_new)
index 0b1d7220b5e42d78bc6e495ae8a1aa52898eecdf..c94d8cf369e3080371fe8596435d16d06f1cdc14 100644 (file)
@@ -5311,11 +5311,12 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
   // constant, then we do not evaluate the range variable.  len(x) is
   // a contant if x is a string constant or if x is an array.  If x is
   // a constant then evaluating it won't make any difference, so the
-  // only case to consider is when x is an array.
+  // only case to consider is when x is an array whose length is constant.
   bool eval = true;
-  if (this->value_var_ == NULL
+  if ((this->value_var_ == NULL || this->value_var_->is_sink_expression())
       && range_type->array_type() != NULL
-      && !range_type->is_slice_type())
+      && !range_type->is_slice_type()
+      && Builtin_call_expression::array_len_is_constant(this->range_))
     eval = false;
 
   Location loc = this->location();
@@ -5341,7 +5342,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
   temp_block->add_statement(index_temp);
 
   Temporary_statement* value_temp = NULL;
-  if (this->value_var_ != NULL)
+  if (this->value_var_ != NULL && !this->value_var_->is_sink_expression())
     {
       value_temp = Statement::make_temporary(value_type, NULL, loc);
       temp_block->add_statement(value_temp);
@@ -5393,7 +5394,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
       Statement* assign;
       Expression* index_ref =
        Expression::make_temporary_reference(index_temp, loc);
-      if (this->value_var_ == NULL)
+      if (this->value_var_ == NULL || this->value_var_->is_sink_expression())
        assign = Statement::make_assignment(this->index_var_, index_ref, loc);
       else
        {