]> Cypherpunks repositories - gostls13.git/commitdiff
gc: fix order of evaluation
authorRuss Cox <rsc@golang.org>
Wed, 25 Jan 2012 22:53:50 +0000 (17:53 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 25 Jan 2012 22:53:50 +0000 (17:53 -0500)
Pulling function calls out to happen before the
expression being evaluated was causing illegal
reorderings even without inlining; with inlining
it got worse.  This CL adds a separate ordering pass
to move things with a fixed order out of expressions
and into the statement sequence, where they will
not be reordered by walk.

Replaces lvd's CL 5534079.

Fixes #2740.

R=lvd
CC=golang-dev
https://golang.org/cl/5569062

14 files changed:
src/cmd/gc/Makefile
src/cmd/gc/fmt.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/inl.c
src/cmd/gc/order.c [new file with mode: 0644]
src/cmd/gc/pgen.c
src/cmd/gc/sinit.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/fixedbugs/bug401.go
test/func8.go [new file with mode: 0644]
test/reorder2.go [new file with mode: 0644]

index 623add4a7fdbe4fa1efcb5890b89f746c4a3e38c..bb0d01637e930a8194b479fff3850eb4667c806e 100644 (file)
@@ -34,6 +34,7 @@ OFILES=\
        mparith2.$O\
        mparith3.$O\
        obj.$O\
+       order.$O\
        range.$O\
        reflect.$O\
        select.$O\
index b7a648789ab235f147d24d120124e9401ca549e9..31b0a623f2149ce326618e0a440a9c8b6ec7f662 100644 (file)
@@ -1263,8 +1263,12 @@ exprfmt(Fmt *f, Node *n, int prec)
        case OMAKEMAP:
        case OMAKECHAN:
        case OMAKESLICE:
-               if(n->list->next)
-                       return fmtprint(f, "make(%T, %,H)", n->type, n->list->next);
+               if(n->list) // pre-typecheck
+                       return fmtprint(f, "make(%T, %,H)", n->type, n->list);
+               if(n->right)
+                       return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
+               if(n->left)
+                       return fmtprint(f, "make(%T, %N)", n->type, n->left);
                return fmtprint(f, "make(%T)", n->type);
 
        // Unary
index ebdd0f02dc27294fba499bfb02fea14674928774..694a10ab5ccdc1b0d479d7722830776b8ebc1b25 100644 (file)
@@ -826,5 +826,6 @@ temp(Type *t)
        
        n = nod(OXXX, N, N);
        tempname(n, t);
+       n->sym->def->used = 1;
        return n;
 }
index 37bf806e36ab2f20c085788a00af0bdbd6fb4489..b4715376f6f03b418370edf5be3feb292dd52a4b 100644 (file)
@@ -1088,6 +1088,11 @@ void     dumpobj(void);
 void   ieeedtod(uint64 *ieee, double native);
 Sym*   stringsym(char*, int);
 
+/*
+ *     order.c
+ */
+void   order(Node *fn);
+
 /*
  *     range.c
  */
@@ -1124,6 +1129,7 @@ int       stataddr(Node *nam, Node *n);
  */
 Node*  adddot(Node *n);
 int    adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
+void   addinit(Node**, NodeList*);
 Type*  aindex(Node *b, Type *t);
 int    algtype(Type *t);
 int    algtype1(Type *t, Type **bad);
@@ -1135,6 +1141,7 @@ int       brcom(int a);
 int    brrev(int a);
 NodeList*      concat(NodeList *a, NodeList *b);
 int    convertop(Type *src, Type *dst, char **why);
+Node*  copyexpr(Node*, Type*, NodeList**);
 int    count(NodeList *l);
 int    cplxsubtype(int et);
 int    eqtype(Type *t1, Type *t2);
index 137d913711862d5b502f2ae54bd0dd1ea2df04d5..b8ebcbcbdaf6289a865008adf06a21b6f5efc725 100644 (file)
@@ -225,6 +225,7 @@ static void
 inlconv2stmt(Node *n)
 {
        n->op = OBLOCK;
+       // n->ninit stays
        n->list = n->nbody;
        n->nbody = nil;
        n->rlist = nil;
@@ -232,13 +233,14 @@ inlconv2stmt(Node *n)
 
 // Turn an OINLCALL into a single valued expression.
 static void
-inlconv2expr(Node *n)
+inlconv2expr(Node **np)
 {
-       n->op = OCONVNOP;
-       n->left = n->rlist->n;
-       n->rlist = nil;
-       n->ninit = concat(n->ninit, n->nbody);
-       n->nbody = nil;
+       Node *n, *r;
+       
+       n = *np;
+       r = n->rlist->n;
+       addinit(&r, concat(n->ninit, n->nbody));
+       *np = r;
 }
 
 // Turn the OINLCALL in n->list into an expression list on n.
@@ -248,7 +250,7 @@ inlgluelist(Node *n)
 {
        Node *c;
 
-       c = n->list->n;
+       c = n->list->n;  // this is the OINLCALL
        n->ninit = concat(n->ninit, c->ninit);
        n->ninit = concat(n->ninit, c->nbody);
        n->list  = c->rlist;
@@ -261,7 +263,7 @@ inlgluerlist(Node *n)
 {
        Node *c;
 
-       c = n->rlist->n;
+       c = n->rlist->n;  // this is the OINLCALL
        n->ninit = concat(n->ninit, c->ninit);
        n->ninit = concat(n->ninit, c->nbody);
        n->rlist = c->rlist;
@@ -322,11 +324,11 @@ inlnode(Node **np)
 
        inlnode(&n->left);
        if(n->left && n->left->op == OINLCALL)
-               inlconv2expr(n->left);
+               inlconv2expr(&n->left);
 
        inlnode(&n->right);
        if(n->right && n->right->op == OINLCALL)
-               inlconv2expr(n->right);
+               inlconv2expr(&n->right);
 
        inlnodelist(n->list);
        switch(n->op) {
@@ -359,7 +361,7 @@ inlnode(Node **np)
        list_dflt:
                for(l=n->list; l; l=l->next)
                        if(l->n->op == OINLCALL)
-                               inlconv2expr(l->n);
+                               inlconv2expr(&l->n);
        }
 
        inlnodelist(n->rlist);
@@ -377,13 +379,13 @@ inlnode(Node **np)
        default:
                for(l=n->rlist; l; l=l->next)
                        if(l->n->op == OINLCALL)
-                               inlconv2expr(l->n);
+                               inlconv2expr(&l->n);
 
        }
 
        inlnode(&n->ntest);
        if(n->ntest && n->ntest->op == OINLCALL)
-               inlconv2expr(n->ntest);
+               inlconv2expr(&n->ntest);
 
        inlnode(&n->nincr);
        if(n->nincr && n->nincr->op == OINLCALL)
@@ -504,11 +506,14 @@ mkinlcall(Node **np, Node *fn)
                        fatal("missing inlvar for %N\n", t->nname);
 
                if(n->left->op == ODOTMETH) {
-                       if (!n->left->left)
+                       if(!n->left->left)
                                fatal("method call without receiver: %+N", n);
-                       if(t != T && t->nname != N && !isblank(t->nname))
+                       if(t == T)
+                               fatal("method call unknown receiver type: %+N", n);
+                       if(t->nname != N && !isblank(t->nname))
                                as = nod(OAS, t->nname->inlvar, n->left->left);
-                       // else if !ONAME add to init anyway?
+                       else
+                               as = nod(OAS, temp(t->type), n->left->left);
                } else {  // non-method call to method
                        if (!n->list)
                                fatal("non-method call to method without first arg: %+N", n);
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
new file mode 100644 (file)
index 0000000..42e32dc
--- /dev/null
@@ -0,0 +1,370 @@
+// 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.
+
+// Rewrite tree to use separate statements to enforce
+// order of evaluation.  Makes walk easier, because it
+// can (after this runs) reorder at will within an expression.
+
+#include       <u.h>
+#include       <libc.h>
+#include       "go.h"
+
+static void    orderstmt(Node*, NodeList**);
+static void    orderstmtlist(NodeList*, NodeList**);
+static void    orderexpr(Node**, NodeList**);
+static void    orderexprlist(NodeList*, NodeList**);
+
+void
+order(Node *fn)
+{
+       NodeList *out;
+       
+       out = nil;
+       orderstmtlist(fn->nbody, &out);
+       fn->nbody = out;
+}
+
+static void
+orderstmtlist(NodeList *l, NodeList **out)
+{
+       for(; l; l=l->next)
+               orderstmt(l->n, out);
+}
+
+// Order the block of statements *l onto a new list,
+// and then replace *l with that list.
+static void
+orderblock(NodeList **l)
+{
+       NodeList *out;
+       
+       out = nil;
+       orderstmtlist(*l, &out);
+       *l = out;
+}
+
+// Order the side effects in *np and leave them as
+// the init list of the final *np.
+static void
+orderexprinplace(Node **np)
+{
+       Node *n;
+       NodeList *out;
+       
+       n = *np;
+       out = nil;
+       orderexpr(&n, &out);
+       addinit(&n, out);
+       *np = n;
+}
+
+// Like orderblock, but applied to a single statement.
+static void
+orderstmtinplace(Node **np)
+{
+       Node *n;
+       NodeList *out;
+
+       n = *np;
+       out = nil;
+       orderstmt(n, &out);
+       *np = liststmt(out);
+}
+
+// Move n's init list to *out.
+static void
+orderinit(Node *n, NodeList **out)
+{
+       *out = concat(*out, n->ninit);
+       n->ninit = nil;
+}
+
+// Is the list l actually just f() for a multi-value function?
+static int
+ismulticall(NodeList *l)
+{
+       Node *n;
+       
+       // one arg only
+       if(l == nil || l->next != nil)
+               return 0;
+       n = l->n;
+       
+       // must be call
+       switch(n->op) {
+       default:
+               return 0;
+       case OCALLFUNC:
+       case OCALLMETH:
+       case OCALLINTER:
+               break;
+       }
+       
+       // call must return multiple values
+       return n->left->type->outtuple > 1;
+}
+
+// n is a multi-value function call.  Add t1, t2, .. = n to out
+// and return the list t1, t2, ...
+static NodeList*
+copyret(Node *n, NodeList **out)
+{
+       Type *t;
+       Node *tmp, *as;
+       NodeList *l1, *l2;
+       Iter tl;
+       
+       if(n->type->etype != TSTRUCT || !n->type->funarg)
+               fatal("copyret %T %d", n->type, n->left->type->outtuple);
+
+       l1 = nil;
+       l2 = nil;
+       for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
+               tmp = temp(t->type);
+               l1 = list(l1, tmp);
+               l2 = list(l2, tmp);
+       }
+       
+       as = nod(OAS2, N, N);
+       as->list = l1;
+       as->rlist = list1(n);
+       typecheck(&as, Etop);
+       orderstmt(as, out);
+
+       return l2;
+}
+
+static void
+ordercallargs(NodeList **l, NodeList **out)
+{
+       if(ismulticall(*l)) {
+               // return f() where f() is multiple values.
+               *l = copyret((*l)->n, out);
+       } else {
+               orderexprlist(*l, out);
+       }
+}
+
+static void
+ordercall(Node *n, NodeList **out)
+{
+       orderexpr(&n->left, out);
+       ordercallargs(&n->list, out);
+}
+
+static void
+orderstmt(Node *n, NodeList **out)
+{
+       int lno;
+       NodeList *l;
+       Node *r;
+
+       if(n == N)
+               return;
+
+       lno = setlineno(n);
+       switch(n->op) {
+       default:
+               fatal("orderstmt %O", n->op);
+
+       case OAS2:
+       case OAS2DOTTYPE:
+       case OAS2MAPR:
+       case OAS:
+       case OASOP:
+       case OCLOSE:
+       case OCOPY:
+       case ODELETE:
+       case OPANIC:
+       case OPRINT:
+       case OPRINTN:
+       case ORECOVER:
+       case ORECV:
+       case OSEND:
+               orderinit(n, out);
+               orderexpr(&n->left, out);
+               orderexpr(&n->right, out);
+               orderexprlist(n->list, out);
+               orderexprlist(n->rlist, out);
+               *out = list(*out, n);
+               break;
+       
+       case OAS2FUNC:
+               // Special: avoid copy of func call n->rlist->n.
+               orderinit(n, out);
+               orderexprlist(n->list, out);
+               ordercall(n->rlist->n, out);
+               *out = list(*out, n);
+               break;
+
+       case OAS2RECV:
+               // Special: avoid copy of receive.
+               orderinit(n, out);
+               orderexprlist(n->list, out);
+               orderexpr(&n->rlist->n->left, out);  // arg to recv
+               *out = list(*out, n);
+               break;
+
+       case OBLOCK:
+       case OEMPTY:
+               // Special: does not save n onto out.
+               orderinit(n, out);
+               orderstmtlist(n->list, out);
+               break;
+
+       case OBREAK:
+       case OCONTINUE:
+       case ODCL:
+       case ODCLCONST:
+       case ODCLTYPE:
+       case OFALL:
+       case_OFALL:
+       case OGOTO:
+       case OLABEL:
+               // Special: n->left is not an expression; save as is.
+               orderinit(n, out);
+               *out = list(*out, n);
+               break;
+
+       case OCALLFUNC:
+       case OCALLINTER:
+       case OCALLMETH:
+               // Special: handle call arguments.
+               orderinit(n, out);
+               ordercall(n, out);
+               *out = list(*out, n);
+               break;
+
+       case ODEFER:
+       case OPROC:
+               // Special: order arguments to inner call but not call itself.
+               orderinit(n, out);
+               ordercall(n->left, out);
+               *out = list(*out, n);
+               break;
+
+       case OFOR:
+               orderinit(n, out);
+               orderexprinplace(&n->ntest);
+               orderstmtinplace(&n->nincr);
+               orderblock(&n->nbody);
+               *out = list(*out, n);
+               break;
+               
+       case OIF:
+               orderinit(n, out);
+               orderexprinplace(&n->ntest);
+               orderblock(&n->nbody);
+               orderblock(&n->nelse);
+               *out = list(*out, n);
+               break;
+
+       case ORANGE:
+               orderinit(n, out);
+               orderexpr(&n->right, out);
+               for(l=n->list; l; l=l->next)
+                       orderexprinplace(&l->n);
+               orderblock(&n->nbody);
+               *out = list(*out, n);
+               break;
+
+       case ORETURN:
+               ordercallargs(&n->list, out);
+               *out = list(*out, n);
+               break;
+               
+       case OSELECT:
+               orderinit(n, out);
+               for(l=n->list; l; l=l->next) {
+                       if(l->n->op != OXCASE)
+                               fatal("order select case %O", l->n->op);
+                       r = l->n->left;
+                       if(r == nil)
+                               continue;
+                       switch(r->op) {
+                       case OSELRECV:
+                       case OSELRECV2:
+                               orderexprinplace(&r->left);
+                               orderexprinplace(&r->ntest);
+                               orderexpr(&r->right->left, out);
+                               break;
+                       case OSEND:
+                               orderexpr(&r->left, out);
+                               orderexpr(&r->right, out);
+                               break;
+                       }
+               }
+               *out = list(*out, n);
+               break;
+
+       case OSWITCH:
+               orderinit(n, out);
+               orderexpr(&n->ntest, out);
+               for(l=n->list; l; l=l->next) {
+                       if(l->n->op != OXCASE)
+                               fatal("order switch case %O", l->n->op);
+                       orderexpr(&l->n->left, &l->n->ninit);
+               }
+               *out = list(*out, n);
+               break;
+
+       case OXFALL:
+               yyerror("fallthrough statement out of place");
+               n->op = OFALL;
+               goto case_OFALL;
+       }
+       
+       lineno = lno;
+}
+
+static void
+orderexprlist(NodeList *l, NodeList **out)
+{
+       for(; l; l=l->next)
+               orderexpr(&l->n, out);
+}
+
+static void
+orderexpr(Node **np, NodeList **out)
+{
+       Node *n;
+       int lno;
+
+       n = *np;
+       if(n == N)
+               return;
+
+       lno = setlineno(n);
+       orderinit(n, out);
+
+       switch(n->op) {
+       default:
+               orderexpr(&n->left, out);
+               orderexpr(&n->right, out);
+               orderexprlist(n->list, out);
+               orderexprlist(n->rlist, out);
+               break;
+       
+       case OANDAND:
+       case OOROR:
+               orderexpr(&n->left, out);
+               orderexprinplace(&n->right);
+               break;
+       
+       case OCALLFUNC:
+       case OCALLMETH:
+       case OCALLINTER:
+               ordercall(n, out);
+               n = copyexpr(n, n->type, out);
+               break;
+
+       case ORECV:
+               n = copyexpr(n, n->type, out);
+               break;
+       }
+       
+       lineno = lno;
+
+       *np = n;
+}
index a54f0978252a3f494be58e58f828c7c49489c90b..8e65ba22dbd0db2aea4d57bc842cc02b3bd11149 100644 (file)
@@ -54,7 +54,11 @@ compile(Node *fn)
                        t = structnext(&save);
                }
        }
-
+       
+       order(curfn);
+       if(nerrors != 0)
+               goto ret;
+       
        hasdefer = 0;
        walk(curfn);
        if(nerrors != 0)
index 73a0af799ef65dc464cffe2f38328be105e82d0e..0cf21e2bbe414262c4c29f64f351137c5a66dc97 100644 (file)
@@ -154,6 +154,10 @@ init2(Node *n, NodeList **out)
 {
        if(n == N || n->initorder == InitDone)
                return;
+
+       if(n->op == ONAME && n->ninit)
+               fatal("name %S with ninit: %+N\n", n->sym, n);
+
        init1(n, out);
        init2(n->left, out);
        init2(n->right, out);
index 9c31dace4c34ae10bdb311b1cdb8ee213291d177..59e18c28856356c9f2f0b821a2728ba5bc050370 100644 (file)
@@ -1957,7 +1957,7 @@ safeexpr(Node *n, NodeList **init)
        return cheapexpr(n, init);
 }
 
-static Node*
+Node*
 copyexpr(Node *n, Type *t, NodeList **init)
 {
        Node *a, *l;
@@ -3522,3 +3522,26 @@ strlit(char *s)
        t->len = strlen(s);
        return t;
 }
+
+void
+addinit(Node **np, NodeList *init)
+{
+       Node *n;
+       
+       if(init == nil)
+               return;
+
+       n = *np;
+       switch(n->op) {
+       case ONAME:
+       case OLITERAL:
+               // There may be multiple refs to this node;
+               // introduce OCONVNOP to hold init list.
+               n = nod(OCONVNOP, n, N);
+               n->type = n->left->type;
+               n->typecheck = 1;
+               *np = n;
+               break;
+       }
+       n->ninit = concat(init, n->ninit);
+}
index f9f0d8b301d6dddcf81827c0355ae2cab8026921..2e8c3b1e255288214a21c366972d091c0ba2a99b 100644 (file)
@@ -1161,6 +1161,7 @@ reswitch:
                        yyerror("missing argument to make");
                        goto error;
                }
