We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot use cffi.from_buffer when explicitly passing signature to JIT
I was experimenting with passing arrays to CFFI functions (see https://github.com/numba/numba/pull/1464) but found that it only works when not specifying the signature. This change makes the test fail in 0.23.1:

``` diff
diff --git a/numba/tests/test_cffi.py b/numba/tests/test_cffi.py
index ca304f9..fa1752d 100644
--- a/numba/tests/test_cffi.py
+++ b/numba/tests/test_cffi.py
@@ -82,7 +82,9 @@ class TestCFFI(TestCase):
         np.testing.assert_equal(pyfunc(x), cfunc(x))

     def test_pass_numpy_array_float32(self):
-        self._test_pass_numpy_array(vector_sin_float32, np.float32)
+        x = np.arange(10).astype(np.float32)
+        cfunc = jit('float32[:](float32[:])', nopython=True)(vector_sin_float32)
+        np.testing.assert_equal(vector_sin_float32(x), cfunc(x))

     def test_pass_numpy_array_float64(self):
         self._test_pass_numpy_array(vector_sin_float64, np.float64)
```

I was not able to try it with latest numba since it requires llvmlite 0.9.0 and it's not available in conda yet.

The workaround for me has been to provide a separate function without signature, but it's a pity because it is preventing me to provide different specializations for CFFI functions (see https://github.com/Pybonacci/cffi_test/).


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `numba/typing/cffi_utils.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 Support for CFFI. Allows checking whether objects are CFFI functions and
4 obtaining the pointer and numba signature.
5 """
6 from __future__ import print_function, division, absolute_import
7 
8 from types import BuiltinFunctionType
9 import ctypes
10 
11 from numba import types
12 from . import templates
13 
14 try:
15     import cffi
16     ffi = cffi.FFI()
17 except ImportError:
18     ffi = None
19 
20 SUPPORTED = ffi is not None
21 _ool_func_types = {}
22 _ool_func_ptr = {}
23 _ffi_instances = set()
24 
25 
26 def is_ffi_instance(obj):
27     # Compiled FFI modules have a member, ffi, which is an instance of
28     # CompiledFFI, which behaves similarly to an instance of cffi.FFI. In
29     # order to simplify handling a CompiledFFI object, we treat them as
30     # if they're cffi.FFI instances for typing and lowering purposes.
31     try:
32         return obj in _ffi_instances or isinstance(obj, cffi.FFI)
33     except TypeError: # Unhashable type possible
34         return False
35 
36 def is_cffi_func(obj):
37     """Check whether the obj is a CFFI function"""
38     try:
39         return ffi.typeof(obj).kind == 'function'
40     except TypeError:
41         try:
42             return obj in _ool_func_types
43         except:
44             return False
45 
46 def get_pointer(cffi_func):
47     """
48     Get a pointer to the underlying function for a CFFI function as an
49     integer.
50     """
51     if cffi_func in _ool_func_ptr:
52         return _ool_func_ptr[cffi_func]
53     return int(ffi.cast("uintptr_t", cffi_func))
54 
55 
56 _cached_type_map = None
57 
58 def _type_map():
59     """
60     Lazily compute type map, as calling ffi.typeof() involves costly
61     parsing of C code...
62     """
63     global _cached_type_map
64     if _cached_type_map is None:
65         _cached_type_map = {
66             ffi.typeof('char') :                types.int8,
67             ffi.typeof('short') :               types.short,
68             ffi.typeof('int') :                 types.intc,
69             ffi.typeof('long') :                types.long_,
70             ffi.typeof('long long') :           types.longlong,
71             ffi.typeof('unsigned char') :       types.uchar,
72             ffi.typeof('unsigned short') :      types.ushort,
73             ffi.typeof('unsigned int') :        types.uintc,
74             ffi.typeof('unsigned long') :       types.ulong,
75             ffi.typeof('unsigned long long') :  types.ulonglong,
76             ffi.typeof('int8_t') :              types.char,
77             ffi.typeof('uint8_t') :             types.uchar,
78             ffi.typeof('int16_t') :             types.short,
79             ffi.typeof('uint16_t') :            types.ushort,
80             ffi.typeof('int32_t') :             types.intc,
81             ffi.typeof('uint32_t') :            types.uintc,
82             ffi.typeof('int64_t') :             types.longlong,
83             ffi.typeof('uint64_t') :            types.ulonglong,
84             ffi.typeof('float') :               types.float_,
85             ffi.typeof('double') :              types.double,
86             ffi.typeof('char *') :              types.voidptr,
87             ffi.typeof('void *') :              types.voidptr,
88             ffi.typeof('uint8_t *') :           types.CPointer(types.uint8),
89             ffi.typeof('float *') :             types.CPointer(types.float32),
90             ffi.typeof('double *') :            types.CPointer(types.float64),
91             ffi.typeof('ssize_t') :             types.intp,
92             ffi.typeof('size_t') :              types.uintp,
93             ffi.typeof('void') :                types.void,
94         }
95     return _cached_type_map
96 
97 
98 def map_type(cffi_type):
99     """
100     Map CFFI type to numba type.
101     """
102     kind = getattr(cffi_type, 'kind', '')
103     if kind in ('struct', 'union'):
104         raise TypeError("No support for struct or union")
105     elif kind == 'function':
106         if cffi_type.ellipsis:
107             raise TypeError("vararg function is not supported")
108         restype = map_type(cffi_type.result)
109         argtypes = [map_type(arg) for arg in cffi_type.args]
110         return templates.signature(restype, *argtypes)
111     else:
112         result = _type_map().get(cffi_type)
113 
114     if result is None:
115         raise TypeError(cffi_type)
116 
117     return result
118 
119 
120 def make_function_type(cffi_func):
121     """
122     Return a Numba type for the given CFFI function pointer.
123     """
124     cffi_type = _ool_func_types.get(cffi_func) or ffi.typeof(cffi_func)
125     sig = map_type(cffi_type)
126     return types.ExternalFunctionPointer(sig, get_pointer=get_pointer)
127 
128 
129 class ExternCFunction(types.ExternalFunction):
130     # XXX unused?
131 
132     def __init__(self, symbol, cstring):
133         """Parse C function declaration/signature"""
134         parser = cffi.cparser.Parser()
135         rft = parser.parse_type(cstring) # "RawFunctionType"
136         type_map = _type_map()
137         self.restype = type_map[rft.result.build_backend_type(ffi, None)]
138         self.argtypes = [type_map[arg.build_backend_type(ffi, None)] for arg in rft.args]
139         signature = templates.signature(self.restype, *self.argtypes)
140         super(ExternCFunction, self).__init__(symbol, signature)
141 
142 
143 registry = templates.Registry()
144 
145 @registry.register
146 class FFI_from_buffer(templates.AbstractTemplate):
147     key = 'ffi.from_buffer'
148 
149     def generic(self, args, kws):
150         if kws or (len(args) != 1):
151             return
152         [ary] = args
153         if not (isinstance(ary, types.Array) and ary.layout in ('C', 'F')):
154             return
155         ptr = types.CPointer(ary.dtype)
156         return templates.signature(ptr, ary)
157 
158 @registry.register_attr
159 class FFIAttribute(templates.AttributeTemplate):
160     key = types.ffi
161 
162     def resolve_from_buffer(self, ffi):
163         return types.BoundFunction(FFI_from_buffer, types.ffi)
164 
165 
166 def register_module(mod):
167     """
168     Add typing for all functions in an out-of-line CFFI module to the typemap
169     """
170     for f in dir(mod.lib):
171         f = getattr(mod.lib, f)
172         if isinstance(f, BuiltinFunctionType):
173             _ool_func_types[f] = mod.ffi.typeof(f)
174             addr = mod.ffi.addressof(mod.lib, f.__name__)
175             _ool_func_ptr[f] = int(mod.ffi.cast("uintptr_t", addr))
176         _ffi_instances.add(mod.ffi)
177
```

Path: `numba/targets/cffiimpl.py`
Content:
```
1 """
2 Implementation of some CFFI functions
3 """
4 
5 from __future__ import print_function, absolute_import, division
6 
7 from numba.targets.imputils import Registry
8 from numba import types
9 from . import arrayobj
10 
11 registry = Registry()
12 
13 @registry.lower('ffi.from_buffer', types.Array)
14 def from_buffer(context, builder, sig, args):
15     assert len(sig.args) == 1
16     assert len(args) == 1
17     [fromty] = sig.args
18     [val] = args
19     # Type inference should have prevented passing a buffer from an
20     # array to a pointer of the wrong type
21     assert fromty.dtype == sig.return_type.dtype
22     ary = arrayobj.make_array(fromty)(context, builder, val)
23     return ary.data
24
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/numba/targets/cffiimpl.py b/numba/targets/cffiimpl.py
--- a/numba/targets/cffiimpl.py
+++ b/numba/targets/cffiimpl.py
@@ -10,7 +10,7 @@
 
 registry = Registry()
 
-@registry.lower('ffi.from_buffer', types.Array)
+@registry.lower('ffi.from_buffer', types.Buffer)
 def from_buffer(context, builder, sig, args):
     assert len(sig.args) == 1
     assert len(args) == 1
diff --git a/numba/typing/cffi_utils.py b/numba/typing/cffi_utils.py
--- a/numba/typing/cffi_utils.py
+++ b/numba/typing/cffi_utils.py
@@ -9,6 +9,7 @@
 import ctypes
 
 from numba import types
+from numba.errors import TypingError
 from . import templates
 
 try:
@@ -63,7 +64,7 @@
     global _cached_type_map
     if _cached_type_map is None:
         _cached_type_map = {
-            ffi.typeof('char') :                types.int8,
+            ffi.typeof('char') :                types.char,
             ffi.typeof('short') :               types.short,
             ffi.typeof('int') :                 types.intc,
             ffi.typeof('long') :                types.long_,
@@ -83,11 +84,6 @@
             ffi.typeof('uint64_t') :            types.ulonglong,
             ffi.typeof('float') :               types.float_,
             ffi.typeof('double') :              types.double,
-            ffi.typeof('char *') :              types.voidptr,
-            ffi.typeof('void *') :              types.voidptr,
-            ffi.typeof('uint8_t *') :           types.CPointer(types.uint8),
-            ffi.typeof('float *') :             types.CPointer(types.float32),
-            ffi.typeof('double *') :            types.CPointer(types.float64),
             ffi.typeof('ssize_t') :             types.intp,
             ffi.typeof('size_t') :              types.uintp,
             ffi.typeof('void') :                types.void,
@@ -101,20 +97,24 @@
     """
     kind = getattr(cffi_type, 'kind', '')
     if kind in ('struct', 'union'):
-        raise TypeError("No support for struct or union")
+        raise TypeError("No support for CFFI %s" % (kind,))
     elif kind == 'function':
         if cffi_type.ellipsis:
             raise TypeError("vararg function is not supported")
         restype = map_type(cffi_type.result)
         argtypes = [map_type(arg) for arg in cffi_type.args]
         return templates.signature(restype, *argtypes)
+    elif kind == 'pointer':
+        pointee = cffi_type.item
+        if pointee.kind == 'void':
+            return types.voidptr
+        else:
+            return types.CPointer(map_type(pointee))
     else:
         result = _type_map().get(cffi_type)
-
-    if result is None:
-        raise TypeError(cffi_type)
-
-    return result
+        if result is None:
+            raise TypeError(cffi_type)
+        return result
 
 
 def make_function_type(cffi_func):
@@ -147,11 +147,15 @@
     key = 'ffi.from_buffer'
 
     def generic(self, args, kws):
-        if kws or (len(args) != 1):
+        if kws or len(args) != 1:
             return
         [ary] = args
-        if not (isinstance(ary, types.Array) and ary.layout in ('C', 'F')):
-            return
+        if not isinstance(ary, types.Buffer):
+            raise TypingError("from_buffer() expected a buffer object, got %s"
+                              % (ary,))
+        if ary.layout not in ('C', 'F'):
+            raise TypingError("from_buffer() unsupported on non-contiguous buffers (got %s)"
+                              % (ary,))
         ptr = types.CPointer(ary.dtype)
         return templates.signature(ptr, ary)

{"golden_diff": "diff --git a/numba/targets/cffiimpl.py b/numba/targets/cffiimpl.py\n--- a/numba/targets/cffiimpl.py\n+++ b/numba/targets/cffiimpl.py\n@@ -10,7 +10,7 @@\n \n registry = Registry()\n \n-@registry.lower('ffi.from_buffer', types.Array)\n+@registry.lower('ffi.from_buffer', types.Buffer)\n def from_buffer(context, builder, sig, args):\n     assert len(sig.args) == 1\n     assert len(args) == 1\ndiff --git a/numba/typing/cffi_utils.py b/numba/typing/cffi_utils.py\n--- a/numba/typing/cffi_utils.py\n+++ b/numba/typing/cffi_utils.py\n@@ -9,6 +9,7 @@\n import ctypes\n \n from numba import types\n+from numba.errors import TypingError\n from . import templates\n \n try:\n@@ -63,7 +64,7 @@\n     global _cached_type_map\n     if _cached_type_map is None:\n         _cached_type_map = {\n-            ffi.typeof('char') :                types.int8,\n+            ffi.typeof('char') :                types.char,\n             ffi.typeof('short') :               types.short,\n             ffi.typeof('int') :                 types.intc,\n             ffi.typeof('long') :                types.long_,\n@@ -83,11 +84,6 @@\n             ffi.typeof('uint64_t') :            types.ulonglong,\n             ffi.typeof('float') :               types.float_,\n             ffi.typeof('double') :              types.double,\n-            ffi.typeof('char *') :              types.voidptr,\n-            ffi.typeof('void *') :              types.voidptr,\n-            ffi.typeof('uint8_t *') :           types.CPointer(types.uint8),\n-            ffi.typeof('float *') :             types.CPointer(types.float32),\n-            ffi.typeof('double *') :            types.CPointer(types.float64),\n             ffi.typeof('ssize_t') :             types.intp,\n             ffi.typeof('size_t') :              types.uintp,\n             ffi.typeof('void') :                types.void,\n@@ -101,20 +97,24 @@\n     \"\"\"\n     kind = getattr(cffi_type, 'kind', '')\n     if kind in ('struct', 'union'):\n-        raise TypeError(\"No support for struct or union\")\n+        raise TypeError(\"No support for CFFI %s\" % (kind,))\n     elif kind == 'function':\n         if cffi_type.ellipsis:\n             raise TypeError(\"vararg function is not supported\")\n         restype = map_type(cffi_type.result)\n         argtypes = [map_type(arg) for arg in cffi_type.args]\n         return templates.signature(restype, *argtypes)\n+    elif kind == 'pointer':\n+        pointee = cffi_type.item\n+        if pointee.kind == 'void':\n+            return types.voidptr\n+        else:\n+            return types.CPointer(map_type(pointee))\n     else:\n         result = _type_map().get(cffi_type)\n-\n-    if result is None:\n-        raise TypeError(cffi_type)\n-\n-    return result\n+        if result is None:\n+            raise TypeError(cffi_type)\n+        return result\n \n \n def make_function_type(cffi_func):\n@@ -147,11 +147,15 @@\n     key = 'ffi.from_buffer'\n \n     def generic(self, args, kws):\n-        if kws or (len(args) != 1):\n+        if kws or len(args) != 1:\n             return\n         [ary] = args\n-        if not (isinstance(ary, types.Array) and ary.layout in ('C', 'F')):\n-            return\n+        if not isinstance(ary, types.Buffer):\n+            raise TypingError(\"from_buffer() expected a buffer object, got %s\"\n+                              % (ary,))\n+        if ary.layout not in ('C', 'F'):\n+            raise TypingError(\"from_buffer() unsupported on non-contiguous buffers (got %s)\"\n+                              % (ary,))\n         ptr = types.CPointer(ary.dtype)\n         return templates.signature(ptr, ary)\n", "issue": "Cannot use cffi.from_buffer when explicitly passing signature to JIT\nI was experimenting with passing arrays to CFFI functions (see https://github.com/numba/numba/pull/1464) but found that it only works when not specifying the signature. This change makes the test fail in 0.23.1:\n\n``` diff\ndiff --git a/numba/tests/test_cffi.py b/numba/tests/test_cffi.py\nindex ca304f9..fa1752d 100644\n--- a/numba/tests/test_cffi.py\n+++ b/numba/tests/test_cffi.py\n@@ -82,7 +82,9 @@ class TestCFFI(TestCase):\n         np.testing.assert_equal(pyfunc(x), cfunc(x))\n\n     def test_pass_numpy_array_float32(self):\n-        self._test_pass_numpy_array(vector_sin_float32, np.float32)\n+        x = np.arange(10).astype(np.float32)\n+        cfunc = jit('float32[:](float32[:])', nopython=True)(vector_sin_float32)\n+        np.testing.assert_equal(vector_sin_float32(x), cfunc(x))\n\n     def test_pass_numpy_array_float64(self):\n         self._test_pass_numpy_array(vector_sin_float64, np.float64)\n```\n\nI was not able to try it with latest numba since it requires llvmlite 0.9.0 and it's not available in conda yet.\n\nThe workaround for me has been to provide a separate function without signature, but it's a pity because it is preventing me to provide different specializations for CFFI functions (see https://github.com/Pybonacci/cffi_test/).\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nSupport for CFFI. Allows checking whether objects are CFFI functions and\nobtaining the pointer and numba signature.\n\"\"\"\nfrom __future__ import print_function, division, absolute_import\n\nfrom types import BuiltinFunctionType\nimport ctypes\n\nfrom numba import types\nfrom . import templates\n\ntry:\n    import cffi\n    ffi = cffi.FFI()\nexcept ImportError:\n    ffi = None\n\nSUPPORTED = ffi is not None\n_ool_func_types = {}\n_ool_func_ptr = {}\n_ffi_instances = set()\n\n\ndef is_ffi_instance(obj):\n    # Compiled FFI modules have a member, ffi, which is an instance of\n    # CompiledFFI, which behaves similarly to an instance of cffi.FFI. In\n    # order to simplify handling a CompiledFFI object, we treat them as\n    # if they're cffi.FFI instances for typing and lowering purposes.\n    try:\n        return obj in _ffi_instances or isinstance(obj, cffi.FFI)\n    except TypeError: # Unhashable type possible\n        return False\n\ndef is_cffi_func(obj):\n    \"\"\"Check whether the obj is a CFFI function\"\"\"\n    try:\n        return ffi.typeof(obj).kind == 'function'\n    except TypeError:\n        try:\n            return obj in _ool_func_types\n        except:\n            return False\n\ndef get_pointer(cffi_func):\n    \"\"\"\n    Get a pointer to the underlying function for a CFFI function as an\n    integer.\n    \"\"\"\n    if cffi_func in _ool_func_ptr:\n        return _ool_func_ptr[cffi_func]\n    return int(ffi.cast(\"uintptr_t\", cffi_func))\n\n\n_cached_type_map = None\n\ndef _type_map():\n    \"\"\"\n    Lazily compute type map, as calling ffi.typeof() involves costly\n    parsing of C code...\n    \"\"\"\n    global _cached_type_map\n    if _cached_type_map is None:\n        _cached_type_map = {\n            ffi.typeof('char') :                types.int8,\n            ffi.typeof('short') :               types.short,\n            ffi.typeof('int') :                 types.intc,\n            ffi.typeof('long') :                types.long_,\n            ffi.typeof('long long') :           types.longlong,\n            ffi.typeof('unsigned char') :       types.uchar,\n            ffi.typeof('unsigned short') :      types.ushort,\n            ffi.typeof('unsigned int') :        types.uintc,\n            ffi.typeof('unsigned long') :       types.ulong,\n            ffi.typeof('unsigned long long') :  types.ulonglong,\n            ffi.typeof('int8_t') :              types.char,\n            ffi.typeof('uint8_t') :             types.uchar,\n            ffi.typeof('int16_t') :             types.short,\n            ffi.typeof('uint16_t') :            types.ushort,\n            ffi.typeof('int32_t') :             types.intc,\n            ffi.typeof('uint32_t') :            types.uintc,\n            ffi.typeof('int64_t') :             types.longlong,\n            ffi.typeof('uint64_t') :            types.ulonglong,\n            ffi.typeof('float') :               types.float_,\n            ffi.typeof('double') :              types.double,\n            ffi.typeof('char *') :              types.voidptr,\n            ffi.typeof('void *') :              types.voidptr,\n            ffi.typeof('uint8_t *') :           types.CPointer(types.uint8),\n            ffi.typeof('float *') :             types.CPointer(types.float32),\n            ffi.typeof('double *') :            types.CPointer(types.float64),\n            ffi.typeof('ssize_t') :             types.intp,\n            ffi.typeof('size_t') :              types.uintp,\n            ffi.typeof('void') :                types.void,\n        }\n    return _cached_type_map\n\n\ndef map_type(cffi_type):\n    \"\"\"\n    Map CFFI type to numba type.\n    \"\"\"\n    kind = getattr(cffi_type, 'kind', '')\n    if kind in ('struct', 'union'):\n        raise TypeError(\"No support for struct or union\")\n    elif kind == 'function':\n        if cffi_type.ellipsis:\n            raise TypeError(\"vararg function is not supported\")\n        restype = map_type(cffi_type.result)\n        argtypes = [map_type(arg) for arg in cffi_type.args]\n        return templates.signature(restype, *argtypes)\n    else:\n        result = _type_map().get(cffi_type)\n\n    if result is None:\n        raise TypeError(cffi_type)\n\n    return result\n\n\ndef make_function_type(cffi_func):\n    \"\"\"\n    Return a Numba type for the given CFFI function pointer.\n    \"\"\"\n    cffi_type = _ool_func_types.get(cffi_func) or ffi.typeof(cffi_func)\n    sig = map_type(cffi_type)\n    return types.ExternalFunctionPointer(sig, get_pointer=get_pointer)\n\n\nclass ExternCFunction(types.ExternalFunction):\n    # XXX unused?\n\n    def __init__(self, symbol, cstring):\n        \"\"\"Parse C function declaration/signature\"\"\"\n        parser = cffi.cparser.Parser()\n        rft = parser.parse_type(cstring) # \"RawFunctionType\"\n        type_map = _type_map()\n        self.restype = type_map[rft.result.build_backend_type(ffi, None)]\n        self.argtypes = [type_map[arg.build_backend_type(ffi, None)] for arg in rft.args]\n        signature = templates.signature(self.restype, *self.argtypes)\n        super(ExternCFunction, self).__init__(symbol, signature)\n\n\nregistry = templates.Registry()\n\n@registry.register\nclass FFI_from_buffer(templates.AbstractTemplate):\n    key = 'ffi.from_buffer'\n\n    def generic(self, args, kws):\n        if kws or (len(args) != 1):\n            return\n        [ary] = args\n        if not (isinstance(ary, types.Array) and ary.layout in ('C', 'F')):\n            return\n        ptr = types.CPointer(ary.dtype)\n        return templates.signature(ptr, ary)\n\n@registry.register_attr\nclass FFIAttribute(templates.AttributeTemplate):\n    key = types.ffi\n\n    def resolve_from_buffer(self, ffi):\n        return types.BoundFunction(FFI_from_buffer, types.ffi)\n\n\ndef register_module(mod):\n    \"\"\"\n    Add typing for all functions in an out-of-line CFFI module to the typemap\n    \"\"\"\n    for f in dir(mod.lib):\n        f = getattr(mod.lib, f)\n        if isinstance(f, BuiltinFunctionType):\n            _ool_func_types[f] = mod.ffi.typeof(f)\n            addr = mod.ffi.addressof(mod.lib, f.__name__)\n            _ool_func_ptr[f] = int(mod.ffi.cast(\"uintptr_t\", addr))\n        _ffi_instances.add(mod.ffi)\n", "path": "numba/typing/cffi_utils.py"}, {"content": "\"\"\"\nImplementation of some CFFI functions\n\"\"\"\n\nfrom __future__ import print_function, absolute_import, division\n\nfrom numba.targets.imputils import Registry\nfrom numba import types\nfrom . import arrayobj\n\nregistry = Registry()\n\n@registry.lower('ffi.from_buffer', types.Array)\ndef from_buffer(context, builder, sig, args):\n    assert len(sig.args) == 1\n    assert len(args) == 1\n    [fromty] = sig.args\n    [val] = args\n    # Type inference should have prevented passing a buffer from an\n    # array to a pointer of the wrong type\n    assert fromty.dtype == sig.return_type.dtype\n    ary = arrayobj.make_array(fromty)(context, builder, val)\n    return ary.data\n", "path": "numba/targets/cffiimpl.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nSupport for CFFI. Allows checking whether objects are CFFI functions and\nobtaining the pointer and numba signature.\n\"\"\"\nfrom __future__ import print_function, division, absolute_import\n\nfrom types import BuiltinFunctionType\nimport ctypes\n\nfrom numba import types\nfrom numba.errors import TypingError\nfrom . import templates\n\ntry:\n    import cffi\n    ffi = cffi.FFI()\nexcept ImportError:\n    ffi = None\n\nSUPPORTED = ffi is not None\n_ool_func_types = {}\n_ool_func_ptr = {}\n_ffi_instances = set()\n\n\ndef is_ffi_instance(obj):\n    # Compiled FFI modules have a member, ffi, which is an instance of\n    # CompiledFFI, which behaves similarly to an instance of cffi.FFI. In\n    # order to simplify handling a CompiledFFI object, we treat them as\n    # if they're cffi.FFI instances for typing and lowering purposes.\n    try:\n        return obj in _ffi_instances or isinstance(obj, cffi.FFI)\n    except TypeError: # Unhashable type possible\n        return False\n\ndef is_cffi_func(obj):\n    \"\"\"Check whether the obj is a CFFI function\"\"\"\n    try:\n        return ffi.typeof(obj).kind == 'function'\n    except TypeError:\n        try:\n            return obj in _ool_func_types\n        except:\n            return False\n\ndef get_pointer(cffi_func):\n    \"\"\"\n    Get a pointer to the underlying function for a CFFI function as an\n    integer.\n    \"\"\"\n    if cffi_func in _ool_func_ptr:\n        return _ool_func_ptr[cffi_func]\n    return int(ffi.cast(\"uintptr_t\", cffi_func))\n\n\n_cached_type_map = None\n\ndef _type_map():\n    \"\"\"\n    Lazily compute type map, as calling ffi.typeof() involves costly\n    parsing of C code...\n    \"\"\"\n    global _cached_type_map\n    if _cached_type_map is None:\n        _cached_type_map = {\n            ffi.typeof('char') :                types.char,\n            ffi.typeof('short') :               types.short,\n            ffi.typeof('int') :                 types.intc,\n            ffi.typeof('long') :                types.long_,\n            ffi.typeof('long long') :           types.longlong,\n            ffi.typeof('unsigned char') :       types.uchar,\n            ffi.typeof('unsigned short') :      types.ushort,\n            ffi.typeof('unsigned int') :        types.uintc,\n            ffi.typeof('unsigned long') :       types.ulong,\n            ffi.typeof('unsigned long long') :  types.ulonglong,\n            ffi.typeof('int8_t') :              types.char,\n            ffi.typeof('uint8_t') :             types.uchar,\n            ffi.typeof('int16_t') :             types.short,\n            ffi.typeof('uint16_t') :            types.ushort,\n            ffi.typeof('int32_t') :             types.intc,\n            ffi.typeof('uint32_t') :            types.uintc,\n            ffi.typeof('int64_t') :             types.longlong,\n            ffi.typeof('uint64_t') :            types.ulonglong,\n            ffi.typeof('float') :               types.float_,\n            ffi.typeof('double') :              types.double,\n            ffi.typeof('ssize_t') :             types.intp,\n            ffi.typeof('size_t') :              types.uintp,\n            ffi.typeof('void') :                types.void,\n        }\n    return _cached_type_map\n\n\ndef map_type(cffi_type):\n    \"\"\"\n    Map CFFI type to numba type.\n    \"\"\"\n    kind = getattr(cffi_type, 'kind', '')\n    if kind in ('struct', 'union'):\n        raise TypeError(\"No support for CFFI %s\" % (kind,))\n    elif kind == 'function':\n        if cffi_type.ellipsis:\n            raise TypeError(\"vararg function is not supported\")\n        restype = map_type(cffi_type.result)\n        argtypes = [map_type(arg) for arg in cffi_type.args]\n        return templates.signature(restype, *argtypes)\n    elif kind == 'pointer':\n        pointee = cffi_type.item\n        if pointee.kind == 'void':\n            return types.voidptr\n        else:\n            return types.CPointer(map_type(pointee))\n    else:\n        result = _type_map().get(cffi_type)\n        if result is None:\n            raise TypeError(cffi_type)\n        return result\n\n\ndef make_function_type(cffi_func):\n    \"\"\"\n    Return a Numba type for the given CFFI function pointer.\n    \"\"\"\n    cffi_type = _ool_func_types.get(cffi_func) or ffi.typeof(cffi_func)\n    sig = map_type(cffi_type)\n    return types.ExternalFunctionPointer(sig, get_pointer=get_pointer)\n\n\nclass ExternCFunction(types.ExternalFunction):\n    # XXX unused?\n\n    def __init__(self, symbol, cstring):\n        \"\"\"Parse C function declaration/signature\"\"\"\n        parser = cffi.cparser.Parser()\n        rft = parser.parse_type(cstring) # \"RawFunctionType\"\n        type_map = _type_map()\n        self.restype = type_map[rft.result.build_backend_type(ffi, None)]\n        self.argtypes = [type_map[arg.build_backend_type(ffi, None)] for arg in rft.args]\n        signature = templates.signature(self.restype, *self.argtypes)\n        super(ExternCFunction, self).__init__(symbol, signature)\n\n\nregistry = templates.Registry()\n\n@registry.register\nclass FFI_from_buffer(templates.AbstractTemplate):\n    key = 'ffi.from_buffer'\n\n    def generic(self, args, kws):\n        if kws or len(args) != 1:\n            return\n        [ary] = args\n        if not isinstance(ary, types.Buffer):\n            raise TypingError(\"from_buffer() expected a buffer object, got %s\"\n                              % (ary,))\n        if ary.layout not in ('C', 'F'):\n            raise TypingError(\"from_buffer() unsupported on non-contiguous buffers (got %s)\"\n                              % (ary,))\n        ptr = types.CPointer(ary.dtype)\n        return templates.signature(ptr, ary)\n\n@registry.register_attr\nclass FFIAttribute(templates.AttributeTemplate):\n    key = types.ffi\n\n    def resolve_from_buffer(self, ffi):\n        return types.BoundFunction(FFI_from_buffer, types.ffi)\n\n\ndef register_module(mod):\n    \"\"\"\n    Add typing for all functions in an out-of-line CFFI module to the typemap\n    \"\"\"\n    for f in dir(mod.lib):\n        f = getattr(mod.lib, f)\n        if isinstance(f, BuiltinFunctionType):\n            _ool_func_types[f] = mod.ffi.typeof(f)\n            addr = mod.ffi.addressof(mod.lib, f.__name__)\n            _ool_func_ptr[f] = int(mod.ffi.cast(\"uintptr_t\", addr))\n        _ffi_instances.add(mod.ffi)\n", "path": "numba/typing/cffi_utils.py"}, {"content": "\"\"\"\nImplementation of some CFFI functions\n\"\"\"\n\nfrom __future__ import print_function, absolute_import, division\n\nfrom numba.targets.imputils import Registry\nfrom numba import types\nfrom . import arrayobj\n\nregistry = Registry()\n\n@registry.lower('ffi.from_buffer', types.Buffer)\ndef from_buffer(context, builder, sig, args):\n    assert len(sig.args) == 1\n    assert len(args) == 1\n    [fromty] = sig.args\n    [val] = args\n    # Type inference should have prevented passing a buffer from an\n    # array to a pointer of the wrong type\n    assert fromty.dtype == sig.return_type.dtype\n    ary = arrayobj.make_array(fromty)(context, builder, val)\n    return ary.data\n", "path": "numba/targets/cffiimpl.py"}]}