Commit 31766e68 by Ian Lance Taylor

compiler: don't incorrectly evaluate range variable

    
    The language spec says that in `for i = range x`, in which there is no
    second iteration variable, if len(x) is constant, then x is not
    evaluated.  This only matters when x is an expression that panics but
    whose type is an array type; in such a case, we should not evaluate x,
    since len of any array type is a constant.
    
    Fixes golang/go#22313
    
    Reviewed-on: https://go-review.googlesource.com/91555

From-SVN: r257330
parent eece7fe5
b332ba2f0d0302eeb01a228c217928296cec56f6 981e6621bcd48670d0b58e51e9eeffe549725378
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -5307,11 +5307,24 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, ...@@ -5307,11 +5307,24 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
return Statement::make_error_statement(this->location()); return Statement::make_error_statement(this->location());
} }
// If there is only one iteration variable, and len(this->range_) is
// 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.
bool eval = true;
if (this->value_var_ == NULL
&& range_type->array_type() != NULL
&& !range_type->is_slice_type())
eval = false;
Location loc = this->location(); Location loc = this->location();
Block* temp_block = new Block(enclosing, loc); Block* temp_block = new Block(enclosing, loc);
Named_object* range_object = NULL; Named_object* range_object = NULL;
Temporary_statement* range_temp = NULL; Temporary_statement* range_temp = NULL;
if (eval)
{
Var_expression* ve = this->range_->var_expression(); Var_expression* ve = this->range_->var_expression();
if (ve != NULL) if (ve != NULL)
range_object = ve->named_object(); range_object = ve->named_object();
...@@ -5321,6 +5334,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, ...@@ -5321,6 +5334,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
temp_block->add_statement(range_temp); temp_block->add_statement(range_temp);
this->range_ = NULL; this->range_ = NULL;
} }
}
Temporary_statement* index_temp = Statement::make_temporary(index_type, Temporary_statement* index_temp = Statement::make_temporary(index_type,
NULL, loc); NULL, loc);
...@@ -5474,12 +5488,22 @@ For_range_statement::lower_range_array(Gogo* gogo, ...@@ -5474,12 +5488,22 @@ For_range_statement::lower_range_array(Gogo* gogo,
Block* init = new Block(enclosing, loc); Block* init = new Block(enclosing, loc);
Expression* len_arg;
if (range_object == NULL && range_temp == NULL)
{
// Don't evaluate this->range_, just get its length.
len_arg = this->range_;
}
else
{
Expression* ref = this->make_range_ref(range_object, range_temp, loc); Expression* ref = this->make_range_ref(range_object, range_temp, loc);
range_temp = Statement::make_temporary(NULL, ref, loc); range_temp = Statement::make_temporary(NULL, ref, loc);
Expression* len_call = this->call_builtin(gogo, "len", ref, loc); init->add_statement(range_temp);
len_arg = ref;
}
Expression* len_call = this->call_builtin(gogo, "len", len_arg, loc);
Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
len_call, loc); len_call, loc);
init->add_statement(range_temp);
init->add_statement(len_temp); init->add_statement(len_temp);
Expression* zexpr = Expression::make_integer_ul(0, NULL, loc); Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
...@@ -5495,7 +5519,7 @@ For_range_statement::lower_range_array(Gogo* gogo, ...@@ -5495,7 +5519,7 @@ For_range_statement::lower_range_array(Gogo* gogo,
// Set *PCOND to // Set *PCOND to
// index_temp < len_temp // index_temp < len_temp
ref = Expression::make_temporary_reference(index_temp, loc); Expression* ref = Expression::make_temporary_reference(index_temp, loc);
Expression* ref2 = Expression::make_temporary_reference(len_temp, loc); Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc); Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
......
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