The predeclared function "closed" has been removed from the Go language,
as it is no longer necessary now that v, ok = <-c returns whether the
channel is closed.  This patch implements that in gccgo.  This patch
also fixes the handling of case v, ok := <-c in a select statement.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

diff -r 8de7f64be423 go/expressions.cc
--- a/go/expressions.cc	Thu Mar 24 16:37:44 2011 -0700
+++ b/go/expressions.cc	Thu Mar 24 21:58:25 2011 -0700
@@ -6530,7 +6530,6 @@
       BUILTIN_APPEND,
       BUILTIN_CAP,
       BUILTIN_CLOSE,
-      BUILTIN_CLOSED,
       BUILTIN_COMPLEX,
       BUILTIN_COPY,
       BUILTIN_IMAG,
@@ -6588,8 +6587,6 @@
     this->code_ = BUILTIN_CAP;
   else if (name == "close")
     this->code_ = BUILTIN_CLOSE;
-  else if (name == "closed")
-    this->code_ = BUILTIN_CLOSED;
   else if (name == "complex")
     this->code_ = BUILTIN_COMPLEX;
   else if (name == "copy")
@@ -7185,9 +7182,6 @@
     case BUILTIN_PRINTLN:
       return Type::make_void_type();
 
-    case BUILTIN_CLOSED:
-      return Type::lookup_bool_type();
-
     case BUILTIN_RECOVER:
       return Type::make_interface_type(NULL, BUILTINS_LOCATION);
 
@@ -7451,7 +7445,6 @@
       break;
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       if (this->check_one_arg())
 	{
 	  if (this->one_arg()->type()->channel_type() == NULL)
@@ -7936,7 +7929,6 @@
       }
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       {
 	const Expression_list* args = this->args();
 	gcc_assert(args != NULL && args->size() == 1);
@@ -7944,28 +7936,14 @@
 	tree arg_tree = arg->get_tree(context);
 	if (arg_tree == error_mark_node)
 	  return error_mark_node;
-	if (this->code_ == BUILTIN_CLOSE)
-	  {
-	    static tree close_fndecl;
-	    return Gogo::call_builtin(&close_fndecl,
-				      location,
-				      "__go_builtin_close",
-				      1,
-				      void_type_node,
-				      TREE_TYPE(arg_tree),
-				      arg_tree);
-	  }
-	else
-	  {
-	    static tree closed_fndecl;
-	    return Gogo::call_builtin(&closed_fndecl,
-				      location,
-				      "__go_builtin_closed",
-				      1,
-				      boolean_type_node,
-				      TREE_TYPE(arg_tree),
-				      arg_tree);
-	  }
+	static tree close_fndecl;
+	return Gogo::call_builtin(&close_fndecl,
+				  location,
+				  "__go_builtin_close",
+				  1,
+				  void_type_node,
+				  TREE_TYPE(arg_tree),
+				  arg_tree);
       }
 
     case BUILTIN_SIZEOF:
diff -r 8de7f64be423 go/gogo.cc
--- a/go/gogo.cc	Thu Mar 24 16:37:44 2011 -0700
+++ b/go/gogo.cc	Thu Mar 24 21:58:25 2011 -0700
@@ -173,15 +173,6 @@
   close_type->set_is_builtin();
   this->globals_->add_function_declaration("close", NULL, close_type, loc);
 
-  Typed_identifier_list* closed_result = new Typed_identifier_list();
-  closed_result->push_back(Typed_identifier("", Type::lookup_bool_type(),
-					    loc));
-  Function_type* closed_type = Type::make_function_type(NULL, NULL,
-							closed_result, loc);
-  closed_type->set_is_varargs();
-  closed_type->set_is_builtin();
-  this->globals_->add_function_declaration("closed", NULL, closed_type, loc);
-
   Typed_identifier_list* copy_result = new Typed_identifier_list();
   copy_result->push_back(Typed_identifier("", int_type, loc));
   Function_type* copy_type = Type::make_function_type(NULL, NULL,
@@ -3506,12 +3497,15 @@
 					  true);
       this->init_ = NULL;
     }
