Commit 2a7ba924 by Ian Lance Taylor

compiler: don't use address of temporary for deferred delete

    
    This CL corrects the handling of a deferred delete in a loop, to not
    use a temporary whose value will, at deferred execution time, wind up
    being the last value in the loop.
    
    The test for this is TestDeferDeleteSlow in the 1.11 runtime package.
    
    Reviewed-on: https://go-review.googlesource.com/135358

From-SVN: r264325
parent 98ef99ab
218c9159635e06e39ae43d0efe1ac1e694fead2e 3fd61802286c81e5fb672f682d9e661181184d1f
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.
...@@ -7409,7 +7409,32 @@ Builtin_call_expression::do_lower(Gogo*, Named_object* function, ...@@ -7409,7 +7409,32 @@ Builtin_call_expression::do_lower(Gogo*, Named_object* function,
loc); loc);
Expression* e3 = Expression::make_temporary_reference(key_temp, Expression* e3 = Expression::make_temporary_reference(key_temp,
loc); loc);
e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
// If the call to delete is deferred, and is in a loop,
// then the loop will only have a single instance of the
// temporary variable. Passing the address of the
// temporary variable here means that the deferred call
// will see the last value in the loop, not the current
// value. So for this unusual case copy the value into
// the heap.
if (!this->is_deferred())
e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
else
{
Expression* a = Expression::make_allocation(mt->key_type(),
loc);
Temporary_statement* atemp =
Statement::make_temporary(NULL, a, loc);
inserter->insert(atemp);
a = Expression::make_temporary_reference(atemp, loc);
a = Expression::make_dereference(a, NIL_CHECK_NOT_NEEDED, loc);
Statement* s = Statement::make_assignment(a, e3, loc);
inserter->insert(s);
e3 = Expression::make_temporary_reference(atemp, loc);
}
return Runtime::make_call(Runtime::MAPDELETE, this->location(), return Runtime::make_call(Runtime::MAPDELETE, this->location(),
3, e1, e2, e3); 3, e1, e2, e3);
} }
...@@ -9024,6 +9049,10 @@ Builtin_call_expression::do_copy() ...@@ -9024,6 +9049,10 @@ Builtin_call_expression::do_copy()
if (this->varargs_are_lowered()) if (this->varargs_are_lowered())
bce->set_varargs_are_lowered(); bce->set_varargs_are_lowered();
if (this->is_deferred())
bce->set_is_deferred();
if (this->is_concurrent())
bce->set_is_concurrent();
return bce; return bce;
} }
...@@ -9606,8 +9635,16 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -9606,8 +9635,16 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
// Recognize a call to a builtin function. // Recognize a call to a builtin function.
if (fntype->is_builtin()) if (fntype->is_builtin())
return new Builtin_call_expression(gogo, this->fn_, this->args_, {
this->is_varargs_, loc); Builtin_call_expression* bce =
new Builtin_call_expression(gogo, this->fn_, this->args_,
this->is_varargs_, loc);
if (this->is_deferred_)
bce->set_is_deferred();
if (this->is_concurrent_)
bce->set_is_concurrent();
return bce;
}
// If this call returns multiple results, create a temporary // If this call returns multiple results, create a temporary
// variable to hold them. // variable to hold them.
...@@ -10275,6 +10312,10 @@ Call_expression::do_copy() ...@@ -10275,6 +10312,10 @@ Call_expression::do_copy()
if (this->varargs_are_lowered_) if (this->varargs_are_lowered_)
call->set_varargs_are_lowered(); call->set_varargs_are_lowered();
if (this->is_deferred_)
call->set_is_deferred();
if (this->is_concurrent_)
call->set_is_concurrent();
return call; return call;
} }
......
...@@ -4304,9 +4304,15 @@ Parse::go_or_defer_stat() ...@@ -4304,9 +4304,15 @@ Parse::go_or_defer_stat()
this->gogo_->start_block(stat_location); this->gogo_->start_block(stat_location);
Statement* stat; Statement* stat;
if (is_go) if (is_go)
stat = Statement::make_go_statement(call_expr, stat_location); {
stat = Statement::make_go_statement(call_expr, stat_location);
call_expr->set_is_concurrent();
}
else else
stat = Statement::make_defer_statement(call_expr, stat_location); {
stat = Statement::make_defer_statement(call_expr, stat_location);
call_expr->set_is_deferred();
}
this->gogo_->add_statement(stat); this->gogo_->add_statement(stat);
this->gogo_->add_block(this->gogo_->finish_block(stat_location), this->gogo_->add_block(this->gogo_->finish_block(stat_location),
stat_location); stat_location);
......
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