OSDN Git Service

Lower calls to bound method expressions.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Aug 2011 22:06:19 +0000 (22:06 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Aug 2011 22:06:19 +0000 (22:06 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178264 138bc75d-0d04-0410-961f-82ee72b054a4

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

index af29a30..8957acb 100644 (file)
@@ -3845,7 +3845,7 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
     go_assert((et->points_to() != NULL
                && et->points_to()->channel_type() != NULL)
               || et->is_nil_type());
-  else if (t->is_unsafe_pointer_type())
+  else if (t->points_to() != NULL)
     go_assert(et->points_to() != NULL || et->is_nil_type());
   else if (et->is_unsafe_pointer_type())
     go_assert(t->points_to() != NULL);
@@ -3908,7 +3908,7 @@ class Unary_expression : public Expression
  public:
   Unary_expression(Operator op, Expression* expr, source_location location)
     : Expression(EXPRESSION_UNARY, location),
-      op_(op), escapes_(true), expr_(expr)
+      op_(op), escapes_(true), create_temp_(false), expr_(expr)
   { }
 
   // Return the operator.
@@ -3929,6 +3929,15 @@ class Unary_expression : public Expression
     this->escapes_ = false;
   }
 
+  // Record that this is an address expression which should create a
+  // temporary variable if necessary.  This is used for method calls.
+  void
+  set_create_temp()
+  {
+    go_assert(this->op_ == OPERATOR_AND);
+    this->create_temp_ = true;
+  }
+
   // Apply unary opcode OP to UVAL, setting VAL.  Return true if this
   // could be done, false if not.
   static bool
@@ -4004,6 +4013,9 @@ class Unary_expression : public Expression
   // Normally true.  False if this is an address expression which does
   // not escape the current function.
   bool escapes_;
+  // True if this is an address expression which should create a
+  // temporary variable if necessary.
+  bool create_temp_;
   // The operand.
   Expression* expr_;
 };
@@ -4428,7 +4440,10 @@ Unary_expression::do_check_types(Gogo*)
 
     case OPERATOR_AND:
       if (!this->expr_->is_addressable())
-       this->report_error(_("invalid operand for unary %<&%>"));
+       {
+         if (!this->create_temp_)
+           this->report_error(_("invalid operand for unary %<&%>"));
+       }
       else
        this->expr_->address_taken(this->escapes_);
       break;
@@ -4486,12 +4501,15 @@ Unary_expression::do_get_tree(Translate_context* context)
       return fold_build1_loc(loc, BIT_NOT_EXPR, TREE_TYPE(expr), expr);
 
     case OPERATOR_AND:
-      // We should not see a non-constant constructor here; cases
-      // where we would see one should have been moved onto the heap
-      // at parse time.  Taking the address of a nonconstant
-      // constructor will not do what the programmer expects.
-      go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
-      go_assert(TREE_CODE(expr) != ADDR_EXPR);
+      if (!this->create_temp_)
+       {
+         // We should not see a non-constant constructor here; cases
+         // where we would see one should have been moved onto the
+         // heap at parse time.  Taking the address of a nonconstant
+         // constructor will not do what the programmer expects.
+         go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
+         go_assert(TREE_CODE(expr) != ADDR_EXPR);
+       }
 
       // Build a decl for a constant constructor.
       if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr))
@@ -4510,6 +4528,22 @@ Unary_expression::do_get_tree(Translate_context* context)
          expr = decl;
        }
 
+      if (this->create_temp_
+         && !TREE_ADDRESSABLE(TREE_TYPE(expr))
+         && !DECL_P(expr)
+         && TREE_CODE(expr) != INDIRECT_REF
+         && TREE_CODE(expr) != COMPONENT_REF)
+       {
+         tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
+         DECL_IGNORED_P(tmp) = 1;
+         DECL_INITIAL(tmp) = expr;
+         TREE_ADDRESSABLE(tmp) = 1;
+         return build2_loc(loc, COMPOUND_EXPR,
+                           build_pointer_type(TREE_TYPE(expr)),
+                           build1_loc(loc, DECL_EXPR, void_type_node, tmp),
+                           build_fold_addr_expr_loc(loc, tmp));
+       }
+
       return build_fold_addr_expr_loc(loc, expr);
 
     case OPERATOR_MULT:
@@ -7223,7 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
          this->set_is_error();
          return this;
        }
-      return this->lower_varargs(gogo, function, inserter, slice_type, 2);
+      this->lower_varargs(gogo, function, inserter, slice_type, 2);
     }
 
   return this;
@@ -8805,12 +8839,14 @@ Expression*
 Call_expression::do_lower(Gogo* gogo, Named_object* function,
                          Statement_inserter* inserter, int)
 {
+  source_location loc = this->location();
+
   // A type cast can look like a function call.
   if (this->fn_->is_type_expression()
       && this->args_ != NULL
       && this->args_->size() == 1)
     return Expression::make_cast(this->fn_->type(), this->args_->front(),
-                                this->location());
+                                loc);
 
   // Recognize a call to a builtin function.
   Func_expression* fne = this->fn_->func_expression();
@@ -8818,7 +8854,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
       && fne->named_object()->is_function_declaration()
       && fne->named_object()->func_declaration_value()->type()->is_builtin())
     return new Builtin_call_expression(gogo, this->fn_, this->args_,
-                                      this->is_varargs_, this->location());
+                                      this->is_varargs_, loc);
 
   // Handle an argument which is a call to a function which returns
   // multiple results.
@@ -8862,8 +8898,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
           ++p)
        {
          Temporary_statement* temp = Statement::make_temporary(p->type(),
-                                                               NULL,
-                                                               p->location());
+                                                               NULL, loc);
          inserter->insert(temp);
          temps->push_back(temp);
        }
@@ -8879,8 +8914,58 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
       const Typed_identifier_list* parameters = fntype->parameters();
       go_assert(parameters != NULL && !parameters->empty());
       Type* varargs_type = parameters->back().type();
-      return this->lower_varargs(gogo, function, inserter, varargs_type,
-                                parameters->size());
+      this->lower_varargs(gogo, function, inserter, varargs_type,
+                         parameters->size());
+    }
+
+  // If this is call to a method, call the method directly passing the
+  // object as the first parameter.
+  Bound_method_expression* bme = this->fn_->bound_method_expression();
+  if (bme != NULL)
+    {
+      Named_object* method = bme->method();
+      Expression* first_arg = bme->first_argument();
+
+      // We always pass a pointer when calling a method.
+      if (first_arg->type()->points_to() == NULL
+         && !first_arg->type()->is_error())
+       {
+         first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
+         // We may need to create a temporary variable so that we can
+         // take the address.  We can't do that here because it will
+         // mess up the order of evaluation.
+         Unary_expression* ue = static_cast<Unary_expression*>(first_arg);
+         ue->set_create_temp();
+       }
+
+      // 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 = bme->first_argument_type();
+      if (fatype != NULL)
+       {
+         if (fatype->points_to() == NULL)
+           fatype = Type::make_pointer_type(fatype);
+         first_arg = Expression::make_unsafe_cast(fatype, first_arg, loc);
+       }
+
+      Expression_list* new_args = new Expression_list();
+      new_args->push_back(first_arg);
+      if (this->args_ != NULL)
+       {
+         for (Expression_list::const_iterator p = this->args_->begin();
+              p != this->args_->end();
+              ++p)
+           new_args->push_back(*p);
+       }
+
+      // We have to change in place because this structure may be
+      // referenced by Call_result_expressions.  We can't delete the
+      // old arguments, because we may be traversing them up in some
+      // caller.  FIXME.
+      this->args_ = new_args;
+      this->fn_ = Expression::make_func_reference(method, NULL,
+                                                 bme->location());
     }
 
   return this;
@@ -8893,13 +8978,13 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
 // calling; the last of these parameters will be the varargs
 // parameter.
 
-Expression*
+void
 Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
                               Statement_inserter* inserter,
                               Type* varargs_type, size_t param_count)
 {
   if (this->varargs_are_lowered_)
-    return this;
+    return;
 
   source_location loc = this->location();
 
@@ -8910,7 +8995,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   if (arg_count < param_count - 1)
     {
       // Not enough arguments; will be caught in check_types.
-      return this;
+      return;
     }
 
   Expression_list* old_args = this->args_;
@@ -8942,7 +9027,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
       else if (this->is_varargs_)
        {
          this->report_error(_("too many arguments"));
-         return this;
+         return;
        }
       else
        {
@@ -8960,6 +9045,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
            }
          Expression* val =
            Expression::make_slice_composite_literal(varargs_type, vals, loc);
+         gogo->lower_expression(function, inserter, &val);
          new_args->push_back(val);
        }
     }
@@ -8973,12 +9059,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   // Builtin_call_expression which refer to them.  FIXME.
   this->args_ = new_args;
   this->varargs_are_lowered_ = true;
-
-  // Lower all the new subexpressions.
-  Expression* ret = this;
-  gogo->lower_expression(function, inserter, &ret);
-  go_assert(ret == this);
-  return ret;
 }
 
 // Get the function type.  This can return NULL in error cases.
@@ -9102,10 +9182,28 @@ Call_expression::do_determine_type(const Type_context*)
       Typed_identifier_list::const_iterator pt;
       if (parameters != NULL)
        pt = parameters->begin();
+      bool first = true;
       for (Expression_list::const_iterator pa = this->args_->begin();
           pa != this->args_->end();
           ++pa)
        {
+         if (first)
+           {
+             first = false;
+             // If this is a method, the first argument is the
+             // receiver.
+             if (fntype != NULL && fntype->is_method())
+               {
+                 Type* rtype = fntype->receiver()->type();
+                 // The receiver is always passed as a pointer.
+                 if (rtype->points_to() == NULL)
+                   rtype = Type::make_pointer_type(rtype);
+                 Type_context subcontext(rtype, false);
+                 (*pa)->determine_type(&subcontext);
+                 continue;
+               }
+           }
+
          if (parameters != NULL && pt != parameters->end())
            {
              Type_context subcontext(pt->type(), false);
@@ -9172,35 +9270,28 @@ Call_expression::do_check_types(Gogo*)
       return;
     }
 
-  if (fntype->is_method())
+  bool is_method = fntype->is_method();
+  if (is_method)
     {
-      // We don't support pointers to methods, so the function has to
-      // be a bound method expression.
-      Bound_method_expression* bme = this->fn_->bound_method_expression();
-      if (bme == NULL)
-       {
-         this->report_error(_("method call without object"));
-         return;
-       }
-      Type* first_arg_type = bme->first_argument()->type();
-      if (first_arg_type->points_to() == NULL)
+      go_assert(this->args_ != NULL && !this->args_->empty());
+      Type* rtype = fntype->receiver()->type();
+      Expression* first_arg = this->args_->front();
+      // The language permits copying hidden fields for a method
+      // receiver.  We dereference the values since receivers are
+      // always passed as pointers.
+      std::string reason;
+      if (!Type::are_assignable_hidden_ok(rtype->deref(),
+                                         first_arg->type()->deref(),
+                                         &reason))
        {
-         // When passing a value, we need to check that we are
-         // permitted to copy it.  The language permits copying
-         // hidden fields for a method receiver.
-         std::string reason;
-         if (!Type::are_assignable_hidden_ok(fntype->receiver()->type(),
-                                             first_arg_type, &reason))
+         if (reason.empty())
+           this->report_error(_("incompatible type for receiver"));
+         else
            {
-             if (reason.empty())
-               this->report_error(_("incompatible type for receiver"));
-             else
-               {
-                 error_at(this->location(),
-                          "incompatible type for receiver (%s)",
-                          reason.c_str());
-                 this->set_is_error();
-               }
+             error_at(this->location(),
+                      "incompatible type for receiver (%s)",
+                      reason.c_str());
+             this->set_is_error();
            }
        }
     }
@@ -9215,25 +9306,30 @@ Call_expression::do_check_types(Gogo*)
        this->report_error(_("not enough arguments"));
     }
   else if (parameters == NULL)
-    this->report_error(_("too many arguments"));
+    {
+      if (!is_method || this->args_->size() > 1)
+       this->report_error(_("too many arguments"));
+    }
   else
     {
       int i = 0;
-      Typed_identifier_list::const_iterator pt = parameters->begin();
-      for (Expression_list::const_iterator pa = this->args_->begin();
-          pa != this->args_->end();
-          ++pa, ++pt, ++i)
-       {
-         if (pt == parameters->end())
+      Expression_list::const_iterator pa = this->args_->begin();
+      if (is_method)
+       ++pa;
+      for (Typed_identifier_list::const_iterator pt = parameters->begin();
+          pt != parameters->end();
+          ++pt, ++pa, ++i)
+       {
+         if (pa == this->args_->end())
            {
-             this->report_error(_("too many arguments"));
+             this->report_error(_("not enough arguments"));
              return;
            }
          this->check_argument_type(i + 1, pt->type(), (*pa)->type(),
                                    (*pa)->location(), false);
        }
-      if (pt != parameters->end())
-       this->report_error(_("not enough arguments"));
+      if (pa != this->args_->end())
+       this->report_error(_("too many arguments"));
     }
 }
 
@@ -9247,83 +9343,6 @@ Call_expression::do_must_eval_in_order() const
   return this->result_count() > 0;
 }
 
-// Get the function and the first argument to use when calling a bound
-// method.
-
-tree
-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)
-    return error_mark_node;
-
-  // We always pass a pointer to the first argument when calling a
-  // method.
-  if (first_argument->type()->points_to() == NULL)
-    {
-      tree pointer_to_arg_type = build_pointer_type(TREE_TYPE(first_arg));
-      if (TREE_ADDRESSABLE(TREE_TYPE(first_arg))
-         || DECL_P(first_arg)
-         || TREE_CODE(first_arg) == INDIRECT_REF
-         || TREE_CODE(first_arg) == COMPONENT_REF)
-       {
-         first_arg = build_fold_addr_expr_loc(loc, first_arg);
-         if (DECL_P(first_arg))
-           TREE_ADDRESSABLE(first_arg) = 1;
-       }
-      else
-       {
-         tree tmp = create_tmp_var(TREE_TYPE(first_arg),
-                                   get_name(first_arg));
-         DECL_IGNORED_P(tmp) = 0;
-         DECL_INITIAL(tmp) = first_arg;
-         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)
-       return error_mark_node;
-    }
-
-  Type* fatype = bound_method->first_argument_type();
-  if (fatype != NULL)
-    {
-      if (fatype->points_to() == NULL)
-       fatype = Type::make_pointer_type(fatype);
-      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;
-    }
-
-  *first_arg_ptr = first_arg;
-
-  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
 // interface method.
 
@@ -9363,35 +9382,46 @@ Call_expression::do_get_tree(Translate_context* context)
   source_location location = this->location();
 
   Func_expression* func = this->fn_->func_expression();
-  Bound_method_expression* bound_method = this->fn_->bound_method_expression();
   Interface_field_reference_expression* interface_method =
     this->fn_->interface_field_reference_expression();
   const bool has_closure = func != NULL && func->closure() != NULL;
-  const bool is_method = bound_method != NULL || interface_method != NULL;
-  go_assert(!fntype->is_method() || is_method);
+  const bool is_interface_method = interface_method != NULL;
 
   int nargs;
   tree* args;
   if (this->args_ == NULL || this->args_->empty())
     {
-      nargs = is_method ? 1 : 0;
+      nargs = is_interface_method ? 1 : 0;
       args = nargs == 0 ? NULL : new tree[nargs];
     }
