Commit 1bbf7edb by Ian Lance Taylor

Lower calls to bound method expressions.

From-SVN: r178264
parent 27311334
......@@ -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*);
......
......@@ -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);
......
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