switch utyp := structure(base).(type) {
case *Struct:
+ // Prevent crash if the struct referred to is not yet set up.
+ // See analogous comment for *Array.
+ if utyp.fields == nil {
+ check.error(e, "illegal cycle in type declaration")
+ goto Error
+ }
if len(e.ElemList) == 0 {
break
}
// A Struct represents a struct type.
type Struct struct {
- fields []*Var
+ fields []*Var // fields != nil indicates the struct is set up (possibly with len(fields) == 0)
tags []string // field tags; nil if there are no tags
}
if len(tags) > len(fields) {
panic("more tags than fields")
}
- return &Struct{fields: fields, tags: tags}
+ s := &Struct{fields: fields, tags: tags}
+ s.markComplete()
+ return s
}
// NumFields returns the number of fields in the struct (including blank and embedded fields).
// ----------------------------------------------------------------------------
// Implementation
+func (s *Struct) markComplete() {
+ if s.fields == nil {
+ s.fields = make([]*Var, 0)
+ }
+}
+
func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
if e.FieldList == nil {
+ styp.markComplete()
return
}
styp.fields = fields
styp.tags = tags
+ styp.markComplete()
}
func embeddedFieldIdent(e syntax.Expr) *syntax.Name {
case *Struct:
if fields, copied := subst.varList(t.fields); copied {
- return &Struct{fields: fields, tags: t.tags}
+ s := &Struct{fields: fields, tags: t.tags}
+ s.markComplete()
+ return s
}
case *Pointer:
--- /dev/null
+// 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 p
+
+import "unsafe"
+
+type S /* ERROR illegal cycle in declaration of S */ struct {
+ _ [unsafe.Sizeof(s)]byte
+}
+
+var s S
+
+// Since f is a pointer, this case could be valid.
+// But it's pathological and not worth the expense.
+type T struct {
+ f *[unsafe.Sizeof(T /* ERROR illegal cycle in type declaration */ {})]int
+}
+
+// a mutually recursive case using unsafe.Sizeof
+type (
+ A1 struct {
+ _ [unsafe.Sizeof(B1{})]int
+ }
+
+ B1 struct {
+ _ [unsafe.Sizeof(A1 /* ERROR illegal cycle in type declaration */ {})]int
+ }
+)
+
+// a mutually recursive case using len
+type (
+ A2 struct {
+ f [len(B2{}.f)]int
+ }
+
+ B2 struct {
+ f [len(A2 /* ERROR illegal cycle in type declaration */ {}.f)]int
+ }
+)
+
+// test case from issue
+type a struct {
+ _ [42 - unsafe.Sizeof(a /* ERROR illegal cycle in type declaration */ {})]byte
+}