diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 3b39b6b128..eb89789a2f 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -35,7 +35,7 @@ type ptabEntry struct { } // runtime interface and reflection data structures -var signatlist []*types.Type +var signatlist = make(map[*types.Type]bool) var itabs []itabEntry var ptabs []ptabEntry @@ -906,15 +906,17 @@ func dcommontype(s *types.Sym, ot int, t *types.Type) int { return ot } -func typesym(t *types.Type) *types.Sym { +func typesymname(t *types.Type) string { name := t.ShortString() - // Use a separate symbol name for Noalg types for #17752. if a, bad := algtype1(t); a == ANOEQ && bad.Noalg() { name = "noalg." + name } + return name +} - return typepkg.Lookup(name) +func typesym(t *types.Type) *types.Sym { + return typepkg.Lookup(typesymname(t)) } // tracksym returns the symbol for tracking use of field/method f, assumed @@ -934,24 +936,23 @@ func typesymprefix(prefix string, t *types.Type) *types.Sym { func typenamesym(t *types.Type) *types.Sym { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { - Fatalf("typename %v", t) + Fatalf("typenamesym %v", t) } s := typesym(t) + addsignat(t) + return s +} + +func typename(t *types.Type) *Node { + s := typenamesym(t) if s.Def == nil { n := newnamel(src.NoXPos, s) n.Type = types.Types[TUINT8] n.Class = PEXTERN n.Typecheck = 1 s.Def = asTypesNode(n) - - signatlist = append(signatlist, t) } - return asNode(s.Def).Sym -} - -func typename(t *types.Type) *Node { - s := typenamesym(t) n := nod(OADDR, asNode(s.Def), nil) n.Type = types.NewPtr(asNode(s.Def).Type) n.SetAddable(true) @@ -1075,14 +1076,18 @@ func needkeyupdate(t *types.Type) bool { } } -func dtypesym(t *types.Type) *types.Sym { - // Replace byte, rune aliases with real type. - // They've been separate internally to make error messages - // better, but we have to merge them in the reflect tables. +// formalType replaces byte and rune aliases with real types. +// They've been separate internally to make error messages +// better, but we have to merge them in the reflect tables. +func formalType(t *types.Type) *types.Type { if t == types.Bytetype || t == types.Runetype { - t = types.Types[t.Etype] + return types.Types[t.Etype] } + return t +} +func dtypesym(t *types.Type) *types.Sym { + t = formalType(t) if t.IsUntyped() { Fatalf("dtypesym %v", t) } @@ -1418,21 +1423,35 @@ func itabsym(it *obj.LSym, offset int64) *obj.LSym { return syms[methodnum] } +func addsignat(t *types.Type) { + signatlist[formalType(t)] = true +} + func dumptypestructs() { // copy types from externdcl list to signatlist for _, n := range externdcl { if n.Op == OTYPE { - signatlist = append(signatlist, n.Type) + addsignat(n.Type) } } - // Process signatlist. This can't use range, as entries are - // added to the list while it is being processed. - for i := 0; i < len(signatlist); i++ { - t := signatlist[i] - dtypesym(t) - if t.Sym != nil { - dtypesym(types.NewPtr(t)) + // Process signatlist. Use a loop, as dtypesym adds + // entries to signatlist while it is being processed. + signats := make([]typeAndStr, len(signatlist)) + for len(signatlist) > 0 { + signats = signats[:0] + // Transfer entries to a slice and sort, for reproducible builds. + for t := range signatlist { + signats = append(signats, typeAndStr{t: t, s: typesymname(t)}) + delete(signatlist, t) + } + sort.Sort(typesByString(signats)) + for _, ts := range signats { + t := ts.t + dtypesym(t) + if t.Sym != nil { + dtypesym(types.NewPtr(t)) + } } } @@ -1528,6 +1547,17 @@ func dumptypestructs() { } } +type typeAndStr struct { + t *types.Type + s string +} + +type typesByString []typeAndStr + +func (a typesByString) Len() int { return len(a) } +func (a typesByString) Less(i, j int) bool { return a[i].s < a[j].s } +func (a typesByString) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + type pkgByPath []*types.Pkg func (a pkgByPath) Len() int { return len(a) } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 196b7b751f..b1903f22ec 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -927,6 +927,8 @@ func (r *Sym) cmpsym(s *Sym) ssa.Cmp { // cmp compares two *Types t and x, returning ssa.CMPlt, // ssa.CMPeq, ssa.CMPgt as tx, for an arbitrary // and optimizer-centric notion of comparison. +// TODO(josharian): make this safe for recursive interface types +// and use in signatlist sorting. See issue 19869. func (t *Type) cmp(x *Type) ssa.Cmp { // This follows the structure of eqtype in subr.go // with two exceptions.