aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/compiler/check.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/compiler/check.go')
-rw-r--r--pkg/compiler/check.go18
1 files changed, 16 insertions, 2 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 8a1a7b7e9..d693fa790 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -949,7 +949,7 @@ func (comp *compiler) checkStructRecursion(checked map[string]bool, n *ast.Struc
str += fmt.Sprintf("%v.%v -> ", elem.Struct, elem.Field)
}
str += name
- comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt)", str)
+ comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt, or use variable-length arrays)", str)
checked[name] = true
return
}
@@ -975,6 +975,9 @@ func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []
if desc == typePtr && base.IsOptional {
return // optional pointers prune recursion
}
+ if desc == typeArray && len(args) == 1 {
+ return // variable-length arrays prune recursion
+ }
for i, arg := range args {
if desc.Args[i].Type == typeArgType {
isArg := false
@@ -1425,8 +1428,19 @@ func (comp *compiler) isVarlen(t *ast.Type) bool {
}
func (comp *compiler) isZeroSize(t *ast.Type) bool {
+ // We can recurse here for a struct that recursively contains itself in an array.
+ // In such case it's safe to say that it is zero size, because if all other fields are zero size,
+ // then the struct is indeed zero size (even if it contains several versions of itself transitively).
+ // If there are any other "normal" fields, then we will still correctly conclude that the whole struct
+ // is not zero size.
+ if comp.recursiveQuery[t] {
+ return true
+ }
+ comp.recursiveQuery[t] = true
desc, args, _ := comp.getArgsBase(t, false)
- return desc.ZeroSize != nil && desc.ZeroSize(comp, t, args)
+ res := desc.ZeroSize != nil && desc.ZeroSize(comp, t, args)
+ delete(comp.recursiveQuery, t)
+ return res
}
func (comp *compiler) checkVarlen(n *ast.Struct) {