summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/statements.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/statements.cc')
-rw-r--r--gcc/go/gofrontend/statements.cc159
1 files changed, 62 insertions, 97 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index f653ef6fdb6..e6462274dff 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1808,10 +1808,6 @@ Statement::make_dec_statement(Expression* expr)
// Class Thunk_statement. This is the base class for go and defer
// statements.
-const char* const Thunk_statement::thunk_field_fn = "fn";
-
-const char* const Thunk_statement::thunk_field_receiver = "receiver";
-
// Constructor.
Thunk_statement::Thunk_statement(Statement_classification classification,
@@ -1862,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;
@@ -1918,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.
@@ -1991,6 +1978,29 @@ Gogo::simplify_thunk_statements()
this->traverse(&thunk_traverse);
}
+// Return true if the thunk function is a constant, which means that
+// it does not need to be passed to the thunk routine.
+
+bool
+Thunk_statement::is_constant_function() const
+{
+ Call_expression* ce = this->call_->call_expression();
+ Function_type* fntype = ce->get_function_type();
+ if (fntype == NULL)
+ {
+ go_assert(saw_errors());
+ return false;
+ }
+ if (fntype->is_builtin())
+ return true;
+ Expression* fn = ce->fn();
+ if (fn->func_expression() != NULL)
+ return fn->func_expression()->closure() == NULL;
+ if (fn->interface_field_reference_expression() != NULL)
+ return true;
+ return false;
+}
+
// Simplify complex thunk statements into simple ones. A complicated
// thunk statement is one which takes anything other than zero
// parameters or a single pointer parameter. We rewrite it into code
@@ -2028,17 +2038,15 @@ 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();
- const bool is_method = bound_method != NULL || interface_method != NULL;
source_location location = this->location();
std::string thunk_name = Gogo::thunk_name();
// Build the thunk.
- this->build_thunk(gogo, thunk_name, fntype);
+ this->build_thunk(gogo, thunk_name);
// Generate code to call the thunk.
@@ -2046,38 +2054,11 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
// argument to the thunk.
Expression_list* vals = new Expression_list();
- if (fntype->is_builtin())
- ;
- else if (!is_method)
+ if (!this->is_constant_function())
vals->push_back(fn);
- else if (interface_method != NULL)
- vals->push_back(interface_method->expr());
- else if (bound_method != NULL)
- {
- vals->push_back(bound_method->method());
- 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);
- }
- else
- go_unreachable();
+ if (interface_method != NULL)
+ vals->push_back(interface_method->expr());
if (ce->args() != NULL)
{
@@ -2152,45 +2133,33 @@ Thunk_statement::build_struct(Function_type* fntype)
Call_expression* ce = this->call_->call_expression();
Expression* fn = ce->fn();
+ if (!this->is_constant_function())
+ {
+ // The function to call.
+ fields->push_back(Struct_field(Typed_identifier("fn", fntype,
+ location)));
+ }
+
+ // If this thunk statement calls a method on an interface, we pass
+ // the interface object to the thunk.
Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression();
if (interface_method != NULL)
{
- // If this thunk statement calls a method on an interface, we
- // pass the interface object to the thunk.
- Typed_identifier tid(Thunk_statement::thunk_field_fn,
- interface_method->expr()->type(),
+ Typed_identifier tid("object", interface_method->expr()->type(),
location);
fields->push_back(Struct_field(tid));
}
- else if (!fntype->is_builtin())
- {
- // The function to call.
- Typed_identifier tid(Go_statement::thunk_field_fn, fntype, location);
- fields->push_back(Struct_field(tid));
- }
- else if (ce->is_recover_call())
+
+ // The predeclared recover function has no argument. However, we
+ // add an argument when building recover thunks. Handle that here.
+ if (ce->is_recover_call())
{
- // The predeclared recover function has no argument. However,
- // we add an argument when building recover thunks. Handle that
- // here.
fields->push_back(Struct_field(Typed_identifier("can_recover",
Type::lookup_bool_type(),
location)));
}
- 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(Thunk_statement::thunk_field_receiver, rtype,
- location);
- fields->push_back(Struct_field(tid));
- }
-
const Expression_list* args = ce->args();
if (args != NULL)
{
@@ -2213,8 +2182,7 @@ Thunk_statement::build_struct(Function_type* fntype)
// artificial, function.
void
-Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
- Function_type* fntype)
+Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
{
source_location location = this->location();
@@ -2301,43 +2269,33 @@ 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();
Expression* func_to_call;
unsigned int next_index;
- if (!fntype->is_builtin())
- {
- func_to_call = Expression::make_field_reference(thunk_parameter,
- 0, location);
- next_index = 1;
- }
- else
+ if (this->is_constant_function())
{
- go_assert(bound_method == NULL && interface_method == NULL);
func_to_call = ce->fn();
next_index = 0;
}
-
- if (bound_method != NULL)
+ else
{
- Expression* r = Expression::make_field_reference(thunk_parameter, 1,
- location);
- // The main program passes in a function pointer from the
- // interface expression, so here we can make a bound method in
- // all cases.
- func_to_call = Expression::make_bound_method(r, func_to_call,
- location);
- next_index = 2;
+ func_to_call = Expression::make_field_reference(thunk_parameter,
+ 0, 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);
+ Expression* r = Expression::make_field_reference(thunk_parameter, 0,
+ location);
const std::string& name(interface_method->name());
- func_to_call = Expression::make_interface_field_reference(func_to_call,
- name,
+ func_to_call = Expression::make_interface_field_reference(r, name,
location);
+ next_index = 1;
}
Expression_list* call_params = new Expression_list();
@@ -2373,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);