===================================================================
@@ -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.
===================================================================
@@ -7957,8 +7957,10 @@ class Find_call_expression : public Trav
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(Express
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(
&& !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())
===================================================================
@@ -2406,6 +2406,11 @@ class Builtin_call_expression : public C
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*
===================================================================
@@ -5459,8 +5459,7 @@ Parse::range_clause_decl(const Typed_ide
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)
===================================================================
@@ -5311,11 +5311,12 @@ For_range_statement::do_lower(Gogo* gogo
// 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
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
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
{