Commit cb856ade authored by Russ Cox's avatar Russ Cox

cmd/gc: annotate local variables with unique ids for inlining

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
parent c6f363b2
......@@ -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;
}
}
......
......@@ -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;
}
......
......@@ -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.
......
......@@ -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
}
......
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
}
package p2
import "./p1"
func NewO() p1.O { return nil }
package q1
func Deref(typ interface{}) interface{} {
if typ, ok := typ.(*int); ok {
return *typ
}
return typ
}
package main
import "./q1"
func main() {
x := 1
y := q1.Deref(&x)
if y != 1 {
panic("y != 1")
}
}
package main
import "./p2"
func main() {
p2.NewO().RemoveOption("hello", "world")
}
// 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
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