Commit 52c17db1 authored by Stefan Behnel's avatar Stefan Behnel

Allow assignment of C function pointers with compatible exception declarations...

Allow assignment of C function pointers with compatible exception declarations (not only exact matches).
parent 75a42b52
...@@ -916,6 +916,7 @@ class ExprNode(Node): ...@@ -916,6 +916,7 @@ class ExprNode(Node):
# in different pxi files. # in different pxi files.
# TODO: Remove this hack and require shared declarations. # TODO: Remove this hack and require shared declarations.
if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)): if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
print(src_type, dst_type)
self.fail_assignment(dst_type) self.fail_assignment(dst_type)
return src return src
......
...@@ -2627,7 +2627,11 @@ class CFuncType(CType): ...@@ -2627,7 +2627,11 @@ class CFuncType(CType):
return self.same_c_signature_as_resolved_type( return self.same_c_signature_as_resolved_type(
other_type.resolve(), as_cmethod) other_type.resolve(), as_cmethod)
def same_c_signature_as_resolved_type(self, other_type, as_cmethod = 0, as_pxd_definition = 0): def same_c_signature_as_resolved_type(self, other_type, as_cmethod=False, as_pxd_definition=False,
exact_semantics=True):
# If 'exact_semantics' is false, allow any C compatible signatures
# if the Cython semantics are compatible.
#print "CFuncType.same_c_signature_as_resolved_type:", \ #print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ### # self, other_type, "as_cmethod =", as_cmethod ###
if other_type is error_type: if other_type is error_type:
...@@ -2656,12 +2660,15 @@ class CFuncType(CType): ...@@ -2656,12 +2660,15 @@ class CFuncType(CType):
else: else:
if not self.return_type.same_as(other_type.return_type): if not self.return_type.same_as(other_type.return_type):
return 0 return 0
if exact_semantics:
if not self.same_calling_convention_as(other_type): if not self.same_calling_convention_as(other_type):
return 0 return 0
if self.exception_check != other_type.exception_check: if self.exception_check != other_type.exception_check:
return 0 return 0
if not self._same_exception_value(other_type.exception_value): if not self._same_exception_value(other_type.exception_value):
return 0 return 0
else:
return self.compatible_signature_with_resolved_type(other_type, as_cmethod=as_cmethod)
return 1 return 1
def _same_exception_value(self, other_exc_value): def _same_exception_value(self, other_exc_value):
...@@ -2770,13 +2777,14 @@ class CFuncType(CType): ...@@ -2770,13 +2777,14 @@ class CFuncType(CType):
sc2 = other.calling_convention == '__stdcall' sc2 = other.calling_convention == '__stdcall'
return sc1 == sc2 return sc1 == sc2
def same_as_resolved_type(self, other_type, as_cmethod = 0): def same_as_resolved_type(self, other_type, as_cmethod=False):
return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \ return self.same_c_signature_as_resolved_type(other_type, as_cmethod=as_cmethod) \
and self.nogil == other_type.nogil and self.nogil == other_type.nogil
def pointer_assignable_from_resolved_type(self, other_type): def pointer_assignable_from_resolved_type(self, rhs_type):
return self.same_c_signature_as_resolved_type(other_type) \ # Accept compatible exception declarations for the RHS.
and not (self.nogil and not other_type.nogil) return rhs_type.same_c_signature_as_resolved_type(self, exact_semantics=False) \
and not (self.nogil and not rhs_type.nogil)
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0, for_display = 0, dll_linkage = None, pyrex = 0,
......
PYTHON setup.py build_ext --inplace PYTHON setup.py build_ext --inplace
PYTHON -c "import foo" PYTHON -c "import foo"
PYTHON -c "import a" PYTHON -c "import a; a.test()"
######## setup.py ######## ######## setup.py ########
...@@ -15,6 +15,9 @@ setup( ...@@ -15,6 +15,9 @@ setup(
cdef int bar(int i) except * cdef int bar(int i) except *
cdef int (*var_opt)(int) except? -1
cdef int (*var_orig)(int) except *
######## foo.pyx ######## ######## foo.pyx ########
cdef int bar(int i) except *: cdef int bar(int i) except *:
...@@ -22,10 +25,13 @@ cdef int bar(int i) except *: ...@@ -22,10 +25,13 @@ cdef int bar(int i) except *:
raise ValueError() raise ValueError()
return i + 1 return i + 1
var_opt = bar # by 'accident' of optimisation
var_orig = bar # by declaration
######## a.pyx ######## ######## a.pyx ########
cimport cython cimport cython
from foo cimport bar from foo cimport bar, var_orig, var_opt
def test(): def test():
assert bar(-2) == -1 assert bar(-2) == -1
...@@ -34,4 +40,20 @@ def test(): ...@@ -34,4 +40,20 @@ def test():
except ValueError: except ValueError:
pass pass
else: else:
assert False, "exception not raised" assert False, "exception not raised in bar()"
assert var_orig(-2) == -1
try:
var_orig(10)
except ValueError:
pass
else:
assert False, "exception not raised in var_orig()"
assert var_opt(-2) == -1
try:
var_opt(10)
except ValueError:
pass
else:
assert False, "exception not raised in var_opt()"
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