diff mbox

[gccgo] Add support for calls with ...

Message ID mcr8w1px2qx.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 22, 2010, 10:48 p.m. UTC
The Go language was tweaked so that you can pass a slice to a varargs
parameter by adding an explicit ... in the call, as in
	f(a ...)
This patch implements that in gccgo.  Committed to gccgo branch.

Ian
diff mbox

Patch

diff -r 7b3973a82c61 go/expressions.cc
--- a/go/expressions.cc	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/expressions.cc	Fri Oct 22 15:43:25 2010 -0700
@@ -6174,7 +6174,7 @@ 
 						 Expression* fn,
 						 Expression_list* args,
 						 source_location location)
-  : Call_expression(fn, args, location),
+  : Call_expression(fn, args, false, location),
     gogo_(gogo), code_(BUILTIN_INVALID)
 {
   Func_expression* fnexp = this->fn()->func_expression();
@@ -7772,8 +7772,10 @@ 
       bool issued_error = false;
       if (pa != old_args->end()
 	  && pa + 1 == old_args->end()
-	  && this->is_compatible_varargs_argument(function, *pa, varargs_type,
-						  &issued_error))
+	  && (this->is_varargs_
+	      || this->is_compatible_varargs_argument(function, *pa,
+						      varargs_type,
+						      &issued_error)))
 	new_args->push_back(*pa);
       else if (pa == old_args->end())
 	push_empty_arg = true;
@@ -8350,10 +8352,10 @@ 
 // Make a call expression.
 
 Call_expression*
-Expression::make_call(Expression* fn, Expression_list* args,
+Expression::make_call(Expression* fn, Expression_list* args, bool is_varargs,
 		      source_location location)
 {
-  return new Call_expression(fn, args, location);
+  return new Call_expression(fn, args, is_varargs, location);
 }
 
 // A single result from a call which returns multiple results.
@@ -9727,7 +9729,9 @@ 
 	}
     }
 
-  Call_expression* call = Expression::make_call(bm, args, location);
+  Call_expression* call = Expression::make_call(bm, args,
+						method_type->is_varargs(),
+						location);
 
   size_t count = call->result_count();
   Statement* s;
diff -r 7b3973a82c61 go/expressions.h
--- a/go/expressions.h	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/expressions.h	Fri Oct 22 15:43:25 2010 -0700
@@ -179,7 +179,8 @@ 
 
   // Make a call expression.
   static Call_expression*
-  make_call(Expression* func, Expression_list* params, source_location);
+  make_call(Expression* func, Expression_list* args, bool is_varargs,
+	    source_location);
 
   // Make a reference to a specific result of a call expression which
   // returns a tuple.
@@ -1157,10 +1158,10 @@ 
 class Call_expression : public Expression
 {
  public:
-  Call_expression(Expression* fn, Expression_list* args,
+  Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
 		  source_location location)
     : Expression(EXPRESSION_CALL, location),
-      fn_(fn), args_(args), type_(NULL), tree_(NULL),
+      fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
       is_value_discarded_(false), varargs_are_lowered_(false),
       is_deferred_(false)
   { }
@@ -1230,7 +1231,7 @@ 
   do_copy()
   {
     return Expression::make_call(this->fn_->copy(), this->args_->copy(),
-				 this->location());
+				 this->is_varargs_, this->location());
   }
 
   bool
@@ -1277,6 +1278,8 @@ 
   Type* type_;
   // The tree for the call, used for a call which returns a tuple.
   tree tree_;
+  // True if the last argument is a varargs argument (f(a...)).
+  bool is_varargs_;
   // True if the value is being discarded.
   bool is_value_discarded_;
   // True if varargs have already been lowered.
diff -r 7b3973a82c61 go/gogo.cc
--- a/go/gogo.cc	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/gogo.cc	Fri Oct 22 15:43:25 2010 -0700
@@ -2074,7 +2074,7 @@ 
     }
   args->push_back(this->can_recover_arg(location));
 
-  Expression* call = Expression::make_call(fn, args, location);
+  Expression* call = Expression::make_call(fn, args, false, location);
 
   Statement* s;
   if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
@@ -2195,13 +2195,13 @@ 
   Expression_list *args = new Expression_list();
   args->push_back(zexpr);
 
-  Expression* call = Expression::make_call(fn, args, location);
+  Expression* call = Expression::make_call(fn, args, false, location);
 
   args = new Expression_list();
   args->push_back(call);
 
   fn = Expression::make_func_reference(can_recover, NULL, location);
