compiler: copy receiver argument for go/defer of method call

Test case is https://golang.org/cl/302371.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/302270
This commit is contained in:
Ian Lance Taylor 2021-03-16 22:34:20 -07:00
parent c86c5195c8
commit f3e9c98a9f
3 changed files with 29 additions and 2 deletions

View File

@ -1,4 +1,4 @@
10b00ad87303d37c68b2d54dd25d655bd316946e
4bdff733a0c2a9ddc3eff104b1be03df058a79c4
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -11017,7 +11017,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
// If this is call to a method, call the method directly passing the
// object as the first parameter.
Bound_method_expression* bme = this->fn_->bound_method_expression();
if (bme != NULL)
if (bme != NULL && !this->is_deferred_ && !this->is_concurrent_)
{
Named_object* methodfn = bme->function();
Function_type* mft = (methodfn->is_function()

View File

@ -2524,6 +2524,8 @@ Thunk_statement::is_constant_function() const
return fn->func_expression()->closure() == NULL;
if (fn->interface_field_reference_expression() != NULL)
return true;
if (fn->bound_method_expression() != NULL)
return true;
return false;
}
@ -2566,6 +2568,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
Expression* fn = ce->fn();
Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression();
Bound_method_expression* bme = fn->bound_method_expression();
Location location = this->location();
@ -2594,6 +2597,8 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
if (interface_method != NULL)
vals->push_back(interface_method->expr());
if (bme != NULL)
vals->push_back(bme->first_argument());
if (ce->args() != NULL)
{
@ -2714,6 +2719,16 @@ Thunk_statement::build_struct(Function_type* fntype)
fields->push_back(Struct_field(tid));
}
// If this thunk statement calls a bound method expression, as in
// "go s.m()", we pass the bound method argument to the thunk,
// to ensure that we make a copy of it if needed.
Bound_method_expression* bme = fn->bound_method_expression();
if (bme != NULL)
{
Typed_identifier tid("object", bme->first_argument()->type(), location);
fields->push_back(Struct_field(tid));
}
// The predeclared recover function has no argument. However, we
// add an argument when building recover thunks. Handle that here.
if (ce->is_recover_call())
@ -2843,6 +2858,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
Interface_field_reference_expression* interface_method =
ce->fn()->interface_field_reference_expression();
Bound_method_expression* bme = ce->fn()->bound_method_expression();
Expression* func_to_call;
unsigned int next_index;
@ -2870,6 +2886,17 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
next_index = 1;
}
if (bme != NULL)
{
// This is a call to a method.
go_assert(next_index == 0);
Expression* r = Expression::make_field_reference(thunk_parameter, 0,
location);
func_to_call = Expression::make_bound_method(r, bme->method(),
bme->function(), location);
next_index = 1;
}
Expression_list* call_params = new Expression_list();
const Struct_field_list* fields = this->struct_type_->fields();
Struct_field_list::const_iterator p = fields->begin();