OSDN Git Service

Change Bound_method_expression to refer to a constant method.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Aug 2011 23:14:20 +0000 (23:14 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Aug 2011 23:14:20 +0000 (23:14 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178091 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/go/gofrontend/types.cc

index a082012..af29a30 100644 (file)
@@ -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
index ec59846..530ea4e 100644 (file)
@@ -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.
index f653ef6..c2caaa4 100644 (file)
@@ -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();
index 8b5263b..0a87a8b 100644 (file)
@@ -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
index 4b2ceeb..cf404a3 100644 (file)
@@ -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