+  else if (this->type_from_chan_element_)
+    {
+      Expression* init = this->init_;
+      init->determine_type_no_context();
+      this->type_ = this->type_from_chan_element(init, true);
+      this->init_ = NULL;
+    }
   else
     {
-      // type_from_chan_element_ should have been cleared during
-      // lowering.
-      gcc_assert(!this->type_from_chan_element_);
-
       Type_context context(this->type_, false);
       this->init_->determine_type(&context);
       if (this->type_ == NULL)
diff -r 8de7f64be423 go/parse.cc
--- a/go/parse.cc	Thu Mar 24 16:37:44 2011 -0700
+++ b/go/parse.cc	Thu Mar 24 21:58:25 2011 -0700
@@ -1717,6 +1717,7 @@
   Statement* s = Statement::make_tuple_receive_assignment(val_var,
 							  received_var,
 							  receive->channel(),
+							  false,
 							  location);
 
   if (!this->gogo_->in_global_scope())
@@ -3629,6 +3630,7 @@
       Expression* channel = receive->channel();
       Statement* s = Statement::make_tuple_receive_assignment(val, success,
 							      channel,
+							      false,
 							      location);
       this->gogo_->add_statement(s);
     }
diff -r 8de7f64be423 go/statements.cc
--- a/go/statements.cc	Thu Mar 24 16:37:44 2011 -0700
+++ b/go/statements.cc	Thu Mar 24 21:58:25 2011 -0700
@@ -1148,10 +1148,10 @@
 {
  public:
   Tuple_receive_assignment_statement(Expression* val, Expression* closed,
-				     Expression* channel,
+				     Expression* channel, bool for_select,
 				     source_location location)
     : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
-      val_(val), closed_(closed), channel_(channel)
+      val_(val), closed_(closed), channel_(channel), for_select_(for_select)
   { }
 
  protected:
@@ -1176,6 +1176,8 @@
   Expression* closed_;
   // The channel on which we receive the value.
   Expression* channel_;
+  // Whether this is for a select statement.
+  bool for_select_;
 };
 
 // Traversal.
@@ -1228,6 +1230,7 @@
   b->add_statement(closed_temp);
 
   // func chanrecv2(c chan T, val *T) bool
+  // func chanrecv3(c chan T, val *T) bool (if for_select)
   source_location bloc = BUILTINS_LOCATION;
   Typed_identifier_list* param_types = new Typed_identifier_list();
   param_types->push_back(Typed_identifier("c", channel_type, bloc));
@@ -1239,12 +1242,22 @@
 
   Function_type* fntype = Type::make_function_type(NULL, param_types,
 						   ret_types, bloc);
-  Named_object* chanrecv2 =
-    Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
-  chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
-
-  // closed_temp = chanrecv2(channel, &val_temp)
-  Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
+  Named_object* chanrecv;
+  if (!this->for_select_)
+    {
+      chanrecv = Named_object::make_function_declaration("chanrecv2", NULL,
+							 fntype, bloc);
+      chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv2");
+    }
+  else
+    {
+      chanrecv = Named_object::make_function_declaration("chanrecv3", NULL,
+							 fntype, bloc);
+      chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv3");
+    }
+
+  // closed_temp = chanrecv[23](channel, &val_temp)
+  Expression* func = Expression::make_func_reference(chanrecv, NULL, loc);
   Expression_list* params = new Expression_list();
   params->push_back(this->channel_);
   Expression* ref = Expression::make_temporary_reference(val_temp, loc);
@@ -1272,10 +1285,11 @@
 Statement*
 Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
 					 Expression* channel,
+					 bool for_select,
 					 source_location location)
 {
   return new Tuple_receive_assignment_statement(val, closed, channel,
-						location);
+						for_select, location);
 }
 
 // An assignment to a pair of values from a type guard.  This is a
@@ -4151,7 +4165,7 @@
 	this->val_ = Expression::make_sink(loc);
       Statement* s = Statement::make_tuple_receive_assignment(this->val_,
 							      this->closed_,
-							      ref, loc);
+							      ref, true, loc);
       init->add_statement(s);
     }
   else if (this->closedvar_ != NULL)
@@ -4165,8 +4179,14 @@
       Expression* closed = Expression::make_var_reference(this->closedvar_,
 							  loc);
       Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref,
-							      loc);
-      init->add_statement(s);
+							      true, loc);
+      // We have to put S in STATEMENTS_, because that is where the
+      // variables are declared.
+      gcc_assert(this->statements_ != NULL);
+      this->statements_->add_statement_at_front(s);
+      // We have to lower STATEMENTS_ again, to lower the tuple
+      // receive assignment we just added.
+      gogo->lower_block(function, this->statements_);
     }
   else
     {
@@ -5281,7 +5301,7 @@
 // Lower a for range over a channel.
 
 void
-For_range_statement::lower_range_channel(Gogo* gogo,
+For_range_statement::lower_range_channel(Gogo*,
 					 Block*,
 					 Block* body_block,
 					 Named_object* range_object,
@@ -5299,12 +5319,11 @@
 
   // The loop we generate:
   //   for {
-  //           index_temp = <-range
-  //           if closed(range) {
+  //           index_temp, ok_temp = <-range
+  //           if !ok_temp {
   //                   break
   //           }
   //           index = index_temp
-  //           value = value_temp
   //           original body
   //   }
 
@@ -5315,26 +5334,30 @@
   *ppost = NULL;
 
   // Set *PITER_INIT to
-  //   index_temp = <-range
-  //   if closed(range) {
+  //   index_temp, ok_temp = <-range
+  //   if !ok_temp {
   //           break
   //   }
 
   Block* iter_init = new Block(body_block, loc);
 
-  Expression* ref = this->make_range_ref(range_object, range_temp, loc);
-  Expression* cond = this->call_builtin(gogo, "closed", ref, loc);
-
-  ref = this->make_range_ref(range_object, range_temp, loc);
-  Expression* recv = Expression::make_receive(ref, loc);
-  ref = Expression::make_temporary_reference(index_temp, loc);
-  Statement* s = Statement::make_assignment(ref, recv, loc);
+  Temporary_statement* ok_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+  iter_init->add_statement(ok_temp);
+
+  Expression* cref = this->make_range_ref(range_object, range_temp, loc);
+  Expression* iref = Expression::make_temporary_reference(index_temp, loc);
+  Expression* oref = Expression::make_temporary_reference(ok_temp, loc);
+  Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
+							  false, loc);
   iter_init->add_statement(s);
 
   Block* then_block = new Block(iter_init, loc);
   s = Statement::make_break_statement(this->break_label(), loc);
   then_block->add_statement(s);
 
+  oref = Expression::make_temporary_reference(ok_temp, loc);
+  Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
   s = Statement::make_if_statement(cond, then_block, NULL, loc);
   iter_init->add_statement(s);
 
diff -r 8de7f64be423 go/statements.h
--- a/go/statements.h	Thu Mar 24 16:37:44 2011 -0700
+++ b/go/statements.h	Thu Mar 24 21:58:25 2011 -0700
@@ -160,10 +160,12 @@
 		      Expression* should_set, source_location);
 
   // Make an assignment from a nonblocking receive to a pair of
-  // variables.
+  // variables.  FOR_SELECT is true is this is being created for a
+  // case x, ok := <-c in a select statement.
   static Statement*
   make_tuple_receive_assignment(Expression* val, Expression* closed,
-				Expression* channel, source_location);
+				Expression* channel, bool for_select,
+				source_location);
 
   // Make an assignment from a type guard to a pair of variables.
   static Statement*
diff -r 8de7f64be423 libgo/Makefile.am
--- a/libgo/Makefile.am	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/Makefile.am	Thu Mar 24 21:58:25 2011 -0700
@@ -358,7 +358,6 @@
 	runtime/go-chan-len.c \
 	runtime/go-check-interface.c \
 	runtime/go-close.c \
-	runtime/go-closed.c \
 	runtime/go-construct-map.c \
 	runtime/go-convert-interface.c \
 	runtime/go-copy.c \
diff -r 8de7f64be423 libgo/runtime/chan.goc
--- a/libgo/runtime/chan.goc	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/runtime/chan.goc	Thu Mar 24 21:58:25 2011 -0700
@@ -10,7 +10,7 @@
 typedef unsigned char byte;
 typedef struct __go_channel chan;
 
-/* Do a nonblocking channel receive.  */
+/* Do a channel receive with closed status.  */
 
 func chanrecv2(c *chan, val *byte) (received bool) {
 	if (c->element_size > 8) {
@@ -31,3 +31,25 @@
 		return received;
 	}
 }
