Commit 1006f703 authored by Robert Griesemer's avatar Robert Griesemer

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/93438Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent ecba3714
......@@ -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:
......
......@@ -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:
......
......@@ -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
......
......@@ -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
}
......@@ -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.
......
......@@ -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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment