// redeclare emits a diagnostic about symbol s being redeclared at pos.
func redeclare(pos src.XPos, s *types.Sym, where string) {
if !s.Lastlineno.IsKnown() {
- pkg := s.Origpkg
- if pkg == nil {
- pkg = s.Pkg
- }
+ pkgName := dotImportRefs[s.Def.(*ir.Ident)]
base.ErrorfAt(pos, "%v redeclared %s\n"+
- "\tprevious declaration during import %q", s, where, pkg.Path)
+ "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
} else {
prevPos := s.Lastlineno
}
base.ErrorfAt(pos, "%v redeclared %s\n"+
- "\tprevious declaration at %v", s, where, base.FmtPos(prevPos))
+ "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
}
}
// Automatically creates a new closure variable if the referenced symbol was
// declared in a different (containing) function.
func oldname(s *types.Sym) ir.Node {
+ if s.Pkg != types.LocalPkg {
+ return ir.NewIdent(base.Pos, s)
+ }
+
n := ir.AsNode(s.Def)
if n == nil {
// Maybe a top-level declaration will come along later to
s := pkg.Lookup(p.stringAt(ird.uint64()))
off := ird.uint64()
- if _, ok := declImporter[s]; ok {
- continue
+ if _, ok := declImporter[s]; !ok {
+ declImporter[s] = iimporterAndOffset{p, off}
}
- declImporter[s] = iimporterAndOffset{p, off}
-
- // Create stub declaration. If used, this will
- // be overwritten by expandDecl.
- if s.Def != nil {
- base.Fatalf("unexpected definition for %v: %v", s, ir.AsNode(s.Def))
- }
- s.Def = ir.NewDeclNameAt(src.NoXPos, s)
}
}
s := pkg.Lookup(p.stringAt(ird.uint64()))
off := ird.uint64()
- if _, ok := inlineImporter[s]; ok {
- continue
+ if _, ok := inlineImporter[s]; !ok {
+ inlineImporter[s] = iimporterAndOffset{p, off}
}
- inlineImporter[s] = iimporterAndOffset{p, off}
}
}
return pkg.Lookup(name)
}
-func (r *importReader) qualifiedIdent() *types.Sym {
+func (r *importReader) qualifiedIdent() *ir.Name {
name := r.string()
pkg := r.pkg()
- return pkg.Lookup(name)
+ sym := pkg.Lookup(name)
+ n := sym.PkgDef()
+ if n == nil {
+ n = ir.NewDeclNameAt(src.NoXPos, sym)
+ sym.SetPkgDef(n)
+ }
+ return n.(*ir.Name)
}
func (r *importReader) pos() src.XPos {
// support inlining functions with local defined
// types. Therefore, this must be a package-scope
// type.
- n := ir.AsNode(r.qualifiedIdent().PkgDef())
+ n := r.qualifiedIdent()
if n.Op() == ir.ONONAME {
- expandDecl(n.(*ir.Name))
+ expandDecl(n)
}
if n.Op() != ir.OTYPE {
base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n)
return n
case ir.ONONAME:
- return mkname(r.qualifiedIdent())
+ return r.qualifiedIdent()
case ir.ONAME:
- return mkname(r.ident())
+ return r.ident().Def.(*ir.Name)
// case OPACK, ONONAME:
// unreachable - should have been resolved by typechecking
// Find imported packages with init tasks.
for _, pkg := range sourceOrderImports {
- n := resolve(ir.AsNode(pkg.Lookup(".inittask").Def))
- if n == nil {
+ n := resolve(oldname(pkg.Lookup(".inittask")))
+ if n.Op() == ir.ONONAME {
continue
}
if n.Op() != ir.ONAME || n.Class() != ir.PEXTERN {
}
}
- // Phase 3.14: With all user code type-checked, it's now safe to verify map keys.
+ // Phase 3.14: With all user code type-checked, it's now safe to verify map keys
+ // and unused dot imports.
checkMapKeys()
+ checkDotImports()
base.ExitIfErrors()
timings.AddEvent(fcount, "funcs")
if IsAlias(s) {
// throw away top-level name left over
// from previous import . "x"
- if name := n.Name(); name != nil && name.PkgName != nil && !name.PkgName.Used && base.SyntaxErrors() == 0 {
- unused = append(unused, importedPkg{name.PkgName.Pos(), name.PkgName.Pkg.Path, ""})
- name.PkgName.Used = true
- }
+ // We'll report errors after type checking in checkDotImports.
s.Def = nil
continue
}
switch my.Name {
case ".":
- importdot(ipkg, pack)
+ importDot(pack)
return
case "init":
base.ErrorfAt(pack.Pos(), "cannot import package as init - init must be a func")
return lookupN(prefix, int(n))
}
-// find all the exported symbols in package opkg
+// dotImports tracks all PkgNames that have been dot-imported.
+var dotImports []*ir.PkgName
+
+// dotImportRefs maps idents introduced by importDot back to the
+// ir.PkgName they were dot-imported through.
+var dotImportRefs map[*ir.Ident]*ir.PkgName
+
+// find all the exported symbols in package referenced by PkgName,
// and make them available in the current package
-func importdot(opkg *types.Pkg, pack *ir.PkgName) {
- n := 0
+func importDot(pack *ir.PkgName) {
+ if dotImportRefs == nil {
+ dotImportRefs = make(map[*ir.Ident]*ir.PkgName)
+ }
+
+ opkg := pack.Pkg
for _, s := range opkg.Syms {
if s.Def == nil {
- continue
+ if _, ok := declImporter[s]; !ok {
+ continue
+ }
}
if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
continue
continue
}
- s1.Def = s.Def
- s1.Block = s.Block
- if ir.AsNode(s1.Def).Name() == nil {
- ir.Dump("s1def", ir.AsNode(s1.Def))
- base.Fatalf("missing Name")
- }
- ir.AsNode(s1.Def).Name().PkgName = pack
- s1.Origpkg = opkg
- n++
+ id := ir.NewIdent(src.NoXPos, s)
+ dotImportRefs[id] = pack
+ s1.Def = id
+ s1.Block = 1
}
- if n == 0 {
- // can't possibly be used - there were no symbols
- base.ErrorfAt(pack.Pos(), "imported and not used: %q", opkg.Path)
+ dotImports = append(dotImports, pack)
+}
+
+// checkDotImports reports errors for any unused dot imports.
+func checkDotImports() {
+ for _, pack := range dotImports {
+ if !pack.Used {
+ base.ErrorfAt(pack.Pos(), "imported and not used: %q", pack.Pkg.Path)
+ }
}
+
+ // No longer needed; release memory.
+ dotImports = nil
+ dotImportRefs = nil
}
// nodAddr returns a node representing &n.
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
+ "cmd/internal/src"
"fmt"
"go/constant"
"go/token"
defer tracePrint("resolve", n)(&res)
}
- // Stub ir.Name left for us by iimport.
- if n, ok := n.(*ir.Name); ok {
- if n.Sym().Pkg == types.LocalPkg {
- base.Fatalf("unexpected Name: %+v", n)
+ if sym := n.Sym(); sym.Pkg != types.LocalPkg {
+ // We might have an ir.Ident from oldname or importDot.
+ if id, ok := n.(*ir.Ident); ok {
+ if pkgName := dotImportRefs[id]; pkgName != nil {
+ pkgName.Used = true
+ }
+
+ if sym.Def == nil {
+ if _, ok := declImporter[sym]; !ok {
+ return n // undeclared name
+ }
+ sym.Def = ir.NewDeclNameAt(src.NoXPos, sym)
+ }
+ n = ir.AsNode(sym.Def)
}
+
+ // Stub ir.Name left for us by iimport.
+ n := n.(*ir.Name)
if inimport {
base.Fatalf("recursive inimport")
}
if l.Op() == ir.OKEY {
key := l.Left()
- sk := ir.NewStructKeyExpr(l.Pos(), nil, l.Right())
- ls[i] = sk
- l = sk
+ // Sym might have resolved to name in other top-level
+ // package, because of import dot. Redirect to correct sym
+ // before we do the lookup.
+ s := key.Sym()
+ if id, ok := key.(*ir.Ident); ok && dotImportRefs[id] != nil {
+ s = lookup(s.Name)
+ }
// An OXDOT uses the Sym field to hold
// the field to the right of the dot,
// so s will be non-nil, but an OXDOT
// is never a valid struct literal key.
- if key.Sym() == nil || key.Op() == ir.OXDOT || key.Sym().IsBlank() {
+ if s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank() {
base.Errorf("invalid field name %v in struct initializer", key)
- sk.SetLeft(typecheck(sk.Left(), ctxExpr))
continue
}
- // Sym might have resolved to name in other top-level
- // package, because of import dot. Redirect to correct sym
- // before we do the lookup.
- s := key.Sym()
- if s.Pkg != types.LocalPkg && types.IsExported(s.Name) {
- s1 := lookup(s.Name)
- if s1.Origpkg == s.Pkg {
- s = s1
- }
- }
- sk.SetSym(s)
+ l = ir.NewStructKeyExpr(l.Pos(), s, l.Right())
+ ls[i] = l
}
if l.Op() != ir.OSTRUCTKEY {
// An Ident is an identifier, possibly qualified.
type Ident struct {
miniExpr
- sym *types.Sym
- Used bool
+ sym *types.Sym
}
func NewIdent(pos src.XPos, sym *types.Sym) *Ident {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Sym{}, 52, 88},
+ {Sym{}, 48, 80},
{Type{}, 56, 96},
{Map{}, 20, 40},
{Forward{}, 20, 32},
Block int32 // blocknumber to catch redeclaration
Lastlineno src.XPos // last declaration for diagnostic
- flags bitset8
- Origpkg *Pkg // original package for . import
+ flags bitset8
}
const (
}
func main() {
- _ = T {
- os.File: 1, // ERROR "unknown T? ?field"
+ _ = T{
+ os.File: 1, // ERROR "invalid field name os.File|unknown field"
}
}
// 1
var f byte
-var f interface{} // ERROR "previous declaration at issue20415.go:12"
+var f interface{} // ERROR "issue20415.go:12: previous declaration"
func _(f int) {
}
func _(g int) {
}
-var g interface{} // ERROR "previous declaration at issue20415.go:20"
+var g interface{} // ERROR "issue20415.go:20: previous declaration"
// 3
func _(h int) {
var h byte
-var h interface{} // ERROR "previous declaration at issue20415.go:31"
+var h interface{} // ERROR "issue20415.go:31: previous declaration"
--- /dev/null
+// Copyright 2020 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.
+
+package p
+
+import . "strings"
+
+var _ = Index // use strings
+
+type t struct{ Index int }
+
+var _ = t{Index: 0}
--- /dev/null
+// Copyright 2020 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.
+
+package p
+
+import . "bytes"
+
+var _ = Index // use bytes
+
+var _ = t{Index: 0}
--- /dev/null
+// compiledir
+
+// Copyright 2020 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.
+
+package ignored
--- /dev/null
+// errorcheck
+
+// Copyright 2020 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.
+
+package p
+
+import . "bytes"
+
+var _ Buffer // use package bytes
+
+var Index byte // ERROR "Index redeclared.*\n\tLINE-4: previous declaration during import .bytes.|already declared|redefinition"
--- /dev/null
+// errorcheck
+
+// Copyright 2020 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.
+
+package p
+
+import . "testing" // ERROR "imported and not used"
+
+type S struct {
+ T int
+}
+
+var _ = S{T: 0}