+
+/* Do a channel receive with closed status for a select statement.  */
+
+func chanrecv3(c *chan, val *byte) (received bool) {
+	if (c->element_size > 8) {
+		return __go_receive_big(c, val, 1);
+	} else {
+		union {
+			char b[8];
+			uint64_t v;
+		} u;
+
+		u.v = __go_receive_small_closed(c, 1, &received);
+#ifndef WORDS_BIGENDIAN
+		__builtin_memcpy(val, u.b, c->element_size);
+#else
+		__builtin_memcpy(val, u.b + 8 - c->element_size,
+				 c->element_size);
+#endif
+		return received;
+	}
+}
diff -r 8de7f64be423 libgo/runtime/channel.h
--- a/libgo/runtime/channel.h	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/runtime/channel.h	Thu Mar 24 21:58:25 2011 -0700
@@ -50,9 +50,6 @@
   _Bool selected_for_receive;
   /* True if this channel has been closed.  */
   _Bool is_closed;
-  /* True if at least one null value has been read from a closed
-     channel.  */
-  _Bool saw_close;
   /* The list of select statements waiting to send on a synchronous
      channel.  */
   struct __go_channel_select *select_send_queue;
diff -r 8de7f64be423 libgo/runtime/go-closed.c
--- a/libgo/runtime/go-closed.c	Thu Mar 24 16:37:44 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/* go-closed.c -- the builtin closed function.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include "go-assert.h"
-#include "channel.h"
-
-/* Return whether a channel is closed.  We only return true after at
-   least one nil value has been read from the channel.  */
-
-_Bool
-__go_builtin_closed (struct __go_channel *channel)
-{
-  int i;
-  _Bool ret;
-
-  i = pthread_mutex_lock (&channel->lock);
-  __go_assert (i == 0);
-
-  while (channel->selected_for_receive)
-    {
-      i = pthread_cond_wait (&channel->cond, &channel->lock);
-      __go_assert (i == 0);
-    }
-
-  ret = channel->saw_close;
-
-  i = pthread_mutex_unlock (&channel->lock);
-  __go_assert (i == 0);
-
-  return ret;
-}
diff -r 8de7f64be423 libgo/runtime/go-new-channel.c
--- a/libgo/runtime/go-new-channel.c	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/runtime/go-new-channel.c	Thu Mar 24 21:58:25 2011 -0700
@@ -44,7 +44,6 @@
   ret->selected_for_send = 0;
   ret->selected_for_receive = 0;
   ret->is_closed = 0;
-  ret->saw_close = 0;
   ret->select_send_queue = NULL;
   ret->select_receive_queue = NULL;
   ret->select_mutex = NULL;
diff -r 8de7f64be423 libgo/runtime/go-rec-nb-small.c
--- a/libgo/runtime/go-rec-nb-small.c	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/runtime/go-rec-nb-small.c	Thu Mar 24 21:58:25 2011 -0700
@@ -32,7 +32,6 @@
 	  ? channel->next_store == 0
 	  : channel->next_fetch == channel->next_store))
     {
-      channel->saw_close = 1;
       __go_unlock_and_notify_selects (channel);
       return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
     }
