aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2018-02-05 01:50:22 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-02-05 01:50:22 +0000
commit964c809fb28f2bbb5b7c35d7951911abff242b94 (patch)
treeb28da004d38101795417db74c7864f081e38ba3f /gcc
parent4cff15eaca92180183608371351ba2c818990304 (diff)
downloadgcc-964c809fb28f2bbb5b7c35d7951911abff242b94.zip
gcc-964c809fb28f2bbb5b7c35d7951911abff242b94.tar.gz
gcc-964c809fb28f2bbb5b7c35d7951911abff242b94.tar.bz2
compiler: in range, evaluate array if it has receives or calls
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc38
-rw-r--r--gcc/go/gofrontend/expressions.h5
-rw-r--r--gcc/go/gofrontend/parse.cc3
-rw-r--r--gcc/go/gofrontend/statements.cc11
5 files changed, 37 insertions, 22 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index edfec39..575756e 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -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.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 715f625..3bcc5ae 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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())
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 6b00cab..18fd91b 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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*
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 86d3510..9700cc3 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -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)
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 0b1d722..c94d8cf 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -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
{