diff options
| author | Robert Griesemer <gri@golang.org> | 2018-02-12 16:42:31 -0800 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2018-02-13 20:31:05 +0000 |
| commit | 1006f703ffc191dbcce3135f1992f1a24a50cb52 (patch) | |
| tree | c987ec00b51b7382aad27bffec36adaf1dc2201b /src | |
| parent | ecba3714a3291073a2cde989c255de568bd1d512 (diff) | |
| download | go-1006f703ffc191dbcce3135f1992f1a24a50cb52.tar.xz | |
go/types: better handle arrays whose length expression is invalid
While doing that, establish a negative value as signal for unknown
array lengths and adjust various array-length processing code to
handle that case.
Fixes #23712.
Change-Id: Icf488faaf972638b42b22d4b4607d1c512c8fc2c
Reviewed-on: https://go-review.googlesource.com/93438
Reviewed-by: Alan Donovan <adonovan@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/go/types/builtins.go | 6 | ||||
| -rw-r--r-- | src/go/types/predicates.go | 4 | ||||
| -rw-r--r-- | src/go/types/sizes.go | 3 | ||||
| -rw-r--r-- | src/go/types/testdata/importC.src | 21 | ||||
| -rw-r--r-- | src/go/types/type.go | 2 | ||||
| -rw-r--r-- | src/go/types/typexpr.go | 9 |
6 files changed, 38 insertions, 7 deletions
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index f22851e240..785daec331 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -158,7 +158,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // function calls; in this case s is not evaluated." if !check.hasCallOrRecv { mode = constant_ - val = constant.MakeInt64(t.len) + if t.len >= 0 { + val = constant.MakeInt64(t.len) + } else { + val = constant.MakeUnknown() + } } case *Slice, *Chan: diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 3aa4878cce..1ca146f590 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -150,7 +150,9 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // Two array types are identical if they have identical element types // and the same array length. if y, ok := y.(*Array); ok { - return x.len == y.len && identical(x.elem, y.elem, cmpTags, p) + // If one or both array lengths are unknown (< 0) due to some error, + // assume they are the same to avoid spurious follow-on errors. + return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p) } case *Slice: diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index 0821a61359..eb274799f4 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -132,9 +132,10 @@ func (s *StdSizes) Sizeof(T Type) int64 { } case *Array: n := t.len - if n == 0 { + if n <= 0 { return 0 } + // n > 0 a := s.Alignof(t.elem) z := s.Sizeof(t.elem) return align(z, a)*(n-1) + z diff --git a/src/go/types/testdata/importC.src b/src/go/types/testdata/importC.src index f50f7f33d3..f55be2d5c5 100644 --- a/src/go/types/testdata/importC.src +++ b/src/go/types/testdata/importC.src @@ -20,7 +20,7 @@ type T struct { Ordinal int } -func f(args []T) { +func _(args []T) { var s string for i, v := range args { cname := C.CString(v.Name) @@ -33,3 +33,22 @@ type CType C.Type const _ CType = C.X // no error due to invalid constant type const _ = C.X + +// Test cases extracted from issue #23712. + +func _() { + var a [C.ArrayLength]byte + _ = a[0] // no index out of bounds error here +} + +// Additional tests to verify fix for #23712. + +func _() { + var a [C.ArrayLength1]byte + _ = 1 / len(a) // no division by zero error here and below + _ = 1 / cap(a) + _ = uint(unsafe.Sizeof(a)) // must not be negative + + var b [C.ArrayLength2]byte + a = b // should be valid +} diff --git a/src/go/types/type.go b/src/go/types/type.go index 50e3c6e4d0..afdbb680f8 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -97,9 +97,11 @@ type Array struct { } // NewArray returns a new array type for the given element type and length. +// A negative length indicates an unknown length. func NewArray(elem Type, len int64) *Array { return &Array{len, elem} } // Len returns the length of array a. +// A negative result indicates an unknown length. func (a *Array) Len() int64 { return a.len } // Elem returns element type of array a. diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index aedd71e918..e86834efdd 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -380,6 +380,9 @@ func (check *Checker) typOrNil(e ast.Expr) Type { return Typ[Invalid] } +// arrayLength type-checks the array length expression e +// and returns the constant length >= 0, or a value < 0 +// to indicate an error (and thus an unknown length). func (check *Checker) arrayLength(e ast.Expr) int64 { var x operand check.expr(&x, e) @@ -387,7 +390,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { if x.mode != invalid { check.errorf(x.pos(), "array length %s must be constant", &x) } - return 0 + return -1 } if isUntyped(x.typ) || isInteger(x.typ) { if val := constant.ToInt(x.val); val.Kind() == constant.Int { @@ -396,12 +399,12 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { return n } check.errorf(x.pos(), "invalid array length %s", &x) - return 0 + return -1 } } } check.errorf(x.pos(), "array length %s must be integer", &x) - return 0 + return -1 } func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) { |
