Commit 1b3244e0 authored by Russ Cox's avatar Russ Cox

cmd/gc: fix eval order in select

Ordinary variable load was assumed to be not worth saving,
but not if one of the function calls later might change
its value.

Fixes #4313.

R=ken2
CC=golang-dev
https://golang.org/cl/6997047
parent b3bb4bd2
...@@ -276,11 +276,11 @@ orderstmt(Node *n, NodeList **out) ...@@ -276,11 +276,11 @@ orderstmt(Node *n, NodeList **out)
case OSELRECV2: case OSELRECV2:
orderexprinplace(&r->left); orderexprinplace(&r->left);
orderexprinplace(&r->ntest); orderexprinplace(&r->ntest);
orderexpr(&r->right->left, out); orderexpr(&r->right->left, &l->n->ninit);
break; break;
case OSEND: case OSEND:
orderexpr(&r->left, out); orderexpr(&r->left, &l->n->ninit);
orderexpr(&r->right, out); orderexpr(&r->right, &l->n->ninit);
break; break;
} }
} }
......
...@@ -297,15 +297,15 @@ walkselect(Node *sel) ...@@ -297,15 +297,15 @@ walkselect(Node *sel)
setlineno(cas); setlineno(cas);
n = cas->left; n = cas->left;
r = nod(OIF, N, N); r = nod(OIF, N, N);
r->nbody = cas->ninit; r->ninit = cas->ninit;
cas->ninit = nil; cas->ninit = nil;
if(n != nil) { if(n != nil) {
r->nbody = concat(r->nbody, n->ninit); r->ninit = concat(r->ninit, n->ninit);
n->ninit = nil; n->ninit = nil;
} }
if(n == nil) { if(n == nil) {
// selectdefault(sel *byte); // selectdefault(sel *byte);
r->ntest = mkcall("selectdefault", types[TBOOL], &init, var); r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var);
} else { } else {
switch(n->op) { switch(n->op) {
default: default:
...@@ -313,25 +313,25 @@ walkselect(Node *sel) ...@@ -313,25 +313,25 @@ walkselect(Node *sel)
case OSEND: case OSEND:
// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
n->left = safeexpr(n->left, &r->ninit); n->left = localexpr(safeexpr(n->left, &r->ninit), n->left->type, &r->ninit);
n->right = localexpr(n->right, n->left->type->type, &r->ninit); n->right = localexpr(n->right, n->left->type->type, &r->ninit);
n->right = nod(OADDR, n->right, N); n->right = nod(OADDR, n->right, N);
n->right->etype = 1; // pointer does not escape n->right->etype = 1; // pointer does not escape
typecheck(&n->right, Erv); typecheck(&n->right, Erv);
r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
&init, var, n->left, n->right); &r->ninit, var, n->left, n->right);
break; break;
case OSELRECV: case OSELRECV:
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
&init, var, n->right->left, n->left); &r->ninit, var, n->right->left, n->left);
break; break;
case OSELRECV2: case OSELRECV2:
// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
&init, var, n->right->left, n->left, n->ntest); &r->ninit, var, n->right->left, n->left, n->ntest);
break; break;
} }
} }
......
...@@ -2040,11 +2040,13 @@ cheapexpr(Node *n, NodeList **init) ...@@ -2040,11 +2040,13 @@ cheapexpr(Node *n, NodeList **init)
/* /*
* return n in a local variable of type t if it is not already. * return n in a local variable of type t if it is not already.
* the value is guaranteed not to change except by direct
* assignment to it.
*/ */
Node* Node*
localexpr(Node *n, Type *t, NodeList **init) localexpr(Node *n, Type *t, NodeList **init)
{ {
if(n->op == ONAME && if(n->op == ONAME && !n->addrtaken &&
(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) && (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
convertop(n->type, t, nil) == OCONVNOP) convertop(n->type, t, nil) == OCONVNOP)
return n; return n;
......
// run
// Copyright 2012 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.
// Order of operations in select.
package main
func main() {
c := make(chan int, 1)
x := 0
select {
case c <- x: // should see x = 0, not x = 42 (after makec)
case <-makec(&x): // should be evaluated only after c and x on previous line
}
y := <-c
if y != 0 {
panic(y)
}
}
func makec(px *int) chan bool {
if false { for {} }
*px = 42
return make(chan bool, 0)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment