]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: allow := to shadow dot-imported names
authorMatthew Dempsky <mdempsky@google.com>
Thu, 28 Sep 2017 06:52:04 +0000 (23:52 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 5 Oct 2017 18:07:37 +0000 (18:07 +0000)
Historically, gc optimistically parsed the left-hand side of
assignments as expressions. Later, if it discovered a ":=" assignment,
it rewrote the parsed expressions as declarations.

This failed in the presence of dot imports though, because we lost
information about whether an imported object was named via a bare
identifier "Foo" or a normal qualified "pkg.Foo".

This CL fixes the issue by specially noding the left-hand side of ":="
assignments.

Fixes #22076.

Change-Id: I18190ecdb863112e7d009e1687e6112eec559921
Reviewed-on: https://go-review.googlesource.com/66810
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/noder.go
test/fixedbugs/bug388.go
test/fixedbugs/issue20250.go
test/fixedbugs/issue22076.go [new file with mode: 0644]

index 4db50117c4a1c637222c347888b31421ea04f0c1..0e14de906622bb38b836200c812622a759d9d3e1 100644 (file)
@@ -758,15 +758,10 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
                        return n
                }
 
-               lhs := p.exprList(stmt.Lhs)
-               rhs := p.exprList(stmt.Rhs)
-
                n := p.nod(stmt, OAS, nil, nil) // assume common case
 
-               if stmt.Op == syntax.Def {
-                       n.SetColas(true)
-                       colasdefn(lhs, n) // modifies lhs, call before using lhs[0] in common case
-               }
+               rhs := p.exprList(stmt.Rhs)
+               lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
 
                if len(lhs) == 1 && len(rhs) == 1 {
                        // common case
@@ -845,6 +840,66 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
        panic("unhandled Stmt")
 }
 
+func (p *noder) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
+       if !colas {
+               return p.exprList(expr)
+       }
+
+       defn.SetColas(true)
+
+       var exprs []syntax.Expr
+       if list, ok := expr.(*syntax.ListExpr); ok {
+               exprs = list.ElemList
+       } else {
+               exprs = []syntax.Expr{expr}
+       }
+
+       res := make([]*Node, len(exprs))
+       seen := make(map[*types.Sym]bool, len(exprs))
+
+       newOrErr := false
+       for i, expr := range exprs {
+               p.lineno(expr)
+               res[i] = nblank
+
+               name, ok := expr.(*syntax.Name)
+               if !ok {
+                       yyerrorpos(expr.Pos(), "non-name %v on left side of :=", p.expr(expr))
+                       newOrErr = true
+                       continue
+               }
+
+               sym := p.name(name)
+               if sym.IsBlank() {
+                       continue
+               }
+
+               if seen[sym] {
+                       yyerrorpos(expr.Pos(), "%v repeated on left side of :=", sym)
+                       newOrErr = true
+                       continue
+               }
+               seen[sym] = true
+
+               if sym.Block == types.Block {
+                       res[i] = oldname(sym)
+                       continue
+               }
+
+               newOrErr = true
+               n := newname(sym)
+               declare(n, dclcontext)
+               n.Name.Defn = defn
+               defn.Ninit.Append(nod(ODCL, n, nil))
+               res[i] = n
+       }
+
+       if !newOrErr {
+               yyerrorl(defn.Pos, "no new variables on left side of :=")
+       }
+       return res
+}
+
 func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
        p.openScope(stmt.Pos())
        nodes := p.stmts(stmt.List)
@@ -884,12 +939,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
 
                n = p.nod(r, ORANGE, nil, p.expr(r.X))
                if r.Lhs != nil {
-                       lhs := p.exprList(r.Lhs)
-                       n.List.Set(lhs)
-                       if r.Def {
-                               n.SetColas(true)
-                               colasdefn(lhs, n)
-                       }
+                       n.List.Set(p.assignList(r.Lhs, n, r.Def))
                }
        } else {
                n = p.nod(stmt, OFOR, nil, nil)
index af0c9d9c574b3ade4e35a40371758c51390910b4..2d508501e07989c7121bc8f0ddb4245268271356 100644 (file)
@@ -14,7 +14,7 @@ func foo(runtime.UintType, i int) {  // ERROR "cannot declare name runtime.UintT
 }
 
 func bar(i int) {
-       runtime.UintType := i       // ERROR "cannot declare name runtime.UintType|non-name on left side|undefined identifier"
+       runtime.UintType := i       // ERROR "non-name runtime.UintType|non-name on left side|undefined identifier"
        println(runtime.UintType)       // GCCGO_ERROR "invalid use of type|undefined identifier"
 }
 
index f24710a0c301cac79e9050b9a306200d9e2ead1c..28c85ff13012a46be32edf9f5df78035f475bf9f 100644 (file)
@@ -16,8 +16,8 @@ type T struct {
 
 func f(a T) { // ERROR "live at entry to f: a"
        var e interface{}
-       func() { // ERROR "live at entry to f.func1: &e a"
-               e = a.s // ERROR "live at call to convT2Estring: &e a" "live at call to writebarrierptr: a"
+       func() { // ERROR "live at entry to f.func1: a &e"
+               e = a.s // ERROR "live at call to convT2Estring: a &e" "live at call to writebarrierptr: a"
        }() // ERROR "live at call to f.func1: e$"
        // Before the fix, both a and e were live at the previous line.
        _ = e
diff --git a/test/fixedbugs/issue22076.go b/test/fixedbugs/issue22076.go
new file mode 100644 (file)
index 0000000..5d628b9
--- /dev/null
@@ -0,0 +1,25 @@
+// compile
+
+// Copyright 2017 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.
+
+// Issue 22076: Couldn't use ":=" to declare names that refer to
+// dot-imported symbols.
+
+package p
+
+import . "bytes"
+
+var _ Reader // use "bytes" import
+
+func _() {
+       Buffer := 0
+       _ = Buffer
+}
+
+func _() {
+       for Buffer := range []int{} {
+               _ = Buffer
+       }
+}