summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatus Valo <matusvalo@users.noreply.github.com>2023-05-03 09:59:43 +0200
committerGitHub <noreply@github.com>2023-05-03 09:59:43 +0200
commitdee8906fe77cb27ce35b835f1b2dc0093ad92cb3 (patch)
tree2d11018cd95d54e996f2103f606a856e525982d6
parentdf0df659747cf8d1b716c04ae9eef83f27d7bfe9 (diff)
downloadcython-dee8906fe77cb27ce35b835f1b2dc0093ad92cb3.tar.gz
Keep 'extern' visibility in context of struct/union to properly infer 'noexcept' for function pointer fields (GH-5386)
-rw-r--r--Cython/Compiler/Nodes.py2
-rw-r--r--Cython/Compiler/Parsing.py2
-rw-r--r--Cython/Compiler/Symtab.py8
-rw-r--r--tests/errors/cfuncptr.pyx24
-rw-r--r--tests/run/extern_impl_excvalue.srctree20
5 files changed, 48 insertions, 8 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 877e7b928..8667e5c74 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -1557,7 +1557,7 @@ class CStructOrUnionDefNode(StatNode):
def analyse_declarations(self, env):
scope = None
if self.attributes is not None:
- scope = StructOrUnionScope(self.name)
+ scope = StructOrUnionScope(self.name, self.visibility)
self.declare(env, scope)
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py
index a796c865a..d7394ca6f 100644
--- a/Cython/Compiler/Parsing.py
+++ b/Cython/Compiler/Parsing.py
@@ -3394,7 +3394,7 @@ def p_c_struct_or_union_definition(s, pos, ctx):
else:
s.expect('NEWLINE')
s.expect_indent()
- body_ctx = Ctx()
+ body_ctx = Ctx(visibility=ctx.visibility)
while s.sy != 'DEDENT':
if s.sy != 'pass':
attributes.append(
diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py
index c92117d8e..5ca22ca86 100644
--- a/Cython/Compiler/Symtab.py
+++ b/Cython/Compiler/Symtab.py
@@ -2094,9 +2094,11 @@ class GeneratorExpressionScope(ClosureScope):
class StructOrUnionScope(Scope):
# Namespace of a C struct or union.
+ # visibility string Visibility of a C struct or union
- def __init__(self, name="?"):
+ def __init__(self, name="?", visibility='private'):
Scope.__init__(self, name, None, None)
+ self.visibility = visibility
def declare_var(self, name, type, pos,
cname=None, visibility='private',
@@ -2123,8 +2125,8 @@ class StructOrUnionScope(Scope):
elif type.needs_refcounting:
if not allow_refcounted:
error(pos, "C struct/union member cannot be reference-counted type '%s'" % type)
- if visibility != 'private':
- error(pos, "C struct/union member cannot be declared %s" % visibility)
+ if visibility != self.visibility:
+ error(pos, "C struct/union visibility %s does not match the member visibility %s" % (self.visibility, visibility))
return entry
def declare_cfunction(self, name, type, pos,
diff --git a/tests/errors/cfuncptr.pyx b/tests/errors/cfuncptr.pyx
index f07ef2167..9b5f12644 100644
--- a/tests/errors/cfuncptr.pyx
+++ b/tests/errors/cfuncptr.pyx
@@ -18,6 +18,10 @@ cdef extern from *:
# define this as extern since Cython converts internal "except*" to "except -1"
cdef int exceptstar(int bad) except *
+ struct mystruct:
+ int (*func_ptr)(int param) nogil
+ void (*func_ptr_void)(int param) nogil
+
def fail_exceptstar(bad):
cdef int (*fptr_a)(int) noexcept
cdef int (*fptr_b)(int) except -1
@@ -26,11 +30,25 @@ def fail_exceptstar(bad):
fptr_b = exceptstar
fptr_c = exceptstar
+cdef int cb(int param) nogil:
+ return param
+
+cdef void cb_void(int param) except * nogil:
+ return
+
+def fail_struct_pointer():
+ cdef mystruct ms = mystruct(&cb, &cb_void)
+
+
_ERRORS = """
13:13: Cannot assign type 'int (int) except? -2' to 'int (*)(int) except -2'
14:13: Cannot assign type 'int (int) except? -2' to 'int (*)(int) except -1'
15:13: Cannot assign type 'int (int) except? -2' to 'int (*)(int) except? -1'
-25:13: Cannot assign type 'int (int) except *' to 'int (*)(int) noexcept'
-26:13: Cannot assign type 'int (int) except *' to 'int (*)(int) except -1'
-27:13: Cannot assign type 'int (int) except *' to 'int (*)(int) except? -1'
+29:13: Cannot assign type 'int (int) except *' to 'int (*)(int) noexcept'
+30:13: Cannot assign type 'int (int) except *' to 'int (*)(int) except -1'
+31:13: Cannot assign type 'int (int) except *' to 'int (*)(int) except? -1'
+40:32: Cannot assign type 'int (*)(int) except? -1 nogil' to 'int (*)(int) noexcept nogil'
+40:32: Cannot assign type 'int (*)(int) except? -1 nogil' to 'int (*)(int) noexcept nogil'
+40:37: Cannot assign type 'void (*)(int) except * nogil' to 'void (*)(int) noexcept nogil'
+40:37: Cannot assign type 'void (*)(int) except * nogil' to 'void (*)(int) noexcept nogil'
"""
diff --git a/tests/run/extern_impl_excvalue.srctree b/tests/run/extern_impl_excvalue.srctree
index 190c81a6d..2495d740c 100644
--- a/tests/run/extern_impl_excvalue.srctree
+++ b/tests/run/extern_impl_excvalue.srctree
@@ -1,6 +1,7 @@
PYTHON setup.py build_ext --inplace
PYTHON -c "import foo"
PYTHON -c "import a"
+PYTHON -c "import b"
######## setup.py ########
@@ -15,6 +16,10 @@ setup(
cdef int bar() except *
+cdef extern from "bar_impl.c":
+ struct mystruct:
+ int (*func_ptr)(int param) nogil
+
######## foo.pyx ########
cdef extern from "bar_impl.c":
@@ -24,9 +29,24 @@ cdef extern from "bar_impl.c":
static int bar() { return -1; }
+typedef struct mystruct {
+ int (*func_ptr)(int param);
+} mystruct_t;
+
######## a.pyx ########
cimport cython
from foo cimport bar
assert bar() == -1
+
+
+######## b.pyx ########
+
+from foo cimport mystruct
+
+cdef int cb(int param) noexcept nogil:
+ return param
+
+cdef mystruct ms = mystruct(&cb)
+assert ms.func_ptr(5) == 5