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
s, where, s->lastlineno);
}
+static int vargen;
+
/*
* declare individual names - var, typ, const
*/
{
Sym *s;
int gen;
- static int typegen, vargen;
+ static int typegen;
if(ctxt == PDISCARD)
return;
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;
if(n->op != ODCLFIELD || n->right == N)
fatal("ifacedcl");
- dclcontext = PAUTO;
+ dclcontext = PPARAM;
markdcl();
funcdepth++;
n->outer = curfn;
// 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);
}
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
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) {
n->left->op = ONAME;
n->left->ntype = n->right;
declare(n->left, PPARAM);
+ if(dclcontext == PAUTO)
+ n->left->vargen = ++vargen;
}
}
n->left->ntype = n->right;
declare(n->left, PPARAMOUT);
- n->left->vargen = i++;
+ if(dclcontext == PAUTO)
+ n->left->vargen = ++i;
}
}
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;
}
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);
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;
break;
}
+ret:
if(extrablock)
fmtstrcpy(f, "}");
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.
{"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
}
--- /dev/null
+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
+}
--- /dev/null
+package p2
+
+import "./p1"
+
+func NewO() p1.O { return nil }
--- /dev/null
+package q1
+
+func Deref(typ interface{}) interface{} {
+ if typ, ok := typ.(*int); ok {
+ return *typ
+ }
+ return typ
+}
--- /dev/null
+package main
+
+import "./q1"
+
+func main() {
+ x := 1
+ y := q1.Deref(&x)
+ if y != 1 {
+ panic("y != 1")
+ }
+}
--- /dev/null
+package main
+
+import "./p2"
+
+func main() {
+ p2.NewO().RemoveOption("hello", "world")
+}
--- /dev/null
+// 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