diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 877e7b92884..8667e5c7470 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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: diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index a796c865abf..d7394ca6fbb 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 c92117d8ec8..5ca22ca8665 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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', @@ -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, diff --git a/tests/errors/cfuncptr.pyx b/tests/errors/cfuncptr.pyx index f07ef216721..9b5f1264481 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 190c81a6dbd..2495d740c27 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