]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: annotate local variables with unique ids for inlining
authorRuss Cox <rsc@golang.org>
Wed, 7 Nov 2012 14:59:19 +0000 (09:59 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 7 Nov 2012 14:59:19 +0000 (09:59 -0500)
Avoids problems with local declarations shadowing other names.
We write a more explicit form than the incoming program, so there
may be additional type annotations. For example:

        int := "hello"
        j := 2

would normally turn into

        var int string = "hello"
        var j int = 2

but the int variable shadows the int type in the second line.

This CL marks all local variables with a per-function sequence number,
so that this would instead be:

        var int·1 string = "hello"
        var j·2 int = 2

Fixes #4326.

R=ken2
CC=golang-dev
https://golang.org/cl/6816100

src/cmd/gc/dcl.c
src/cmd/gc/esc.c
src/cmd/gc/fmt.c
src/pkg/exp/types/gcimporter_test.go
test/fixedbugs/issue4326.dir/p1.go [new file with mode: 0644]
test/fixedbugs/issue4326.dir/p2.go [new file with mode: 0644]
test/fixedbugs/issue4326.dir/q1.go [new file with mode: 0644]
test/fixedbugs/issue4326.dir/q2.go [new file with mode: 0644]
test/fixedbugs/issue4326.dir/z.go [new file with mode: 0644]
test/fixedbugs/issue4326.go [new file with mode: 0644]

index d20f64357b639eedae9787fb17ba0956b994e24c..7748289b413bd0c9422428ce1a150328feba7beb 100644 (file)
@@ -163,6 +163,8 @@ redeclare(Sym *s, char *where)
                        s, where, s->lastlineno);
 }
 
+static int vargen;
+
 /*
  * declare individual names - var, typ, const
  */
@@ -171,7 +173,7 @@ declare(Node *n, int ctxt)
 {
        Sym *s;
        int gen;
-       static int typegen, vargen;
+       static int typegen;
        
        if(ctxt == PDISCARD)
                return;
@@ -198,7 +200,7 @@ declare(Node *n, int ctxt)
                        curfn->dcl = list(curfn->dcl, n);
                if(n->op == OTYPE)
                        gen = ++typegen;
-               else if(n->op == ONAME)
+               else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil)
                        gen = ++vargen;
                pushdcl(s);
                n->curfn = curfn;
@@ -522,7 +524,7 @@ ifacedcl(Node *n)
        if(n->op != ODCLFIELD || n->right == N)
                fatal("ifacedcl");
 
-       dclcontext = PAUTO;
+       dclcontext = PPARAM;
        markdcl();
        funcdepth++;
        n->outer = curfn;
@@ -533,6 +535,7 @@ ifacedcl(Node *n)
        // seen the body of a function but since an interface
        // field declaration does not have a body, we must
        // call it now to pop the current declaration context.
+       dclcontext = PAUTO;
        funcbody(n);
 }
 
@@ -574,6 +577,11 @@ funcargs(Node *nt)
        if(nt->op != OTFUNC)
                fatal("funcargs %O", nt->op);
 
+       // re-start the variable generation number
+       // we want to use small numbers for the return variables,
+       // so let them have the chunk starting at 1.
+       vargen = count(nt->rlist);
+
        // declare the receiver and in arguments.
        // no n->defn because type checking of func header
        // will not fill in the types until later
@@ -585,6 +593,8 @@ funcargs(Node *nt)
                        n->left->op = ONAME;
                        n->left->ntype = n->right;
                        declare(n->left, PPARAM);
+                       if(dclcontext == PAUTO)
+                               n->left->vargen = ++vargen;
                }
        }
        for(l=nt->list; l; l=l->next) {
@@ -595,6 +605,8 @@ funcargs(Node *nt)
                        n->left->op = ONAME;
                        n->left->ntype = n->right;
                        declare(n->left, PPARAM);
+                       if(dclcontext == PAUTO)
+                               n->left->vargen = ++vargen;
                }
        }
 
@@ -630,7 +642,8 @@ funcargs(Node *nt)
 
                n->left->ntype = n->right;
                declare(n->left, PPARAMOUT);
-               n->left->vargen = i++;
+               if(dclcontext == PAUTO)
+                       n->left->vargen = ++i;
        }
 }
 
index 6ac0ea530ffb6512686a2e2e5403d446b66927fa..f789386bc92ea4642d9d974fd5a6f81d68f3565f 100644 (file)
@@ -997,14 +997,14 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
        e->pdepth++;
 
        // Input parameter flowing to output parameter?
-       if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen < 20) {
+       if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
                if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
                        if(src->esc != EscScope && src->esc != EscHeap) {
                                if(debug['m'])
                                        warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
                                if((src->esc&EscMask) != EscReturn)
                                        src->esc = EscReturn;
-                               src->esc |= 1<<(dst->vargen + EscBits);
+                               src->esc |= 1<<((dst->vargen-1) + EscBits);
                        }
                        goto recurse;
                }
index e8c0571e5c4a4fc01cc9bb054b08e041a02c2752..114c3f02526ee4990e9fb67e5285158b33761b76 100644 (file)
@@ -724,7 +724,9 @@ typefmt(Fmt *fp, Type *t)
                                        s = S;
                        
                        if(s != S && !t->embedded) {
-                               if(fp->flags&FmtLong)
+                               if(t->funarg)
+                                       fmtprint(fp, "%N ", t->nname);
+                               else if(fp->flags&FmtLong)
                                        fmtprint(fp, "%hhS ", s);  // qualify non-exported names (used on structs, not on funarg)
                                else 
                                        fmtprint(fp, "%S ", s);
@@ -802,6 +804,15 @@ stmtfmt(Fmt *f, Node *n)
 
        switch(n->op){
        case ODCL:
+               if(fmtmode == FExp) {
+                       switch(n->left->class&~PHEAP) {
+                       case PPARAM:
+                       case PPARAMOUT:
+                       case PAUTO:
+                               fmtprint(f, "var %N %T", n->left, n->left->type);
+                               goto ret;
+                       }
+               }                       
                fmtprint(f, "var %S %T", n->left->sym, n->left->type);
                break;
 
@@ -939,6 +950,7 @@ stmtfmt(Fmt *f, Node *n)
                break;
          
        }
+ret:
 
        if(extrablock)
                fmtstrcpy(f, "}");
@@ -1111,6 +1123,15 @@ exprfmt(Fmt *f, Node *n, int prec)
                return fmtprint(f, "%V", &n->val);
 
        case ONAME:
+               // Special case: name used as local variable in export.
+               switch(n->class&~PHEAP){
+               case PAUTO:
+               case PPARAM:
+               case PPARAMOUT:
+                       if(fmtmode == FExp && n->sym && !isblanksym(n->sym) && n->vargen > 0)
+                               return fmtprint(f, "%S·%d", n->sym, n->vargen);
+               }
+
                // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
                // but for export, this should be rendered as (*pkg.T).meth.
                // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
index 2f89d3ac91274888d316778e8a91674733cc429f..d6795fae70cf599f14013ad26e326e04d9520cd4 100644 (file)
@@ -122,7 +122,7 @@ var importedObjectTests = []struct {
        {"math.Pi", ast.Con, "untyped float"},
        {"io.Reader", ast.Typ, "interface{Read(p []byte) (n int, err error)}"},
        {"io.ReadWriter", ast.Typ, "interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
-       {"math.Sin", ast.Fun, "func(x float64) (_ float64)"},
+       {"math.Sin", ast.Fun, "func(x·2 float64) (_ float64)"},
        // TODO(gri) add more tests
 }
 
diff --git a/test/fixedbugs/issue4326.dir/p1.go b/test/fixedbugs/issue4326.dir/p1.go
new file mode 100644 (file)
index 0000000..ab214be
--- /dev/null
@@ -0,0 +1,12 @@
+package p1
+
+type O map[string]map[string]string
+
+func (opts O) RemoveOption(sect, opt string) bool {
+       if _, ok := opts[sect]; !ok {
+               return false
+       }
+       _, ok := opts[sect][opt]
+       delete(opts[sect], opt)
+       return ok
+}
diff --git a/test/fixedbugs/issue4326.dir/p2.go b/test/fixedbugs/issue4326.dir/p2.go
new file mode 100644 (file)
index 0000000..8e86266
--- /dev/null
@@ -0,0 +1,5 @@
+package p2
+
+import "./p1"
+
+func NewO() p1.O { return nil }
diff --git a/test/fixedbugs/issue4326.dir/q1.go b/test/fixedbugs/issue4326.dir/q1.go
new file mode 100644 (file)
index 0000000..f118eb0
--- /dev/null
@@ -0,0 +1,8 @@
+package q1
+
+func Deref(typ interface{}) interface{} {
+      if typ, ok := typ.(*int); ok {
+            return *typ
+      }
+      return typ
+}
diff --git a/test/fixedbugs/issue4326.dir/q2.go b/test/fixedbugs/issue4326.dir/q2.go
new file mode 100644 (file)
index 0000000..075e2b2
--- /dev/null
@@ -0,0 +1,11 @@
+package main
+
+import "./q1"
+
+func main() {
+      x := 1
+      y := q1.Deref(&x)
+      if y != 1 {
+            panic("y != 1")
+      }
+}
diff --git a/test/fixedbugs/issue4326.dir/z.go b/test/fixedbugs/issue4326.dir/z.go
new file mode 100644 (file)
index 0000000..cd97ff0
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+import "./p2"
+
+func main() {
+       p2.NewO().RemoveOption("hello", "world")
+}
diff --git a/test/fixedbugs/issue4326.go b/test/fixedbugs/issue4326.go
new file mode 100644 (file)
index 0000000..5ce2eea
--- /dev/null
@@ -0,0 +1,9 @@
+// compiledir
+
+// 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.
+
+// Printing local variables in inliner shadows global names.
+
+package ignored