+               n->list = nil;
                l = args->n;
                args = args->next;
                typecheck(&l, Etype);
index 6ec978f0bb2d97c9cf060fb5e3225e0e5e02f0cb..53040fe93d4bfa2b933d359850e3d00a759786fe 100644 (file)
@@ -199,14 +199,12 @@ walkstmt(Node **np)
        case OPANIC:
        case OEMPTY:
        case ORECOVER:
-               if(n->typecheck == 0) {
-                       dump("missing typecheck:", n);
-                       fatal("missing typecheck");
-               }
+               if(n->typecheck == 0)
+                       fatal("missing typecheck: %+N", n);
                init = n->ninit;
                n->ninit = nil;
                walkexpr(&n, &init);
-               n->ninit = concat(init, n->ninit);
+               addinit(&n, init);
                break;
 
        case OBREAK:
@@ -250,7 +248,7 @@ walkstmt(Node **np)
                        init = n->ntest->ninit;
                        n->ntest->ninit = nil;
                        walkexpr(&n->ntest, &init);
-                       n->ntest->ninit = concat(init, n->ntest->ninit);
+                       addinit(&n->ntest, init);
                }
                walkstmt(&n->nincr);
                walkstmtlist(n->nbody);
@@ -332,6 +330,9 @@ walkstmt(Node **np)
                break;
        }
 
