Commit 964c809f by Ian Lance Taylor

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
parent 4cff15ea
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 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())
......
......@@ -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*
......
......@@ -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)
......
......@@ -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
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment