This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Lower calls to bound method expressions


This patch to the Go frontend lowers calls to bound method expressions,
rather than handling them when converting to GENERIC.  Bootstrapped and
ran Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian

diff -r 5097a3ef0927 go/expressions.cc
--- a/go/expressions.cc	Mon Aug 29 15:00:07 2011 -0700
+++ b/go/expressions.cc	Mon Aug 29 15:02:20 2011 -0700
@@ -3845,7 +3845,7 @@
     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 @@
  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 @@
     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 @@
   // 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 @@
 
     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 @@
       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 @@
 	  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 @@
 	  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 @@
 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 @@
       && 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 @@
 	   ++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 @@
       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 @@
 // 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 @@
   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 @@
       else if (this->is_varargs_)
 	{
 	  this->report_error(_("too many arguments"));
-	  return this;
+	  return;
 	}
       else
 	{
@@ -8960,6 +9045,7 @@
 	    }
 	  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 @@
   // 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 @@
       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 @@
       return;
     }
 
-  if (fntype->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)
-	{
-	  // 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))
+  bool is_method = fntype->is_method();
+  if (is_method)
+    {
+      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))
+	{
+	  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 @@
 	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 @@
   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 @@
   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 @@
   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)
+  else
     fn = this->interface_method_function(context, interface_method, &args[0]);
-  else
-    go_unreachable();
 
   if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
     {
diff -r 5097a3ef0927 go/expressions.h
--- a/go/expressions.h	Mon Aug 29 15:00:07 2011 -0700
+++ b/go/expressions.h	Mon Aug 29 15:02:20 2011 -0700
@@ -1244,6 +1244,11 @@
   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 @@
   { 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 @@
   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*);
diff -r 5097a3ef0927 go/statements.cc
--- a/go/statements.cc	Mon Aug 29 15:00:07 2011 -0700
+++ b/go/statements.cc	Mon Aug 29 15:02:20 2011 -0700
@@ -1858,8 +1858,7 @@
   // 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 @@
 	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 @@
   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 @@
     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 @@
   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 @@
       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_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 @@
       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 @@
 
   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);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]