-  return Expression::make_call(fn, args, location);
+  return Expression::make_call(fn, args, false, location);
 }
 
 // Build thunks for functions which call recover.  We build a new
diff -r 7b3973a82c61 go/parse.cc
--- a/go/parse.cc	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/parse.cc	Fri Oct 22 15:43:25 2010 -0700
@@ -2698,18 +2698,25 @@ 
   return Expression::make_index(expr, start, end, location);
 }
 
-// Call = "(" [ ExpressionList [ "," ] ] ")" .
+// Call           = "(" [ ArgumentList [ "," ] ] ")" .
+// ArgumentList   = ExpressionList [ "..." ] .
 
 Expression*
 Parse::call(Expression* func)
 {
   gcc_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
   Expression_list* args = NULL;
+  bool is_varargs = false;
   const Token* token = this->advance_token();
   if (!token->is_op(OPERATOR_RPAREN))
     {
       args = this->expression_list(NULL, false);
       token = this->peek_token();
+      if (token->is_op(OPERATOR_ELLIPSIS))
+	{
+	  is_varargs = true;
+	  token = this->advance_token();
+	}
     }
   if (token->is_op(OPERATOR_COMMA))
     token = this->advance_token();
@@ -2719,7 +2726,7 @@ 
     this->advance_token();
   if (func->is_error_expression())
     return func;
-  return Expression::make_call(func, args, func->location());
+  return Expression::make_call(func, args, is_varargs, func->location());
 }
 
 // Return an expression for a single unqualified identifier.
diff -r 7b3973a82c61 go/statements.cc
--- a/go/statements.cc	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/statements.cc	Fri Oct 22 15:43:25 2010 -0700
@@ -934,7 +934,7 @@ 
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
   ref = Expression::make_temporary_reference(val_temp, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, loc);
+  Expression* call = Expression::make_call(func, params, false, loc);
 
   ref = Expression::make_temporary_reference(present_temp, loc);
   Statement* s = Statement::make_assignment(ref, call, loc);
@@ -1069,7 +1069,7 @@ 
   ref = Expression::make_temporary_reference(val_temp, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
   params->push_back(this->should_set_);
-  Expression* call = Expression::make_call(func, params, loc);
+  Expression* call = Expression::make_call(func, params, false, loc);
   Statement* s = Statement::make_statement(call);
   b->add_statement(s);
 
@@ -1192,7 +1192,7 @@ 
   params->push_back(this->channel_);
   Expression* ref = Expression::make_temporary_reference(val_temp, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, loc);
+  Expression* call = Expression::make_call(func, params, false, loc);
   ref = Expression::make_temporary_reference(success_temp, loc);
   Statement* s = Statement::make_assignment(ref, call, loc);
   b->add_statement(s);
@@ -1363,7 +1363,7 @@ 
   Expression* func = Expression::make_func_reference(fn, NULL, loc);
   Expression_list* params = new Expression_list();
   params->push_back(this->expr_);
-  return Expression::make_call(func, params, loc);
+  return Expression::make_call(func, params, false, loc);
 }
 
 // Lower a conversion to a non-empty interface type or a pointer type.
@@ -1396,7 +1396,7 @@ 
   Expression_list* params = new Expression_list();
   params->push_back(Expression::make_type_descriptor(this->type_, loc));
   params->push_back(this->expr_);
-  return Expression::make_call(func, params, loc);
+  return Expression::make_call(func, params, false, loc);
 }
 
 // Lower a conversion to a non-interface non-pointer type.
@@ -1438,7 +1438,7 @@ 
   params->push_back(this->expr_);
   Expression* ref = Expression::make_temporary_reference(val_temp, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, loc);
+  Expression* call = Expression::make_call(func, params, false, loc);
   Statement* s = Statement::make_assignment(this->ok_, call, loc);
   b->add_statement(s);
 
@@ -1886,7 +1886,7 @@ 
 						     location);
   Expression_list* params = new Expression_list();
   params->push_back(constructor);
-  Call_expression* call = Expression::make_call(func, params, location);
+  Call_expression* call = Expression::make_call(func, params, false, location);
 
   // Build the simple go or defer statement.
   Statement* s;
@@ -2080,7 +2080,7 @@ 
 
       Expression* fn = Expression::make_func_reference(set_defer_retaddr,
 						       NULL, location);
-      Expression* call = Expression::make_call(fn, args, location);
+      Expression* call = Expression::make_call(fn, args, false, location);
 
       // This is a hack to prevent the middle-end from deleting the
       // label.
@@ -2163,7 +2163,8 @@ 
       call_params->push_back(param);
     }
 
