diff options
| author | Necip Fazil Yildiran <necip@google.com> | 2020-08-10 14:43:38 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-08-13 13:50:25 +0200 |
| commit | f5442bde55872d703f184f8617329f706bad8149 (patch) | |
| tree | 14e121020d6aacd857b80351f01546818f19a74b /pkg/compiler | |
| parent | ee7cb8b69583db417b187b53f4765c3a403cd4cf (diff) | |
pkg, prog: add per-field direction attribute
Diffstat (limited to 'pkg/compiler')
| -rw-r--r-- | pkg/compiler/attrs.go | 4 | ||||
| -rw-r--r-- | pkg/compiler/check.go | 24 | ||||
| -rw-r--r-- | pkg/compiler/gen.go | 22 | ||||
| -rw-r--r-- | pkg/compiler/testdata/all.txt | 10 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors.txt | 10 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors2.txt | 94 |
6 files changed, 155 insertions, 9 deletions
diff --git a/pkg/compiler/attrs.go b/pkg/compiler/attrs.go index c0fa04211..5de19f884 100644 --- a/pkg/compiler/attrs.go +++ b/pkg/compiler/attrs.go @@ -23,9 +23,13 @@ var ( attrVarlen = &attrDesc{Name: "varlen"} attrSize = &attrDesc{Name: "size", HasArg: true} attrAlign = &attrDesc{Name: "align", HasArg: true} + attrIn = &attrDesc{Name: "in"} + attrOut = &attrDesc{Name: "out"} + attrInOut = &attrDesc{Name: "inout"} structAttrs = makeAttrs(attrPacked, attrSize, attrAlign) unionAttrs = makeAttrs(attrVarlen, attrSize) + fieldAttrs = makeAttrs(attrIn, attrOut, attrInOut) callAttrs = make(map[string]*attrDesc) ) diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 9bb8c1c0c..468b6e35e 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -168,6 +168,14 @@ func (comp *compiler) checkStructFields(n *ast.Struct, typ, name string) { if len(n.Fields) < 1 { comp.error(n.Pos, "%v %v has no fields, need at least 1 field", typ, name) } + for _, f := range n.Fields { + attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs) + + if attrs[attrIn]+attrs[attrOut]+attrs[attrInOut] > 1 { + _, typ, _ := f.Info() + comp.error(f.Pos, "%v has multiple direction attributes", typ) + } + } } func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) { @@ -267,6 +275,16 @@ func (comp *compiler) checkAttributeValues() { desc.CheckConsts(comp, n, attr) } } + // Check each field's attributes. + st := decl.(*ast.Struct) + for _, f := range st.Fields { + for _, attr := range f.Attrs { + desc := fieldAttrs[attr.Ident] + if desc.CheckConsts != nil { + desc.CheckConsts(comp, f, attr) + } + } + } } } } @@ -614,7 +632,11 @@ func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg bool, } checked[key] = true for _, fld := range s.Fields { - comp.checkTypeCtors(fld.Type, dir, false, ctors, inputs, checked) + fldDir, fldHasDir := comp.genFieldDir(fld) + if !fldHasDir { + fldDir = dir + } + comp.checkTypeCtors(fld.Type, fldDir, false, ctors, inputs, checked) } return } diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index d4834e40e..bd487432a 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -441,10 +441,28 @@ func (comp *compiler) genFieldArray(fields []*ast.Field, argSizes []uint64) []pr return res } +func (comp *compiler) genFieldDir(f *ast.Field) (prog.Dir, bool) { + attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs) + switch { + case attrs[attrIn] != 0: + return prog.DirIn, true + case attrs[attrOut] != 0: + return prog.DirOut, true + case attrs[attrInOut] != 0: + return prog.DirInOut, true + default: + return prog.DirIn, false + } +} + func (comp *compiler) genField(f *ast.Field, argSize uint64) prog.Field { + dir, hasDir := comp.genFieldDir(f) + return prog.Field{ - Name: f.Name.Name, - Type: comp.genType(f.Type, argSize), + Name: f.Name.Name, + Type: comp.genType(f.Type, argSize), + HasDirection: hasDir, + Direction: dir, } } diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index b9e144d73..17b7c838d 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -276,7 +276,15 @@ s4 { f2 int8 } [size[19]] -foo_s0(a ptr[in, s0], b ptr[in, s1], c ptr[in, s2], d ptr[in, s4]) +s5 { + f_in0 int32 (in) + f_in1 int32[0:1] (in) + f_out int32 (out) + f_inout0 int32 (inout) + f_inout1 int32[0:1] (inout) +} + +foo_s0(a ptr[in, s0], b ptr[in, s1], c ptr[in, s2], d ptr[in, s4], e ptr[in, s5]) # Unions. diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index cc0f47508..d3658d239 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -346,3 +346,13 @@ struct$fmt0 { f0 fmt[dec, int8:3] ### unexpected ':', only struct fields can be bitfields f1 int32:-1 ### bitfield of size 18446744073709551615 is too large for base type of size 32 } + +struct$perfielddir { + f0 int32 (in, in) ### duplicate arg/field f0 attribute in + f1 int32 (out, out) ### duplicate arg/field f1 attribute out + f2 int32 (inout, inout) ### duplicate arg/field f2 attribute inout + f3 int32 (in, out) ### arg/field has multiple direction attributes + f4 int32 (in, inout) ### arg/field has multiple direction attributes + f5 int32 (out, inout) ### arg/field has multiple direction attributes + f6 int32 (in, out, inout) ### arg/field has multiple direction attributes +}
\ No newline at end of file diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 68b8a66df..c862358cf 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -176,11 +176,26 @@ resource r104[int8] resource r105[int8] resource r106[int8] ### resource r106 can't be created (never mentioned as a syscall return value or output argument/field) resource r107[int8] ### resource r107 can't be created (never mentioned as a syscall return value or output argument/field) -resource r108[int8] ### resource r108 is never used as an input(such resources are not useful) - -foo$300(a0 r100, a1 r101, a2 r102, a3 r103, a4 r104) -foo$301(a ptr[out, array[r103]], b ptr[in, s300], c r107) r104 -foo$302() r108 +resource r108[int8] ### resource r108 can't be created (never mentioned as a syscall return value or output argument/field) +resource r109[int8] ### resource r109 can't be created (never mentioned as a syscall return value or output argument/field) +resource r110[int8] +resource r111[int8] +resource r112[int8] ### resource r112 can't be created (never mentioned as a syscall return value or output argument/field) +resource r113[int8] +resource r114[int8] +resource r115[int8] ### resource r115 can't be created (never mentioned as a syscall return value or output argument/field) +resource r116[int8] ### resource r116 is never used as an input(such resources are not useful) +resource r117[int8] ### resource r117 is never used as an input(such resources are not useful) +resource r118[int8] ### resource r118 is never used as an input(such resources are not useful) +resource r119[int8] ### resource r119 is never used as an input(such resources are not useful) +resource r120[int8] ### resource r120 can't be created (never mentioned as a syscall return value or output argument/field) +resource r121[int8] + +foo$300(a0 r100, a1 r101, a2 r102, a3 r103, a4 r104, a5 r105, a6 r106, a7 r107, a8 r108) +foo$301(a0 r109, a1 r110, a2 r111, a3 r112, a4 r113, a5 r114, a6 r115, a7 r120, a8 r121) +foo$302(a ptr[out, array[r103]], b ptr[in, s300], c r107) r104 +foo$303(a ptr[in, s302], b ptr[in, s303], c ptr[in, s304], d ptr[out, s305], e ptr[inout, s306], f ptr[inout, s307], g ptr[in, s308], h ptr[out, s310]) +foo$304(a ptr[out, r117], b ptr[in, s312], c ptr[in, s313], d ptr[inout, u100]) r116 s300 { f1 ptr[inout, s301] @@ -191,6 +206,75 @@ s301 { f2 r105 } +s302 { + f1 r108 +} + +s303 { + f1 r109 (in) +} + +# ptr to struct is in, field is out (valid, resource can be created) +s304 { + f1 r110 (out) +} + +# ptr to struct is out, field is in (error, resource can't be created) +s305 { + f1 r111 (in) +} + +# ptr to struct is inout, field is inout (valid, resource can be created) +s306 { + f1 r111 (inout) +} + +# ptr to struct is inout, fields are in (error) and out (valid) +s307 { + f1 r112 (in) + f2 r113 (out) +} + +# recurse the out field inside two levels of in ptrs (valid, resource can be created) +s308 { + f1 ptr[in, s309] +} + +s309 { + f1 ptr[out, r114] +} + +# recurse the in field inside two levels of out ptrs (error, resource can't be created) +s310 { + f1 ptr[out, s311] +} + +s311 { + f1 ptr[in, r115] +} + +# ptr to struct is in, field is out (error, never used as an input) +s312 { + f1 r118 (out) +} + +# recurse the out field inside two levels of in ptrs (error, never used as an input) +s313 { + f1 ptr[in, s314] +} + +s314 { + f1 r119 (out) +} + +u100 [ + f1 r120 (in) + f2 r121 (out) +] + +# TODO: Two instances of the same resource might exist in the same structure as +# both in and out. How common is this and how to handle this? + # Varlen field tests. s400 { |
