aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/compiler')
-rw-r--r--pkg/compiler/check.go18
-rw-r--r--pkg/compiler/compiler.go12
-rw-r--r--pkg/compiler/gen.go2
-rw-r--r--pkg/compiler/testdata/all.txt19
-rw-r--r--pkg/compiler/testdata/errors2.txt23
5 files changed, 57 insertions, 17 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) {
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go
index 3f10ae5fe..978255219 100644
--- a/pkg/compiler/compiler.go
+++ b/pkg/compiler/compiler.go
@@ -65,6 +65,7 @@ func createCompiler(desc *ast.Description, target *targets.Target, eh ast.ErrorH
structVarlen: make(map[string]bool),
structTypes: make(map[string]prog.Type),
structFiles: make(map[*ast.Struct]map[string]ast.Pos),
+ recursiveQuery: make(map[ast.Node]bool),
builtinConsts: map[string]uint64{
"PTR_SIZE": target.PtrSize,
},
@@ -135,11 +136,12 @@ type compiler struct {
usedTypedefs map[string]bool
brokenTypedefs map[string]bool
- structVarlen map[string]bool
- structTypes map[string]prog.Type
- structFiles map[*ast.Struct]map[string]ast.Pos
- builtinConsts map[string]uint64
- fileMeta map[string]Meta
+ structVarlen map[string]bool
+ structTypes map[string]prog.Type
+ structFiles map[*ast.Struct]map[string]ast.Pos
+ builtinConsts map[string]uint64
+ fileMeta map[string]Meta
+ recursiveQuery map[ast.Node]bool
}
type warn struct {
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go
index 104c2899b..a6fd938a9 100644
--- a/pkg/compiler/gen.go
+++ b/pkg/compiler/gen.go
@@ -224,6 +224,7 @@ func (comp *compiler) layoutType(typ prog.Type, padded map[prog.Type]bool) {
if padded[typ] {
return
}
+ padded[typ] = true
switch t := typ.(type) {
case *prog.ArrayType:
comp.layoutType(t.Elem, padded)
@@ -244,7 +245,6 @@ func (comp *compiler) layoutType(typ prog.Type, padded map[prog.Type]bool) {
if !typ.Varlen() && typ.Size() == sizeUnassigned {
panic("size unassigned")
}
- padded[typ] = true
}
func (comp *compiler) layoutArray(t *prog.ArrayType) {
diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt
index 098da4604..b19b85980 100644
--- a/pkg/compiler/testdata/all.txt
+++ b/pkg/compiler/testdata/all.txt
@@ -373,3 +373,22 @@ union$conditional3 [
]
conditional(a ptr[in, struct$conditional])
+
+# Struct recusrion via arrays.
+
+recursive_struct_call(a ptr[in, recursive_struct], b ptr[in, recursive_struct3])
+
+recursive_struct {
+ f0 array[recursive_struct]
+ f1 recursive_struct2
+ f2 array[recursive_struct2]
+} [packed]
+
+recursive_struct2 {
+ f0 int32
+ f1 array[recursive_struct]
+}
+
+recursive_struct3 {
+ f0 array[recursive_struct3]
+}
diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt
index 71e2aa5ad..9bdccb8fe 100644
--- a/pkg/compiler/testdata/errors2.txt
+++ b/pkg/compiler/testdata/errors2.txt
@@ -16,7 +16,7 @@ foo$1(a0 r0, a1 r1, a2 r2)
# Recursive structs/unions.
sr1 {
- f1 sr1 ### recursive declaration: sr1.f1 -> sr1 (mark some pointers as opt)
+ f1 sr1 ### recursive declaration: sr1.f1 -> sr1 (mark some pointers as opt, or use variable-length arrays)
}
sr2 {
@@ -25,12 +25,12 @@ sr2 {
}
sr3 {
- f1 ptr[in, sr3] ### recursive declaration: sr3.f1 -> sr3 (mark some pointers as opt)
+ f1 ptr[in, sr3] ### recursive declaration: sr3.f1 -> sr3 (mark some pointers as opt, or use variable-length arrays)
}
sr4 {
f1 ptr[in, sr3]
- f2 array[ptr[in, sr5], 4] ### recursive declaration: sr4.f2 -> sr5.f2 -> sr6.f1 -> sr4 (mark some pointers as opt)
+ f2 array[ptr[in, sr5], 4] ### recursive declaration: sr4.f2 -> sr5.f2 -> sr6.f1 -> sr4 (mark some pointers as opt, or use variable-length arrays)
}
sr5 [
@@ -51,26 +51,31 @@ type templ_sr[T] {
}
sr8 {
- f templ_sr[sr8] ### recursive declaration: sr8.f -> templ_sr[sr8].f -> sr8 (mark some pointers as opt)
+ f templ_sr[sr8] ### recursive declaration: sr8.f -> templ_sr[sr8].f -> sr8 (mark some pointers as opt, or use variable-length arrays)
}
sr9 {
- f templ_sr[ptr[in, sr9]] ### recursive declaration: sr9.f -> templ_sr[ptr[in, sr9]].f -> sr9 (mark some pointers as opt)
+ f templ_sr[ptr[in, sr9]] ### recursive declaration: sr9.f -> templ_sr[ptr[in, sr9]].f -> sr9 (mark some pointers as opt, or use variable-length arrays)
+}
+
+sr10 {
+ f0 array[sr10, 10] ### recursive declaration: sr10.f0 -> sr10 (mark some pointers as opt, or use variable-length arrays)
}
use_sr {
u2 u2
- u3 u3
+ u3 u3
s3 s3
s4 s4
s6 s6
s8 s8
- sr1 sr1
+ sr1 sr1
sr2 sr2
sr5 sr5
sr7 sr7
- sr8 sr8
- sr9 sr9
+ sr8 sr8
+ sr9 sr9
+ sr10 sr10
s400 s400
s401 s401
u400 u400