Skip to content

Commit

Permalink
Keep 'extern' visibility in context of struct/union to properly infer…
Browse files Browse the repository at this point in the history
… 'noexcept' for function pointer fields (GH-5386)
  • Loading branch information
matusvalo committed May 3, 2023
1 parent df0df65 commit dee8906
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Cython/Compiler/Nodes.py
Expand Up @@ -1557,7 +1557,7 @@ def declare(self, env, scope=None):
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:
Expand Down
2 changes: 1 addition & 1 deletion Cython/Compiler/Parsing.py
Expand Up @@ -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(
Expand Down
8 changes: 5 additions & 3 deletions Cython/Compiler/Symtab.py
Expand Up @@ -2094,9 +2094,11 @@ def lookup_assignment_expression_target(self, name):

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',
Expand All @@ -2123,8 +2125,8 @@ def declare_var(self, name, type, pos,
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,
Expand Down
24 changes: 21 additions & 3 deletions tests/errors/cfuncptr.pyx
Expand Up @@ -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
Expand All @@ -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'
"""
20 changes: 20 additions & 0 deletions 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 ########

Expand All @@ -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":
Expand All @@ -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

0 comments on commit dee8906

Please sign in to comment.