+  else if (fntype->parameters() == NULL || fntype->parameters()->empty())
+    {
+      // Passing a receiver parameter.
+      go_assert(!is_interface_method
+               && fntype->is_method()
+               && this->args_->size() == 1);
+      nargs = 1;
+      args = new tree[nargs];
+      args[0] = this->args_->front()->get_tree(context);
+    }
   else
     {
       const Typed_identifier_list* params = fntype->parameters();
-      go_assert(params != NULL);
 
       nargs = this->args_->size();
-      int i = is_method ? 1 : 0;
+      int i = is_interface_method ? 1 : 0;
       nargs += i;
       args = new tree[nargs];
 
       Typed_identifier_list::const_iterator pp = params->begin();
-      Expression_list::const_iterator pe;
-      for (pe = this->args_->begin();
-          pe != this->args_->end();
-          ++pe, ++pp, ++i)
+      Expression_list::const_iterator pe = this->args_->begin();
+      if (!is_interface_method && fntype->is_method())
+       {
+         args[i] = (*pe)->get_tree(context);
+         ++pe;
+         ++i;
+       }
+      for (; pe != this->args_->end(); ++pe, ++pp, ++i)
        {
          go_assert(pp != params->end());
          tree arg_val = (*pe)->get_tree(context);
@@ -9420,14 +9450,10 @@ Call_expression::do_get_tree(Translate_context* context)
   tree fn;
   if (has_closure)
     fn = func->get_tree_without_closure(gogo);
-  else if (!is_method)
+  else if (!is_interface_method)
     fn = this->fn_->get_tree(context);
-  else if (bound_method != NULL)
-    fn = this->bound_method_function(context, bound_method, &args[0]);
-  else if (interface_method != NULL)
-    fn = this->interface_method_function(context, interface_method, &args[0]);
   else
-    go_unreachable();
+    fn = this->interface_method_function(context, interface_method, &args[0]);
 
   if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
     {
index 530ea4e..bb4f23e 100644 (file)
@@ -1244,6 +1244,11 @@ class Call_expression : public Expression
   is_varargs() const
   { return this->is_varargs_; }
 
+  // Note that varargs have already been lowered.
+  void
+  set_varargs_are_lowered()
+  { this->varargs_are_lowered_ = true; }
+
   // Whether this call is being deferred.
   bool
   is_deferred() const
@@ -1307,7 +1312,7 @@ class Call_expression : public Expression
   { this->args_ = args; }
 
   // Let a builtin expression lower varargs.
-  Expression*
+  void
   lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
                Type* varargs_type, size_t param_count);
 
@@ -1324,9 +1329,6 @@ class Call_expression : public Expression
   check_argument_type(int, const Type*, const Type*, source_location, bool);
 
   tree
-  bound_method_function(Translate_context*, Bound_method_expression*, tree*);
-
-  tree
   interface_method_function(Translate_context*,
                            Interface_field_reference_expression*,
                            tree*);
index c2caaa4..e646227 100644 (file)
@@ -1858,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;
@@ -1914,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.
@@ -2005,8 +1996,7 @@ Thunk_statement::is_constant_function() const
   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)
+  if (fn->interface_field_reference_expression() != NULL)
     return true;
   return false;
 }
@@ -2048,7 +2038,6 @@ 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();
 
@@ -2071,30 +2060,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
   if (interface_method != NULL)
     vals->push_back(interface_method->expr());
 
-  if (bound_method != NULL)
-    {
-      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);
-    }
-
   if (ce->args() != NULL)
     {
       for (Expression_list::const_iterator p = ce->args()->begin();
@@ -2186,19 +2151,6 @@ Thunk_statement::build_struct(Function_type* fntype)
       fields->push_back(Struct_field(tid));
     }
 
-  // If this is a method call, pass down the expression we are
-  // calling.
-  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("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())
@@ -2317,7 +2269,6 @@ 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();
 
@@ -2335,16 +2286,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
       next_index = 1;
     }
 
-  if (bound_method != NULL)
-    {
-      go_assert(next_index == 0);
-      Expression* r = Expression::make_field_reference(thunk_parameter, 0,
-                                                      location);
-      func_to_call = Expression::make_bound_method(r, bound_method->method(),
-                                                  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);
@@ -2389,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);