]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: fix spurious type errors in walkselect.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 13 Mar 2014 07:14:05 +0000 (08:14 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 13 Mar 2014 07:14:05 +0000 (08:14 +0100)
The lowering to runtime calls introduces hidden pointers to the
arguments of select clauses. When implicit conversions were
involved it could end up with incompatible pointers. Since the
pointed-to types have the same representation, we can introduce a
forced conversion.

Fixes #6847.

LGTM=rsc
R=rsc, iant, khr
CC=golang-codereviews
https://golang.org/cl/72380043

src/cmd/gc/select.c
test/fixedbugs/issue6847.go [new file with mode: 0644]

index 35da0557b61698d58b21f79f14d2234aa801b737..d3c04c659e4ec73150fe560bcdee37f098957116 100644 (file)
@@ -214,6 +214,11 @@ walkselect(Node *sel)
                                n->left = nod(OADDR, n->left, N);
                                n->left->etype = 1;  // pointer does not escape
                                typecheck(&n->left, Erv);
+                               if(!eqtype(ch->type->type, n->left->type->type)) {
+                                       n->left = nod(OCONVNOP, n->left, N);
+                                       n->left->type = ptrto(ch->type->type);
+                                       n->left->typecheck = 1;
+                               }
                        } else {
                                tmp = temp(ch->type->type);
                                a = nod(OADDR, tmp, N);
@@ -330,6 +335,13 @@ walkselect(Node *sel)
                                n->right = nod(OADDR, n->right, N);
                                n->right->etype = 1;  // pointer does not escape
                                typecheck(&n->right, Erv);
+                               // cast to appropriate type if necessary.
+                               if(!eqtype(n->right->type->type, n->left->type->type) &&
+                                       assignop(n->right->type->type, n->left->type->type, nil) == OCONVNOP) {
+                                       n->right = nod(OCONVNOP, n->right, N);
+                                       n->right->type = ptrto(n->left->type->type);
+                                       n->right->typecheck = 1;
+                               }
                                r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
                                        &r->ninit, var, n->left, n->right);
                                break;
diff --git a/test/fixedbugs/issue6847.go b/test/fixedbugs/issue6847.go
new file mode 100644 (file)
index 0000000..e6427e1
--- /dev/null
@@ -0,0 +1,85 @@
+// compile
+
+// Copyright 2014 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.
+
+// Issue 6847: select clauses involving implicit conversion
+// of channels trigger a spurious typechecking error during walk.
+
+package p
+
+type I1 interface {
+       String()
+}
+type I2 interface {
+       String()
+}
+
+func F() {
+       var (
+               cr <-chan int
+               cs chan<- int
+               c  chan int
+
+               ccr chan (<-chan int)
+               ccs chan chan<- int
+               cc  chan chan int
+
+               ok bool
+       )
+       // Send cases.
+       select {
+       case ccr <- cr:
+       case ccr <- c:
+       }
+       select {
+       case ccs <- cs:
+       case ccs <- c:
+       }
+       select {
+       case ccr <- c:
+       default:
+       }
+       // Receive cases.
+       select {
+       case cr = <-cc:
+       case cs = <-cc:
+       case c = <-cc:
+       }
+       select {
+       case cr = <-cc:
+       default:
+       }
+       select {
+       case cr, ok = <-cc:
+       case cs, ok = <-cc:
+       case c = <-cc:
+       }
+      // Interfaces.
+       var (
+               c1 chan I1
+               c2 chan I2
+               x1 I1
+               x2 I2
+       )
+       select {
+       case c1 <- x1:
+       case c1 <- x2:
+       case c2 <- x1:
+       case c2 <- x2:
+       }
+       select {
+       case x1 = <-c1:
+       case x1 = <-c2:
+       case x2 = <-c1:
+       case x2 = <-c2:
+       }
+       select {
+       case x1, ok = <-c1:
+       case x1, ok = <-c2:
+       case x2, ok = <-c1:
+       case x2, ok = <-c2:
+       }
+       _ = ok
+}