mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: fix CheckSize() calculation for -G=3 and stencils
Because the Align/Width of pointer types are always set when created, CalcSize() never descends past a pointer. Therefore, we need to do CheckSize() at every level when creating type. We need to do this for types creates by types2-to-types1 conversion and also by type substitution (mostly for stenciling). We also need to do Defer/ResumeCheckSize() at the top level in each of these cases to deal with potentially recursive types. These changes fix issue #47929 and also allow us to remove the special-case CheckSize() call that causes the problem for issue #47901. Fixes #47901 Fixes #47929 Change-Id: Icd8192431c145009cd6df2f4ade6db7da0f4dd3e Reviewed-on: https://go-review.googlesource.com/c/go/+/344829 Trust: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
e1fcf8857e
commit
099b819085
4 changed files with 88 additions and 38 deletions
|
|
@ -30,21 +30,11 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
|
||||||
// typ converts a types2.Type to a types.Type, including caching of previously
|
// typ converts a types2.Type to a types.Type, including caching of previously
|
||||||
// translated types.
|
// translated types.
|
||||||
func (g *irgen) typ(typ types2.Type) *types.Type {
|
func (g *irgen) typ(typ types2.Type) *types.Type {
|
||||||
|
// Defer the CheckSize calls until we have fully-defined a
|
||||||
|
// (possibly-recursive) top-level type.
|
||||||
|
types.DeferCheckSize()
|
||||||
res := g.typ1(typ)
|
res := g.typ1(typ)
|
||||||
|
types.ResumeCheckSize()
|
||||||
// Calculate the size for all concrete types seen by the frontend. The old
|
|
||||||
// typechecker calls CheckSize() a lot, and we want to eliminate calling
|
|
||||||
// it eventually, so we should do it here instead. We only call it for
|
|
||||||
// top-level types (i.e. we do it here rather in typ1), to make sure that
|
|
||||||
// recursive types have been fully constructed before we call CheckSize.
|
|
||||||
if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
|
|
||||||
types.CheckSize(res)
|
|
||||||
if res.IsPtr() {
|
|
||||||
// Pointers always have their size set, even though their element
|
|
||||||
// may not have its size set.
|
|
||||||
types.CheckSize(res.Elem())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +49,12 @@ func (g *irgen) typ1(typ types2.Type) *types.Type {
|
||||||
res, ok := g.typs[typ]
|
res, ok := g.typs[typ]
|
||||||
if !ok {
|
if !ok {
|
||||||
res = g.typ0(typ)
|
res = g.typ0(typ)
|
||||||
|
// Calculate the size for all concrete types seen by the frontend.
|
||||||
|
// This is the replacement for the CheckSize() calls in the types1
|
||||||
|
// typechecker. These will be deferred until the top-level g.typ().
|
||||||
|
if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
|
||||||
|
types.CheckSize(res)
|
||||||
|
}
|
||||||
g.typs[typ] = res
|
g.typs[typ] = res
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
|
|
||||||
|
|
@ -1003,6 +1003,15 @@ type Tsubster struct {
|
||||||
// result is t; otherwise the result is a new type. It deals with recursive types
|
// result is t; otherwise the result is a new type. It deals with recursive types
|
||||||
// by using TFORW types and finding partially or fully created types via sym.Def.
|
// by using TFORW types and finding partially or fully created types via sym.Def.
|
||||||
func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
|
// Defer the CheckSize calls until we have fully-defined
|
||||||
|
// (possibly-recursive) top-level type.
|
||||||
|
types.DeferCheckSize()
|
||||||
|
r := ts.typ1(t)
|
||||||
|
types.ResumeCheckSize()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *Tsubster) typ1(t *types.Type) *types.Type {
|
||||||
if !t.HasTParam() && t.Kind() != types.TFUNC {
|
if !t.HasTParam() && t.Kind() != types.TFUNC {
|
||||||
// Note: function types need to be copied regardless, as the
|
// Note: function types need to be copied regardless, as the
|
||||||
// types of closures may contain declarations that need
|
// types of closures may contain declarations that need
|
||||||
|
|
@ -1047,7 +1056,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
// the tparam/targs mapping from subst.
|
// the tparam/targs mapping from subst.
|
||||||
neededTargs = make([]*types.Type, len(t.RParams()))
|
neededTargs = make([]*types.Type, len(t.RParams()))
|
||||||
for i, rparam := range t.RParams() {
|
for i, rparam := range t.RParams() {
|
||||||
neededTargs[i] = ts.Typ(rparam)
|
neededTargs[i] = ts.typ1(rparam)
|
||||||
if !types.Identical(neededTargs[i], rparam) {
|
if !types.Identical(neededTargs[i], rparam) {
|
||||||
targsChanged = true
|
targsChanged = true
|
||||||
}
|
}
|
||||||
|
|
@ -1085,26 +1094,26 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
}
|
}
|
||||||
// Substitute the underlying typeparam (e.g. T in P[T], see
|
// Substitute the underlying typeparam (e.g. T in P[T], see
|
||||||
// the example describing type P[T] above).
|
// the example describing type P[T] above).
|
||||||
newt = ts.Typ(t.Underlying())
|
newt = ts.typ1(t.Underlying())
|
||||||
assert(newt != t)
|
assert(newt != t)
|
||||||
|
|
||||||
case types.TARRAY:
|
case types.TARRAY:
|
||||||
elem := t.Elem()
|
elem := t.Elem()
|
||||||
newelem := ts.Typ(elem)
|
newelem := ts.typ1(elem)
|
||||||
if newelem != elem || targsChanged {
|
if newelem != elem || targsChanged {
|
||||||
newt = types.NewArray(newelem, t.NumElem())
|
newt = types.NewArray(newelem, t.NumElem())
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.TPTR:
|
case types.TPTR:
|
||||||
elem := t.Elem()
|
elem := t.Elem()
|
||||||
newelem := ts.Typ(elem)
|
newelem := ts.typ1(elem)
|
||||||
if newelem != elem || targsChanged {
|
if newelem != elem || targsChanged {
|
||||||
newt = types.NewPtr(newelem)
|
newt = types.NewPtr(newelem)
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.TSLICE:
|
case types.TSLICE:
|
||||||
elem := t.Elem()
|
elem := t.Elem()
|
||||||
newelem := ts.Typ(elem)
|
newelem := ts.typ1(elem)
|
||||||
if newelem != elem || targsChanged {
|
if newelem != elem || targsChanged {
|
||||||
newt = types.NewSlice(newelem)
|
newt = types.NewSlice(newelem)
|
||||||
}
|
}
|
||||||
|
|
@ -1159,22 +1168,17 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.TMAP:
|
case types.TMAP:
|
||||||
newkey := ts.Typ(t.Key())
|
newkey := ts.typ1(t.Key())
|
||||||
newval := ts.Typ(t.Elem())
|
newval := ts.typ1(t.Elem())
|
||||||
if newkey != t.Key() || newval != t.Elem() || targsChanged {
|
if newkey != t.Key() || newval != t.Elem() || targsChanged {
|
||||||
newt = types.NewMap(newkey, newval)
|
newt = types.NewMap(newkey, newval)
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.TCHAN:
|
case types.TCHAN:
|
||||||
elem := t.Elem()
|
elem := t.Elem()
|
||||||
newelem := ts.Typ(elem)
|
newelem := ts.typ1(elem)
|
||||||
if newelem != elem || targsChanged {
|
if newelem != elem || targsChanged {
|
||||||
newt = types.NewChan(newelem, t.ChanDir())
|
newt = types.NewChan(newelem, t.ChanDir())
|
||||||
if !newt.HasTParam() {
|
|
||||||
// TODO(danscales): not sure why I have to do this
|
|
||||||
// only for channels.....
|
|
||||||
types.CheckSize(newt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case types.TFORW:
|
case types.TFORW:
|
||||||
if ts.SubstForwFunc != nil {
|
if ts.SubstForwFunc != nil {
|
||||||
|
|
@ -1194,7 +1198,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
for i := 0; i < nt; i++ {
|
for i := 0; i < nt; i++ {
|
||||||
term, tilde := t.Term(i)
|
term, tilde := t.Term(i)
|
||||||
tildes[i] = tilde
|
tildes[i] = tilde
|
||||||
newterms[i] = ts.Typ(term)
|
newterms[i] = ts.typ1(term)
|
||||||
if newterms[i] != term {
|
if newterms[i] != term {
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
@ -1212,24 +1216,24 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Sym() == nil && t.Kind() != types.TINTER {
|
|
||||||
// Not a named type or interface type, so there was no forwarding type
|
|
||||||
// and there are no methods to substitute.
|
|
||||||
assert(t.Methods().Len() == 0)
|
|
||||||
return newt
|
|
||||||
}
|
|
||||||
|
|
||||||
if forw != nil {
|
if forw != nil {
|
||||||
forw.SetUnderlying(newt)
|
forw.SetUnderlying(newt)
|
||||||
newt = forw
|
newt = forw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !newt.HasTParam() {
|
||||||
|
// Calculate the size of any new types created. These will be
|
||||||
|
// deferred until the top-level ts.Typ() or g.typ() (if this is
|
||||||
|
// called from g.fillinMethods()).
|
||||||
|
types.CheckSize(newt)
|
||||||
|
}
|
||||||
|
|
||||||
if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
|
if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
|
||||||
// Fill in the method info for the new type.
|
// Fill in the method info for the new type.
|
||||||
var newfields []*types.Field
|
var newfields []*types.Field
|
||||||
newfields = make([]*types.Field, t.Methods().Len())
|
newfields = make([]*types.Field, t.Methods().Len())
|
||||||
for i, f := range t.Methods().Slice() {
|
for i, f := range t.Methods().Slice() {
|
||||||
t2 := ts.Typ(f.Type)
|
t2 := ts.typ1(f.Type)
|
||||||
oldsym := f.Nname.Sym()
|
oldsym := f.Nname.Sym()
|
||||||
newsym := MakeFuncInstSym(oldsym, ts.Targs, true)
|
newsym := MakeFuncInstSym(oldsym, ts.Targs, true)
|
||||||
var nname *ir.Name
|
var nname *ir.Name
|
||||||
|
|
@ -1272,7 +1276,7 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
|
||||||
newfields = make([]*types.Field, t.NumFields())
|
newfields = make([]*types.Field, t.NumFields())
|
||||||
}
|
}
|
||||||
for i, f := range t.Fields().Slice() {
|
for i, f := range t.Fields().Slice() {
|
||||||
t2 := ts.Typ(f.Type)
|
t2 := ts.typ1(f.Type)
|
||||||
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
||||||
newfields = make([]*types.Field, t.NumFields())
|
newfields = make([]*types.Field, t.NumFields())
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
|
|
@ -1325,7 +1329,7 @@ func (ts *Tsubster) tinter(t *types.Type) *types.Type {
|
||||||
}
|
}
|
||||||
var newfields []*types.Field
|
var newfields []*types.Field
|
||||||
for i, f := range t.Methods().Slice() {
|
for i, f := range t.Methods().Slice() {
|
||||||
t2 := ts.Typ(f.Type)
|
t2 := ts.typ1(f.Type)
|
||||||
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
||||||
newfields = make([]*types.Field, t.Methods().Len())
|
newfields = make([]*types.Field, t.Methods().Len())
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
|
|
|
||||||
21
test/typeparam/issue47901.go
Normal file
21
test/typeparam/issue47901.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// run -gcflags=-G=3
|
||||||
|
|
||||||
|
// Copyright 2021 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 main
|
||||||
|
|
||||||
|
type Chan[T any] chan Chan[T]
|
||||||
|
|
||||||
|
func (ch Chan[T]) recv() Chan[T] {
|
||||||
|
return <-ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ch := Chan[int](make(chan Chan[int]))
|
||||||
|
go func() {
|
||||||
|
ch <- make(Chan[int])
|
||||||
|
}()
|
||||||
|
ch.recv()
|
||||||
|
}
|
||||||
29
test/typeparam/issue47929.go
Normal file
29
test/typeparam/issue47929.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
// compile -G=3 -p=p
|
||||||
|
|
||||||
|
// Copyright 2021 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 v4
|
||||||
|
|
||||||
|
var sink interface{}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func Do(result, body interface{}) {
|
||||||
|
sink = &result
|
||||||
|
}
|
||||||
|
|
||||||
|
func DataAction(result DataActionResponse, body DataActionRequest) {
|
||||||
|
Do(&result, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataActionRequest struct {
|
||||||
|
Action *interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataActionResponse struct {
|
||||||
|
ValidationErrors *ValidationError
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidationError struct {
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue