aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-10-13 16:58:04 -0400
committerRuss Cox <rsc@golang.org>2011-10-13 16:58:04 -0400
commitf58ed4e64126b595efbde9df04e63c7ea2a4fbd6 (patch)
tree96948e47d2e0751de6c51e6d941ed8defaf70fc6
parentd65aaf24a6f7c4752aa5609f3f40433218483e72 (diff)
downloadgo-f58ed4e64126b595efbde9df04e63c7ea2a4fbd6.tar.xz
gc: disallow close on receive-only channels
Fixes #2353. Fixes #2246. R=golang-dev, r, gri CC=golang-dev https://golang.org/cl/5282042
-rw-r--r--doc/go_spec.html7
-rw-r--r--src/cmd/gc/typecheck.c4
-rw-r--r--src/pkg/runtime/chan.c3
-rw-r--r--test/chan/perm.go4
-rw-r--r--test/closedchan.go11
5 files changed, 26 insertions, 3 deletions
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 13f52996c4..810df2c46a 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -4531,12 +4531,13 @@ BuiltinArgs = Type [ "," ExpressionList ] | ExpressionList .
<p>
For a channel <code>c</code>, the built-in function <code>close(c)</code>
-marks the channel as unable to accept more values through a send operation;
-sending to or closing a closed channel causes a <a href="#Run_time_panics">run-time panic</a>.
+records that no more values will be sent on the channel.
+It is an error if <code>c</code> is a receive-only channel.
+Sending to or closing a closed channel causes a <a href="#Run_time_panics">run-time panic</a>.
+Closing the nil channel also causes a <a href="#Run_time_panics">run-time panic</a>.
After calling <code>close</code>, and after any previously
sent values have been received, receive operations will return
the zero value for the channel's type without blocking.
-
The multi-valued <a href="#Receive_operator">receive operation</a>
returns a received value along with an indication of whether the channel is closed.
</p>
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 052fc74dff..0b2e6f0ca6 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -984,6 +984,10 @@ reswitch:
yyerror("invalid operation: %#N (non-chan type %T)", n, t);
goto error;
}
+ if(!(t->chan & Csend)) {
+ yyerror("invalid operation: %#N (cannot close receive-only channel)", n);
+ goto error;
+ }
ok |= Etop;
goto ret;
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index cc056f65f1..475da233c1 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -1052,6 +1052,9 @@ runtime·closechan(Hchan *c)
SudoG *sg;
G* gp;
+ if(c == nil)
+ runtime·panicstring("close of nil channel");
+
if(runtime·gcwaiting)
runtime·gosched();
diff --git a/test/chan/perm.go b/test/chan/perm.go
index 038ff94e36..af054450ea 100644
--- a/test/chan/perm.go
+++ b/test/chan/perm.go
@@ -48,4 +48,8 @@ func main() {
case x := <-cs: // ERROR "receive"
_ = x
}
+
+ close(c)
+ close(cs)
+ close(cr) // ERROR "receive"
}
diff --git a/test/closedchan.go b/test/closedchan.go
index 95314b3345..0dbe662d84 100644
--- a/test/closedchan.go
+++ b/test/closedchan.go
@@ -327,4 +327,15 @@ func main() {
testclosed(mk(closedasync()))
}
}
+
+ var ch chan int
+ shouldPanic(func() {
+ close(ch)
+ })
+
+ ch = make(chan int)
+ close(ch)
+ shouldPanic(func() {
+ close(ch)
+ })
}