From f7e77cdc290825c173e4eac5c95e17ed19a0fc06 Mon Sep 17 00:00:00 2001
From: gsamain <gwenael.samain@nexedi.com>
Date: Mon, 8 Jul 2019 11:24:34 +0000
Subject: [PATCH] Make declaration of cypclass methods work when declaring
 without defining a pointer type as return type

---
 Cython/Compiler/Nodes.py | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index d6a1ba5ef..9df1fb331 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -1391,28 +1391,35 @@ class CVarDefNode(StatNode):
                 return
             if type.is_reference and self.visibility != 'extern':
                 error(declarator.pos, "C++ references cannot be declared; use a pointer instead")
+            cfunc_declarator = declarator
             if type.is_cfunction:
+                while not isinstance(cfunc_declarator, (CFuncDeclaratorNode, CNameDeclaratorNode)):
+                    cfunc_declarator = cfunc_declarator.base
+                if isinstance(cfunc_declarator, CNameDeclaratorNode):
+                    # It's probably a typedef'ed attribute, in which case the self
+                    # handling has already been done, so skip all self hacks.
+                    cfunc_declarator = None
                 if 'staticmethod' in env.directives:
                     type.is_static_method = True
-                elif name in ("__new__", "__alloc__") and\
+                elif cfunc_declarator and name in ("__new__", "__alloc__") and\
                      env.is_cpp_class_scope and env.parent_type.is_cyp_class:
                     type.is_static_method = True
 
-                    if declarator.skipped_self:
-                        _name, _type, _pos, _arg = declarator.skipped_self
+                    if cfunc_declarator.skipped_self:
+                        _name, _type, _pos, _arg = cfunc_declarator.skipped_self
                         if name == "__new__":
                             _type = PyrexTypes.CPtrType(PyrexTypes.CFuncType(_type, [], nogil=1))
                             # aka _type = {class_type} (*f)() nogil
                             reinjected_arg = PyrexTypes.CFuncTypeArg(_name, _type, _pos)
                             type.args = [reinjected_arg] + type.args
-                            declarator.args = [_arg] + declarator.args
+                            cfunc_declarator.args = [_arg] + cfunc_declarator.args
                         elif name == "__alloc__":
                             # Force __alloc__ to have the signature:
                             # {class_type} f() nogil
                             type.return_type = _type
                             type.args = []
-                            declarator.args = []
-                        declarator.skipped_self = None
+                            cfunc_declarator.args = []
+                        cfunc_declarator.skipped_self = None
 
                 self.entry = dest_scope.declare_cfunction(
                     name, type, declarator.pos,
@@ -1423,8 +1430,8 @@ class CVarDefNode(StatNode):
                 if create_extern_wrapper:
                     self.entry.type.create_to_py_utility_code(env)
                     self.entry.create_wrapper = True
-                if env.is_cpp_class_scope and env.parent_type.is_cyp_class\
-                   and not declarator.skipped_self and not type.is_static_method:
+                if cfunc_declarator and type.is_cfunction and env.is_cpp_class_scope and env.parent_type.is_cyp_class\
+                   and not cfunc_declarator.skipped_self and not type.is_static_method:
                     # It means we have a cypclass method without the self argument
                     # => shout
                     error(self.pos, "Cypclass methods must have a self argument")
-- 
2.30.9