mirror of https://github.com/golang/go.git
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
This commit is contained in:
parent
c6f363b22a
commit
cb856adea9
|
|
@ -163,6 +163,8 @@ redeclare(Sym *s, char *where)
|
||||||
s, where, s->lastlineno);
|
s, where, s->lastlineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vargen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* declare individual names - var, typ, const
|
* declare individual names - var, typ, const
|
||||||
*/
|
*/
|
||||||
|
|
@ -171,7 +173,7 @@ declare(Node *n, int ctxt)
|
||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s;
|
||||||
int gen;
|
int gen;
|
||||||
static int typegen, vargen;
|
static int typegen;
|
||||||
|
|
||||||
if(ctxt == PDISCARD)
|
if(ctxt == PDISCARD)
|
||||||
return;
|
return;
|
||||||
|
|
@ -198,7 +200,7 @@ declare(Node *n, int ctxt)
|
||||||
curfn->dcl = list(curfn->dcl, n);
|
curfn->dcl = list(curfn->dcl, n);
|
||||||
if(n->op == OTYPE)
|
if(n->op == OTYPE)
|
||||||
gen = ++typegen;
|
gen = ++typegen;
|
||||||
else if(n->op == ONAME)
|
else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil)
|
||||||
gen = ++vargen;
|
gen = ++vargen;
|
||||||
pushdcl(s);
|
pushdcl(s);
|
||||||
n->curfn = curfn;
|
n->curfn = curfn;
|
||||||
|
|
@ -522,7 +524,7 @@ ifacedcl(Node *n)
|
||||||
if(n->op != ODCLFIELD || n->right == N)
|
if(n->op != ODCLFIELD || n->right == N)
|
||||||
fatal("ifacedcl");
|
fatal("ifacedcl");
|
||||||
|
|
||||||
dclcontext = PAUTO;
|
dclcontext = PPARAM;
|
||||||
markdcl();
|
markdcl();
|
||||||
funcdepth++;
|
funcdepth++;
|
||||||
n->outer = curfn;
|
n->outer = curfn;
|
||||||
|
|
@ -533,6 +535,7 @@ ifacedcl(Node *n)
|
||||||
// seen the body of a function but since an interface
|
// seen the body of a function but since an interface
|
||||||
// field declaration does not have a body, we must
|
// field declaration does not have a body, we must
|
||||||
// call it now to pop the current declaration context.
|
// call it now to pop the current declaration context.
|
||||||
|
dclcontext = PAUTO;
|
||||||
funcbody(n);
|
funcbody(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,6 +577,11 @@ funcargs(Node *nt)
|
||||||
if(nt->op != OTFUNC)
|
if(nt->op != OTFUNC)
|
||||||
fatal("funcargs %O", nt->op);
|
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.
|
// declare the receiver and in arguments.
|
||||||
// no n->defn because type checking of func header
|
// no n->defn because type checking of func header
|
||||||
// will not fill in the types until later
|
// will not fill in the types until later
|
||||||
|
|
@ -585,6 +593,8 @@ funcargs(Node *nt)
|
||||||
n->left->op = ONAME;
|
n->left->op = ONAME;
|
||||||
n->left->ntype = n->right;
|
n->left->ntype = n->right;
|
||||||
declare(n->left, PPARAM);
|
declare(n->left, PPARAM);
|
||||||
|
if(dclcontext == PAUTO)
|
||||||
|
n->left->vargen = ++vargen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(l=nt->list; l; l=l->next) {
|
for(l=nt->list; l; l=l->next) {
|
||||||
|
|
@ -595,6 +605,8 @@ funcargs(Node *nt)
|
||||||
n->left->op = ONAME;
|
n->left->op = ONAME;
|
||||||
n->left->ntype = n->right;
|
n->left->ntype = n->right;
|
||||||
declare(n->left, PPARAM);
|
declare(n->left, PPARAM);
|
||||||
|
if(dclcontext == PAUTO)
|
||||||
|
n->left->vargen = ++vargen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -630,7 +642,8 @@ funcargs(Node *nt)
|
||||||
|
|
||||||
n->left->ntype = n->right;
|
n->left->ntype = n->right;
|
||||||
declare(n->left, PPARAMOUT);
|
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++;
|
e->pdepth++;
|
||||||
|
|
||||||
// Input parameter flowing to output parameter?
|
// 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->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
|
||||||
if(src->esc != EscScope && src->esc != EscHeap) {
|
if(src->esc != EscScope && src->esc != EscHeap) {
|
||||||
if(debug['m'])
|
if(debug['m'])
|
||||||
warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
|
warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
|
||||||
if((src->esc&EscMask) != EscReturn)
|
if((src->esc&EscMask) != EscReturn)
|
||||||
src->esc = EscReturn;
|
src->esc = EscReturn;
|
||||||
src->esc |= 1<<(dst->vargen + EscBits);
|
src->esc |= 1<<((dst->vargen-1) + EscBits);
|
||||||
}
|
}
|
||||||
goto recurse;
|
goto recurse;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -724,7 +724,9 @@ typefmt(Fmt *fp, Type *t)
|
||||||
s = S;
|
s = S;
|
||||||
|
|
||||||
if(s != S && !t->embedded) {
|
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)
|
fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg)
|
||||||
else
|
else
|
||||||
fmtprint(fp, "%S ", s);
|
fmtprint(fp, "%S ", s);
|
||||||
|
|
@ -802,6 +804,15 @@ stmtfmt(Fmt *f, Node *n)
|
||||||
|
|
||||||
switch(n->op){
|
switch(n->op){
|
||||||
case ODCL:
|
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);
|
fmtprint(f, "var %S %T", n->left->sym, n->left->type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -939,6 +950,7 @@ stmtfmt(Fmt *f, Node *n)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
ret:
|
||||||
|
|
||||||
if(extrablock)
|
if(extrablock)
|
||||||
fmtstrcpy(f, "}");
|
fmtstrcpy(f, "}");
|
||||||
|
|
@ -1111,6 +1123,15 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||||
return fmtprint(f, "%V", &n->val);
|
return fmtprint(f, "%V", &n->val);
|
||||||
|
|
||||||
case ONAME:
|
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,
|
// 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.
|
// 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.
|
// 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"},
|
{"math.Pi", ast.Con, "untyped float"},
|
||||||
{"io.Reader", ast.Typ, "interface{Read(p []byte) (n int, err error)}"},
|
{"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)}"},
|
{"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
|
// TODO(gri) add more tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package p2
|
||||||
|
|
||||||
|
import "./p1"
|
||||||
|
|
||||||
|
func NewO() p1.O { return nil }
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package q1
|
||||||
|
|
||||||
|
func Deref(typ interface{}) interface{} {
|
||||||
|
if typ, ok := typ.(*int); ok {
|
||||||
|
return *typ
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "./q1"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
x := 1
|
||||||
|
y := q1.Deref(&x)
|
||||||
|
if y != 1 {
|
||||||
|
panic("y != 1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "./p2"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
p2.NewO().RemoveOption("hello", "world")
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue