summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2014-08-12 09:42:51 +1000
committerAndrew Gerrand <adg@golang.org>2014-08-12 09:42:51 +1000
commit0dcffe1e2ae52fb4e2cffc5c657d2e6f29d3a524 (patch)
treea14fe82a2b0c92b2ccb45656ec2a7aeafbcf418c
parent17922a7a92f53aec0d0157339383d26f859bcde0 (diff)
downloadgo-0dcffe1e2ae52fb4e2cffc5c657d2e6f29d3a524.tar.gz
[release-branch.go1.3] cmd/cgo: fix recursive type mapping
??? CL 122850043 / 0015a2541545 cmd/cgo: fix recursive type mapping Instead of immediately completing pointer type mappings, add them to a queue to allow them to be completed later. This fixes issues caused by Type() returning arbitrary in-progress type mappings. Fixes issue 8368. Fixes issue 8441. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://codereview.appspot.com/122850043 Committer: Ian Lance Taylor <iant@golang.org> ??? TBR=rsc R=rsc CC=golang-codereviews https://codereview.appspot.com/128940043
-rw-r--r--misc/cgo/test/issue8441.go27
-rw-r--r--src/cmd/cgo/gcc.go57
2 files changed, 71 insertions, 13 deletions
diff --git a/misc/cgo/test/issue8441.go b/misc/cgo/test/issue8441.go
new file mode 100644
index 000000000..2d871f083
--- /dev/null
+++ b/misc/cgo/test/issue8441.go
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+// Issue 8368 and 8441. Recursive struct definitions didn't work.
+// No runtime test; just make sure it compiles.
+
+package cgotest
+
+/*
+typedef struct one one;
+typedef struct two two;
+struct one {
+ two *x;
+};
+struct two {
+ one *x;
+};
+*/
+import "C"
+
+func issue8368(one *C.struct_one, two *C.struct_two) {
+}
+
+func issue8441(one *C.one, two *C.two) {
+ issue8441(two.x, one.x)
+}
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 7a802102d..f55cfbac4 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -552,8 +552,8 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
n.Const = fmt.Sprintf("%#x", enumVal[i])
}
}
+ conv.FinishType(pos)
}
-
}
// mangleName does name mangling to translate names
@@ -926,6 +926,12 @@ type typeConv struct {
m map[dwarf.Type]*Type
typedef map[string]ast.Expr
+ // Map from types to incomplete pointers to those types.
+ ptrs map[dwarf.Type][]*Type
+
+ // Fields to be processed by godefsField after completing pointers.
+ todoFlds [][]*ast.Field
+
// Predeclared types.
bool ast.Expr
byte ast.Expr // denotes padding
@@ -950,6 +956,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
c.m = make(map[dwarf.Type]*Type)
+ c.ptrs = make(map[dwarf.Type][]*Type)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
@@ -1029,6 +1036,32 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
tr.FormatArgs = fargs
}
+// FinishType completes any outstanding type mapping work.
+// In particular, it resolves incomplete pointer types and also runs
+// godefsFields on any new struct types.
+func (c *typeConv) FinishType(pos token.Pos) {
+ // Completing one pointer type might produce more to complete.
+ // Keep looping until they're all done.
+ for len(c.ptrs) > 0 {
+ for dtype := range c.ptrs {
+ // Note Type might invalidate c.ptrs[dtype].
+ t := c.Type(dtype, pos)
+ for _, ptr := range c.ptrs[dtype] {
+ ptr.Go.(*ast.StarExpr).X = t.Go
+ ptr.C.Set("%s*", t.C)
+ }
+ delete(c.ptrs, dtype)
+ }
+ }
+
+ // Now that pointer types are completed, we can invoke godefsFields
+ // to rewrite struct definitions.
+ for _, fld := range c.todoFlds {
+ godefsFields(fld)
+ }
+ c.todoFlds = nil
+}
+
// Type returns a *Type with the same memory layout as
// dtype when used as the type of a variable or a struct field.
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
@@ -1068,13 +1101,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.Opaque(t.Size)
break
}
- gt := &ast.ArrayType{
- Len: c.intExpr(dt.Count),
- }
- t.Go = gt // publish before recursive call
sub := c.Type(dt.Type, pos)
t.Align = sub.Align
- gt.Elt = sub.Go
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(dt.Count),
+ Elt: sub.Go,
+ }
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
case *dwarf.BoolType:
@@ -1184,11 +1216,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
break
}
- gt := &ast.StarExpr{}
- t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type, pos)
- gt.X = sub.Go
- t.C.Set("%s*", sub.C)
+ // Placeholder initialization; completed in FinishType.
+ t.Go = &ast.StarExpr{}
+ t.C.Set("<incomplete>*")
+ c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType:
// Ignore qualifier.
@@ -1265,8 +1296,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
name := c.Ident("_Ctype_" + dt.Name)
goIdent[name.Name] = name
- t.Go = name // publish before recursive call
sub := c.Type(dt.Type, pos)
+ t.Go = name
t.Size = sub.Size
t.Align = sub.Align
oldType := typedef[name.Name]
@@ -1604,7 +1635,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
csyntax = buf.String()
if *godefs || *cdefs {
- godefsFields(fld)
+ c.todoFlds = append(c.todoFlds, fld)
}
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return