}
for _, arg := range x.Args {
- if !typeOKForCgoCall(cgoBaseType(f, arg)) {
+ if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
}
arg = conv.Args[0]
}
if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
- if !typeOKForCgoCall(cgoBaseType(f, u.X)) {
+ if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
}
}
return f.pkg.types[arg].Type
}
-// typeOKForCgoCall returns true if the type of arg is OK to pass to a
+// typeOKForCgoCall reports whether the type of arg is OK to pass to a
// C function using cgo. This is not true for Go types with embedded
-// pointers.
-func typeOKForCgoCall(t types.Type) bool {
- if t == nil {
+// pointers. m is used to avoid infinite recursion on recursive types.
+func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
+ if t == nil || m[t] {
return true
}
+ m[t] = true
switch t := t.Underlying().(type) {
case *types.Chan, *types.Map, *types.Signature, *types.Slice:
return false
case *types.Pointer:
- return typeOKForCgoCall(t.Elem())
+ return typeOKForCgoCall(t.Elem(), m)
case *types.Array:
- return typeOKForCgoCall(t.Elem())
+ return typeOKForCgoCall(t.Elem(), m)
case *types.Struct:
for i := 0; i < t.NumFields(); i++ {
- if !typeOKForCgoCall(t.Field(i).Type()) {
+ if !typeOKForCgoCall(t.Field(i).Type(), m) {
return false
}
}