-  Expression* call = Expression::make_call(func_to_call, call_params, location);
+  Expression* call = Expression::make_call(func_to_call, call_params, false,
+					   location);
   // We need to lower in case this is a builtin function.
   call = call->lower(gogo, function, -1);
   if (may_call_recover)
@@ -3621,7 +3622,7 @@ 
 	  Expression* ref =
 	    Expression::make_temporary_reference(descriptor_temp, loc);
 	  params->push_back(ref);
-	  cond = Expression::make_call(func, params, loc);
+	  cond = Expression::make_call(func, params, false, loc);
 	}
 
       Unnamed_label* dest;
@@ -3834,7 +3835,7 @@ 
       else
 	ref = Expression::make_var_reference(this->var_, loc);
       params->push_back(ref);
-      Expression* call = Expression::make_call(func, params, loc);
+      Expression* call = Expression::make_call(func, params, false, loc);
       Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
 							     loc);
       Statement* s = Statement::make_assignment(lhs, call, loc);
@@ -4616,7 +4617,7 @@ 
   Expression* func = Expression::make_func_reference(no, NULL, loc);
   Expression_list* params = new Expression_list();
   params->push_back(arg);
-  return Expression::make_call(func, params, loc);
+  return Expression::make_call(func, params, false, loc);
 }
 
 // Lower a for range over an array or slice.
@@ -4830,7 +4831,7 @@ 
   Expression_list* params = new Expression_list();
   params->push_back(this->make_range_ref(range_object, range_temp, loc));
   params->push_back(Expression::make_temporary_reference(index_temp, loc));
-  Call_expression* call = Expression::make_call(func, params, loc);
+  Call_expression* call = Expression::make_call(func, params, false, loc);
 
   if (value_temp == NULL)
     {
@@ -4949,7 +4950,7 @@ 
   params->push_back(this->make_range_ref(range_object, range_temp, loc));
   Expression* ref = Expression::make_temporary_reference(hiter, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, loc);
+  Expression* call = Expression::make_call(func, params, false, loc);
   init->add_statement(Statement::make_statement(call));
 
   *pinit = init;
@@ -5006,7 +5007,7 @@ 
       ref = Expression::make_temporary_reference(value_temp, loc);
       params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
     }
-  call = Expression::make_call(func, params, loc);
+  call = Expression::make_call(func, params, false, loc);
   iter_init->add_statement(Statement::make_statement(call));
 
   *piter_init = iter_init;
@@ -5033,7 +5034,7 @@ 
   params = new Expression_list();
   ref = Expression::make_temporary_reference(hiter, loc);
   params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  call = Expression::make_call(func, params, loc);
+  call = Expression::make_call(func, params, false, loc);
   post->add_statement(Statement::make_statement(call));
 
   *ppost = post;
diff -r 7b3973a82c61 go/types.cc
--- a/go/types.cc	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/types.cc	Fri Oct 22 15:43:25 2010 -0700
@@ -7296,7 +7296,8 @@ 
 	{
 	  stub = gogo->start_function(name, stub_type, false,
 				      fntype->location());
-	  Type::build_one_stub_method(gogo, m, buf, stub_params, location);
+	  Type::build_one_stub_method(gogo, m, buf, stub_params,
+				      fntype->is_varargs(), location);
 	  gogo->finish_function(fntype->location());
 	}
 
@@ -7312,6 +7313,7 @@ 
 Type::build_one_stub_method(Gogo* gogo, Method* method,
 			    const char* receiver_name,
 			    const Typed_identifier_list* params,
+			    bool is_varargs,
 			    source_location location)
 {
   Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
@@ -7342,7 +7344,8 @@ 
 
   Expression* func = method->bind_method(expr, location);
   gcc_assert(func != NULL);
-  Call_expression* call = Expression::make_call(func, arguments, location);
+  Call_expression* call = Expression::make_call(func, arguments, is_varargs,
+						location);
   size_t count = call->result_count();
   if (count == 0)
     gogo->add_statement(Statement::make_statement(call));
diff -r 7b3973a82c61 go/types.h
--- a/go/types.h	Fri Oct 22 15:11:02 2010 -0700
+++ b/go/types.h	Fri Oct 22 15:43:25 2010 -0700
@@ -1042,7 +1042,8 @@ 
 
   static void
   build_one_stub_method(Gogo*, Method*, const char* receiver_name,
-			const Typed_identifier_list*, source_location);
+			const Typed_identifier_list*, bool is_varargs,
+			source_location);
 
   static Expression*
   apply_field_indexes(Expression*, const Method::Field_indexes*,