Commit 48ab8ba6 by Ian Lance Taylor

Change Bound_method_expression to refer to a constant method.

From-SVN: r178091
parent 2e335040
...@@ -6798,9 +6798,7 @@ Expression::comparison_tree(Translate_context* context, Operator op, ...@@ -6798,9 +6798,7 @@ Expression::comparison_tree(Translate_context* context, Operator op,
int int
Bound_method_expression::do_traverse(Traverse* traverse) Bound_method_expression::do_traverse(Traverse* traverse)
{ {
if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT) return Expression::traverse(&this->expr_, traverse);
return TRAVERSE_EXIT;
return Expression::traverse(&this->method_, traverse);
} }
// Return the type of a bound method expression. The type of this // Return the type of a bound method expression. The type of this
...@@ -6811,7 +6809,12 @@ Bound_method_expression::do_traverse(Traverse* traverse) ...@@ -6811,7 +6809,12 @@ Bound_method_expression::do_traverse(Traverse* traverse)
Type* Type*
Bound_method_expression::do_type() Bound_method_expression::do_type()
{ {
return this->method_->type(); if (this->method_->is_function())
return this->method_->func_value()->type();
else if (this->method_->is_function_declaration())
return this->method_->func_declaration_value()->type();
else
return Type::make_error_type();
} }
// Determine the types of a method expression. // Determine the types of a method expression.
...@@ -6819,9 +6822,7 @@ Bound_method_expression::do_type() ...@@ -6819,9 +6822,7 @@ Bound_method_expression::do_type()
void void
Bound_method_expression::do_determine_type(const Type_context*) Bound_method_expression::do_determine_type(const Type_context*)
{ {
this->method_->determine_type_no_context(); Function_type* fntype = this->type()->function_type();
Type* mtype = this->method_->type();
Function_type* fntype = mtype == NULL ? NULL : mtype->function_type();
if (fntype == NULL || !fntype->is_method()) if (fntype == NULL || !fntype->is_method())
this->expr_->determine_type_no_context(); this->expr_->determine_type_no_context();
else else
...@@ -6836,14 +6837,12 @@ Bound_method_expression::do_determine_type(const Type_context*) ...@@ -6836,14 +6837,12 @@ Bound_method_expression::do_determine_type(const Type_context*)
void void
Bound_method_expression::do_check_types(Gogo*) Bound_method_expression::do_check_types(Gogo*)
{ {
Type* type = this->method_->type()->deref(); if (!this->method_->is_function()
if (type == NULL && !this->method_->is_function_declaration())
|| type->function_type() == NULL
|| !type->function_type()->is_method())
this->report_error(_("object is not a method")); this->report_error(_("object is not a method"));
else else
{ {
Type* rtype = type->function_type()->receiver()->type()->deref(); Type* rtype = this->type()->function_type()->receiver()->type()->deref();
Type* etype = (this->expr_type_ != NULL Type* etype = (this->expr_type_ != NULL
? this->expr_type_ ? this->expr_type_
: this->expr_->type()); : this->expr_->type());
...@@ -6881,14 +6880,13 @@ Bound_method_expression::do_dump_expression(Ast_dump_context* ast_dump_context) ...@@ -6881,14 +6880,13 @@ Bound_method_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
ast_dump_context->ostream() << ")"; ast_dump_context->ostream() << ")";
} }
ast_dump_context->ostream() << "."; ast_dump_context->ostream() << "." << this->method_->name();
ast_dump_context->dump_expression(method_);
} }
// Make a method expression. // Make a method expression.
Bound_method_expression* Bound_method_expression*
Expression::make_bound_method(Expression* expr, Expression* method, Expression::make_bound_method(Expression* expr, Named_object* method,
source_location location) source_location location)
{ {
return new Bound_method_expression(expr, method, location); return new Bound_method_expression(expr, method, location);
...@@ -9257,6 +9255,9 @@ Call_expression::bound_method_function(Translate_context* context, ...@@ -9257,6 +9255,9 @@ Call_expression::bound_method_function(Translate_context* context,
Bound_method_expression* bound_method, Bound_method_expression* bound_method,
tree* first_arg_ptr) tree* first_arg_ptr)
{ {
Gogo* gogo = context->gogo();
source_location loc = this->location();
Expression* first_argument = bound_method->first_argument(); Expression* first_argument = bound_method->first_argument();
tree first_arg = first_argument->get_tree(context); tree first_arg = first_argument->get_tree(context);
if (first_arg == error_mark_node) if (first_arg == error_mark_node)
...@@ -9272,7 +9273,7 @@ Call_expression::bound_method_function(Translate_context* context, ...@@ -9272,7 +9273,7 @@ Call_expression::bound_method_function(Translate_context* context,
|| TREE_CODE(first_arg) == INDIRECT_REF || TREE_CODE(first_arg) == INDIRECT_REF
|| TREE_CODE(first_arg) == COMPONENT_REF) || TREE_CODE(first_arg) == COMPONENT_REF)
{ {
first_arg = build_fold_addr_expr(first_arg); first_arg = build_fold_addr_expr_loc(loc, first_arg);
if (DECL_P(first_arg)) if (DECL_P(first_arg))
TREE_ADDRESSABLE(first_arg) = 1; TREE_ADDRESSABLE(first_arg) = 1;
} }
...@@ -9282,9 +9283,10 @@ Call_expression::bound_method_function(Translate_context* context, ...@@ -9282,9 +9283,10 @@ Call_expression::bound_method_function(Translate_context* context,
get_name(first_arg)); get_name(first_arg));
DECL_IGNORED_P(tmp) = 0; DECL_IGNORED_P(tmp) = 0;
DECL_INITIAL(tmp) = first_arg; DECL_INITIAL(tmp) = first_arg;
first_arg = build2(COMPOUND_EXPR, pointer_to_arg_type, first_arg = build2_loc(loc, COMPOUND_EXPR, pointer_to_arg_type,
build1(DECL_EXPR, void_type_node, tmp), build1_loc(loc, DECL_EXPR, void_type_node,
build_fold_addr_expr(tmp)); tmp),
build_fold_addr_expr_loc(loc, tmp));
TREE_ADDRESSABLE(tmp) = 1; TREE_ADDRESSABLE(tmp) = 1;
} }
if (first_arg == error_mark_node) if (first_arg == error_mark_node)
...@@ -9296,8 +9298,8 @@ Call_expression::bound_method_function(Translate_context* context, ...@@ -9296,8 +9298,8 @@ Call_expression::bound_method_function(Translate_context* context,
{ {
if (fatype->points_to() == NULL) if (fatype->points_to() == NULL)
fatype = Type::make_pointer_type(fatype); fatype = Type::make_pointer_type(fatype);
Btype* bfatype = fatype->get_backend(context->gogo()); Btype* bfatype = fatype->get_backend(gogo);
first_arg = fold_convert(type_to_tree(bfatype), first_arg); first_arg = fold_convert_loc(loc, type_to_tree(bfatype), first_arg);
if (first_arg == error_mark_node if (first_arg == error_mark_node
|| TREE_TYPE(first_arg) == error_mark_node) || TREE_TYPE(first_arg) == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -9305,7 +9307,21 @@ Call_expression::bound_method_function(Translate_context* context, ...@@ -9305,7 +9307,21 @@ Call_expression::bound_method_function(Translate_context* context,
*first_arg_ptr = first_arg; *first_arg_ptr = first_arg;
return bound_method->method()->get_tree(context); 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 // Get the function and the first argument to use when calling an
......
...@@ -192,7 +192,7 @@ class Expression ...@@ -192,7 +192,7 @@ class Expression
// Make an expression which is a method bound to its first // Make an expression which is a method bound to its first
// parameter. // parameter.
static Bound_method_expression* static Bound_method_expression*
make_bound_method(Expression* object, Expression* method, source_location); make_bound_method(Expression* object, Named_object* method, source_location);
// Make an index or slice expression. This is a parser expression // Make an index or slice expression. This is a parser expression
// which represents LEFT[START:END]. END may be NULL, meaning an // which represents LEFT[START:END]. END may be NULL, meaning an
...@@ -1636,7 +1636,7 @@ class Map_index_expression : public Expression ...@@ -1636,7 +1636,7 @@ class Map_index_expression : public Expression
class Bound_method_expression : public Expression class Bound_method_expression : public Expression
{ {
public: public:
Bound_method_expression(Expression* expr, Expression* method, Bound_method_expression(Expression* expr, Named_object* method,
source_location location) source_location location)
: Expression(EXPRESSION_BOUND_METHOD, location), : Expression(EXPRESSION_BOUND_METHOD, location),
expr_(expr), expr_type_(NULL), method_(method) expr_(expr), expr_type_(NULL), method_(method)
...@@ -1654,8 +1654,8 @@ class Bound_method_expression : public Expression ...@@ -1654,8 +1654,8 @@ class Bound_method_expression : public Expression
first_argument_type() const first_argument_type() const
{ return this->expr_type_; } { return this->expr_type_; }
// Return the reference to the method function. // Return the method function.
Expression* Named_object*
method() method()
{ return this->method_; } { return this->method_; }
...@@ -1680,8 +1680,7 @@ class Bound_method_expression : public Expression ...@@ -1680,8 +1680,7 @@ class Bound_method_expression : public Expression
Expression* Expression*
do_copy() do_copy()
{ {
return new Bound_method_expression(this->expr_->copy(), return new Bound_method_expression(this->expr_->copy(), this->method_,
this->method_->copy(),
this->location()); this->location());
} }
...@@ -1699,8 +1698,8 @@ class Bound_method_expression : public Expression ...@@ -1699,8 +1698,8 @@ class Bound_method_expression : public Expression
// NULL in the normal case, non-NULL when using a method from an // NULL in the normal case, non-NULL when using a method from an
// anonymous field which does not require a stub. // anonymous field which does not require a stub.
Type* expr_type_; Type* expr_type_;
// The method itself. This is a Func_expression. // The method itself.
Expression* method_; Named_object* method_;
}; };
// A reference to a field in a struct. // A reference to a field in a struct.
......
...@@ -1808,10 +1808,6 @@ Statement::make_dec_statement(Expression* expr) ...@@ -1808,10 +1808,6 @@ Statement::make_dec_statement(Expression* expr)
// Class Thunk_statement. This is the base class for go and defer // Class Thunk_statement. This is the base class for go and defer
// statements. // statements.
const char* const Thunk_statement::thunk_field_fn = "fn";
const char* const Thunk_statement::thunk_field_receiver = "receiver";
// Constructor. // Constructor.
Thunk_statement::Thunk_statement(Statement_classification classification, Thunk_statement::Thunk_statement(Statement_classification classification,
...@@ -1991,6 +1987,30 @@ Gogo::simplify_thunk_statements() ...@@ -1991,6 +1987,30 @@ Gogo::simplify_thunk_statements()
this->traverse(&thunk_traverse); 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->bound_method_expression() != NULL
|| fn->interface_field_reference_expression() != NULL)
return true;
return false;
}
// Simplify complex thunk statements into simple ones. A complicated // Simplify complex thunk statements into simple ones. A complicated
// thunk statement is one which takes anything other than zero // thunk statement is one which takes anything other than zero
// parameters or a single pointer parameter. We rewrite it into code // parameters or a single pointer parameter. We rewrite it into code
...@@ -2031,14 +2051,13 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, ...@@ -2031,14 +2051,13 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
Bound_method_expression* bound_method = fn->bound_method_expression(); Bound_method_expression* bound_method = fn->bound_method_expression();
Interface_field_reference_expression* interface_method = Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression(); fn->interface_field_reference_expression();
const bool is_method = bound_method != NULL || interface_method != NULL;
source_location location = this->location(); source_location location = this->location();
std::string thunk_name = Gogo::thunk_name(); std::string thunk_name = Gogo::thunk_name();
// Build the thunk. // Build the thunk.
this->build_thunk(gogo, thunk_name, fntype); this->build_thunk(gogo, thunk_name);
// Generate code to call the thunk. // Generate code to call the thunk.
...@@ -2046,15 +2065,14 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, ...@@ -2046,15 +2065,14 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
// argument to the thunk. // argument to the thunk.
Expression_list* vals = new Expression_list(); Expression_list* vals = new Expression_list();
if (fntype->is_builtin()) if (!this->is_constant_function())
;
else if (!is_method)
vals->push_back(fn); vals->push_back(fn);
else if (interface_method != NULL)
if (interface_method != NULL)
vals->push_back(interface_method->expr()); vals->push_back(interface_method->expr());
else if (bound_method != NULL)
if (bound_method != NULL)
{ {
vals->push_back(bound_method->method());
Expression* first_arg = bound_method->first_argument(); Expression* first_arg = bound_method->first_argument();
// We always pass a pointer when calling a method. // We always pass a pointer when calling a method.
...@@ -2076,8 +2094,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, ...@@ -2076,8 +2094,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
vals->push_back(first_arg); vals->push_back(first_arg);
} }
else
go_unreachable();
if (ce->args() != NULL) if (ce->args() != NULL)
{ {
...@@ -2152,33 +2168,26 @@ Thunk_statement::build_struct(Function_type* fntype) ...@@ -2152,33 +2168,26 @@ Thunk_statement::build_struct(Function_type* fntype)
Call_expression* ce = this->call_->call_expression(); Call_expression* ce = this->call_->call_expression();
Expression* fn = ce->fn(); 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 = Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression(); fn->interface_field_reference_expression();
if (interface_method != NULL) if (interface_method != NULL)
{ {
// If this thunk statement calls a method on an interface, we Typed_identifier tid("object", interface_method->expr()->type(),
// pass the interface object to the thunk.
Typed_identifier tid(Thunk_statement::thunk_field_fn,
interface_method->expr()->type(),
location); location);
fields->push_back(Struct_field(tid)); 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.
fields->push_back(Struct_field(Typed_identifier("can_recover",
Type::lookup_bool_type(),
location)));
}
// If this is a method call, pass down the expression we are
// calling.
if (fn->bound_method_expression() != NULL) if (fn->bound_method_expression() != NULL)
{ {
go_assert(fntype->is_method()); go_assert(fntype->is_method());
...@@ -2186,11 +2195,19 @@ Thunk_statement::build_struct(Function_type* fntype) ...@@ -2186,11 +2195,19 @@ Thunk_statement::build_struct(Function_type* fntype)
// We always pass the receiver as a pointer. // We always pass the receiver as a pointer.
if (rtype->points_to() == NULL) if (rtype->points_to() == NULL)
rtype = Type::make_pointer_type(rtype); rtype = Type::make_pointer_type(rtype);
Typed_identifier tid(Thunk_statement::thunk_field_receiver, rtype, Typed_identifier tid("receiver", rtype, location);
location);
fields->push_back(Struct_field(tid)); 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())
{
fields->push_back(Struct_field(Typed_identifier("can_recover",
Type::lookup_bool_type(),
location)));
}
const Expression_list* args = ce->args(); const Expression_list* args = ce->args();
if (args != NULL) if (args != NULL)
{ {
...@@ -2213,8 +2230,7 @@ Thunk_statement::build_struct(Function_type* fntype) ...@@ -2213,8 +2230,7 @@ Thunk_statement::build_struct(Function_type* fntype)
// artificial, function. // artificial, function.
void void
Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
Function_type* fntype)
{ {
source_location location = this->location(); source_location location = this->location();
...@@ -2307,37 +2323,37 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, ...@@ -2307,37 +2323,37 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
Expression* func_to_call; Expression* func_to_call;
unsigned int next_index; unsigned int next_index;
if (!fntype->is_builtin()) if (this->is_constant_function())
{ {
func_to_call = Expression::make_field_reference(thunk_parameter, func_to_call = ce->fn();
0, location); next_index = 0;
next_index = 1;
} }
else else
{ {
go_assert(bound_method == NULL && interface_method == NULL); func_to_call = Expression::make_field_reference(thunk_parameter,
func_to_call = ce->fn(); 0, location);
next_index = 0; next_index = 1;
} }
if (bound_method != NULL) if (bound_method != NULL)
{ {
Expression* r = Expression::make_field_reference(thunk_parameter, 1, go_assert(next_index == 0);
Expression* r = Expression::make_field_reference(thunk_parameter, 0,
location); location);
// The main program passes in a function pointer from the func_to_call = Expression::make_bound_method(r, bound_method->method(),
// 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); location);
next_index = 2; next_index = 1;
} }
else if (interface_method != NULL) else if (interface_method != NULL)
{ {
// The main program passes the interface object. // 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()); const std::string& name(interface_method->name());
func_to_call = Expression::make_interface_field_reference(func_to_call, func_to_call = Expression::make_interface_field_reference(r, name,
name,
location); location);
next_index = 1;
} }
Expression_list* call_params = new Expression_list(); Expression_list* call_params = new Expression_list();
......
...@@ -906,21 +906,17 @@ class Thunk_statement : public Statement ...@@ -906,21 +906,17 @@ class Thunk_statement : public Statement
bool bool
is_simple(Function_type*) const; is_simple(Function_type*) const;
// Return whether the thunk function is a constant.
bool
is_constant_function() const;
// Build the struct to use for a complex case. // Build the struct to use for a complex case.
Struct_type* Struct_type*
build_struct(Function_type* fntype); build_struct(Function_type* fntype);
// Build the thunk. // Build the thunk.
void void
build_thunk(Gogo*, const std::string&, Function_type* fntype); build_thunk(Gogo*, const std::string&);
// The field name used in the thunk structure for the function
// pointer.
static const char* const thunk_field_fn;
// The field name used in the thunk structure for the receiver, if
// there is one.
static const char* const thunk_field_receiver;
// Set the name to use for thunk field N. // Set the name to use for thunk field N.
void void
......
...@@ -6085,10 +6085,7 @@ Method::bind_method(Expression* expr, source_location location) const ...@@ -6085,10 +6085,7 @@ Method::bind_method(Expression* expr, source_location location) const
// the child class. // the child class.
return this->do_bind_method(expr, location); return this->do_bind_method(expr, location);
} }
return Expression::make_bound_method(expr, this->stub_, location);
Expression* func = Expression::make_func_reference(this->stub_, NULL,
location);
return Expression::make_bound_method(expr, func, location);
} }
// Return the named object associated with a method. This may only be // Return the named object associated with a method. This may only be
...@@ -6130,9 +6127,8 @@ Named_method::do_receiver_location() const ...@@ -6130,9 +6127,8 @@ Named_method::do_receiver_location() const
Expression* Expression*
Named_method::do_bind_method(Expression* expr, source_location location) const Named_method::do_bind_method(Expression* expr, source_location location) const
{ {
Expression* func = Expression::make_func_reference(this->named_object_, NULL, Named_object* no = this->named_object_;
location); Bound_method_expression* bme = Expression::make_bound_method(expr, no,
Bound_method_expression* bme = Expression::make_bound_method(expr, func,
location); location);
// If this is not a local method, and it does not use a stub, then // If this is not a local method, and it does not use a stub, then
// the real method expects a different type. We need to cast the // the real method expects a different type. We need to cast the
......
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