Commit 3ad62f34 authored by Stefan Behnel's avatar Stefan Behnel

make array slice guard code work for bounds that are unknown at translation time

parent 848b6027
......@@ -4143,47 +4143,77 @@ class SliceIndexNode(ExprNode):
if not self.base.type.is_array:
return
slice_size = self.base.type.size
try:
total_length = slice_size = int(slice_size)
except ValueError:
total_length = None
start = stop = None
if self.stop:
stop = self.stop.result()
try:
stop = int(stop)
if stop < 0:
slice_size = self.base.type.size + stop
if total_length is None:
slice_size = '%s + %d' % (slice_size, stop)
else:
slice_size += stop
else:
slice_size = stop
stop = None
except ValueError:
pass
if self.start:
start = self.start.result()
try:
start = int(start)
if start < 0:
start = self.base.type.size + start
slice_size -= start
if total_length is None:
start = '%s + %d' % (self.base.type.size, start)
else:
start += total_length
if isinstance(slice_size, (int, long)):
slice_size -= start
else:
slice_size = '%s - (%s)' % (slice_size, start)
start = None
except ValueError:
pass
check = None
if slice_size < 0:
if target_size > 0:
runtime_check = None
compile_time_check = False
try:
int_target_size = int(target_size)
except ValueError:
int_target_size = None
else:
compile_time_check = isinstance(slice_size, (int, long))
if compile_time_check and slice_size < 0:
if int_target_size > 0:
error(self.pos, "Assignment to empty slice.")
elif start is None and stop is None:
elif compile_time_check and start is None and stop is None:
# we know the exact slice length
if target_size != slice_size:
error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % (
slice_size, target_size))
if int_target_size != slice_size:
error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % (
slice_size, target_size))
elif start is not None:
if stop is None:
stop = slice_size
check = "(%s)-(%s)" % (stop, start)
else: # stop is not None:
check = stop
if check:
code.putln("if (unlikely((%s) != %d)) {" % (check, target_size))
code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d", (Py_ssize_t)%d, (Py_ssize_t)(%s));' % (
target_size, check))
runtime_check = "(%s)-(%s)" % (stop, start)
elif stop is not None:
runtime_check = stop
else:
runtime_check = slice_size
if runtime_check:
code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size))
code.putln(
'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,'
' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",'
' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % (
target_size, runtime_check))
code.putln(code.error_goto(self.pos))
code.putln("}")
......
# mode: error
ctypedef int[1] int_array
ctypedef int[2] int_array2
cdef int_array x, y
x = y # not an error
cdef int_array *x_ptr = &x
x_ptr[0] = y # not an error
cdef class A:
cdef int_array value
def __init__(self):
self.value = x # not an error
cdef int_array2 z
z = x # error
x = z # error
cdef enum:
SIZE = 2
ctypedef int[SIZE] int_array_dyn
cdef int_array_dyn d
d = z # not an error
_ERRORS = u"""
20:2: Assignment to slice of wrong length, expected 2, got 1
21:2: Assignment to slice of wrong length, expected 1, got 2
"""
......@@ -10,40 +10,8 @@ cdef void foo(obj):
obj = p2 # error
ctypedef int[1] int_array
cdef int_array x, y
x = y # not an error
cdef int_array *x_ptr = &x
x_ptr[0] = y # not an error
cdef class A:
cdef int_array value
def __init__(self):
self.value = x # not an error
ctypedef int[2] int_array2
cdef int_array2 z
z = x # error
cdef enum:
SIZE = 2
ctypedef int[SIZE] int_array_dyn
cdef int_array_dyn d
d = z # error
_ERRORS = u"""
7:19: Cannot assign type 'char *' to 'int'
8:20: Cannot convert Python object to 'int *'
10:20: Cannot convert 'int *' to Python object
31:14: Cannot assign type 'int_array' to 'int_array2'
40:14: Cannot assign type 'int_array2' to 'int_array_dyn'
"""
......@@ -226,4 +226,74 @@ def assign_slice_start_end_from_sliced_pointer():
a[4] = 345
a[2:4] = v[2:4]
return (a[0], a[1], a[2], a[3], a[4])
def assign_from_longer_array_slice():
"""
>>> assign_from_longer_array_slice()
[3, 4, 5]
"""
cdef int[5] a
cdef int[3] b
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
b[0] = 11
b[1] = 12
b[2] = 13
b = a[2:]
return b
'''
def assign_slice_from_shorter_array():
"""
>>> assign_slice_from_shorter_array()
[1, 11, 12, 13, 5]
"""
cdef int[5] a
cdef int[3] b
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
b[0] = 11
b[1] = 12
b[2] = 13
a[1:4] = b
return a
cdef enum:
SIZE = 2
ctypedef int[SIZE] int_array_dyn
def assign_ptr_to_unknown_csize():
"""
>>> assign_ptr_to_unknown_csize()
[1, 2]
"""
cdef int* v = [1, 2, 3, 4, 5]
cdef int_array_dyn d
d = v
return d
def assign_to_wrong_csize():
"""
>>> assign_to_wrong_csize()
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 3, got 2
"""
cdef int_array_dyn d
cdef int v[3]
v[0] = 1
v[1] = 2
v[2] = 3
d = v
return d
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