+       if(n->op == ONAME)
+               fatal("walkstmt ended up with name: %+N", n);
+       
        *np = n;
 }
 
@@ -402,10 +403,8 @@ walkexpr(Node **np, NodeList **init)
        if(debug['w'] > 1)
                dump("walk-before", n);
 
-       if(n->typecheck != 1) {
-               dump("missed typecheck", n);
-               fatal("missed typecheck");
-       }
+       if(n->typecheck != 1)
+               fatal("missed typecheck: %+N\n", n);
 
        switch(n->op) {
        default:
@@ -481,7 +480,7 @@ walkexpr(Node **np, NodeList **init)
                // save elsewhere and store on the eventual n->right.
                ll = nil;
                walkexpr(&n->right, &ll);
-               n->right->ninit = concat(n->right->ninit, ll);
+               addinit(&n->right, ll);
                goto ret;
 
        case OPRINT:
@@ -994,8 +993,10 @@ walkexpr(Node **np, NodeList **init)
        case ONEW:
                if(n->esc == EscNone && n->type->type->width < (1<<16)) {
                        r = temp(n->type->type);
-                       *init = list(*init, nod(OAS, r, N));  // zero temp
-                       r = nod(OADDR, r, N);
+                       r = nod(OAS, r, N);  // zero temp
+                       typecheck(&r, Etop);
+                       *init = list(*init, r);
+                       r = nod(OADDR, r->left, N);
                        typecheck(&r, Erv);
                        n = r;
                } else {
@@ -1878,7 +1879,7 @@ reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
        
        q = temp(n->type);
        q = nod(OAS, q, n);
-       q->typecheck = 1;
+       typecheck(&q, Etop);
        *early = list(*early, q);
        *np = q->left;
 }
index baad1bc7da2eb08bb7b039e6aa40332c8df4861d..553e217b7d48a380d840609bfe4c925f670206e8 100644 (file)
@@ -1,29 +1,46 @@
-// $G $D/$F.go || echo "Bug398"
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo "Bug401"
 
 // Copyright 2011 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 2582
-package foo
-    
-type T struct {}
+package main
+
+type T struct{}
+
 func (T) cplx() complex128 {
-       for false {}  // avoid inlining
-       return complex(1,0)
+       for false {
+       } // avoid inlining
+       return complex(1, 0)
+}
+
+func (T) cplx2() complex128 {
+       return complex(0, 1)
 }
 
 type I interface {
        cplx() complex128
 }
 
-func f(e float32, t T) {
+func main() {
 
-       _ = real(t.cplx())
-       _ = imag(t.cplx())
+       var t T
+
+       if v := real(t.cplx()); v != 1 {
+               panic("not-inlined complex call failed")
+       }
+       _ = imag(t.cplx())
+
+       _ = real(t.cplx2())
+       if v := imag(t.cplx2()); v != 1 {
+               panic("potentially inlined complex call failed")
+       }
 
        var i I
        i = t
-       _ = real(i.cplx())
-       _ = imag(i.cplx())
-}
\ No newline at end of file
+       if v := real(i.cplx()); v != 1 {
+               panic("potentially inlined complex call failed")
+       }
+       _ = imag(i.cplx())
+}
diff --git a/test/func8.go b/test/func8.go
new file mode 100644 (file)
index 0000000..bb61064
--- /dev/null
@@ -0,0 +1,47 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 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.
+
+package main
+
+var calledf int
+
+func f() int {
+       calledf++
+       return 0
+}
+
+func g() int {
+       return calledf
+}
+
+var xy string
+
+func x() bool {
+       for false {
+       } // no inlining
+       xy += "x"
+       return false
+}
+
+func y() string {
+       for false {
+       } // no inlining
+       xy += "y"
+       return "abc"
+}
+
+func main() {
+       if f() == g() {
+               println("wrong f,g order")
+       }
+
+       if x() == (y() == "abc") {
+               panic("wrong compare")
+       }
+       if xy != "xy" {
+               println("wrong x,y order")
+       }
+}
diff --git a/test/reorder2.go b/test/reorder2.go
new file mode 100644 (file)
index 0000000..3e14985
--- /dev/null
@@ -0,0 +1,174 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 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.
+
+// derived from fixedbugs/bug294.go
+
+package main
+
+var log string
+
+type TT int
+
+func (t TT) a(s string) TT {
+       log += "a(" + s + ")"
+       return t
+}
+
+func (TT) b(s string) string {
+       log += "b(" + s + ")"
+       return s
+}
+
+type F func(s string) F
+
+func a(s string) F {
+       log += "a(" + s + ")"
+       return F(a)
+}
+
+func b(s string) string {
+       log += "b(" + s + ")"
+       return s
+}
+
+type I interface {
+       a(s string) I
+       b(s string) string
+}
+
+type T1 int
+
+func (t T1) a(s string) I {
+       log += "a(" + s + ")"
+       return t
+}
+
+func (T1) b(s string) string {
+       log += "b(" + s + ")"
+       return s
+}
+
+// f(g(), h()) where g is not inlinable but h is will have the same problem.
+// As will x := g() + h() (same conditions).
+// And g() <- h().
+func f(x, y string) {
+       log += "f(" + x + ", " + y + ")"
+}
+
+func ff(x, y string) {
+       for false {
+       } // prevent inl
+       log += "ff(" + x + ", " + y + ")"
+}
+
+func h(x string) string {
+       log += "h(" + x + ")"
+       return x
+}
+
+func g(x string) string {
+       for false {
+       } // prevent inl
+       log += "g(" + x + ")"
+       return x
+}
+
+func main() {
+       err := 0
+       var t TT
+       if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+               println("expecting a(1)a(2)a(3) , got ", log)
+               err++
+       }
+       log = ""
+
+       if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+               println("expecting a(1)b(2)a(2), got ", log)
+               err++
+       }
+       log = ""
+       if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+               println("expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+               err++
+       }
+       log = ""
+       var i I = T1(0)
+       if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+               println("expecting a(6)ba(7)ba(8)ba(9), got", log)
+               err++
+       }
+       log = ""
+
+       if s := t.a("1").b("3"); log != "a(1)b(3)" || s != "3" {
+               println("expecting a(1)b(3) and 3, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if s := t.a("1").a(t.b("2")).b("3") + t.a("4").b("5"); log != "a(1)b(2)a(2)b(3)a(4)b(5)" || s != "35" {
+               println("expecting a(1)b(2)a(2)b(3)a(4)b(5) and 35, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if s := t.a("4").b("5") + t.a("1").a(t.b("2")).b("3"); log != "a(4)b(5)a(1)b(2)a(2)b(3)" || s != "53" {
+               println("expecting a(4)b(5)a(1)b(2)a(2)b(3) and 35, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if ff(g("1"), g("2")); log != "g(1)g(2)ff(1, 2)" {
+               println("expecting g(1)g(2)ff..., got ", log)
+               err++
+       }
+       log = ""
+
+       if ff(g("1"), h("2")); log != "g(1)h(2)ff(1, 2)" {
+               println("expecting g(1)h(2)ff..., got ", log)
+               err++
+       }
+       log = ""
+
+       if ff(h("1"), g("2")); log != "h(1)g(2)ff(1, 2)" {
+               println("expecting h(1)g(2)ff..., got ", log)
+               err++
+       }
+       log = ""
+
+       if ff(h("1"), h("2")); log != "h(1)h(2)ff(1, 2)" {
+               println("expecting h(1)h(2)ff..., got ", log)
+               err++
+       }
+       log = ""
+
+       if s := g("1") + g("2"); log != "g(1)g(2)" || s != "12" {
+               println("expecting g1g2 and 12, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if s := g("1") + h("2"); log != "g(1)h(2)" || s != "12" {
+               println("expecting g1h2 and 12, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if s := h("1") + g("2"); log != "h(1)g(2)" || s != "12" {
+               println("expecting h1g2 and 12, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if s := h("1") + h("2"); log != "h(1)h(2)" || s != "12" {
+               println("expecting h1h2 and 12, got ", log, " and ", s)
+               err++
+       }
+       log = ""
+
+       if err > 0 {
+               panic("fail")
+       }
+}