Skip to content

Commit

Permalink
[release-branch.go1.3] cmd/cgo: fix recursive type mapping
Browse files Browse the repository at this point in the history
««« 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 #8368.
Fixes #8441.

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/122850043

»»»

TBR=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/128940043
  • Loading branch information
adg authored and ianlancetaylor committed Aug 11, 2014
1 parent b48cd4b commit b0454f5
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 13 deletions.
27 changes: 27 additions & 0 deletions 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)
}
57 changes: 44 additions & 13 deletions src/cmd/cgo/gcc.go
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b0454f5

Please sign in to comment.