From cb856adea965955c4d2424b2946b0db90a682b78 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 7 Nov 2012 09:59:19 -0500 Subject: [PATCH] cmd/gc: annotate local variables with unique ids for inlining MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 21 +++++++++++++++++---- src/cmd/gc/esc.c | 4 ++-- src/cmd/gc/fmt.c | 23 ++++++++++++++++++++++- src/pkg/exp/types/gcimporter_test.go | 2 +- test/fixedbugs/issue4326.dir/p1.go | 12 ++++++++++++ test/fixedbugs/issue4326.dir/p2.go | 5 +++++ test/fixedbugs/issue4326.dir/q1.go | 8 ++++++++ test/fixedbugs/issue4326.dir/q2.go | 11 +++++++++++ test/fixedbugs/issue4326.dir/z.go | 7 +++++++ test/fixedbugs/issue4326.go | 9 +++++++++ 10 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue4326.dir/p1.go create mode 100644 test/fixedbugs/issue4326.dir/p2.go create mode 100644 test/fixedbugs/issue4326.dir/q1.go create mode 100644 test/fixedbugs/issue4326.dir/q2.go create mode 100644 test/fixedbugs/issue4326.dir/z.go create mode 100644 test/fixedbugs/issue4326.go diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index d20f64357b..7748289b41 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -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; } } diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index 6ac0ea530f..f789386bc9 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -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; } diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index e8c0571e5c..114c3f0252 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -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. diff --git a/src/pkg/exp/types/gcimporter_test.go b/src/pkg/exp/types/gcimporter_test.go index 2f89d3ac91..d6795fae70 100644 --- a/src/pkg/exp/types/gcimporter_test.go +++ b/src/pkg/exp/types/gcimporter_test.go @@ -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 index 0000000000..ab214befb4 --- /dev/null +++ b/test/fixedbugs/issue4326.dir/p1.go @@ -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 index 0000000000..8e86266dd8 --- /dev/null +++ b/test/fixedbugs/issue4326.dir/p2.go @@ -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 index 0000000000..f118eb0925 --- /dev/null +++ b/test/fixedbugs/issue4326.dir/q1.go @@ -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 index 0000000000..075e2b21e7 --- /dev/null +++ b/test/fixedbugs/issue4326.dir/q2.go @@ -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 index 0000000000..cd97ff0f7f --- /dev/null +++ b/test/fixedbugs/issue4326.dir/z.go @@ -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 index 0000000000..5ce2eea266 --- /dev/null +++ b/test/fixedbugs/issue4326.go @@ -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 -- 2.48.1