mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: avoid double export of aliased objects
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>
This commit is contained in:
parent
1a0b1cca4c
commit
bcc0247331
4 changed files with 47 additions and 59 deletions
|
|
@ -458,21 +458,18 @@ func (p *exporter) obj(sym *Sym) {
|
||||||
Fatalf("exporter: export of non-local alias: %v", sym)
|
Fatalf("exporter: export of non-local alias: %v", sym)
|
||||||
}
|
}
|
||||||
p.string(sym.Name)
|
p.string(sym.Name)
|
||||||
sym = sym.Def.Sym // original object
|
orig := sym.Def.Sym
|
||||||
// fall through to export original
|
if orig.Flags&SymAlias != 0 {
|
||||||
// Multiple aliases to the same original will cause that
|
Fatalf("exporter: original object %v marked as alias", sym)
|
||||||
// original to be exported multiple times (issue #17636).
|
}
|
||||||
// TODO(gri) fix this
|
p.qualifiedName(orig)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if sym != sym.Def.Sym {
|
if sym != sym.Def.Sym {
|
||||||
Fatalf("exporter: exported object %v is not original %v", 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
|
// Exported objects may be from different packages because they
|
||||||
// may be re-exported via an exported alias or as dependencies in
|
// may be re-exported via an exported alias or as dependencies in
|
||||||
// exported inlined function bodies. Thus, exported object names
|
// exported inlined function bodies. Thus, exported object names
|
||||||
|
|
|
||||||
|
|
@ -307,35 +307,26 @@ func idealType(typ *Type) *Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) obj(tag int) {
|
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 {
|
switch tag {
|
||||||
case constTag:
|
case constTag:
|
||||||
p.pos()
|
p.pos()
|
||||||
sym = p.qualifiedName()
|
sym := p.qualifiedName()
|
||||||
typ := p.typ()
|
typ := p.typ()
|
||||||
val := p.value(typ)
|
val := p.value(typ)
|
||||||
importconst(sym, idealType(typ), nodlit(val))
|
importconst(sym, idealType(typ), nodlit(val))
|
||||||
|
|
||||||
case typeTag:
|
case typeTag:
|
||||||
sym = p.typ().Sym
|
p.typ()
|
||||||
|
|
||||||
case varTag:
|
case varTag:
|
||||||
p.pos()
|
p.pos()
|
||||||
sym = p.qualifiedName()
|
sym := p.qualifiedName()
|
||||||
typ := p.typ()
|
typ := p.typ()
|
||||||
importvar(sym, typ)
|
importvar(sym, typ)
|
||||||
|
|
||||||
case funcTag:
|
case funcTag:
|
||||||
p.pos()
|
p.pos()
|
||||||
sym = p.qualifiedName()
|
sym := p.qualifiedName()
|
||||||
params := p.paramList()
|
params := p.paramList()
|
||||||
result := 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:
|
default:
|
||||||
formatErrorf("unexpected object (tag = %d)", tag)
|
formatErrorf("unexpected object (tag = %d)", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if alias != nil {
|
|
||||||
alias.Def = sym.Def
|
|
||||||
importsym(alias, sym.Def.Op)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) pos() {
|
func (p *importer) pos() {
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,15 @@ func exportsym(n *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Sym.Flags |= SymExport
|
n.Sym.Flags |= SymExport
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug['E'] != 0 {
|
||||||
fmt.Printf("export symbol %v\n", n.Sym)
|
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)
|
exportlist = append(exportlist, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,10 +221,11 @@ func objTag(obj types.Object) int {
|
||||||
return funcTag
|
return funcTag
|
||||||
// Aliases are not exported multiple times, thus we should not see them here.
|
// Aliases are not exported multiple times, thus we should not see them here.
|
||||||
default:
|
default:
|
||||||
errorf("unexpected object: %v (%T)", obj, obj)
|
errorf("unexpected object: %v (%T)", obj, obj) // panics
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sameObj(a, b types.Object) bool {
|
func sameObj(a, b types.Object) bool {
|
||||||
// Because unnamed types are not canonicalized, we cannot simply compare types for
|
// Because unnamed types are not canonicalized, we cannot simply compare types for
|
||||||
// (pointer) identity.
|
// (pointer) identity.
|
||||||
|
|
@ -232,7 +233,7 @@ func sameObj(a, b types.Object) bool {
|
||||||
return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
|
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()
|
pkg := obj.Pkg()
|
||||||
if alt := pkg.Scope().Insert(obj); alt != nil {
|
if alt := pkg.Scope().Insert(obj); alt != nil {
|
||||||
// This can only trigger if we import a (non-type) object a second time.
|
// 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
|
// once; and b) we ignore compiler-specific export data which may contain
|
||||||
// functions whose inlined function bodies refer to other functions that
|
// functions whose inlined function bodies refer to other functions that
|
||||||
// were already imported.
|
// were already imported.
|
||||||
// However, if a package exports multiple aliases referring to the same
|
// However, aliases require reexporting the original object, so we need
|
||||||
// original object, that object is currently exported multiple times.
|
// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
|
||||||
// Check for that specific case and accept it if the aliases correspond
|
// method importer.obj, switch case importing functions).
|
||||||
// (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.
|
// 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) {
|
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) {
|
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 {
|
switch tag {
|
||||||
case constTag:
|
case constTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
pkg, name := p.qualifiedName()
|
pkg, name := p.qualifiedName()
|
||||||
typ := p.typ(nil)
|
typ := p.typ(nil)
|
||||||
val := p.value()
|
val := p.value()
|
||||||
obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
|
p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||||
|
|
||||||
case typeTag:
|
case typeTag:
|
||||||
obj = p.typ(nil).(*types.Named).Obj()
|
p.typ(nil)
|
||||||
|
|
||||||
case varTag:
|
case varTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
pkg, name := p.qualifiedName()
|
pkg, name := p.qualifiedName()
|
||||||
typ := p.typ(nil)
|
typ := p.typ(nil)
|
||||||
obj = p.declare(types.NewVar(pos, pkg, name, typ))
|
p.declare(types.NewVar(pos, pkg, name, typ))
|
||||||
|
|
||||||
case funcTag:
|
case funcTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
|
|
@ -289,15 +275,18 @@ func (p *importer) obj(tag int) {
|
||||||
params, isddd := p.paramList()
|
params, isddd := p.paramList()
|
||||||
result, _ := p.paramList()
|
result, _ := p.paramList()
|
||||||
sig := types.NewSignature(nil, params, result, isddd)
|
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:
|
default:
|
||||||
errorf("unexpected object tag %d", tag)
|
errorf("unexpected object tag %d", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if aliasName != "" {
|
|
||||||
p.declare(types.NewAlias(aliasPos, p.pkgList[0], aliasName, obj))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) pos() token.Pos {
|
func (p *importer) pos() token.Pos {
|
||||||
|
|
@ -549,7 +538,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
|
||||||
return t
|
return t
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorf("unexpected type tag %d", i)
|
errorf("unexpected type tag %d", i) // panics
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -700,7 +689,7 @@ func (p *importer) value() constant.Value {
|
||||||
case unknownTag:
|
case unknownTag:
|
||||||
return constant.MakeUnknown()
|
return constant.MakeUnknown()
|
||||||
default:
|
default:
|
||||||
errorf("unexpected value tag %d", tag)
|
errorf("unexpected value tag %d", tag) // panics
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue