]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: avoid double export of aliased objects
authorMatthew Dempsky <mdempsky@google.com>
Wed, 2 Nov 2016 16:47:43 +0000 (09:47 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 2 Nov 2016 19:19:36 +0000 (19:19 +0000)
Instead of writing out the original object for each alias, ensure we
export the original object before any aliases. This allows the aliases
to simply refer back to the original object by qualified name.

Fixes #17636.

Change-Id: If80fa8c66b8fee8344a00b55d25a8aef22abd859
Reviewed-on: https://go-review.googlesource.com/32575
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/export.go
src/go/internal/gcimporter/bimport.go

index 933fd72fa02fac1ac856a14c99d8f311ed29bf6e..ec3e4db761f7d7f547c405a09559b4591040e82d 100644 (file)
@@ -458,21 +458,18 @@ func (p *exporter) obj(sym *Sym) {
                        Fatalf("exporter: export of non-local alias: %v", sym)
                }
                p.string(sym.Name)
-               sym = sym.Def.Sym // original object
-               // fall through to export original
-               // Multiple aliases to the same original will cause that
-               // original to be exported multiple times (issue #17636).
-               // TODO(gri) fix this
+               orig := sym.Def.Sym
+               if orig.Flags&SymAlias != 0 {
+                       Fatalf("exporter: original object %v marked as alias", sym)
+               }
+               p.qualifiedName(orig)
+               return
        }
 
        if sym != sym.Def.Sym {
                Fatalf("exporter: exported object %v is not original %v", sym, sym.Def.Sym)
        }
 
-       if sym.Flags&SymAlias != 0 {
-               Fatalf("exporter: original object %v marked as alias", sym)
-       }
-
        // Exported objects may be from different packages because they
        // may be re-exported via an exported alias or as dependencies in
        // exported inlined function bodies. Thus, exported object names
index 11154ef7ba26fc5f01b5b1b220f4a594d3873cea..61ef348e23816c3c2d80129cde4d504e9831134e 100644 (file)
@@ -307,35 +307,26 @@ func idealType(typ *Type) *Type {
 }
 
 func (p *importer) obj(tag int) {
-       var alias *Sym
-       if tag == aliasTag {
-               p.pos()
-               alias = importpkg.Lookup(p.string())
-               alias.Flags |= SymAlias
-               tag = p.tagOrIndex()
-       }
-
-       var sym *Sym
        switch tag {
        case constTag:
                p.pos()
-               sym = p.qualifiedName()
+               sym := p.qualifiedName()
                typ := p.typ()
                val := p.value(typ)
                importconst(sym, idealType(typ), nodlit(val))
 
        case typeTag:
-               sym = p.typ().Sym
+               p.typ()
 
        case varTag:
                p.pos()
-               sym = p.qualifiedName()
+               sym := p.qualifiedName()
                typ := p.typ()
                importvar(sym, typ)
 
        case funcTag:
                p.pos()
-               sym = p.qualifiedName()
+               sym := p.qualifiedName()
                params := p.paramList()
                result := p.paramList()
 
@@ -363,14 +354,20 @@ func (p *importer) obj(tag int) {
                        }
                }
 
+       case aliasTag:
+               p.pos()
+               alias := importpkg.Lookup(p.string())
+               orig := p.qualifiedName()
+
+               // Although the protocol allows the alias to precede the original,
+               // this never happens in files produced by gc.
+               alias.Flags |= SymAlias
+               alias.Def = orig.Def
+               importsym(alias, orig.Def.Op)
+
        default:
                formatErrorf("unexpected object (tag = %d)", tag)
        }
-
-       if alias != nil {
-               alias.Def = sym.Def
-               importsym(alias, sym.Def.Op)
-       }
 }
 
 func (p *importer) pos() {
index 8df871d08e41a205ce3b4f9f302c4aa5f4ede499..b4c15e40b1d14ac31adfe567158d2f15f47db85c 100644 (file)
@@ -41,10 +41,15 @@ func exportsym(n *Node) {
        }
 
        n.Sym.Flags |= SymExport
-
        if Debug['E'] != 0 {
                fmt.Printf("export symbol %v\n", n.Sym)
        }
+
+       // Ensure original object is on exportlist before aliases.
+       if n.Sym.Flags&SymAlias != 0 {
+               exportlist = append(exportlist, n.Sym.Def)
+       }
+
        exportlist = append(exportlist, n)
 }
 
