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:
parent
c86c5195c8
commit
f3e9c98a9f
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user