diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-08-25 23:14:20 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-08-25 23:14:20 +0000 |
commit | 48ab8ba6b82ce10cb5f726d2ae95d4b4b857ba9c (patch) | |
tree | f2687d565e5bf329a4cdc9c5a8665365460a026e /gcc/go/gofrontend | |
parent | 2e335040bcd1fddb5a775d537092c5a3b783263e (diff) | |
download | gcc-48ab8ba6b82ce10cb5f726d2ae95d4b4b857ba9c.zip gcc-48ab8ba6b82ce10cb5f726d2ae95d4b4b857ba9c.tar.gz gcc-48ab8ba6b82ce10cb5f726d2ae95d4b4b857ba9c.tar.bz2 |
Change Bound_method_expression to refer to a constant method.
From-SVN: r178091
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 60 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 120 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 10 |
5 files changed, 121 insertions, 98 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a082012..af29a30 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6798,9 +6798,7 @@ Expression::comparison_tree(Translate_context* context, Operator op, int Bound_method_expression::do_traverse(Traverse* traverse) { - if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Expression::traverse(&this->method_, traverse); + return Expression::traverse(&this->expr_, traverse); } // Return the type of a bound method expression. The type of this @@ -6811,7 +6809,12 @@ Bound_method_expression::do_traverse(Traverse* traverse) 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. @@ -6819,9 +6822,7 @@ Bound_method_expression::do_type() void Bound_method_expression::do_determine_type(const Type_context*) { - this->method_->determine_type_no_context(); - Type* mtype = this->method_->type(); - Function_type* fntype = mtype == NULL ? NULL : mtype->function_type(); + Function_type* fntype = this->type()->function_type(); if (fntype == NULL || !fntype->is_method()) this->expr_->determine_type_no_context(); else @@ -6836,14 +6837,12 @@ Bound_method_expression::do_determine_type(const Type_context*) void Bound_method_expression::do_check_types(Gogo*) { - Type* type = this->method_->type()->deref(); - if (type == NULL - || type->function_type() == NULL - || !type->function_type()->is_method()) + if (!this->method_->is_function() + && !this->method_->is_function_declaration()) this->report_error(_("object is not a method")); else { - Type* rtype = type->function_type()->receiver()->type()->deref(); + Type* rtype = this->type()->function_type()->receiver()->type()->deref(); Type* etype = (this->expr_type_ != NULL ? this->expr_type_ : this->expr_->type()); @@ -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->dump_expression(method_); + ast_dump_context->ostream() << "." << this->method_->name(); } // Make a 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) { return new Bound_method_expression(expr, method, location); @@ -9257,6 +9255,9 @@ 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) @@ -9272,7 +9273,7 @@ Call_expression::bound_method_function(Translate_context* context, || TREE_CODE(first_arg) == INDIRECT_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)) TREE_ADDRESSABLE(first_arg) = 1; } @@ -9282,9 +9283,10 @@ Call_expression::bound_method_function(Translate_context* context, get_name(first_arg)); DECL_IGNORED_P(tmp) = 0; DECL_INITIAL(tmp) = first_arg; - first_arg = build2(COMPOUND_EXPR, pointer_to_arg_type, - build1(DECL_EXPR, void_type_node, tmp), - build_fold_addr_expr(tmp)); + 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) @@ -9296,8 +9298,8 @@ Call_expression::bound_method_function(Translate_context* context, { if (fatype->points_to() == NULL) fatype = Type::make_pointer_type(fatype); - Btype* bfatype = fatype->get_backend(context->gogo()); - first_arg = fold_convert(type_to_tree(bfatype), first_arg); + 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; @@ -9305,7 +9307,21 @@ Call_expression::bound_method_function(Translate_context* context, *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 diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index ec59846..530ea4e 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -192,7 +192,7 @@ class Expression // Make an expression which is a method bound to its first // parameter. 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 // which represents LEFT[START:END]. END may be NULL, meaning an @@ -1636,7 +1636,7 @@ class Map_index_expression : public Expression class Bound_method_expression : public Expression { public: - Bound_method_expression(Expression* expr, Expression* method, + Bound_method_expression(Expression* expr, Named_object* method, source_location location) : Expression(EXPRESSION_BOUND_METHOD, location), expr_(expr), expr_type_(NULL), method_(method) @@ -1654,8 +1654,8 @@ class Bound_method_expression : public Expression first_argument_type() const { return this->expr_type_; } - // Return the reference to the method function. - Expression* + // Return the method function. + Named_object* method() { return this->method_; } @@ -1680,8 +1680,7 @@ class Bound_method_expression : public Expression Expression* do_copy() { - return new Bound_method_expression(this->expr_->copy(), - this->method_->copy(), + return new Bound_method_expression(this->expr_->copy(), this->method_, this->location()); } @@ -1699,8 +1698,8 @@ class Bound_method_expression : public Expression // NULL in the normal case, non-NULL when using a method from an // anonymous field which does not require a stub. Type* expr_type_; - // The method itself. This is a Func_expression. - Expression* method_; + // The method itself. + Named_object* method_; }; // A reference to a field in a struct. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index f653ef6..c2caaa4 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, @@ -1991,6 +1987,30 @@ 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->bound_method_expression() != NULL + || 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 @@ -2031,14 +2051,13 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, 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,15 +2065,14 @@ 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) + + if (interface_method != NULL) 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(); // We always pass a pointer when calling a method. @@ -2076,8 +2094,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, vals->push_back(first_arg); } - else - go_unreachable(); if (ce->args() != NULL) { @@ -2152,33 +2168,26 @@ 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. - 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) { go_assert(fntype->is_method()); @@ -2186,11 +2195,19 @@ Thunk_statement::build_struct(Function_type* fntype) // 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); + 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()) + { + fields->push_back(Struct_field(Typed_identifier("can_recover", + Type::lookup_bool_type(), + location))); + } + const Expression_list* args = ce->args(); if (args != NULL) { @@ -2213,8 +2230,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(); @@ -2307,37 +2323,37 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Expression* func_to_call; unsigned int next_index; - if (!fntype->is_builtin()) + if (this->is_constant_function()) { - func_to_call = Expression::make_field_reference(thunk_parameter, - 0, location); - next_index = 1; + func_to_call = ce->fn(); + next_index = 0; } else { - go_assert(bound_method == NULL && interface_method == NULL); - func_to_call = ce->fn(); - next_index = 0; + func_to_call = Expression::make_field_reference(thunk_parameter, + 0, location); + next_index = 1; } 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); - // 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, + func_to_call = Expression::make_bound_method(r, bound_method->method(), location); - next_index = 2; + next_index = 1; } else 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(); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 8b5263b..0a87a8b 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -906,21 +906,17 @@ class Thunk_statement : public Statement bool 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. Struct_type* build_struct(Function_type* fntype); // Build the thunk. void - build_thunk(Gogo*, const std::string&, Function_type* fntype); - - // 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; + build_thunk(Gogo*, const std::string&); // Set the name to use for thunk field N. void diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 4b2ceeb..cf404a3 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -6085,10 +6085,7 @@ Method::bind_method(Expression* expr, source_location location) const // the child class. return this->do_bind_method(expr, location); } - - Expression* func = Expression::make_func_reference(this->stub_, NULL, - location); - return Expression::make_bound_method(expr, func, location); + return Expression::make_bound_method(expr, this->stub_, location); } // Return the named object associated with a method. This may only be @@ -6130,9 +6127,8 @@ Named_method::do_receiver_location() const Expression* Named_method::do_bind_method(Expression* expr, source_location location) const { - Expression* func = Expression::make_func_reference(this->named_object_, NULL, - location); - Bound_method_expression* bme = Expression::make_bound_method(expr, func, + Named_object* no = this->named_object_; + Bound_method_expression* bme = Expression::make_bound_method(expr, no, location); // 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 |