Skip to content

Commit b0454f5

Browse files
adgianlancetaylor
authored andcommitted
[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 #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
1 parent b48cd4b commit b0454f5

File tree

2 files changed

+71
-13
lines changed

2 files changed

+71
-13
lines changed

misc/cgo/test/issue8441.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2014 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Issue 8368 and 8441. Recursive struct definitions didn't work.
6+
// No runtime test; just make sure it compiles.
7+
8+
package cgotest
9+
10+
/*
11+
typedef struct one one;
12+
typedef struct two two;
13+
struct one {
14+
two *x;
15+
};
16+
struct two {
17+
one *x;
18+
};
19+
*/
20+
import "C"
21+
22+
func issue8368(one *C.struct_one, two *C.struct_two) {
23+
}
24+
25+
func issue8441(one *C.one, two *C.two) {
26+
issue8441(two.x, one.x)
27+
}

src/cmd/cgo/gcc.go

+44-13
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,8 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
552552
n.Const = fmt.Sprintf("%#x", enumVal[i])
553553
}
554554
}
555+
conv.FinishType(pos)
555556
}
556-
557557
}
558558

559559
// mangleName does name mangling to translate names
@@ -926,6 +926,12 @@ type typeConv struct {
926926
m map[dwarf.Type]*Type
927927
typedef map[string]ast.Expr
928928

929+
// Map from types to incomplete pointers to those types.
930+
ptrs map[dwarf.Type][]*Type
931+
932+
// Fields to be processed by godefsField after completing pointers.
933+
todoFlds [][]*ast.Field
934+
929935
// Predeclared types.
930936
bool ast.Expr
931937
byte ast.Expr // denotes padding
@@ -950,6 +956,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
950956
c.ptrSize = ptrSize
951957
c.intSize = intSize
952958
c.m = make(map[dwarf.Type]*Type)
959+
c.ptrs = make(map[dwarf.Type][]*Type)
953960
c.bool = c.Ident("bool")
954961
c.byte = c.Ident("byte")
955962
c.int8 = c.Ident("int8")
@@ -1029,6 +1036,32 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
10291036
tr.FormatArgs = fargs
10301037
}
10311038

1039+
// FinishType completes any outstanding type mapping work.
1040+
// In particular, it resolves incomplete pointer types and also runs
1041+
// godefsFields on any new struct types.
1042+
func (c *typeConv) FinishType(pos token.Pos) {
1043+
// Completing one pointer type might produce more to complete.
1044+
// Keep looping until they're all done.
1045+
for len(c.ptrs) > 0 {
1046+
for dtype := range c.ptrs {
1047+
// Note Type might invalidate c.ptrs[dtype].
1048+
t := c.Type(dtype, pos)
1049+
for _, ptr := range c.ptrs[dtype] {
1050+
ptr.Go.(*ast.StarExpr).X = t.Go
1051+
ptr.C.Set("%s*", t.C)
1052+
}
1053+
delete(c.ptrs, dtype)
1054+
}
1055+
}
1056+
1057+
// Now that pointer types are completed, we can invoke godefsFields
1058+
// to rewrite struct definitions.
1059+
for _, fld := range c.todoFlds {
1060+
godefsFields(fld)
1061+
}
1062+
c.todoFlds = nil
1063+
}
1064+
10321065
// Type returns a *Type with the same memory layout as
10331066
// dtype when used as the type of a variable or a struct field.
10341067
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 {
10681101
t.Go = c.Opaque(t.Size)
10691102
break
10701103
}
1071-
gt := &ast.ArrayType{
1072-
Len: c.intExpr(dt.Count),
1073-
}
1074-
t.Go = gt // publish before recursive call
10751104
sub := c.Type(dt.Type, pos)
10761105
t.Align = sub.Align
1077-
gt.Elt = sub.Go
1106+
t.Go = &ast.ArrayType{
1107+
Len: c.intExpr(dt.Count),
1108+
Elt: sub.Go,
1109+
}
10781110
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
10791111

10801112
case *dwarf.BoolType:
@@ -1184,11 +1216,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
11841216
break
11851217
}
11861218

1187-
gt := &ast.StarExpr{}
1188-
t.Go = gt // publish before recursive call
1189-
sub := c.Type(dt.Type, pos)
1190-
gt.X = sub.Go
1191-
t.C.Set("%s*", sub.C)
1219+
// Placeholder initialization; completed in FinishType.
1220+
t.Go = &ast.StarExpr{}
1221+
t.C.Set("<incomplete>*")
1222+
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
11921223

11931224
case *dwarf.QualType:
11941225
// Ignore qualifier.
@@ -1265,8 +1296,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
12651296
}
12661297
name := c.Ident("_Ctype_" + dt.Name)
12671298
goIdent[name.Name] = name
1268-
t.Go = name // publish before recursive call
12691299
sub := c.Type(dt.Type, pos)
1300+
t.Go = name
12701301
t.Size = sub.Size
12711302
t.Align = sub.Align
12721303
oldType := typedef[name.Name]
@@ -1604,7 +1635,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
16041635
csyntax = buf.String()
16051636

16061637
if *godefs || *cdefs {
1607-
godefsFields(fld)
1638+
c.todoFlds = append(c.todoFlds, fld)
16081639
}
16091640
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
16101641
return

0 commit comments

Comments
 (0)