aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-11-04 23:03:37 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-11-04 23:03:37 +0000
commit95ac3b7ad0b595c58cb56e9106f93e56a43282e6 (patch)
tree44cbefd0fecf973f2127b8b276de9ef5e912f6ab
parentcf9e9959d1a5e8c7ddb506f68017b4f9c9292b94 (diff)
downloadgcc-95ac3b7ad0b595c58cb56e9106f93e56a43282e6.zip
gcc-95ac3b7ad0b595c58cb56e9106f93e56a43282e6.tar.gz
gcc-95ac3b7ad0b595c58cb56e9106f93e56a43282e6.tar.bz2
Fix select { case v, ok := <-c: }.
From-SVN: r180992
-rw-r--r--gcc/go/gofrontend/statements.cc24
-rw-r--r--gcc/testsuite/go.test/test/closedchan.go29
2 files changed, 49 insertions, 4 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index abc629e..156977d 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -4559,10 +4559,26 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
loc);
Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref,
true, loc);
+
// We have to put S in STATEMENTS_, because that is where the
// variables are declared.
+
go_assert(this->statements_ != NULL);
- this->statements_->add_statement_at_front(s);
+
+ // Skip the variable declaration statements themselves.
+ size_t skip = 1;
+ if (this->var_ != NULL)
+ skip = 2;
+
+ // Verify that we are only skipping variable declarations.
+ size_t i = 0;
+ for (Block::iterator p = this->statements_->begin();
+ i < skip && p != this->statements_->end();
+ ++p, ++i)
+ go_assert((*p)->variable_declaration_statement() != NULL);
+
+ this->statements_->insert_statement_before(skip, s);
+
// We have to lower STATEMENTS_ again, to lower the tuple
// receive assignment we just added.
gogo->lower_block(function, this->statements_);
@@ -4655,7 +4671,8 @@ Select_clauses::Select_clause::dump_clause(
{
ast_dump_context->dump_expression(this->channel_);
ast_dump_context->ostream() << " <- " ;
- ast_dump_context->dump_expression(this->val_);
+ if (this->val_ != NULL)
+ ast_dump_context->dump_expression(this->val_);
}
else
{
@@ -4667,8 +4684,7 @@ Select_clauses::Select_clause::dump_clause(
ast_dump_context->ostream() << " , " ;
ast_dump_context->dump_expression(this->closed_);
}
- if (this->closedvar_ != NULL ||
- this->var_ != NULL)
+ if (this->closedvar_ != NULL || this->var_ != NULL)
ast_dump_context->ostream() << " := " ;
ast_dump_context->ostream() << " <- " ;
diff --git a/gcc/testsuite/go.test/test/closedchan.go b/gcc/testsuite/go.test/test/closedchan.go
index 95314b3..c2bbec5 100644
--- a/gcc/testsuite/go.test/test/closedchan.go
+++ b/gcc/testsuite/go.test/test/closedchan.go
@@ -11,6 +11,10 @@
package main
+import "os"
+
+var failed bool
+
type Chan interface {
Send(int)
Nbsend(int) bool
@@ -225,19 +229,23 @@ func test1(c Chan) {
// recv a close signal (a zero value)
if x := c.Recv(); x != 0 {
println("test1: recv on closed:", x, c.Impl())
+ failed = true
}
if x, ok := c.Recv2(); x != 0 || ok {
println("test1: recv2 on closed:", x, ok, c.Impl())
+ failed = true
}
// 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())
+ failed = true
}
x, ok, selected := c.Nbrecv2()
if x != 0 || ok || !selected {
println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
+ failed = true
}
}
@@ -247,12 +255,14 @@ func test1(c Chan) {
// the value should have been discarded.
if x := c.Recv(); x != 0 {
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
+ failed = true
}
// similarly Send.
shouldPanic(func() { c.Send(2) })
if x := c.Recv(); x != 0 {
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
+ failed = true
}
}
@@ -260,6 +270,7 @@ func testasync1(c Chan) {
// 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())
+ failed = true
}
test1(c)
@@ -269,6 +280,7 @@ func testasync2(c Chan) {
// 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())
+ failed = true
}
test1(c)
@@ -278,6 +290,7 @@ func testasync3(c Chan) {
// should be able to get the last value via Nbrecv
if x, selected := c.Nbrecv(); x != 1 || !selected {
println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
+ failed = true
}
test1(c)
@@ -287,6 +300,7 @@ 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())
+ failed = true
}
test1(c)
}
@@ -327,4 +341,19 @@ func main() {
testclosed(mk(closedasync()))
}
}
+
+ var ch chan int
+ shouldPanic(func() {
+ close(ch)
+ })
+
+ ch = make(chan int)
+ close(ch)
+ shouldPanic(func() {
+ close(ch)
+ })
+
+ if failed {
+ os.Exit(1)
+ }
}