prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  `copyto` does not test shape for memcpy cases
  ### Description
  
  There should be a shape check before these:
  https://github.com/cupy/cupy/blob/e7f2e797216954dd152efe0169ec6a0094d7777d/cupy/_manipulation/basic.py#L54-L55
  https://github.com/cupy/cupy/blob/e7f2e797216954dd152efe0169ec6a0094d7777d/cupy/_manipulation/basic.py#L76-L80
  
  ### To Reproduce
  
  ```py
  >>> dst = cupy.ones((2, 3), dtype=int)
  >>> cupy.copyto(dst, cupy.arange(6))
  >>> dst
  array([[0, 1, 2],
         [3, 4, 5]])
  >>> numpy.copyto(numpy.ones((2, 3), dtype=int), numpy.arange(6))
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<__array_function__ internals>", line 5, in copyto
  ValueError: could not broadcast input array from shape (6,) into shape (2,3)
  ```
  
  ```py
  >>> cupy.copyto(cupy.empty((3, 0, 4, 5)), cupy.empty((6, 7, 0)))
  >>> numpy.copyto(numpy.empty((3, 0, 4, 5)), numpy.empty((6, 7, 0)))
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<__array_function__ internals>", line 5, in copyto
  ValueError: could not broadcast input array from shape (6,7,0) into shape (3,0,4,5)
  ```
  
  
  </issue>
  <code>
  [start of cupy/_manipulation/basic.py]
  1 import numpy
  2 
  3 from cupy import _core
  4 from cupy._core import _fusion_interface
  5 from cupy._core import fusion
  6 from cupy._sorting import search
  7 from cupy_backends.cuda.api import runtime
  8 
  9 
  10 def copyto(dst, src, casting='same_kind', where=None):
  11     """Copies values from one array to another with broadcasting.
  12 
  13     This function can be called for arrays on different devices. In this case,
  14     casting, ``where``, and broadcasting is not supported, and an exception is
  15     raised if these are used.
  16 
  17     Args:
  18         dst (cupy.ndarray): Target array.
  19         src (cupy.ndarray): Source array.
  20         casting (str): Casting rule. See :func:`numpy.can_cast` for detail.
  21         where (cupy.ndarray of bool): If specified, this array acts as a mask,
  22             and an element is copied only if the corresponding element of
  23             ``where`` is True.
  24 
  25     .. seealso:: :func:`numpy.copyto`
  26 
  27     """
  28 
  29     src_type = type(src)
  30     src_is_python_scalar = src_type in (
  31         int, bool, float, complex,
  32         fusion._FusionVarScalar, _fusion_interface._ScalarProxy)
  33     if src_is_python_scalar:
  34         src_dtype = numpy.dtype(type(src))
  35         can_cast = numpy.can_cast(src, dst.dtype, casting)
  36     else:
  37         src_dtype = src.dtype
  38         can_cast = numpy.can_cast(src_dtype, dst.dtype, casting)
  39 
  40     if not can_cast:
  41         raise TypeError('Cannot cast %s to %s in %s casting mode' %
  42                         (src_dtype, dst.dtype, casting))
  43 
  44     if not src_is_python_scalar and src.ndim > dst.ndim:
  45         # NumPy allows stripping leading unit dimensions.
  46         try:
  47             src = src.squeeze(tuple(range(src.ndim - dst.ndim)))
  48         except ValueError:
  49             # "cannot select an axis to squeeze out
  50             # which has size not equal to one"
  51             pass  # raise an error later
  52 
  53     if fusion._is_fusing():
  54         if where is None:
  55             _core.elementwise_copy(src, dst)
  56         else:
  57             fusion._call_ufunc(search._where_ufunc, where, src, dst, dst)
  58         return
  59 
  60     if where is not None:
  61         _core.elementwise_copy(src, dst, _where=where)
  62         return
  63 
  64     if dst.size == 0:
  65         return
  66 
  67     if src_is_python_scalar:
  68         dst.fill(src)
  69         return
  70 
  71     if _can_memcpy(dst, src):
  72         dst.data.copy_from_async(src.data, src.nbytes)
  73         return
  74 
  75     device = dst.device
  76     prev_device = runtime.getDevice()
  77     try:
  78         runtime.setDevice(device.id)
  79         if src.device != device:
  80             src = src.copy()
  81         _core.elementwise_copy(src, dst)
  82     finally:
  83         runtime.setDevice(prev_device)
  84 
  85 
  86 def _can_memcpy(dst, src):
  87     c_contiguous = dst.flags.c_contiguous and src.flags.c_contiguous
  88     f_contiguous = dst.flags.f_contiguous and src.flags.f_contiguous
  89     return (c_contiguous or f_contiguous) and dst.dtype == src.dtype and \
  90         dst.size == src.size
  91
  [end of cupy/_manipulation/basic.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/cupy/_manipulation/basic.py b/cupy/_manipulation/basic.py
  --- a/cupy/_manipulation/basic.py
  +++ b/cupy/_manipulation/basic.py
  @@ -1,3 +1,5 @@
  +import itertools
  +
   import numpy
   
   from cupy import _core
  @@ -41,22 +43,35 @@
           raise TypeError('Cannot cast %s to %s in %s casting mode' %
                           (src_dtype, dst.dtype, casting))
   
  -    if not src_is_python_scalar and src.ndim > dst.ndim:
  -        # NumPy allows stripping leading unit dimensions.
  -        try:
  -            src = src.squeeze(tuple(range(src.ndim - dst.ndim)))
  -        except ValueError:
  -            # "cannot select an axis to squeeze out
  -            # which has size not equal to one"
  -            pass  # raise an error later
  -
       if fusion._is_fusing():
  +        # TODO(kataoka): NumPy allows stripping leading unit dimensions.
  +        # But fusion array proxy does not currently support
  +        # `shape` and `squeeze`.
  +
           if where is None:
               _core.elementwise_copy(src, dst)
           else:
               fusion._call_ufunc(search._where_ufunc, where, src, dst, dst)
           return
   
  +    if not src_is_python_scalar:
  +        # Check broadcast condition
  +        # - for fast-paths and
  +        # - for a better error message (than ufunc's).
  +        # NumPy allows stripping leading unit dimensions.
  +        if not all([
  +            s in (d, 1)
  +            for s, d in itertools.zip_longest(
  +                reversed(src.shape), reversed(dst.shape), fillvalue=1)
  +        ]):
  +            raise ValueError(
  +                "could not broadcast input array "
  +                f"from shape {src.shape} into shape {dst.shape}")
  +        squeeze_ndim = src.ndim - dst.ndim
  +        if squeeze_ndim > 0:
  +            # always succeeds because broadcast conition is checked.
  +            src = src.squeeze(tuple(range(squeeze_ndim)))
  +
       if where is not None:
           _core.elementwise_copy(src, dst, _where=where)
           return
  
verification_info: {"golden_diff": "diff --git a/cupy/_manipulation/basic.py b/cupy/_manipulation/basic.py\n--- a/cupy/_manipulation/basic.py\n+++ b/cupy/_manipulation/basic.py\n@@ -1,3 +1,5 @@\n+import itertools\n+\n import numpy\n \n from cupy import _core\n@@ -41,22 +43,35 @@\n         raise TypeError('Cannot cast %s to %s in %s casting mode' %\n                         (src_dtype, dst.dtype, casting))\n \n-    if not src_is_python_scalar and src.ndim > dst.ndim:\n-        # NumPy allows stripping leading unit dimensions.\n-        try:\n-            src = src.squeeze(tuple(range(src.ndim - dst.ndim)))\n-        except ValueError:\n-            # \"cannot select an axis to squeeze out\n-            # which has size not equal to one\"\n-            pass  # raise an error later\n-\n     if fusion._is_fusing():\n+        # TODO(kataoka): NumPy allows stripping leading unit dimensions.\n+        # But fusion array proxy does not currently support\n+        # `shape` and `squeeze`.\n+\n         if where is None:\n             _core.elementwise_copy(src, dst)\n         else:\n             fusion._call_ufunc(search._where_ufunc, where, src, dst, dst)\n         return\n \n+    if not src_is_python_scalar:\n+        # Check broadcast condition\n+        # - for fast-paths and\n+        # - for a better error message (than ufunc's).\n+        # NumPy allows stripping leading unit dimensions.\n+        if not all([\n+            s in (d, 1)\n+            for s, d in itertools.zip_longest(\n+                reversed(src.shape), reversed(dst.shape), fillvalue=1)\n+        ]):\n+            raise ValueError(\n+                \"could not broadcast input array \"\n+                f\"from shape {src.shape} into shape {dst.shape}\")\n+        squeeze_ndim = src.ndim - dst.ndim\n+        if squeeze_ndim > 0:\n+            # always succeeds because broadcast conition is checked.\n+            src = src.squeeze(tuple(range(squeeze_ndim)))\n+\n     if where is not None:\n         _core.elementwise_copy(src, dst, _where=where)\n         return\n", "issue": "`copyto` does not test shape for memcpy cases\n### Description\r\n\r\nThere should be a shape check before these:\r\nhttps://github.com/cupy/cupy/blob/e7f2e797216954dd152efe0169ec6a0094d7777d/cupy/_manipulation/basic.py#L54-L55\r\nhttps://github.com/cupy/cupy/blob/e7f2e797216954dd152efe0169ec6a0094d7777d/cupy/_manipulation/basic.py#L76-L80\r\n\r\n### To Reproduce\r\n\r\n```py\r\n>>> dst = cupy.ones((2, 3), dtype=int)\r\n>>> cupy.copyto(dst, cupy.arange(6))\r\n>>> dst\r\narray([[0, 1, 2],\r\n       [3, 4, 5]])\r\n>>> numpy.copyto(numpy.ones((2, 3), dtype=int), numpy.arange(6))\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\n  File \"<__array_function__ internals>\", line 5, in copyto\r\nValueError: could not broadcast input array from shape (6,) into shape (2,3)\r\n```\r\n\r\n```py\r\n>>> cupy.copyto(cupy.empty((3, 0, 4, 5)), cupy.empty((6, 7, 0)))\r\n>>> numpy.copyto(numpy.empty((3, 0, 4, 5)), numpy.empty((6, 7, 0)))\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\n  File \"<__array_function__ internals>\", line 5, in copyto\r\nValueError: could not broadcast input array from shape (6,7,0) into shape (3,0,4,5)\r\n```\r\n\n", "before_files": [{"content": "import numpy\n\nfrom cupy import _core\nfrom cupy._core import _fusion_interface\nfrom cupy._core import fusion\nfrom cupy._sorting import search\nfrom cupy_backends.cuda.api import runtime\n\n\ndef copyto(dst, src, casting='same_kind', where=None):\n    \"\"\"Copies values from one array to another with broadcasting.\n\n    This function can be called for arrays on different devices. In this case,\n    casting, ``where``, and broadcasting is not supported, and an exception is\n    raised if these are used.\n\n    Args:\n        dst (cupy.ndarray): Target array.\n        src (cupy.ndarray): Source array.\n        casting (str): Casting rule. See :func:`numpy.can_cast` for detail.\n        where (cupy.ndarray of bool): If specified, this array acts as a mask,\n            and an element is copied only if the corresponding element of\n            ``where`` is True.\n\n    .. seealso:: :func:`numpy.copyto`\n\n    \"\"\"\n\n    src_type = type(src)\n    src_is_python_scalar = src_type in (\n        int, bool, float, complex,\n        fusion._FusionVarScalar, _fusion_interface._ScalarProxy)\n    if src_is_python_scalar:\n        src_dtype = numpy.dtype(type(src))\n        can_cast = numpy.can_cast(src, dst.dtype, casting)\n    else:\n        src_dtype = src.dtype\n        can_cast = numpy.can_cast(src_dtype, dst.dtype, casting)\n\n    if not can_cast:\n        raise TypeError('Cannot cast %s to %s in %s casting mode' %\n                        (src_dtype, dst.dtype, casting))\n\n    if not src_is_python_scalar and src.ndim > dst.ndim:\n        # NumPy allows stripping leading unit dimensions.\n        try:\n            src = src.squeeze(tuple(range(src.ndim - dst.ndim)))\n        except ValueError:\n            # \"cannot select an axis to squeeze out\n            # which has size not equal to one\"\n            pass  # raise an error later\n\n    if fusion._is_fusing():\n        if where is None:\n            _core.elementwise_copy(src, dst)\n        else:\n            fusion._call_ufunc(search._where_ufunc, where, src, dst, dst)\n        return\n\n    if where is not None:\n        _core.elementwise_copy(src, dst, _where=where)\n        return\n\n    if dst.size == 0:\n        return\n\n    if src_is_python_scalar:\n        dst.fill(src)\n        return\n\n    if _can_memcpy(dst, src):\n        dst.data.copy_from_async(src.data, src.nbytes)\n        return\n\n    device = dst.device\n    prev_device = runtime.getDevice()\n    try:\n        runtime.setDevice(device.id)\n        if src.device != device:\n            src = src.copy()\n        _core.elementwise_copy(src, dst)\n    finally:\n        runtime.setDevice(prev_device)\n\n\ndef _can_memcpy(dst, src):\n    c_contiguous = dst.flags.c_contiguous and src.flags.c_contiguous\n    f_contiguous = dst.flags.f_contiguous and src.flags.f_contiguous\n    return (c_contiguous or f_contiguous) and dst.dtype == src.dtype and \\\n        dst.size == src.size\n", "path": "cupy/_manipulation/basic.py"}]}