diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 125715bb2de..861d5c0ca99 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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: diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index f39124c1643..a6411d362c4 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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) diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 1f6e687ec82..f1b93429ff2 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -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); } diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index f9b0853e2ea..d24d98f4f88 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index bb2922f180f..5199981ea64 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -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* diff --git a/gcc/testsuite/go.test/test/chan/doubleselect.go b/gcc/testsuite/go.test/test/chan/doubleselect.go index 592d2f54a43..3c7412ed6ab 100644 --- a/gcc/testsuite/go.test/test/chan/doubleselect.go +++ b/gcc/testsuite/go.test/test/chan/doubleselect.go @@ -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") } diff --git a/gcc/testsuite/go.test/test/chan/perm.go b/gcc/testsuite/go.test/test/chan/perm.go index c725829d132..038ff94e369 100644 --- a/gcc/testsuite/go.test/test/chan/perm.go +++ b/gcc/testsuite/go.test/test/chan/perm.go @@ -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 diff --git a/gcc/testsuite/go.test/test/chan/select3.go b/gcc/testsuite/go.test/test/chan/select3.go index 9877b12a98c..b4e8f8e4bf9 100644 --- a/gcc/testsuite/go.test/test/chan/select3.go +++ b/gcc/testsuite/go.test/test/chan/select3.go @@ -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: + } + }) } diff --git a/gcc/testsuite/go.test/test/closedchan.go b/gcc/testsuite/go.test/test/closedchan.go index 46d9d0f5d21..95314b3345e 100644 --- a/gcc/testsuite/go.test/test/closedchan.go +++ b/gcc/testsuite/go.test/test/closedchan.go @@ -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) Closed() bool { - return closed(c) +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) 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()) + } + if x, ok := c.Recv2(); x != 0 || ok { + println("test1: recv2 on closed:", x, ok, c.Impl()) } - // should now be closed. - if !c.Closed() { - println("test1: not closed after recv zero", 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()) } - - // 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()) - } - 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 } -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())) +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() { + for _, mk := range mks { + test1(mk(closedsync())) + } + + for _, testclosed := range testcloseds { + for _, mk := range mks { + testclosed(mk(closedasync())) + } + } } diff --git a/gcc/testsuite/go.test/test/named1.go b/gcc/testsuite/go.test/test/named1.go index 1776313f05c..7e7aab9c1d8 100644 --- a/gcc/testsuite/go.test/test/named1.go +++ b/gcc/testsuite/go.test/test/named1.go @@ -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" diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 77bf27a7c53..e761e3c37d6 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -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 \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index dd942254dcb..5c2407bb027 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -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 diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc index c9de71f8d5e..9326f2689ae 100644 --- a/libgo/runtime/chan.goc +++ b/libgo/runtime/chan.goc @@ -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; + } +} diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h index 743af8bee9a..cd439bf4ccb 100644 --- a/libgo/runtime/channel.h +++ b/libgo/runtime/channel.h @@ -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 index bfa9cd6f9cc..00000000000 --- a/libgo/runtime/go-closed.c +++ /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; -} diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c index d16bde62d75..3ddc205e05d 100644 --- a/libgo/runtime/go-new-channel.c +++ b/libgo/runtime/go-new-channel.c @@ -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; diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c index d09901b0c88..29cad9af620 100644 --- a/libgo/runtime/go-rec-nb-small.c +++ b/libgo/runtime/go-rec-nb-small.c @@ -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; } diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c index ee85cde566b..019b20a456b 100644 --- a/libgo/runtime/go-rec-small.c +++ b/libgo/runtime/go-rec-small.c @@ -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;