aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-08-29 22:06:19 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-08-29 22:06:19 +0000
commit1bbf7edba0f3518d91b6622761b634bda2ca8a29 (patch)
tree723b92c72a0ba175df1059b88a1244ec013d0891 /gcc/go
parent273113346e85423e88d1352c4acafe41e7dd90b5 (diff)
downloadgcc-1bbf7edba0f3518d91b6622761b634bda2ca8a29.zip
gcc-1bbf7edba0f3518d91b6622761b634bda2ca8a29.tar.gz
gcc-1bbf7edba0f3518d91b6622761b634bda2ca8a29.tar.bz2
Lower calls to bound method expressions.
From-SVN: r178264
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/expressions.cc336
-rw-r--r--gcc/go/gofrontend/expressions.h10
-rw-r--r--gcc/go/gofrontend/statements.cc71
3 files changed, 197 insertions, 220 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index af29a30..8957acb 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -3845,7 +3845,7 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
go_assert((et->points_to() != NULL
&& et->points_to()->channel_type() != NULL)
|| et->is_nil_type());
- else if (t->is_unsafe_pointer_type())
+ else if (t->points_to() != NULL)
go_assert(et->points_to() != NULL || et->is_nil_type());
else if (et->is_unsafe_pointer_type())
go_assert(t->points_to() != NULL);
@@ -3908,7 +3908,7 @@ class Unary_expression : public Expression
public:
Unary_expression(Operator op, Expression* expr, source_location location)
: Expression(EXPRESSION_UNARY, location),
- op_(op), escapes_(true), expr_(expr)
+ op_(op), escapes_(true), create_temp_(false), expr_(expr)
{ }
// Return the operator.
@@ -3929,6 +3929,15 @@ class Unary_expression : public Expression
this->escapes_ = false;
}
+ // Record that this is an address expression which should create a
+ // temporary variable if necessary. This is used for method calls.
+ void
+ set_create_temp()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->create_temp_ = true;
+ }
+
// Apply unary opcode OP to UVAL, setting VAL. Return true if this
// could be done, false if not.
static bool
@@ -4004,6 +4013,9 @@ class Unary_expression : public Expression
// Normally true. False if this is an address expression which does
// not escape the current function.
bool escapes_;
+ // True if this is an address expression which should create a
+ // temporary variable if necessary.
+ bool create_temp_;
// The operand.
Expression* expr_;
};
@@ -4428,7 +4440,10 @@ Unary_expression::do_check_types(Gogo*)
case OPERATOR_AND:
if (!this->expr_->is_addressable())
- this->report_error(_("invalid operand for unary %<&%>"));
+ {
+ if (!this->create_temp_)
+ this->report_error(_("invalid operand for unary %<&%>"));
+ }
else
this->expr_->address_taken(this->escapes_);
break;
@@ -4486,12 +4501,15 @@ Unary_expression::do_get_tree(Translate_context* context)
return fold_build1_loc(loc, BIT_NOT_EXPR, TREE_TYPE(expr), expr);
case OPERATOR_AND:
- // We should not see a non-constant constructor here; cases
- // where we would see one should have been moved onto the heap
- // at parse time. Taking the address of a nonconstant
- // constructor will not do what the programmer expects.
- go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
- go_assert(TREE_CODE(expr) != ADDR_EXPR);
+ if (!this->create_temp_)
+ {
+ // We should not see a non-constant constructor here; cases
+ // where we would see one should have been moved onto the
+ // heap at parse time. Taking the address of a nonconstant
+ // constructor will not do what the programmer expects.
+ go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
+ go_assert(TREE_CODE(expr) != ADDR_EXPR);
+ }
// Build a decl for a constant constructor.
if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr))
@@ -4510,6 +4528,22 @@ Unary_expression::do_get_tree(Translate_context* context)
expr = decl;
}
+ if (this->create_temp_
+ && !TREE_ADDRESSABLE(TREE_TYPE(expr))
+ && !DECL_P(expr)
+ && TREE_CODE(expr) != INDIRECT_REF
+ && TREE_CODE(expr) != COMPONENT_REF)
+ {
+ tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
+ DECL_IGNORED_P(tmp) = 1;
+ DECL_INITIAL(tmp) = expr;
+ TREE_ADDRESSABLE(tmp) = 1;
+ return build2_loc(loc, COMPOUND_EXPR,
+ build_pointer_type(TREE_TYPE(expr)),
+ build1_loc(loc, DECL_EXPR, void_type_node, tmp),
+ build_fold_addr_expr_loc(loc, tmp));
+ }
+
return build_fold_addr_expr_loc(loc, expr);
case OPERATOR_MULT:
@@ -7223,7 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
this->set_is_error();
return this;
}
- return this->lower_varargs(gogo, function, inserter, slice_type, 2);
+ this->lower_varargs(gogo, function, inserter, slice_type, 2);
}
return this;
@@ -8805,12 +8839,14 @@ Expression*
Call_expression::do_lower(Gogo* gogo, Named_object* function,
Statement_inserter* inserter, int)
{
+ source_location loc = this->location();
+
// A type cast can look like a function call.
if (this->fn_->is_type_expression()
&& this->args_ != NULL
&& this->args_->size() == 1)
return Expression::make_cast(this->fn_->type(), this->args_->front(),
- this->location());
+ loc);
// Recognize a call to a builtin function.
Func_expression* fne = this->fn_->func_expression();
@@ -8818,7 +8854,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
&& fne->named_object()->is_function_declaration()
&& fne->named_object()->func_declaration_value()->type()->is_builtin())
return new Builtin_call_expression(gogo, this->fn_, this->args_,
- this->is_varargs_, this->location());
+ this->is_varargs_, loc);
// Handle an argument which is a call to a function which returns
// multiple results.
@@ -8862,8 +8898,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
++p)
{
Temporary_statement* temp = Statement::make_temporary(p->type(),
- NULL,
- p->location());
+ NULL, loc);
inserter->insert(temp);
temps->push_back(temp);
}
@@ -8879,8 +8914,58 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
const Typed_identifier_list* parameters = fntype->parameters();
go_assert(parameters != NULL && !parameters->empty());
Type* varargs_type = parameters->back().type();
- return this->lower_varargs(gogo, function, inserter, varargs_type,
- parameters->size());
+ this->lower_varargs(gogo, function, inserter, varargs_type,
+ parameters->size());
+ }
+
+ // 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)
+ {
+ Named_object* method = bme->method();
+ Expression* first_arg = bme->first_argument();
+
+ // We always pass a pointer when calling a method.
+ if (first_arg->type()->points_to() == NULL
+ && !first_arg->type()->is_error())
+ {
+ first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
+ // We may need to create a temporary variable so that we can
+ // take the address. We can't do that here because it will
+ // mess up the order of evaluation.
+ Unary_expression* ue = static_cast<Unary_expression*>(first_arg);
+ ue->set_create_temp();
+ }
+
+ // If we are calling a method which was inherited from an
+ // embedded struct, and the method did not get a stub, then the
+ // first type may be wrong.
+ Type* fatype = bme->first_argument_type();
+ if (fatype != NULL)
+ {
+ if (fatype->points_to() == NULL)
+ fatype = Type::make_pointer_type(fatype);
+ first_arg = Expression::make_unsafe_cast(fatype, first_arg, loc);
+ }
+
+ Expression_list* new_args = new Expression_list();
+ new_args->push_back(first_arg);
+ if (this->args_ != NULL)
+ {
+ for (Expression_list::const_iterator p = this->args_->begin();
+ p != this->args_->end();
+ ++p)
+ new_args->push_back(*p);
+ }
+
+ // We have to change in place because this structure may be
+ // referenced by Call_result_expressions. We can't delete the
+ // old arguments, because we may be traversing them up in some
+ // caller. FIXME.
+ this->args_ = new_args;
+ this->fn_ = Expression::make_func_reference(method, NULL,
+ bme->location());
}
return this;
@@ -8893,13 +8978,13 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
// calling; the last of these parameters will be the varargs
// parameter.
-Expression*
+void
Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
Statement_inserter* inserter,
Type* varargs_type, size_t param_count)
{
if (this->varargs_are_lowered_)
- return this;
+ return;
source_location loc = this->location();
@@ -8910,7 +8995,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
if (arg_count < param_count - 1)
{
// Not enough arguments; will be caught in check_types.
- return this;
+ return;
}
Expression_list* old_args = this->args_;
@@ -8942,7 +9027,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
else if (this->is_varargs_)
{
this->report_error(_("too many arguments"));
- return this;
+ return;
}
else
{
@@ -8960,6 +9045,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
}
Expression* val =
Expression::make_slice_composite_literal(varargs_type, vals, loc);
+ gogo->lower_expression(function, inserter, &val);
new_args->push_back(val);
}
}
@@ -8973,12 +9059,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
// Builtin_call_expression which refer to them. FIXME.
this->args_ = new_args;
this->varargs_are_lowered_ = true;
-
- // Lower all the new subexpressions.
- Expression* ret = this;
- gogo->lower_expression(function, inserter, &ret);
- go_assert(ret == this);
- return ret;
}
// Get the function type. This can return NULL in error cases.
@@ -9102,10 +9182,28 @@ Call_expression::do_determine_type(const Type_context*)
Typed_identifier_list::const_iterator pt;
if (parameters != NULL)
pt = parameters->begin();
+ bool first = true;
for (Expression_list::const_iterator pa = this->args_->begin();
pa != this->args_->end();
++pa)
{
+ if (first)
+ {
+ first = false;
+ // If this is a method, the first argument is the
+ // receiver.
+ if (fntype != NULL && fntype->is_method())
+ {
+ Type* rtype = fntype->receiver()->type();
+ // The receiver is always passed as a pointer.
+ if (rtype->points_to() == NULL)
+ rtype = Type::make_pointer_type(rtype);
+ Type_context subcontext(rtype, false);
+ (*pa)->determine_type(&subcontext);
+ continue;
+ }
+ }
+
if (parameters != NULL && pt != parameters->end())
{
Type_context subcontext(pt->type(), false);
@@ -9172,35 +9270,28 @@ Call_expression::do_check_types(Gogo*)
return;
}
- if (fntype->is_method())
+ bool is_method = fntype->is_method();
+ if (is_method)
{
- // We don't support pointers to methods, so the function has to
- // be a bound method expression.
- Bound_method_expression* bme = this->fn_->bound_method_expression();
- if (bme == NULL)
- {
- this->report_error(_("method call without object"));
- return;
- }
- Type* first_arg_type = bme->first_argument()->type();
- if (first_arg_type->points_to() == NULL)
+ go_assert(this->args_ != NULL && !this->args_->empty());
+ Type* rtype = fntype->receiver()->type();
+ Expression* first_arg = this->args_->front();
+ // The language permits copying hidden fields for a method
+ // receiver. We dereference the values since receivers are
+ // always passed as pointers.
+ std::string reason;
+ if (!Type::are_assignable_hidden_ok(rtype->deref(),
+ first_arg->type()->deref(),
+ &reason))
{
- // When passing a value, we need to check that we are
- // permitted to copy it. The language permits copying
- // hidden fields for a method receiver.
- std::string reason;
- if (!Type::are_assignable_hidden_ok(fntype->receiver()->type(),
- first_arg_type, &reason))
+ if (reason.empty())
+ this->report_error(_("incompatible type for receiver"));
+ else
{
- if (reason.empty())
- this->report_error(_("incompatible type for receiver"));
- else
- {
- error_at(this->location(),
- "incompatible type for receiver (%s)",
- reason.c_str());
- this->set_is_error();
- }
+ error_at(this->location(),
+ "incompatible type for receiver (%s)",
+ reason.c_str());
+ this->set_is_error();
}
}
}
@@ -9215,25 +9306,30 @@ Call_expression::do_check_types(Gogo*)
this->report_error(_("not enough arguments"));
}
else if (parameters == NULL)
- this->report_error(_("too many arguments"));
+ {
+ if (!is_method || this->args_->size() > 1)
+ this->report_error(_("too many arguments"));
+ }
else
{
int i = 0;
- Typed_identifier_list::const_iterator pt = parameters->begin();
- for (Expression_list::const_iterator pa = this->args_->begin();
- pa != this->args_->end();
- ++pa, ++pt, ++i)
- {
- if (pt == parameters->end())
+ Expression_list::const_iterator pa = this->args_->begin();
+ if (is_method)
+ ++pa;
+ for (Typed_identifier_list::const_iterator pt = parameters->begin();
+ pt != parameters->end();
+ ++pt, ++pa, ++i)
+ {
+ if (pa == this->args_->end())
{
- this->report_error(_("too many arguments"));
+ this->report_error(_("not enough arguments"));
return;
}
this->check_argument_type(i + 1, pt->type(), (*pa)->type(),
(*pa)->location(), false);
}
- if (pt != parameters->end())
- this->report_error(_("not enough arguments"));
+ if (pa != this->args_->end())
+ this->report_error(_("too many arguments"));
}
}
@@ -9247,83 +9343,6 @@ Call_expression::do_must_eval_in_order() const
return this->result_count() > 0;
}
-// Get the function and the first argument to use when calling a bound
-// method.
-
-tree
-Call_expression::bound_method_function(Translate_context* context,
- Bound_method_expression* bound_method,
- tree* first_arg_ptr)
-{
- Gogo* gogo = context->gogo();
- source_location loc = this->location();
-
- Expression* first_argument = bound_method->first_argument();
- tree first_arg = first_argument->get_tree(context);
- if (first_arg == error_mark_node)
- return error_mark_node;
-
- // We always pass a pointer to the first argument when calling a
- // method.
- if (first_argument->type()->points_to() == NULL)
- {
- tree pointer_to_arg_type = build_pointer_type(TREE_TYPE(first_arg));
- if (TREE_ADDRESSABLE(TREE_TYPE(first_arg))
- || DECL_P(first_arg)
- || TREE_CODE(first_arg) == INDIRECT_REF
- || TREE_CODE(first_arg) == COMPONENT_REF)
- {
- first_arg = build_fold_addr_expr_loc(loc, first_arg);
- if (DECL_P(first_arg))
- TREE_ADDRESSABLE(first_arg) = 1;
- }
- else
- {
- tree tmp = create_tmp_var(TREE_TYPE(first_arg),
- get_name(first_arg));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = first_arg;
- first_arg = build2_loc(loc, COMPOUND_EXPR, pointer_to_arg_type,
- build1_loc(loc, DECL_EXPR, void_type_node,
- tmp),
- build_fold_addr_expr_loc(loc, tmp));
- TREE_ADDRESSABLE(tmp) = 1;
- }
- if (first_arg == error_mark_node)
- return error_mark_node;
- }
-
- Type* fatype = bound_method->first_argument_type();
- if (fatype != NULL)
- {
- if (fatype->points_to() == NULL)
- fatype = Type::make_pointer_type(fatype);
- Btype* bfatype = fatype->get_backend(gogo);
- first_arg = fold_convert_loc(loc, type_to_tree(bfatype), first_arg);
- if (first_arg == error_mark_node
- || TREE_TYPE(first_arg) == error_mark_node)
- return error_mark_node;
- }
-
- *first_arg_ptr = first_arg;
-
- Named_object* method = bound_method->method();
- tree id = method->get_id(gogo);
- if (id == error_mark_node)
- return error_mark_node;
-
- tree fndecl;
- if (method->is_function())
- fndecl = method->func_value()->get_or_make_decl(gogo, method, id);
- else if (method->is_function_declaration())
- fndecl = method->func_declaration_value()->get_or_make_decl(gogo, method,
- id);
- else
- go_unreachable();
-
- return build_fold_addr_expr_loc(loc, fndecl);
-}
-
// Get the function and the first argument to use when calling an
// interface method.
@@ -9363,35 +9382,46 @@ Call_expression::do_get_tree(Translate_context* context)
source_location location = this->location();
Func_expression* func = this->fn_->func_expression();
- Bound_method_expression* bound_method = this->fn_->bound_method_expression();
Interface_field_reference_expression* interface_method =
this->fn_->interface_field_reference_expression();
const bool has_closure = func != NULL && func->closure() != NULL;
- const bool is_method = bound_method != NULL || interface_method != NULL;
- go_assert(!fntype->is_method() || is_method);
+ const bool is_interface_method = interface_method != NULL;
int nargs;
tree* args;
if (this->args_ == NULL || this->args_->empty())
{
- nargs = is_method ? 1 : 0;
+ nargs = is_interface_method ? 1 : 0;
args = nargs == 0 ? NULL : new tree[nargs];
}
+ else if (fntype->parameters() == NULL || fntype->parameters()->empty())
+ {
+ // Passing a receiver parameter.
+ go_assert(!is_interface_method
+ && fntype->is_method()
+ && this->args_->size() == 1);
+ nargs = 1;
+ args = new tree[nargs];
+ args[0] = this->args_->front()->get_tree(context);
+ }
else
{
const Typed_identifier_list* params = fntype->parameters();
- go_assert(params != NULL);
nargs = this->args_->size();
- int i = is_method ? 1 : 0;
+ int i = is_interface_method ? 1 : 0;
nargs += i;
args = new tree[nargs];
Typed_identifier_list::const_iterator pp = params->begin();
- Expression_list::const_iterator pe;
- for (pe = this->args_->begin();
- pe != this->args_->end();
- ++pe, ++pp, ++i)
+ Expression_list::const_iterator pe = this->args_->begin();
+ if (!is_interface_method && fntype->is_method())
+ {
+ args[i] = (*pe)->get_tree(context);
+ ++pe;
+ ++i;
+ }
+ for (; pe != this->args_->end(); ++pe, ++pp, ++i)
{
go_assert(pp != params->end());
tree arg_val = (*pe)->get_tree(context);
@@ -9420,14 +9450,10 @@ Call_expression::do_get_tree(Translate_context* context)
tree fn;
if (has_closure)
fn = func->get_tree_without_closure(gogo);
- else if (!is_method)
+ else if (!is_interface_method)
fn = this->fn_->get_tree(context);
- else if (bound_method != NULL)
- fn = this->bound_method_function(context, bound_method, &args[0]);
- else if (interface_method != NULL)
- fn = this->interface_method_function(context, interface_method, &args[0]);
else
- go_unreachable();
+ fn = this->interface_method_function(context, interface_method, &args[0]);
if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
{
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 530ea4e..bb4f23e 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1244,6 +1244,11 @@ class Call_expression : public Expression
is_varargs() const
{ return this->is_varargs_; }
+ // Note that varargs have already been lowered.
+ void
+ set_varargs_are_lowered()
+ { this->varargs_are_lowered_ = true; }
+
// Whether this call is being deferred.
bool
is_deferred() const
@@ -1307,7 +1312,7 @@ class Call_expression : public Expression
{ this->args_ = args; }
// Let a builtin expression lower varargs.
- Expression*
+ void
lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
Type* varargs_type, size_t param_count);
@@ -1324,9 +1329,6 @@ class Call_expression : public Expression
check_argument_type(int, const Type*, const Type*, source_location, bool);
tree
- bound_method_function(Translate_context*, Bound_method_expression*, tree*);
-
- tree
interface_method_function(Translate_context*,
Interface_field_reference_expression*,
tree*);
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index c2caaa4..e646227 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1858,8 +1858,7 @@ Thunk_statement::is_simple(Function_type* fntype) const
// If this calls something which is not a simple function, then we
// need a thunk.
Expression* fn = this->call_->call_expression()->fn();
- if (fn->bound_method_expression() != NULL
- || fn->interface_field_reference_expression() != NULL)
+ if (fn->interface_field_reference_expression() != NULL)
return false;
return true;
@@ -1914,14 +1913,6 @@ Thunk_statement::do_check_types(Gogo*)
this->report_error("expected call expression");
return;
}
- Function_type* fntype = ce->get_function_type();
- if (fntype != NULL && fntype->is_method())
- {
- Expression* fn = ce->fn();
- if (fn->bound_method_expression() == NULL
- && fn->interface_field_reference_expression() == NULL)
- this->report_error(_("no object for method call"));
- }
}
// The Traverse class used to find and simplify thunk statements.
@@ -2005,8 +1996,7 @@ Thunk_statement::is_constant_function() const
Expression* fn = ce->fn();
if (fn->func_expression() != NULL)
return fn->func_expression()->closure() == NULL;
- if (fn->bound_method_expression() != NULL
- || fn->interface_field_reference_expression() != NULL)
+ if (fn->interface_field_reference_expression() != NULL)
return true;
return false;
}
@@ -2048,7 +2038,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
return false;
Expression* fn = ce->fn();
- Bound_method_expression* bound_method = fn->bound_method_expression();
Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression();
@@ -2071,30 +2060,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
if (interface_method != NULL)
vals->push_back(interface_method->expr());
- if (bound_method != NULL)
- {
- Expression* first_arg = bound_method->first_argument();
-
- // We always pass a pointer when calling a method.
- if (first_arg->type()->points_to() == NULL)
- first_arg = Expression::make_unary(OPERATOR_AND, first_arg, location);
-
- // If we are calling a method which was inherited from an
- // embedded struct, and the method did not get a stub, then the
- // first type may be wrong.
- Type* fatype = bound_method->first_argument_type();
- if (fatype != NULL)
- {
- if (fatype->points_to() == NULL)
- fatype = Type::make_pointer_type(fatype);
- Type* unsafe = Type::make_pointer_type(Type::make_void_type());
- first_arg = Expression::make_cast(unsafe, first_arg, location);
- first_arg = Expression::make_cast(fatype, first_arg, location);
- }
-
- vals->push_back(first_arg);
- }
-
if (ce->args() != NULL)
{
for (Expression_list::const_iterator p = ce->args()->begin();
@@ -2186,19 +2151,6 @@ Thunk_statement::build_struct(Function_type* fntype)
fields->push_back(Struct_field(tid));
}
- // If this is a method call, pass down the expression we are
- // calling.
- if (fn->bound_method_expression() != NULL)
- {
- go_assert(fntype->is_method());
- Type* rtype = fntype->receiver()->type();
- // We always pass the receiver as a pointer.
- if (rtype->points_to() == NULL)
- rtype = Type::make_pointer_type(rtype);
- Typed_identifier tid("receiver", rtype, 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())
@@ -2317,7 +2269,6 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
location);
- Bound_method_expression* bound_method = ce->fn()->bound_method_expression();
Interface_field_reference_expression* interface_method =
ce->fn()->interface_field_reference_expression();
@@ -2335,16 +2286,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
next_index = 1;
}
- if (bound_method != NULL)
- {
- go_assert(next_index == 0);
- Expression* r = Expression::make_field_reference(thunk_parameter, 0,
- location);
- func_to_call = Expression::make_bound_method(r, bound_method->method(),
- location);
- next_index = 1;
- }
- else if (interface_method != NULL)
+ if (interface_method != NULL)
{
// The main program passes the interface object.
go_assert(next_index == 0);
@@ -2389,6 +2331,13 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
Call_expression* call = Expression::make_call(func_to_call, call_params,
false, location);
+
+ // This call expression was already lowered before entering the
+ // thunk statement. Don't try to lower varargs again, as that will
+ // cause confusion for, e.g., method calls which already have a
+ // receiver parameter.
+ call->set_varargs_are_lowered();
+
Statement* call_statement = Statement::make_statement(call);
gogo->add_statement(call_statement);