diff options
Diffstat (limited to 'gcc/go/gofrontend/statements.cc')
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 159 |
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); |