diff -r 8de7f64be423 libgo/runtime/go-rec-small.c
--- a/libgo/runtime/go-rec-small.c	Thu Mar 24 16:37:44 2011 -0700
+++ b/libgo/runtime/go-rec-small.c	Thu Mar 24 21:58:25 2011 -0700
@@ -124,7 +124,6 @@
 	      ? channel->next_store == 0
 	      : channel->next_fetch == channel->next_store))
 	{
-	  channel->saw_close = 1;
 	  channel->selected_for_receive = 0;
 	  __go_unlock_and_notify_selects (channel);
 	  return 0;
Index: gcc/testsuite/go.test/test/closedchan.go
===================================================================
--- gcc/testsuite/go.test/test/closedchan.go	(revision 171371)
+++ gcc/testsuite/go.test/test/closedchan.go	(working copy)
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test close(c), closed(c).
+// Test close(c), receive of closed channel.
 //
 // TODO(rsc): Doesn't check behavior of close(c) when there
 // are blocked senders/receivers.
@@ -14,10 +14,11 @@ package main
 type Chan interface {
 	Send(int)
 	Nbsend(int) bool
-	Recv() int
+	Recv() (int)
 	Nbrecv() (int, bool)
+	Recv2() (int, bool)
+	Nbrecv2() (int, bool, bool)
 	Close()
-	Closed() bool
 	Impl() string
 }
 
@@ -52,12 +53,23 @@ func (c XChan) Nbrecv() (int, bool) {
 	panic("nbrecv")
 }
 
-func (c XChan) Close() {
-	close(c)
+func (c XChan) Recv2() (int, bool) {
+	x, ok := <-c
+	return x, ok
+}
+
+func (c XChan) Nbrecv2() (int, bool, bool) {
+	select {
+	case x, ok := <-c:
+		return x, ok, true
+	default:
+		return 0, false, false
+	}
+	panic("nbrecv2")
 }
 
-func (c XChan) Closed() bool {
-	return closed(c)
+func (c XChan) Close() {
+	close(c)
 }
 
 func (c XChan) Impl() string {
@@ -101,12 +113,26 @@ func (c SChan) Nbrecv() (int, bool) {
 	panic("nbrecv")
 }
 
-func (c SChan) Close() {
-	close(c)
+func (c SChan) Recv2() (int, bool) {
+	select {
+	case x, ok := <-c:
+		return x, ok
+	}
+	panic("recv")
 }
 
-func (c SChan) Closed() bool {
-	return closed(c)
+func (c SChan) Nbrecv2() (int, bool, bool) {
+	select {
+	default:
+		return 0, false, false
+	case x, ok := <-c:
+		return x, ok, true
+	}
+	panic("nbrecv")
+}
+
+func (c SChan) Close() {
+	close(c)
 }
 
 func (c SChan) Impl() string {
@@ -156,12 +182,28 @@ func (c SSChan) Nbrecv() (int, bool) {
 	panic("nbrecv")
 }
 
-func (c SSChan) Close() {
-	close(c)
+func (c SSChan) Recv2() (int, bool) {
+	select {
+	case <-dummy:
+	case x, ok := <-c:
+		return x, ok
+	}
+	panic("recv")
 }
 
-func (c SSChan) Closed() bool {
-	return closed(c)
+func (c SSChan) Nbrecv2() (int, bool, bool) {
+	select {
+	case <-dummy:
+	default:
+		return 0, false, false
+	case x, ok := <-c:
+		return x, ok, true
+	}
+	panic("nbrecv")
+}
+
+func (c SSChan) Close() {
+	close(c)
 }
 
 func (c SSChan) Impl() string {
@@ -179,29 +221,23 @@ func shouldPanic(f func()) {
 }
 
 func test1(c Chan) {
-	// not closed until the close signal (a zero value) has been received.
-	if c.Closed() {
-		println("test1: Closed before Recv zero:", c.Impl())
-	}
-
 	for i := 0; i < 3; i++ {
 		// recv a close signal (a zero value)
 		if x := c.Recv(); x != 0 {
-			println("test1: recv on closed got non-zero:", x, c.Impl())
+			println("test1: recv on closed:", x, c.Impl())
 		}
-
-		// should now be closed.
-		if !c.Closed() {
-			println("test1: not closed after recv zero", c.Impl())
+		if x, ok := c.Recv2(); x != 0 || ok {
+			println("test1: recv2 on closed:", x, ok, c.Impl())
 		}
 
-		// should work with ,ok: received a value without blocking, so ok == true.
-		x, ok := c.Nbrecv()
-		if !ok {
-			println("test1: recv on closed got not ok", c.Impl())
+		// should work with select: received a value without blocking, so selected == true.
+		x, selected := c.Nbrecv()
+		if x != 0 || !selected {
+			println("test1: recv on closed nb:", x, selected, c.Impl())
 		}
-		if x != 0 {
-			println("test1: recv ,ok on closed got non-zero:", x, c.Impl())
+		x, ok, selected := c.Nbrecv2()
+		if x != 0 || ok || !selected {
+			println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
 		}
 	}
 
@@ -221,11 +257,6 @@ func test1(c Chan) {
 }
 
 func testasync1(c Chan) {
-	// not closed until the close signal (a zero value) has been received.
-	if c.Closed() {
-		println("testasync1: Closed before Recv zero:", c.Impl())
-	}
-
 	// should be able to get the last value via Recv
 	if x := c.Recv(); x != 1 {
 		println("testasync1: Recv did not get 1:", x, c.Impl())
@@ -235,19 +266,31 @@ func testasync1(c Chan) {
 }
 
 func testasync2(c Chan) {
-	// not closed until the close signal (a zero value) has been received.
-	if c.Closed() {
-		println("testasync2: Closed before Recv zero:", c.Impl())
+	// should be able to get the last value via Recv2
+	if x, ok := c.Recv2(); x != 1 || !ok {
+		println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
 	}
 
+	test1(c)
+}
+
+func testasync3(c Chan) {
 	// should be able to get the last value via Nbrecv
-	if x, ok := c.Nbrecv(); !ok || x != 1 {
-		println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl())
+	if x, selected := c.Nbrecv(); x != 1 || !selected {
+		println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
 	}
 
 	test1(c)
 }
 
+func testasync4(c Chan) {
+	// should be able to get the last value via Nbrecv2
+	if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
+		println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
+	}
+	test1(c)
+}
+
 func closedsync() chan int {
 	c := make(chan int)
 	close(c)
@@ -261,15 +304,27 @@ func closedasync() chan int {
 	return c
 }
 
+var mks = []func(chan int) Chan {
+	func(c chan int) Chan { return XChan(c) },
+	func(c chan int) Chan { return SChan(c) },
+	func(c chan int) Chan { return SSChan(c) },
+}
+
+var testcloseds = []func(Chan) {
+	testasync1,
+	testasync2,
+	testasync3,
+	testasync4,
+}
+
 func main() {
-	test1(XChan(closedsync()))
-	test1(SChan(closedsync()))
-	test1(SSChan(closedsync()))
-
-	testasync1(XChan(closedasync()))
-	testasync1(SChan(closedasync()))
-	testasync1(SSChan(closedasync()))
-	testasync2(XChan(closedasync()))
-	testasync2(SChan(closedasync()))
-	testasync2(SSChan(closedasync()))
+	for _, mk := range mks {
+		test1(mk(closedsync()))
+	}
+	
+	for _, testclosed := range testcloseds {
+		for _, mk := range mks {
+			testclosed(mk(closedasync()))
+		}
+	}
 }
Index: gcc/testsuite/go.test/test/named1.go
===================================================================
--- gcc/testsuite/go.test/test/named1.go	(revision 171371)
+++ gcc/testsuite/go.test/test/named1.go	(working copy)
@@ -43,10 +43,6 @@ func main() {
 	_, b = m[2] // ERROR "cannot .* bool.*type Bool"
 	m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
 
-	////TODO(rsc): uncomment when this syntax is valid for receive+check closed
-	////	_, b = <-c // ERROR "cannot .* bool.*type Bool"
-	////	_ = b
-
 	var inter interface{}
 	_, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
 	_ = b
@@ -57,8 +53,9 @@ func main() {
 	_, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
 	_ = b
 
-	asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
-	b = closed(c)     // ERROR "cannot use.*type bool.*type Bool"
+	_, bb := <-c
+	asBool(bb) // ERROR "cannot use.*type bool.*as type Bool"
+	_, b = <-c     // ERROR "cannot .* bool.*type Bool"
 	_ = b
 
 	asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
Index: gcc/testsuite/go.test/test/chan/select3.go
===================================================================
--- gcc/testsuite/go.test/test/chan/select3.go	(revision 171364)
+++ gcc/testsuite/go.test/test/chan/select3.go	(working copy)
@@ -88,12 +88,16 @@ func main() {
 		ch <- 7
 	})
 
-	// receiving (a small number of times) from a closed channel never blocks
+	// receiving from a closed channel never blocks
 	testBlock(never, func() {
 		for i := 0; i < 10; i++ {
 			if <-closedch != 0 {
 				panic("expected zero value when reading from closed channel")
 			}
+			if x, ok := <-closedch; x != 0 || ok {
+				println("closedch:", x, ok)
+				panic("expected 0, false from closed channel")
+			}
 		}
 	})
 
@@ -191,9 +195,30 @@ func main() {
 		case <-closedch:
 		}
 	})
+	testBlock(never, func() {
+		select {
+		case x := <-closedch:
+			_ = x
+		}
+	})
+	testBlock(never, func() {
+		select {
+		case x, ok := <-closedch:
+			_, _ = x, ok
+		}
+	})
 	testPanic(always, func() {
 		select {
 		case closedch <- 7:
 		}
 	})
+
+	// select should not get confused if it sees itself
+	testBlock(always, func() {
+		c := make(chan int)
+		select {
+		case c <- 1:
+		case <-c:
+		}
+	})
 }
Index: gcc/testsuite/go.test/test/chan/perm.go
===================================================================
--- gcc/testsuite/go.test/test/chan/perm.go	(revision 171371)
+++ gcc/testsuite/go.test/test/chan/perm.go	(working copy)
@@ -22,21 +22,18 @@ func main() {
 
 	c <- 0 // ok
 	<-c    // ok
-	//TODO(rsc): uncomment when this syntax is valid for receive+check closed
-	//	x, ok := <-c	// ok
-	//	_, _ = x, ok
+	x, ok := <-c	// ok
+	_, _ = x, ok
 
 	cr <- 0 // ERROR "send"
 	<-cr    // ok
-	//TODO(rsc): uncomment when this syntax is valid for receive+check closed
-	//	x, ok = <-cr	// ok
-	//	_, _ = x, ok
+	x, ok = <-cr	// ok
+	_, _ = x, ok
 
 	cs <- 0 // ok
 	<-cs    // ERROR "receive"
-	////TODO(rsc): uncomment when this syntax is valid for receive+check closed
-	////	x, ok = <-cs	// ERROR "receive"
-	////	_, _ = x, ok
+	x, ok = <-cs	// ERROR "receive"
+	_, _ = x, ok
 
 	select {
 	case c <- 0: // ok
Index: gcc/testsuite/go.test/test/chan/doubleselect.go
===================================================================
--- gcc/testsuite/go.test/test/chan/doubleselect.go	(revision 171359)
+++ gcc/testsuite/go.test/test/chan/doubleselect.go	(working copy)
@@ -21,6 +21,8 @@ var iterations *int = flag.Int("n", 1000
 func sender(n int, c1, c2, c3, c4 chan<- int) {
 	defer close(c1)
 	defer close(c2)
+	defer close(c3)
+	defer close(c4)
 
 	for i := 0; i < n; i++ {
 		select {
@@ -35,26 +37,18 @@ func sender(n int, c1, c2, c3, c4 chan<-
 // mux receives the values from sender and forwards them onto another channel.
 // It would be simplier to just have sender's four cases all be the same
 // channel, but this doesn't actually trigger the bug.
-func mux(out chan<- int, in <-chan int) {
-	for {
-		v := <-in
-		if closed(in) {
-			close(out)
-			break
-		}
+func mux(out chan<- int, in <-chan int, done chan<- bool) {
+	for v := range in {
 		out <- v
 	}
+	done <- true
 }
 
 // recver gets a steam of values from the four mux's and checks for duplicates.
 func recver(in <-chan int) {
 	seen := make(map[int]bool)
 
-	for {
-		v := <-in
-		if closed(in) {
-			break
-		}
+	for v := range in {
 		if _, ok := seen[v]; ok {
 			println("got duplicate value: ", v)
 			panic("fail")
@@ -70,15 +64,23 @@ func main() {
 	c2 := make(chan int)
 	c3 := make(chan int)
 	c4 := make(chan int)
+	done := make(chan bool)
 	cmux := make(chan int)
 	go sender(*iterations, c1, c2, c3, c4)
-	go mux(cmux, c1)
-	go mux(cmux, c2)
-	go mux(cmux, c3)
-	go mux(cmux, c4)
+	go mux(cmux, c1, done)
+	go mux(cmux, c2, done)
+	go mux(cmux, c3, done)
+	go mux(cmux, c4, done)
+	go func() {
+		<-done
+		<-done
+		<-done
+		<-done
+		close(cmux)
+	}()
 	// We keep the recver because it might catch more bugs in the future.
 	// However, the result of the bug linked to at the top is that we'll
-	// end up panicing with: "throw: bad g->status in ready".
+	// end up panicking with: "throw: bad g->status in ready".
 	recver(cmux)
 	print("PASS\n")
 }

Reply via email to