aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2018-02-12 16:42:31 -0800
committerRobert Griesemer <gri@golang.org>2018-02-13 20:31:05 +0000
commit1006f703ffc191dbcce3135f1992f1a24a50cb52 (patch)
treec987ec00b51b7382aad27bffec36adaf1dc2201b /src
parentecba3714a3291073a2cde989c255de568bd1d512 (diff)
downloadgo-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.go6
-rw-r--r--src/go/types/predicates.go4
-rw-r--r--src/go/types/sizes.go3
-rw-r--r--src/go/types/testdata/importC.src21
-rw-r--r--src/go/types/type.go2
-rw-r--r--src/go/types/typexpr.go9
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) {