From: Ian Lance Taylor Date: Wed, 17 Mar 2021 05:34:20 +0000 (-0700) Subject: compiler: copy receiver argument for go/defer of method call X-Git-Tag: upstream/12.2.0~9249 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f3e9c98a9f40fc24bb4ecef6aaa94ff799c8d587;p=platform%2Fupstream%2Fgcc.git 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c0bfa1f..a3eef23 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 101cbe7..5409d26 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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() diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 7ad7339..b066011 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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();