Remove closed function. Fix tuple receive in select.
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 25 Mar 2011 05:14:57 +0000 (05:14 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 25 Mar 2011 05:14:57 +0000 (05:14 +0000)
From-SVN: r171440

18 files changed:
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/testsuite/go.test/test/chan/doubleselect.go
gcc/testsuite/go.test/test/chan/perm.go
gcc/testsuite/go.test/test/chan/select3.go
gcc/testsuite/go.test/test/closedchan.go
gcc/testsuite/go.test/test/named1.go
libgo/Makefile.am
libgo/Makefile.in
libgo/runtime/chan.goc
libgo/runtime/channel.h
libgo/runtime/go-closed.c [deleted file]
libgo/runtime/go-new-channel.c
libgo/runtime/go-rec-nb-small.c
libgo/runtime/go-rec-small.c

index 125715bb2de8bb325f3c67a4ed18a3d9a7d3493c..861d5c0ca9914291a20da8821faf42a24b4702d8 100644 (file)
@@ -6530,7 +6530,6 @@ class Builtin_call_expression : public Call_expression
       BUILTIN_APPEND,
       BUILTIN_CAP,
       BUILTIN_CLOSE,
-      BUILTIN_CLOSED,
       BUILTIN_COMPLEX,
       BUILTIN_COPY,
       BUILTIN_IMAG,
@@ -6588,8 +6587,6 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
     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 @@ Builtin_call_expression::do_type()
     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 @@ Builtin_call_expression::do_check_types(Gogo*)
       break;
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       if (this->check_one_arg())
        {
          if (this->one_arg()->type()->channel_type() == NULL)
@@ -7936,7 +7929,6 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
       }
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       {
        const Expression_list* args = this->args();
        gcc_assert(args != NULL && args->size() == 1);
@@ -7944,28 +7936,14 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        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:
index f39124c1643a2ec8ffba2386f0cf3ae68de908b6..a6411d362c484a1a21c2f54479be72eb6f8aa7ba 100644 (file)
@@ -173,15 +173,6 @@ Gogo::Gogo(int int_type_size, int pointer_size)
   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 @@ Variable::determine_type()
                                          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)
index 1f6e687ec82221dad725267209e55e1630d3bec7..f1b93429ff20c921e27b1d78ec264f4603263c71 100644 (file)
@@ -1717,6 +1717,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
   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 @@ Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause)
       Expression* channel = receive->channel();
       Statement* s = Statement::make_tuple_receive_assignment(val, success,
                                                              channel,
+                                                             false,
                                                              location);
       this->gogo_->add_statement(s);
     }
index f9b0853e2eaabd2559319246ccc9fb04bef93097..d24d98f4f88e28f4ea5c59e130b1176bfd17e4be 100644 (file)
@@ -1148,10 +1148,10 @@ class Tuple_receive_assignment_statement : public Statement
 {
  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 @@ class Tuple_receive_assignment_statement : public Statement
   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 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
   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 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
 
   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");
+  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 = chanrecv2(channel, &val_temp)
-  Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
+  // 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 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
 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 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
        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 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
       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 @@ For_range_statement::lower_range_map(Gogo* gogo,
 // 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 @@ For_range_statement::lower_range_channel(Gogo* gogo,
 
   // 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 @@ For_range_statement::lower_range_channel(Gogo* gogo,
   *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);
+  Temporary_statement* ok_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+  iter_init->add_statement(ok_temp);
 
-  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);
+  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);
 
index bb2922f180f240495095a7efb9dec352230588c6..5199981ea64e937036dab7f6f593737c9d6f60c2 100644 (file)
@@ -160,10 +160,12 @@ class Statement
                      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*
index 592d2f54a431e0c71bcfaa5f411929793093d243..3c7412ed6ab56f071f1428c02b397cf2e3039081 100644 (file)
@@ -21,6 +21,8 @@ var iterations *int = flag.Int("n", 100000, "number of iterations")
 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<- int) {
 // 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")
 }
index c725829d13293aa8817b6ee2f239d8788728910e..038ff94e369b980baa7bed42b8fec65a9a52ee4e 100644 (file)
@@ -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 9877b12a98ce04e1f481453d0809f356fa8afae4..b4e8f8e4bf9589e5ef7da9b79bbbad9e9a488f9e 100644 (file)
@@ -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 46d9d0f5d211effcf6a34cd4e06dc034b6b93abc..95314b3345e4475e1ba6492ae2a667a91c9a775b 100644 (file)
@@ -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 1776313f05cea2de56c2cba1e61b7de4d5635d4b..7e7aab9c1d815dd7b2f0a47a6e8bb8e487ac4ac3 100644 (file)
@@ -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 77bf27a7c53af9a48559614b4a7fad3d7020d650..e761e3c37d659aaa8068ced1f5bd7e18c53cabdd 100644 (file)
@@ -358,7 +358,6 @@ runtime_files = \
        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 \
index dd942254dcb7e53fff1d4d0de2755ed9c516ab4d..5c2407bb027f2cbc1526cb0c2dfcc63fb0fb4975 100644 (file)
@@ -174,11 +174,11 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \
        runtime/go-caller.c runtime/go-can-convert-interface.c \
        runtime/go-cgo.c runtime/go-chan-cap.c 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 \
-       runtime/go-defer.c runtime/go-deferred-recover.c \
-       runtime/go-eface-compare.c runtime/go-eface-val-compare.c \
-       runtime/go-getgoroot.c runtime/go-go.c runtime/go-gomaxprocs.c \
+       runtime/go-construct-map.c runtime/go-convert-interface.c \
+       runtime/go-copy.c runtime/go-defer.c \
+       runtime/go-deferred-recover.c runtime/go-eface-compare.c \
+       runtime/go-eface-val-compare.c runtime/go-getgoroot.c \
+       runtime/go-go.c runtime/go-gomaxprocs.c \
        runtime/go-int-array-to-string.c runtime/go-int-to-string.c \
        runtime/go-interface-compare.c \
        runtime/go-interface-eface-compare.c \
@@ -219,7 +219,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \
 am__objects_3 = go-append.lo go-assert.lo go-assert-interface.lo \
        go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
        go-can-convert-interface.lo go-cgo.lo go-chan-cap.lo \
-       go-chan-len.lo go-check-interface.lo go-close.lo go-closed.lo \
+       go-chan-len.lo go-check-interface.lo go-close.lo \
        go-construct-map.lo go-convert-interface.lo go-copy.lo \
        go-defer.lo go-deferred-recover.lo go-eface-compare.lo \
        go-eface-val-compare.lo go-getgoroot.lo go-go.lo \
@@ -771,7 +771,6 @@ runtime_files = \
        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 \
@@ -2177,7 +2176,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-closed.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@
@@ -2383,13 +2381,6 @@ go-close.lo: runtime/go-close.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c
 
-go-closed.lo: runtime/go-closed.c
-@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-closed.lo -MD -MP -MF $(DEPDIR)/go-closed.Tpo -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
-@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-closed.Tpo $(DEPDIR)/go-closed.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-closed.c' object='go-closed.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
-
 go-construct-map.lo: runtime/go-construct-map.c
 @am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo
index c9de71f8d5e4379c73948267db90634a94254ffc..9326f2689ae2ddc265699b644b9d7f2b3d5cc3b6 100644 (file)
@@ -10,7 +10,7 @@ typedef _Bool bool;
 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 @@ func chanrecv2(c *chan, val *byte) (received bool) {
                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;
+       }
+}
index 743af8bee9ace6886ef46ee82baf972b96da06c9..cd439bf4ccb7a942b050c08c6bd0f363a3275d09 100644 (file)
@@ -50,9 +50,6 @@ struct __go_channel
   _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 --git a/libgo/runtime/go-closed.c b/libgo/runtime/go-closed.c
deleted file mode 100644 (file)
index bfa9cd6..0000000
+++ /dev/null
@@ -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;
-}
index d16bde62d75a4df534230be79f07dc541e5c4103..3ddc205e05d01e09b276d573660417af3a1da375 100644 (file)
@@ -44,7 +44,6 @@ __go_new_channel (size_t element_size, size_t entries)
   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;
index d09901b0c88365348c1a5f6cee532b82b541a529..29cad9af620cc1ad2148185fbf6a6a26e0ed97ce 100644 (file)
@@ -32,7 +32,6 @@ __go_receive_nonblocking_acquire (struct __go_channel *channel)
          ? 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;
     }
index ee85cde566be4e5457146c9bab981a8a42f3146b..019b20a456ba8d63ed1c23992e039d53f88c9551 100644 (file)
@@ -124,7 +124,6 @@ __go_receive_acquire (struct __go_channel *channel, _Bool for_select)
              ? 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;