index 9e2fbd3c684a83272faaba008a60f8a62519cd50..a8e4a7e718da3fd6f893e134c114f7df3ea5e8e0 100644 (file)
@@ -221,10 +221,11 @@ func objTag(obj types.Object) int {
                return funcTag
        // Aliases are not exported multiple times, thus we should not see them here.
        default:
-               errorf("unexpected object: %v (%T)", obj, obj)
+               errorf("unexpected object: %v (%T)", obj, obj) // panics
                panic("unreachable")
        }
 }
+
 func sameObj(a, b types.Object) bool {
        // Because unnamed types are not canonicalized, we cannot simply compare types for
        // (pointer) identity.
@@ -232,7 +233,7 @@ func sameObj(a, b types.Object) bool {
        return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
 }
 
-func (p *importer) declare(obj types.Object) types.Object {
+func (p *importer) declare(obj types.Object) {
        pkg := obj.Pkg()
        if alt := pkg.Scope().Insert(obj); alt != nil {
                // This can only trigger if we import a (non-type) object a second time.
@@ -240,48 +241,33 @@ func (p *importer) declare(obj types.Object) types.Object {
                // once; and b) we ignore compiler-specific export data which may contain
                // functions whose inlined function bodies refer to other functions that
                // were already imported.
-               // However, if a package exports multiple aliases referring to the same
-               // original object, that object is currently exported multiple times.
-               // Check for that specific case and accept it if the aliases correspond
-               // (see also the comment in cmd/compile/internal/gc/bimport.go, method
-               // importer.obj, switch case importing functions).
+               // However, aliases require reexporting the original object, so we need
+               // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
+               // method importer.obj, switch case importing functions).
                // Note that the original itself cannot be an alias.
-               // TODO(gri) We can avoid doing this once objects are exported only once
-               // per package again (issue #17636).
                if !sameObj(obj, alt) {
-                       errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)
+                       errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
                }
-               obj = alt // use object that was imported first
        }
-       return obj
 }
 
 func (p *importer) obj(tag int) {
-       var aliasPos token.Pos
-       var aliasName string
-       if tag == aliasTag {
-               aliasPos = p.pos()
-               aliasName = p.string()
-               tag = p.tagOrIndex()
-       }
-
-       var obj types.Object
        switch tag {
        case constTag:
                pos := p.pos()
                pkg, name := p.qualifiedName()
                typ := p.typ(nil)
                val := p.value()
-               obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
+               p.declare(types.NewConst(pos, pkg, name, typ, val))
 
        case typeTag:
-               obj = p.typ(nil).(*types.Named).Obj()
+               p.typ(nil)
 
        case varTag:
                pos := p.pos()
                pkg, name := p.qualifiedName()
                typ := p.typ(nil)
-               obj = p.declare(types.NewVar(pos, pkg, name, typ))
+               p.declare(types.NewVar(pos, pkg, name, typ))
 
        case funcTag:
                pos := p.pos()
@@ -289,15 +275,18 @@ func (p *importer) obj(tag int) {
                params, isddd := p.paramList()
                result, _ := p.paramList()
                sig := types.NewSignature(nil, params, result, isddd)
-               obj = p.declare(types.NewFunc(pos, pkg, name, sig))
+               p.declare(types.NewFunc(pos, pkg, name, sig))
+
+       case aliasTag:
+               aliasPos := p.pos()
+               aliasName := p.string()
+               pkg, name := p.qualifiedName()
+               obj := pkg.Scope().Lookup(name)
+               p.declare(types.NewAlias(aliasPos, p.pkgList[0], aliasName, obj))
 
        default:
                errorf("unexpected object tag %d", tag)
        }
-
-       if aliasName != "" {
-               p.declare(types.NewAlias(aliasPos, p.pkgList[0], aliasName, obj))
-       }
 }
 
 func (p *importer) pos() token.Pos {
@@ -549,7 +538,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
                return t
 
        default:
-               errorf("unexpected type tag %d", i)
+               errorf("unexpected type tag %d", i) // panics
                panic("unreachable")
        }
 }
@@ -700,7 +689,7 @@ func (p *importer) value() constant.Value {
        case unknownTag:
                return constant.MakeUnknown()
        default:
-               errorf("unexpected value tag %d", tag)
+               errorf("unexpected value tag %d", tag) // panics
                panic("unreachable")
        }
 }