diff --git a/numba/cuda/cudadrv/devicearray.py b/numba/cuda/cudadrv/devicearray.py index 651f06bf698..21adaa94cf3 100644 --- a/numba/cuda/cudadrv/devicearray.py +++ b/numba/cuda/cudadrv/devicearray.py @@ -895,6 +895,8 @@ def check_array_compatibility(ary1, ary2): if ary1sq.shape != ary2sq.shape: raise ValueError('incompatible shape: %s vs. %s' % (ary1.shape, ary2.shape)) - if ary1sq.strides != ary2sq.strides: + # We check strides only if the size is nonzero, because strides are + # irrelevant (and can differ) for zero-length copies. + if ary1.size and ary1sq.strides != ary2sq.strides: raise ValueError('incompatible strides: %s vs. %s' % (ary1.strides, ary2.strides)) diff --git a/numba/cuda/tests/cudadrv/test_cuda_ndarray.py b/numba/cuda/tests/cudadrv/test_cuda_ndarray.py index d84d297ebca..1e674df7aca 100644 --- a/numba/cuda/tests/cudadrv/test_cuda_ndarray.py +++ b/numba/cuda/tests/cudadrv/test_cuda_ndarray.py @@ -420,6 +420,41 @@ def test_bug6697(self): got = np.asarray(dary) self.assertEqual(got.dtype, dary.dtype) + @skip_on_cudasim('DeviceNDArray class not present in simulator') + def test_issue_8477(self): + # Ensure that we can copy a zero-length device array to a zero-length + # host array when the strides of the device and host arrays differ - + # this should be possible because the strides are irrelevant when the + # length is zero. For more info see + # https://github.com/numba/numba/issues/8477. + + # Create a device array with shape (0,) and strides (8,) + dev_array = devicearray.DeviceNDArray(shape=(0,), strides=(8,), + dtype=np.int8) + + # Create a host array with shape (0,) and strides (0,) + host_array = np.ndarray(shape=(0,), strides=(0,), dtype=np.int8) + + # Sanity check for this test - ensure our destination has the strides + # we expect, because strides can be ignored in some cases by the + # ndarray constructor - checking here ensures that we haven't failed to + # account for unexpected behaviour across different versions of NumPy + self.assertEqual(host_array.strides, (0,)) + + # Ensure that the copy succeeds in both directions + dev_array.copy_to_host(host_array) + dev_array.copy_to_device(host_array) + + # Ensure that a device-to-device copy also succeeds when the strides + # differ - one way of doing this is to copy the host array across and + # use that for copies in both directions. + dev_array_from_host = cuda.to_device(host_array) + self.assertEqual(dev_array_from_host.shape, (0,)) + self.assertEqual(dev_array_from_host.strides, (0,)) + + dev_array.copy_to_device(dev_array_from_host) + dev_array_from_host.copy_to_device(dev_array) + class TestRecarray(CUDATestCase): def test_recarray(self):