]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: report error for incomplete struct composite literal type
authorRobert Findley <rfindley@google.com>
Tue, 9 Nov 2021 19:20:11 +0000 (14:20 -0500)
committerRobert Findley <rfindley@google.com>
Tue, 9 Nov 2021 22:14:26 +0000 (22:14 +0000)
This is a port of CL 361412 to go/types.

Change-Id: Ie5bccc7faba7ca9230e712f867b27ca9dcddba79
Reviewed-on: https://go-review.googlesource.com/c/go/+/362739
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/expr.go
src/go/types/struct.go
src/go/types/subst.go
src/go/types/testdata/fixedbugs/issue49276.go2 [new file with mode: 0644]

index 83022ed660eea76ce50e47ed499c24d4b3290034..224185b6a9b05d238785955190d57eeda24bfada 100644 (file)
@@ -1230,6 +1230,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
 
                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, _Todo, "illegal cycle in type declaration")
+                               goto Error
+                       }
                        if len(e.Elts) == 0 {
                                break
                        }
index 442c7a66e329daa5acd7e9148b815f8764381998..60640ac5786e4de742fd2a55897204604cf3c90f 100644 (file)
@@ -15,7 +15,7 @@ import (
 
 // 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
 }
 
@@ -33,7 +33,9 @@ func NewStruct(fields []*Var, tags []string) *Struct {
        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).
@@ -56,9 +58,16 @@ func (t *Struct) String() string   { return TypeString(t, nil) }
 // ----------------------------------------------------------------------------
 // Implementation
 
+func (s *Struct) markComplete() {
+       if s.fields == nil {
+               s.fields = make([]*Var, 0)
+       }
+}
+
 func (check *Checker) structType(styp *Struct, e *ast.StructType) {
        list := e.Fields
        if list == nil {
+               styp.markComplete()
                return
        }
 
@@ -161,6 +170,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
 
        styp.fields = fields
        styp.tags = tags
+       styp.markComplete()
 }
 
 func embeddedFieldIdent(e ast.Expr) *ast.Ident {
index f0b79f60c6f7133709c98317ea3227f0a1dfa958..1fac82fe8a79e6b1af7e97dbea21f8b83cc4344d 100644 (file)
@@ -91,7 +91,9 @@ func (subst *subster) typ(typ Type) Type {
 
        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:
diff --git a/src/go/types/testdata/fixedbugs/issue49276.go2 b/src/go/types/testdata/fixedbugs/issue49276.go2
new file mode 100644 (file)
index 0000000..8839087
--- /dev/null
@@ -0,0 +1,46 @@
+// 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
+}