diff options
-rw-r--r-- | .travis.yml | 15 | ||||
-rw-r--r-- | Cython/Compiler/Code.py | 32 | ||||
-rw-r--r-- | Cython/Compiler/ModuleNode.py | 39 | ||||
-rw-r--r-- | Cython/Compiler/Naming.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/Nodes.py | 327 | ||||
-rw-r--r-- | Cython/Compiler/TypeSlots.py | 102 | ||||
-rw-r--r-- | Cython/Utility/AsyncGen.c | 130 | ||||
-rw-r--r-- | Cython/Utility/CommonStructures.c | 30 | ||||
-rw-r--r-- | Cython/Utility/Coroutine.c | 166 | ||||
-rw-r--r-- | Cython/Utility/CythonFunction.c | 198 | ||||
-rw-r--r-- | Cython/Utility/ExtensionTypes.c | 196 | ||||
-rw-r--r-- | Cython/Utility/ImportExport.c | 14 | ||||
-rw-r--r-- | Cython/Utility/ModuleSetupCode.c | 88 | ||||
-rw-r--r-- | Cython/Utility/ObjectHandling.c | 1 | ||||
-rw-r--r-- | appveyor.yml | 18 | ||||
-rw-r--r-- | tests/compile/types_and_names.pyx | 13 | ||||
-rw-r--r-- | tests/limited_api_bugs.txt | 3 | ||||
-rw-r--r-- | tests/run/cdef_multiple_inheritance_errors.srctree | 10 |
18 files changed, 1026 insertions, 358 deletions
diff --git a/.travis.yml b/.travis.yml index bb3aa5a94..81a6120c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ env: - CCACHE_MAXSIZE=250M - PATH="/usr/lib/ccache:$HOME/miniconda/bin:$PATH" - BACKEND=c,cpp + - EXTRA_CFLAGS= matrix: - BACKEND=c - BACKEND=cpp @@ -60,6 +61,18 @@ matrix: # env: COVERAGE=1 - python: 3.7 env: TEST_CODE_STYLE=1 + - python: 3.9-dev + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c + - python: 3.8 + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c + - python: 3.7 + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c + - python: 3.6 + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c + - python: 3.5 + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c + - python: 3.4 + env: EXTRA_CFLAGS="-DCYTHON_USE_TYPE_SPECS=1" BACKEND=c - python: 3.8 env: LIMITED_API=--limited-api EXCLUDE=--no-file - python: 3.7 @@ -158,5 +171,5 @@ script: # Need to clear the ccache? Try something like this: # - if [ -n "${BACKEND##*cpp*}" -a -z "${TRAVIS_PYTHON_VERSION##*3.4}" ]; then ccache -C || true; fi - if [ "$COVERAGE" != "1" ]; then CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build_ext -i $(python -c 'import sys; print("-j5" if sys.version_info >= (3,5) else "")'); fi - - CFLAGS="-O0 -ggdb -Wall -Wextra" python runtests.py -vv $STYLE_ARGS -x Debugger --backends=$BACKEND $LIMITED_API $EXCLUDE $(if [ "$COVERAGE" == "1" ]; then echo " --coverage"; fi) $(if [ -z "$TEST_CODE_STYLE" ]; then echo " -j7 "; fi) + - CFLAGS="-O0 -ggdb -Wall -Wextra $EXTRA_CFLAGS" python runtests.py -vv $STYLE_ARGS -x Debugger --backends=$BACKEND $LIMITED_API $EXCLUDE $(if [ "$COVERAGE" == "1" ]; then echo " --coverage"; fi) $(if [ -z "$TEST_CODE_STYLE" ]; then echo " -j7 "; fi) - ccache -s || true diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index c7ee4d82d..9968a6336 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -1476,7 +1476,7 @@ class GlobalState(object): for c in self.py_constants] consts.sort() decls_writer = self.parts['decls'] - decls_writer.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + decls_writer.putln("#if !CYTHON_USE_MODULE_STATE") for _, cname, c in consts: self.parts['module_state'].putln("%s;" % c.type.declaration_code(cname)) self.parts['module_state_defines'].putln( @@ -1551,16 +1551,16 @@ class GlobalState(object): w = self.parts['pystring_table'] w.putln("") w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname) - w.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - w_limited_writer = w.insertion_point() + w.putln("#if CYTHON_USE_MODULE_STATE") + w_in_module_state = w.insertion_point() w.putln("#else") - w_not_limited_writer = w.insertion_point() + w_not_in_module_state = w.insertion_point() w.putln("#endif") - decls_writer.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + decls_writer.putln("#if !CYTHON_USE_MODULE_STATE") not_limited_api_decls_writer = decls_writer.insertion_point() decls_writer.putln("#endif") - init_globals.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - init_globals_limited_api = init_globals.insertion_point() + init_globals.putln("#if CYTHON_USE_MODULE_STATE") + init_globals_in_module_state = init_globals.insertion_point() init_globals.putln("#endif") for idx, py_string_args in enumerate(py_strings): c_cname, _, py_string = py_string_args @@ -1583,16 +1583,16 @@ class GlobalState(object): not_limited_api_decls_writer.putln( "static PyObject *%s;" % py_string.cname) if py_string.py3str_cstring: - w_not_limited_writer.putln("#if PY_MAJOR_VERSION >= 3") - w_not_limited_writer.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( + w_not_in_module_state.putln("#if PY_MAJOR_VERSION >= 3") + w_not_in_module_state.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, py_string.py3str_cstring.cname, py_string.py3str_cstring.cname, '0', 1, 0, py_string.intern )) - w_not_limited_writer.putln("#else") - w_not_limited_writer.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( + w_not_in_module_state.putln("#else") + w_not_in_module_state.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, c_cname, c_cname, @@ -1602,8 +1602,8 @@ class GlobalState(object): py_string.intern )) if py_string.py3str_cstring: - w_not_limited_writer.putln("#endif") - w_limited_writer.putln("{0, %s, sizeof(%s), %s, %d, %d, %d}," % ( + w_not_in_module_state.putln("#endif") + w_in_module_state.putln("{0, %s, sizeof(%s), %s, %d, %d, %d}," % ( c_cname if not py_string.py3str_cstring else py_string.py3str_cstring.cname, c_cname if not py_string.py3str_cstring else py_string.py3str_cstring.cname, encoding if not py_string.py3str_cstring else '0', @@ -1611,7 +1611,7 @@ class GlobalState(object): py_string.is_str, py_string.intern )) - init_globals_limited_api.putln("if (__Pyx_InitString(%s[%d], &%s) < 0) %s;" % ( + init_globals_in_module_state.putln("if (__Pyx_InitString(%s[%d], &%s) < 0) %s;" % ( Naming.stringtab_cname, idx, py_string.cname, @@ -1619,7 +1619,7 @@ class GlobalState(object): w.putln("{0, 0, 0, 0, 0, 0, 0}") w.putln("};") - init_globals.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + init_globals.putln("#if !CYTHON_USE_MODULE_STATE") init_globals.putln( "if (__Pyx_InitStrings(%s) < 0) %s;" % ( Naming.stringtab_cname, @@ -1631,7 +1631,7 @@ class GlobalState(object): for c in self.num_const_index.values()] consts.sort() decls_writer = self.parts['decls'] - decls_writer.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + decls_writer.putln("#if !CYTHON_USE_MODULE_STATE") init_globals = self.parts['init_globals'] for py_type, _, _, value, value_code, c in consts: cname = c.cname diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 77a92368c..41c959796 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -804,7 +804,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.put(Nodes.branch_prediction_macros) code.putln('static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; }') code.putln('') - code.putln('#if !CYTHON_COMPILING_IN_LIMITED_API') + code.putln('#if !CYTHON_USE_MODULE_STATE') code.putln('static PyObject *%s = NULL;' % env.module_cname) code.putln('static PyObject *%s;' % env.module_dict_cname) code.putln('static PyObject *%s;' % Naming.builtins_cname) @@ -1239,7 +1239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): module_state_defines = globalstate['module_state_defines'] module_state_clear = globalstate['module_state_clear'] module_state_traverse = globalstate['module_state_traverse'] - code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if !CYTHON_USE_MODULE_STATE") for entry in env.c_class_entries: if definition or entry.defined_in_pxd: code.putln("static PyTypeObject *%s = 0;" % ( @@ -1376,7 +1376,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_property_accessors(scope, code) self.generate_method_table(scope, code) self.generate_getset_table(scope, code) - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_TYPE_SPECS") self.generate_typeobj_spec(entry, code) code.putln("#else") self.generate_typeobj_definition(full_module_name, entry, code) @@ -1566,11 +1566,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): slot_func_cname = scope.mangle_internal("tp_dealloc") code.putln("") - cdealloc_func_entry = scope.lookup_here("__dealloc__") - if cdealloc_func_entry and not cdealloc_func_entry.is_special: - cdealloc_func_entry = None - if cdealloc_func_entry is None: - code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") code.putln( "static void %s(PyObject *o) {" % slot_func_cname) @@ -1700,8 +1695,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln( "}") - if cdealloc_func_entry is None: - code.putln("#endif") def generate_usr_dealloc_call(self, scope, code): entry = scope.lookup_here("__dealloc__") @@ -2376,6 +2369,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_typeobj_spec(self, entry, code): ext_type = entry.type scope = ext_type.scope + + members_slot = TypeSlots.get_slot_by_name("tp_members") + members_slot.generate_substructure_spec(scope, code) + + buffer_slot = TypeSlots.get_slot_by_name("tp_as_buffer") + if not buffer_slot.is_empty(scope): + code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + buffer_slot.generate_substructure(scope, code) + code.putln("#endif") + code.putln("static PyType_Slot %s_slots[] = {" % ext_type.typeobj_cname) for slot in TypeSlots.slot_table: slot.generate_spec(scope, code) @@ -2567,8 +2570,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.exit_cfunc_scope() # done with labels def generate_module_state_start(self, env, code): - # TODO: Reactor LIMITED_API struct decl closer to the static decl - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + # TODO: Refactor to move module state struct decl closer to the static decl + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln('typedef struct {') code.putln('PyObject *%s;' % env.module_dict_cname) code.putln('PyObject *%s;' % Naming.builtins_cname) @@ -2622,7 +2625,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): module_state_traverse.putln("#endif") def generate_module_state_defines(self, env, code): - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln('#define %s %s->%s' % ( env.module_dict_cname, Naming.modulestateglobal_cname, @@ -2666,7 +2669,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln('#endif') def generate_module_state_clear(self, env, code): - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln("static int %s_clear(PyObject *m) {" % Naming.module_cname) code.putln("%s *clear_module_state = %s(m);" % ( Naming.modulestate_cname, @@ -2694,7 +2697,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln('#endif') def generate_module_state_traverse(self, env, code): - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln("static int %s_traverse(PyObject *m, visitproc visit, void *arg) {" % Naming.module_cname) code.putln("%s *traverse_module_state = %s(m);" % ( Naming.modulestate_cname, @@ -2838,7 +2841,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): for ext_type in ('CyFunction', 'FusedFunction', 'Coroutine', 'Generator', 'AsyncGen', 'StopAsyncIteration'): code.putln("#ifdef __Pyx_%s_USED" % ext_type) - code.put_error_if_neg(self.pos, "__pyx_%s_init()" % ext_type) + code.put_error_if_neg(self.pos, "__pyx_%s_init(%s)" % (ext_type, env.module_cname)) code.putln("#endif") code.putln("/*--- Library function declarations ---*/") @@ -3247,7 +3250,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln(" %s, /* m_doc */" % doc) code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT") code.putln(" 0, /* m_size */") - code.putln("#elif CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#elif CYTHON_USE_MODULE_STATE") # FIXME: should allow combination with PEP-489 code.putln(" sizeof(%s), /* m_size */" % Naming.modulestate_cname) code.putln("#else") code.putln(" -1, /* m_size */") @@ -3258,7 +3261,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("#else") code.putln(" NULL, /* m_reload */") code.putln("#endif") - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln(" %s_traverse, /* m_traverse */" % Naming.module_cname) code.putln(" %s_clear, /* m_clear */" % Naming.module_cname) code.putln(" %s /* m_free */" % cleanup_func) diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index b36239433..005bd0530 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -131,7 +131,7 @@ fused_func_prefix = pyrex_prefix + 'fuse_' quick_temp_cname = pyrex_prefix + "temp" # temp variable for quick'n'dirty temping tp_dict_version_temp = pyrex_prefix + "tp_dict_version" obj_dict_version_temp = pyrex_prefix + "obj_dict_version" -type_dict_guard_temp = pyrex_prefix + "type_dict_guard" +type_dict_guard_temp = pyrex_prefix + "typedict_guard" cython_runtime_cname = pyrex_prefix + "cython_runtime" cyfunction_type_cname = pyrex_prefix + "CyFunctionType" fusedfunction_type_cname = pyrex_prefix + "FusedFunctionType" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 5f935360f..5fd378c96 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -2562,38 +2562,45 @@ class CFuncDefNode(FuncDefNode): self.create_local_scope(env) def declare_cpdef_wrapper(self, env): - if self.overridable: - if self.is_static_method: - # TODO(robertwb): Finish this up, perhaps via more function refactoring. - error(self.pos, "static cpdef methods not yet supported") - name = self.entry.name - py_func_body = self.call_self_node(is_module_scope=env.is_module_scope) - if self.is_static_method: - from .ExprNodes import NameNode - decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name=EncodedString('staticmethod')))] - decorators[0].decorator.analyse_types(env) + if not self.overridable: + return + if self.is_static_method: + # TODO(robertwb): Finish this up, perhaps via more function refactoring. + error(self.pos, "static cpdef methods not yet supported") + + name = self.entry.name + py_func_body = self.call_self_node(is_module_scope=env.is_module_scope) + if self.is_static_method: + from .ExprNodes import NameNode + decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name=EncodedString('staticmethod')))] + decorators[0].decorator.analyse_types(env) + else: + decorators = [] + self.py_func = DefNode(pos=self.pos, + name=self.entry.name, + args=self.args, + star_arg=None, + starstar_arg=None, + doc=self.doc, + body=py_func_body, + decorators=decorators, + is_wrapper=1) + self.py_func.is_module_scope = env.is_module_scope + self.py_func.analyse_declarations(env) + self.py_func.entry.is_overridable = True + self.py_func_stat = StatListNode(self.pos, stats=[self.py_func]) + self.py_func.type = PyrexTypes.py_object_type + self.entry.as_variable = self.py_func.entry + self.entry.used = self.entry.as_variable.used = True + # Reset scope entry the above cfunction + env.entries[name] = self.entry + if (not self.entry.is_final_cmethod and + (not env.is_module_scope or Options.lookup_module_cpdef)): + if self.override: + # This is a hack: we shouldn't create the wrapper twice, but we do for fused functions. + assert self.entry.is_fused_specialized # should not happen for non-fused cpdef functions + self.override.py_func = self.py_func else: - decorators = [] - self.py_func = DefNode(pos=self.pos, - name=self.entry.name, - args=self.args, - star_arg=None, - starstar_arg=None, - doc=self.doc, - body=py_func_body, - decorators=decorators, - is_wrapper=1) - self.py_func.is_module_scope = env.is_module_scope - self.py_func.analyse_declarations(env) - self.py_func.entry.is_overridable = True - self.py_func_stat = StatListNode(self.pos, stats=[self.py_func]) - self.py_func.type = PyrexTypes.py_object_type - self.entry.as_variable = self.py_func.entry - self.entry.used = self.entry.as_variable.used = True - # Reset scope entry the above cfunction - env.entries[name] = self.entry - if (not self.entry.is_final_cmethod and - (not env.is_module_scope or Options.lookup_module_cpdef)): self.override = OverrideCheckNode(self.pos, py_func=self.py_func) self.body = StatListNode(self.pos, stats=[self.override, self.body]) @@ -3866,7 +3873,7 @@ class DefNodeWrapper(FuncDefNode): non_posonly_args = [arg for arg in all_args if not arg.pos_only] non_pos_args_id = ','.join( ['&%s' % code.intern_identifier(arg.entry.name) for arg in non_posonly_args] + ['0']) - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") + code.putln("#if CYTHON_USE_MODULE_STATE") code.putln("PyObject **%s[] = {%s};" % ( Naming.pykwdlist_cname, non_pos_args_id)) @@ -4663,7 +4670,10 @@ class OverrideCheckNode(StatNode): return self def generate_execution_code(self, code): - interned_attr_cname = code.intern_identifier(self.py_func.entry.name) + # For fused functions, look up the dispatch function, not the specialisation. + method_entry = self.py_func.fused_py_func.entry if self.py_func.fused_py_func else self.py_func.entry + interned_attr_cname = code.intern_identifier(method_entry.name) + # Check to see if we are an extension type if self.py_func.is_module_scope: self_arg = "((PyObject *)%s)" % Naming.module_cname @@ -4704,10 +4714,14 @@ class OverrideCheckNode(StatNode): func_node_temp, self_arg, interned_attr_cname, err)) code.put_gotref(func_node_temp, py_object_type) - is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % ( - func_node_temp, self.py_func.entry.func_cname) - code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden)) + func_node_temp, method_entry.func_cname) + code.putln("#ifdef __Pyx_CyFunction_USED") + code.putln("if (!__Pyx_IsCyOrPyCFunction(%s)" % func_node_temp) + code.putln("#else") + code.putln("if (!PyCFunction_Check(%s)" % func_node_temp) + code.putln("#endif") + code.putln(" || %s) {" % is_overridden) self.body.generate_execution_code(code) code.putln("}") @@ -5219,12 +5233,18 @@ class CClassDefNode(ClassDefNode): # default values of method arguments. code.mark_pos(self.pos) if not self.entry.type.early_init: + bases = None if self.type_init_args: + # Extract bases tuple and validate 'best base' by actually calling 'type()'. + bases = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) + self.type_init_args.generate_evaluation_code(code) - bases = "PyTuple_GET_ITEM(%s, 1)" % self.type_init_args.result() + code.putln("%s = PyTuple_GET_ITEM(%s, 1);" % (bases, self.type_init_args.result())) + code.put_incref(bases, PyrexTypes.py_object_type) + first_base = "((PyTypeObject*)PyTuple_GET_ITEM(%s, 0))" % bases # Let Python do the base types compatibility checking. - trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True) + trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % ( trial_type, self.type_init_args.result())) code.putln(code.error_goto_if_null(trial_type, self.pos)) @@ -5240,73 +5260,156 @@ class CClassDefNode(ClassDefNode): code.putln("__Pyx_DECREF_TypeName(type_name);") code.putln(code.error_goto(self.pos)) code.putln("}") - code.funcstate.release_temp(trial_type) - code.put_incref(bases, PyrexTypes.py_object_type) - code.put_giveref(bases, py_object_type) - code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases)) + code.put_decref_clear(trial_type, PyrexTypes.py_object_type) + code.funcstate.release_temp(trial_type) + self.type_init_args.generate_disposal_code(code) self.type_init_args.free_temps(code) - self.generate_type_ready_code(self.entry, code) + self.generate_type_ready_code(self.entry, code, bases_tuple_cname=bases, check_heap_type_bases=True) + if bases is not None: + code.put_decref_clear(bases, PyrexTypes.py_object_type) + code.funcstate.release_temp(bases) + if self.body: self.body.generate_execution_code(code) # Also called from ModuleNode for early init types. @staticmethod - def generate_type_ready_code(entry, code): + def generate_type_ready_code(entry, code, bases_tuple_cname=None, check_heap_type_bases=False): # Generate a call to PyType_Ready for an extension # type defined in this module. type = entry.type - typeobj_cname = type.typeobj_cname + typeptr_cname = type.typeptr_cname scope = type.scope if not scope: # could be None if there was an error return - if entry.visibility != 'extern': - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - base_type = scope.parent_type.base_type - if base_type: + if entry.visibility == 'extern': + # Generate code to initialise the typeptr of an external extension + # type defined in this module to point to its type object. + if type.typeobj_cname: + # FIXME: this should not normally be set :-? + assert not type.typeobj_cname + code.putln("%s = &%s;" % ( + type.typeptr_cname, + type.typeobj_cname, + )) + return + # TODO: remove 'else:' and dedent + else: + assert typeptr_cname + assert type.typeobj_cname + typespec_cname = "%s_spec" % type.typeobj_cname + code.putln("#if CYTHON_USE_TYPE_SPECS") + tuple_temp = None + if not bases_tuple_cname and scope.parent_type.base_type: tuple_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) - code.putln( - "%s = PyTuple_Pack(1, (PyObject *)%s); %s" % ( + code.putln("%s = PyTuple_Pack(1, (PyObject *)%s); %s" % ( tuple_temp, - base_type.typeptr_cname, - code.error_goto_if_null(tuple_temp, entry.pos))) + scope.parent_type.base_type.typeptr_cname, + code.error_goto_if_null(tuple_temp, entry.pos), + )) code.put_gotref(tuple_temp, py_object_type) - code.putln( - "%s = PyType_FromSpecWithBases(&%s_spec, %s); %s" % ( - typeobj_cname, - typeobj_cname, - tuple_temp, - code.error_goto_if_null(typeobj_cname, entry.pos))) - code.put_xdecref_clear(tuple_temp, type=py_object_type) - code.funcstate.release_temp(tuple_temp) + + if bases_tuple_cname or tuple_temp: + if check_heap_type_bases: + code.globalstate.use_utility_code( + UtilityCode.load_cached('ValidateBasesTuple', 'ExtensionTypes.c')) + code.put_error_if_neg(entry.pos, "__Pyx_validate_bases_tuple(%s.name, %s, %s)" % ( + typespec_cname, + TypeSlots.get_slot_by_name("tp_dictoffset").slot_code(scope), + bases_tuple_cname or tuple_temp, + )) + + code.putln("%s = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(%s, &%s, %s);" % ( + typeptr_cname, + Naming.module_cname, + typespec_cname, + bases_tuple_cname or tuple_temp, + )) + if tuple_temp: + code.put_xdecref_clear(tuple_temp, type=py_object_type) + code.funcstate.release_temp(tuple_temp) + code.putln(code.error_goto_if_null(typeptr_cname, entry.pos)) else: code.putln( - "%s = PyType_FromSpec(&%s_spec); %s" % ( - typeobj_cname, - typeobj_cname, - code.error_goto_if_null(typeobj_cname, entry.pos))) + "%s = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(%s, &%s, NULL); %s" % ( + typeptr_cname, + Naming.module_cname, + typespec_cname, + code.error_goto_if_null(typeptr_cname, entry.pos), + )) + + # The buffer interface is not currently supported by PyType_FromSpec(). + buffer_slot = TypeSlots.get_slot_by_name("tp_as_buffer") + if not buffer_slot.is_empty(scope): + code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + code.putln("%s->%s = %s;" % ( + typeptr_cname, + buffer_slot.slot_name, + buffer_slot.slot_code(scope), + )) + # Still need to inherit buffer methods since PyType_Ready() didn't do it for us. + for buffer_method_name in ("__getbuffer__", "__releasebuffer__"): + buffer_slot = TypeSlots.get_slot_by_method_name(buffer_method_name) + if buffer_slot.slot_code(scope) == "0" and not TypeSlots.get_base_slot_function(scope, buffer_slot): + code.putln("if (!%s->tp_as_buffer->%s &&" + " %s->tp_base->tp_as_buffer &&" + " %s->tp_base->tp_as_buffer->%s) {" % ( + typeptr_cname, buffer_slot.slot_name, + typeptr_cname, + typeptr_cname, buffer_slot.slot_name, + )) + code.putln("%s->tp_as_buffer->%s = %s->tp_base->tp_as_buffer->%s;" % ( + typeptr_cname, buffer_slot.slot_name, + typeptr_cname, buffer_slot.slot_name, + )) + code.putln("}") + code.putln("#else") + code.putln("#warning The buffer protocol is not supported in the Limited C-API.") + code.putln("#endif") + + code.globalstate.use_utility_code( + UtilityCode.load_cached("FixUpExtensionType", "ExtensionTypes.c")) + code.put_error_if_neg(entry.pos, "__Pyx_fix_up_extension_type_from_spec(&%s, %s)" % ( + typespec_cname, typeptr_cname)) + code.putln("#else") + if bases_tuple_cname: + code.put_incref(bases_tuple_cname, py_object_type) + code.put_giveref(bases_tuple_cname, py_object_type) + code.putln("%s.tp_bases = %s;" % (type.typeobj_cname, bases_tuple_cname)) + code.putln("%s = &%s;" % ( + typeptr_cname, + type.typeobj_cname, + )) + code.putln("#endif") # if CYTHON_USE_TYPE_SPECS + + code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") + # FIXME: these still need to get initialised even with the limited-API for slot in TypeSlots.slot_table: slot.generate_dynamic_init_code(scope, code) + code.putln("#endif") + + code.putln("#if !CYTHON_USE_TYPE_SPECS") code.globalstate.use_utility_code( UtilityCode.load_cached('PyType_Ready', 'ExtensionTypes.c')) - code.putln( - "if (__Pyx_PyType_Ready(&%s) < 0) %s" % ( - typeobj_cname, - code.error_goto(entry.pos))) + code.put_error_if_neg(entry.pos, "__Pyx_PyType_Ready(%s)" % typeptr_cname) + code.putln("#endif") + # Don't inherit tp_print from builtin types in Python 2, restoring the # behavior of using tp_repr or tp_str instead. # ("tp_print" was renamed to "tp_vectorcall_offset" in Py3.8b1) code.putln("#if PY_MAJOR_VERSION < 3") - code.putln("%s.tp_print = 0;" % typeobj_cname) + code.putln("%s->tp_print = 0;" % typeptr_cname) code.putln("#endif") # Use specialised attribute lookup for types with generic lookup but no instance dict. getattr_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_getattro') dictoffset_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_dictoffset') if getattr_slot_func == '0' and dictoffset_slot_func == '0': + code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") # FIXME if type.is_final_type: py_cfunc = "__Pyx_PyObject_GenericGetAttrNoDict" # grepable utility_func = "PyObject_GenericGetAttrNoDict" @@ -5316,12 +5419,12 @@ class CClassDefNode(ClassDefNode): code.globalstate.use_utility_code(UtilityCode.load_cached(utility_func, "ObjectHandling.c")) code.putln("if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) &&" - " likely(!%s.tp_dictoffset && %s.tp_getattro == PyObject_GenericGetAttr)) {" % ( - typeobj_cname, typeobj_cname)) - code.putln("%s.tp_getattro = %s;" % ( - typeobj_cname, py_cfunc)) + " likely(!%s->tp_dictoffset && %s->tp_getattro == PyObject_GenericGetAttr)) {" % ( + typeptr_cname, typeptr_cname)) + code.putln("%s->tp_getattro = %s;" % ( + typeptr_cname, py_cfunc)) code.putln("}") - code.putln("#endif") + code.putln("#endif") # if !CYTHON_COMPILING_IN_LIMITED_API # Fix special method docstrings. This is a bit of a hack, but # unless we let PyType_Ready create the slot wrappers we have @@ -5337,8 +5440,8 @@ class CClassDefNode(ClassDefNode): code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln("{") code.putln( - 'PyObject *wrapper = PyObject_GetAttrString((PyObject *)&%s, "%s"); %s' % ( - typeobj_cname, + 'PyObject *wrapper = PyObject_GetAttrString((PyObject *)%s, "%s"); %s' % ( + typeptr_cname, func.name, code.error_goto_if_null('wrapper', entry.pos))) code.putln( @@ -5356,50 +5459,33 @@ class CClassDefNode(ClassDefNode): code.putln('#endif') if preprocessor_guard: code.putln('#endif') + if type.vtable_cname: code.globalstate.use_utility_code( UtilityCode.load_cached('SetVTable', 'ImportExport.c')) - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - code.putln( - "if (__Pyx_SetVtable(%s, %s) < 0) %s" % ( - typeobj_cname, - type.vtabptr_cname, - code.error_goto(entry.pos))) - code.putln("#else") - code.putln( - "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % ( - typeobj_cname, - type.vtabptr_cname, - code.error_goto(entry.pos))) - code.putln("#endif") - code.globalstate.use_utility_code( - UtilityCode.load_cached('MergeVTables', 'ImportExport.c')) - code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % ( - typeobj_cname, - code.error_goto(entry.pos))) + code.put_error_if_neg(entry.pos, "__Pyx_SetVtable(%s, %s)" % ( + typeptr_cname, + type.vtabptr_cname, + )) + if bases_tuple_cname: + code.globalstate.use_utility_code( + UtilityCode.load_cached('MergeVTables', 'ImportExport.c')) + code.put_error_if_neg(entry.pos, "__Pyx_MergeVtables(%s)" % typeptr_cname) + if not type.scope.is_internal and not type.scope.directives.get('internal'): # scope.is_internal is set for types defined by # Cython (such as closures), the 'internal' # directive is set by users - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - code.putln( - 'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % ( - Naming.module_cname, - code.intern_identifier(scope.class_name), - typeobj_cname, - code.error_goto(entry.pos))) - code.putln("#else") - code.putln( - 'if (PyObject_SetAttr(%s, %s, (PyObject *)&%s) < 0) %s' % ( - Naming.module_cname, - code.intern_identifier(scope.class_name), - typeobj_cname, - code.error_goto(entry.pos))) - code.putln("#endif") + code.put_error_if_neg(entry.pos, "PyObject_SetAttr(%s, %s, (PyObject *) %s)" % ( + Naming.module_cname, + code.intern_identifier(scope.class_name), + typeptr_cname, + )) + weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None if weakref_entry: if weakref_entry.type is py_object_type: - tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname + tp_weaklistoffset = "%s->tp_weaklistoffset" % typeptr_cname if type.typedef_flag: objstruct = type.objstruct_cname else: @@ -5411,29 +5497,16 @@ class CClassDefNode(ClassDefNode): weakref_entry.cname)) else: error(weakref_entry.pos, "__weakref__ slot must be of type 'object'") + if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None: # Unfortunately, we cannot reliably detect whether a # superclass defined __reduce__ at compile time, so we must # do so at runtime. code.globalstate.use_utility_code( UtilityCode.load_cached('SetupReduce', 'ExtensionTypes.c')) - code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") - code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % ( - typeobj_cname, - code.error_goto(entry.pos))) + code.putln("#if !CYTHON_COMPILING_IN_LIMITED_API") # FIXME + code.put_error_if_neg(entry.pos, "__Pyx_setup_reduce((PyObject *) %s)" % typeptr_cname) code.putln("#endif") - # Generate code to initialise the typeptr of an extension - # type defined in this module to point to its type object. - if type.typeobj_cname: - code.putln("#if CYTHON_COMPILING_IN_LIMITED_API") - code.putln( - "%s = (PyTypeObject *)%s;" % ( - type.typeptr_cname, type.typeobj_cname)) - code.putln("#else") - code.putln( - "%s = &%s;" % ( - type.typeptr_cname, type.typeobj_cname)) - code.putln("#endif") def annotate(self, code): if self.type_init_args: diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index 1db912991..c260ada1d 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -276,7 +276,7 @@ class SlotDescriptor(object): # PyPy currently has a broken PyType_Ready() that fails to # inherit some slots. To work around this, we explicitly # set inherited slots here, but only in PyPy since CPython - # handles this better than we do. + # handles this better than we do (except for buffer slots in type specs). inherited_value = value current_scope = scope while (inherited_value == "0" @@ -286,7 +286,9 @@ class SlotDescriptor(object): current_scope = current_scope.parent_type.base_type.scope inherited_value = self.slot_code(current_scope) if inherited_value != "0": - code.putln("#if CYTHON_COMPILING_IN_PYPY") + # we always need inherited buffer slots for the type spec + is_buffer_slot = int(self.slot_name in ("bf_getbuffer", "bf_releasebuffer")) + code.putln("#if CYTHON_COMPILING_IN_PYPY || %d" % is_buffer_slot) code.putln("%s, /*%s*/" % (inherited_value, self.slot_name)) code.putln("#else") end_pypy_guard = True @@ -315,11 +317,14 @@ class SlotDescriptor(object): def generate_set_slot_code(self, value, scope, code): if value == "0": return - code.putln("%s.%s = %s;" % ( - scope.parent_type.typeobj_cname, - self.slot_name, - value, - )) + + if scope.parent_type.typeptr_cname: + target = "%s->%s" % (scope.parent_type.typeptr_cname, self.slot_name) + else: + assert scope.parent_type.typeobj_cname + target = "%s.%s" % (scope.parent_type.typeobj_cname, self.slot_name) + + code.putln("%s = %s;" % (target, value)) class FixedSlot(SlotDescriptor): @@ -458,9 +463,11 @@ class ConstructorSlot(InternalMethodSlot): return InternalMethodSlot.slot_code(self, scope) def spec_value(self, scope): - if self.slot_name == "tp_dealloc" and not scope.lookup_here("__dealloc__"): + slot_function = self.slot_code(scope) + if self.slot_name == "tp_dealloc" and slot_function != scope.mangle_internal("tp_dealloc"): + # Not used => inherit from base type. return "0" - return self.slot_code(scope) + return slot_function def generate_dynamic_init_code(self, scope, code): if self.slot_code(scope) != '0': @@ -468,10 +475,10 @@ class ConstructorSlot(InternalMethodSlot): # If we don't have our own slot function and don't know the # parent function statically, copy it dynamically. base_type = scope.parent_type.base_type - if base_type.is_extension_type and base_type.typeobj_cname: - src = '%s.%s' % (base_type.typeobj_cname, self.slot_name) - elif base_type.typeptr_cname: + if base_type.typeptr_cname: src = '%s->%s' % (base_type.typeptr_cname, self.slot_name) + elif base_type.is_extension_type and base_type.typeobj_cname: + src = '%s.%s' % (base_type.typeobj_cname, self.slot_name) else: return @@ -498,8 +505,6 @@ class SyntheticSlot(InternalMethodSlot): return self.default_value def spec_value(self, scope): - if self.slot_name == "tp_getattro" and not scope.defines_any_special(self.user_methods): - return "PyObject_GenericGetAttr" return self.slot_code(scope) @@ -623,8 +628,43 @@ class MemberTableSlot(SlotDescriptor): # Slot descriptor for the table of Python-accessible attributes. def slot_code(self, scope): + # Only used in specs. return "0" + def get_member_specs(self, scope): + return [ + get_slot_by_name("tp_dictoffset").members_slot_value(scope), + #get_slot_by_name("tp_weaklistoffset").spec_value(scope), + ] + + def is_empty(self, scope): + for member_entry in self.get_member_specs(scope): + if member_entry: + return False + return True + + def substructure_cname(self, scope): + return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name) + + def generate_substructure_spec(self, scope, code): + if self.is_empty(scope): + return + from .Code import UtilityCode + code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStructmemberH", "ModuleSetupCode.c")) + + ext_type = scope.parent_type + code.putln("static struct PyMemberDef %s[] = {" % self.substructure_cname(scope)) + for member_entry in self.get_member_specs(scope): + if member_entry: + code.putln(member_entry) + code.putln("{NULL, 0, 0, 0, NULL}") + code.putln("};") + + def spec_value(self, scope): + if self.is_empty(scope): + return "0" + return self.substructure_cname(scope) + class GetSetSlot(SlotDescriptor): # Slot descriptor for the table of attribute get & set methods. @@ -645,8 +685,8 @@ class BaseClassSlot(SlotDescriptor): def generate_dynamic_init_code(self, scope, code): base_type = scope.parent_type.base_type if base_type: - code.putln("%s.%s = %s;" % ( - scope.parent_type.typeobj_cname, + code.putln("%s->%s = %s;" % ( + scope.parent_type.typeptr_cname, self.slot_name, base_type.typeptr_cname)) @@ -671,6 +711,13 @@ class DictOffsetSlot(SlotDescriptor): else: return "0" + def members_slot_value(self, scope): + dict_offset = self.slot_code(scope) + if dict_offset == "0": + return None + return '{"__dictoffset__", T_PYSSIZET, %s, READONLY, NULL},' % dict_offset + + # The following dictionary maps __xxx__ method names to slot descriptors. @@ -712,7 +759,7 @@ def get_base_slot_function(scope, slot): # This is useful for enabling the compiler to optimize calls # that recursively climb the class hierarchy. base_type = scope.parent_type.base_type - if scope.parent_scope is base_type.scope.parent_scope: + if base_type and scope.parent_scope is base_type.scope.parent_scope: parent_slot = slot.slot_code(base_type.scope) if parent_slot != '0': entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) @@ -741,6 +788,11 @@ def get_slot_by_name(slot_name): assert False, "Slot not found: %s" % slot_name +def get_slot_by_method_name(method_name): + # For now, only search the type struct, no referenced sub-structs. + return method_name_to_slot[method_name] + + def get_slot_code_by_name(scope, slot_name): slot = get_slot_by_name(slot_name) return slot.slot_code(scope) @@ -845,38 +897,38 @@ property_accessor_signatures = { # #------------------------------------------------------------------------------------------ -PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" +PyNumberMethods_Py2only_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" PyNumberMethods = ( BinopSlot(binaryfunc, "nb_add", "__add__"), BinopSlot(binaryfunc, "nb_subtract", "__sub__"), BinopSlot(binaryfunc, "nb_multiply", "__mul__"), - BinopSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), + BinopSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py2only_GUARD), BinopSlot(binaryfunc, "nb_remainder", "__mod__"), BinopSlot(binaryfunc, "nb_divmod", "__divmod__"), BinopSlot(ternaryfunc, "nb_power", "__pow__"), MethodSlot(unaryfunc, "nb_negative", "__neg__"), MethodSlot(unaryfunc, "nb_positive", "__pos__"), MethodSlot(unaryfunc, "nb_absolute", "__abs__"), - MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")), + MethodSlot(inquiry, "nb_bool", "__bool__", py2 = ("nb_nonzero", "__nonzero__")), MethodSlot(unaryfunc, "nb_invert", "__invert__"), BinopSlot(binaryfunc, "nb_lshift", "__lshift__"), BinopSlot(binaryfunc, "nb_rshift", "__rshift__"), BinopSlot(binaryfunc, "nb_and", "__and__"), BinopSlot(binaryfunc, "nb_xor", "__xor__"), BinopSlot(binaryfunc, "nb_or", "__or__"), - EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), + EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py2only_GUARD), MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"), MethodSlot(unaryfunc, "nb_float", "__float__"), - MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD), - MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py2only_GUARD), + MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py2only_GUARD), # Added in release 2.0 MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"), MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"), MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"), - MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py2only_GUARD), MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"), MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!! MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"), @@ -992,7 +1044,7 @@ slot_table = ( SyntheticSlot("tp_descr_get", ["__get__"], "0"), SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"), - DictOffsetSlot("tp_dictoffset"), + DictOffsetSlot("tp_dictoffset", ifdef="!CYTHON_USE_TYPE_SPECS"), # otherwise set via "__dictoffset__" member MethodSlot(initproc, "tp_init", "__init__"), EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"), diff --git a/Cython/Utility/AsyncGen.c b/Cython/Utility/AsyncGen.c index ab2dbdb90..8aee0e78a 100644 --- a/Cython/Utility/AsyncGen.c +++ b/Cython/Utility/AsyncGen.c @@ -47,7 +47,7 @@ static __pyx_CoroutineObject *__Pyx_AsyncGen_New( return __Pyx__Coroutine_NewInit((__pyx_CoroutineObject*)gen, body, code, closure, name, qualname, module_name); } -static int __pyx_AsyncGen_init(void); +static int __pyx_AsyncGen_init(PyObject *module); static void __Pyx_PyAsyncGen_Fini(void); //////////////////// AsyncGenerator.cleanup //////////////////// @@ -322,6 +322,10 @@ static PyMemberDef __Pyx_async_gen_memberlist[] = { //ADDED: "ag_await" {(char*) "ag_await", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, (char*) PyDoc_STR("object being awaited on, or None")}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif {0, 0, 0, 0, 0} /* Sentinel */ }; @@ -350,6 +354,31 @@ static PyMethodDef __Pyx_async_gen_methods[] = { }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_AsyncGenType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_am_aiter, (void *)PyObject_SelfIter}, + {Py_am_anext, (void *)__Pyx_async_gen_anext}, + {Py_tp_repr, (void *)__Pyx_async_gen_repr}, + {Py_tp_traverse, (void *)__Pyx_async_gen_traverse}, + {Py_tp_methods, (void *)__Pyx_async_gen_methods}, + {Py_tp_members, (void *)__Pyx_async_gen_memberlist}, + {Py_tp_getset, (void *)__Pyx_async_gen_getsetlist}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; + +static PyType_Spec __pyx_AsyncGenType_spec = { + __PYX_TYPE_MODULE_PREFIX "async_generator", + sizeof(__pyx_PyAsyncGenObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + __pyx_AsyncGenType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + #if CYTHON_USE_ASYNC_SLOTS static __Pyx_PyAsyncMethodsStruct __Pyx_async_gen_as_async = { 0, /* am_await */ @@ -435,6 +464,7 @@ static PyTypeObject __pyx_AsyncGenType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ static int @@ -446,14 +476,14 @@ __Pyx_PyAsyncGen_ClearFreeLists(void) __pyx__PyAsyncGenWrappedValue *o; o = __Pyx_ag_value_freelist[--__Pyx_ag_value_freelist_free]; assert(__pyx__PyAsyncGenWrappedValue_CheckExact(o)); - PyObject_GC_Del(o); + __Pyx_PyHeapTypeObject_GC_Del(o); } while (__Pyx_ag_asend_freelist_free) { __pyx_PyAsyncGenASend *o; o = __Pyx_ag_asend_freelist[--__Pyx_ag_asend_freelist_free]; assert(__Pyx_IS_TYPE(o, __pyx__PyAsyncGenASendType)); - PyObject_GC_Del(o); + __Pyx_PyHeapTypeObject_GC_Del(o); } return ret; @@ -507,7 +537,7 @@ __Pyx_async_gen_asend_dealloc(__pyx_PyAsyncGenASend *o) assert(__pyx_PyAsyncGenASend_CheckExact(o)); __Pyx_ag_asend_freelist[__Pyx_ag_asend_freelist_free++] = o; } else { - PyObject_GC_Del(o); + __Pyx_PyHeapTypeObject_GC_Del(o); } } @@ -603,6 +633,26 @@ static PyMethodDef __Pyx_async_gen_asend_methods[] = { }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx__PyAsyncGenASendType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_async_gen_asend_dealloc}, + {Py_am_await, (void *)PyObject_SelfIter}, + {Py_tp_traverse, (void *)__Pyx_async_gen_asend_traverse}, + {Py_tp_methods, (void *)__Pyx_async_gen_asend_methods}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_async_gen_asend_iternext}, + {0, 0}, +}; + +static PyType_Spec __pyx__PyAsyncGenASendType_spec = { + __PYX_TYPE_MODULE_PREFIX "async_generator_asend", + sizeof(__pyx_PyAsyncGenASend), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + __pyx__PyAsyncGenASendType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + #if CYTHON_USE_ASYNC_SLOTS static __Pyx_PyAsyncMethodsStruct __Pyx_async_gen_asend_as_async = { PyObject_SelfIter, /* am_await */ @@ -611,7 +661,6 @@ static __Pyx_PyAsyncMethodsStruct __Pyx_async_gen_asend_as_async = { }; #endif - static PyTypeObject __pyx__PyAsyncGenASendType_type = { PyVarObject_HEAD_INIT(0, 0) "async_generator_asend", /* tp_name */ @@ -683,6 +732,7 @@ static PyTypeObject __pyx__PyAsyncGenASendType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ static PyObject * @@ -725,7 +775,7 @@ __Pyx_async_gen_wrapped_val_dealloc(__pyx__PyAsyncGenWrappedValue *o) assert(__pyx__PyAsyncGenWrappedValue_CheckExact(o)); __Pyx_ag_value_freelist[__Pyx_ag_value_freelist_free++] = o; } else { - PyObject_GC_Del(o); + __Pyx_PyHeapTypeObject_GC_Del(o); } } @@ -739,6 +789,22 @@ __Pyx_async_gen_wrapped_val_traverse(__pyx__PyAsyncGenWrappedValue *o, } +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx__PyAsyncGenWrappedValueType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_async_gen_wrapped_val_dealloc}, + {Py_tp_traverse, (void *)__Pyx_async_gen_wrapped_val_traverse}, + {0, 0}, +}; + +static PyType_Spec __pyx__PyAsyncGenWrappedValueType_spec = { + __PYX_TYPE_MODULE_PREFIX "async_generator_wrapped_value", + sizeof(__pyx__PyAsyncGenWrappedValue), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + __pyx__PyAsyncGenWrappedValueType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + static PyTypeObject __pyx__PyAsyncGenWrappedValueType_type = { PyVarObject_HEAD_INIT(0, 0) "async_generator_wrapped_value", /* tp_name */ @@ -801,6 +867,7 @@ static PyTypeObject __pyx__PyAsyncGenWrappedValueType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ static PyObject * @@ -838,7 +905,7 @@ __Pyx_async_gen_athrow_dealloc(__pyx_PyAsyncGenAThrow *o) PyObject_GC_UnTrack((PyObject *)o); Py_CLEAR(o->agt_gen); Py_CLEAR(o->agt_args); - PyObject_GC_Del(o); + __Pyx_PyHeapTypeObject_GC_Del(o); } @@ -1038,6 +1105,27 @@ static PyMethodDef __Pyx_async_gen_athrow_methods[] = { }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx__PyAsyncGenAThrowType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_async_gen_athrow_dealloc}, + {Py_am_await, (void *)PyObject_SelfIter}, + {Py_tp_traverse, (void *)__Pyx_async_gen_athrow_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_async_gen_athrow_iternext}, + {Py_tp_methods, (void *)__Pyx_async_gen_athrow_methods}, + {Py_tp_getattro, (void *)__Pyx_PyObject_GenericGetAttrNoDict}, + {0, 0}, +}; + +static PyType_Spec __pyx__PyAsyncGenAThrowType_spec = { + __PYX_TYPE_MODULE_PREFIX "async_generator_athrow", + sizeof(__pyx_PyAsyncGenAThrow), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + __pyx__PyAsyncGenAThrowType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + #if CYTHON_USE_ASYNC_SLOTS static __Pyx_PyAsyncMethodsStruct __Pyx_async_gen_athrow_as_async = { PyObject_SelfIter, /* am_await */ @@ -1046,7 +1134,6 @@ static __Pyx_PyAsyncMethodsStruct __Pyx_async_gen_athrow_as_async = { }; #endif - static PyTypeObject __pyx__PyAsyncGenAThrowType_type = { PyVarObject_HEAD_INIT(0, 0) "async_generator_athrow", /* tp_name */ @@ -1117,6 +1204,7 @@ static PyTypeObject __pyx__PyAsyncGenAThrowType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ static PyObject * @@ -1139,26 +1227,42 @@ __Pyx_async_gen_athrow_new(__pyx_PyAsyncGenObject *gen, PyObject *args) /* ---------- global type sharing ------------ */ -static int __pyx_AsyncGen_init(void) { +static int __pyx_AsyncGen_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_AsyncGenType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_AsyncGenType_spec, NULL); +#else + (void) module; // on Windows, C-API functions can't be used in slots statically __pyx_AsyncGenType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; - __pyx__PyAsyncGenWrappedValueType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; - __pyx__PyAsyncGenAThrowType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; - __pyx__PyAsyncGenASendType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; - __pyx_AsyncGenType = __Pyx_FetchCommonType(&__pyx_AsyncGenType_type); +#endif if (unlikely(!__pyx_AsyncGenType)) return -1; +#if CYTHON_USE_TYPE_SPECS + __pyx__PyAsyncGenAThrowType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx__PyAsyncGenAThrowType_spec, NULL); +#else + __pyx__PyAsyncGenAThrowType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx__PyAsyncGenAThrowType = __Pyx_FetchCommonType(&__pyx__PyAsyncGenAThrowType_type); +#endif if (unlikely(!__pyx__PyAsyncGenAThrowType)) return -1; +#if CYTHON_USE_TYPE_SPECS + __pyx__PyAsyncGenWrappedValueType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx__PyAsyncGenWrappedValueType_spec, NULL); +#else + __pyx__PyAsyncGenWrappedValueType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx__PyAsyncGenWrappedValueType = __Pyx_FetchCommonType(&__pyx__PyAsyncGenWrappedValueType_type); +#endif if (unlikely(!__pyx__PyAsyncGenWrappedValueType)) return -1; +#if CYTHON_USE_TYPE_SPECS + __pyx__PyAsyncGenASendType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx__PyAsyncGenASendType_spec, NULL); +#else + __pyx__PyAsyncGenASendType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx__PyAsyncGenASendType = __Pyx_FetchCommonType(&__pyx__PyAsyncGenASendType_type); +#endif if (unlikely(!__pyx__PyAsyncGenASendType)) return -1; diff --git a/Cython/Utility/CommonStructures.c b/Cython/Utility/CommonStructures.c index 4b572defb..80055a330 100644 --- a/Cython/Utility/CommonStructures.c +++ b/Cython/Utility/CommonStructures.c @@ -1,11 +1,13 @@ /////////////// FetchCommonType.proto /////////////// +#if !CYTHON_USE_TYPE_SPECS static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); -#if CYTHON_COMPILING_IN_LIMITED_API -static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyType_Spec *spec, PyObject *bases); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); #endif /////////////// FetchCommonType /////////////// +//@requires:ExtensionTypes.c::FixUpExtensionType static PyObject *__Pyx_FetchSharedCythonABIModule(void) { PyObject *abi_module = PyImport_AddModule((char*) __PYX_ABI_MODULE_NAME); @@ -32,6 +34,7 @@ static int __Pyx_VerifyCachedType(PyObject *cached_type, return 0; } +#if !CYTHON_USE_TYPE_SPECS static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { PyObject* abi_module; PyTypeObject *cached_type = NULL; @@ -68,22 +71,28 @@ bad: cached_type = NULL; goto done; } +#else -#if CYTHON_COMPILING_IN_LIMITED_API -static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyType_Spec *spec, PyObject *bases) { - PyObject *abi_module, *py_basicsize, *cached_type = NULL; - Py_ssize_t basicsize; +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; abi_module = __Pyx_FetchSharedCythonABIModule(); if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, spec->name); if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); - if (!py_basicsize) goto bad; + if (unlikely(!py_basicsize)) goto bad; basicsize = PyLong_AsSsize_t(py_basicsize); Py_DECREF(py_basicsize); py_basicsize = 0; - if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) goto bad; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif if (__Pyx_VerifyCachedType( cached_type, spec->name, @@ -96,8 +105,11 @@ static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyType_Spec *spec, PyObject * if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; PyErr_Clear(); - cached_type = PyType_FromSpecWithBases(spec, bases); + // We pass the ABI module reference to avoid keeping the user module alive by foreign type usages. + (void) module; + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; if (PyObject_SetAttrString(abi_module, spec->name, cached_type) < 0) goto bad; done: diff --git a/Cython/Utility/Coroutine.c b/Cython/Utility/Coroutine.c index a2540d5d4..6cd1b78b4 100644 --- a/Cython/Utility/Coroutine.c +++ b/Cython/Utility/Coroutine.c @@ -452,7 +452,7 @@ static PyTypeObject *__pyx_CoroutineAwaitType = 0; #define __Pyx_Coroutine_New(body, code, closure, name, qualname, module_name) \ __Pyx__Coroutine_New(__pyx_CoroutineType, body, code, closure, name, qualname, module_name) -static int __pyx_Coroutine_init(void); /*proto*/ +static int __pyx_Coroutine_init(PyObject *module); /*proto*/ static PyObject *__Pyx__Coroutine_await(PyObject *coroutine); /*proto*/ typedef struct { @@ -474,7 +474,7 @@ static PyTypeObject *__pyx_GeneratorType = 0; __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) static PyObject *__Pyx_Generator_Next(PyObject *self); -static int __pyx_Generator_init(void); /*proto*/ +static int __pyx_Generator_init(PyObject *module); /*proto*/ //////////////////// AsyncGen //////////////////// @@ -495,8 +495,8 @@ static int __pyx_Generator_init(void); /*proto*/ //@requires: ObjectHandling.c::PyObjectGetAttrStr //@requires: ObjectHandling.c::PyObjectGetAttrStrNoError //@requires: CommonStructures.c::FetchCommonType +//@requires: ModuleSetupCode.c::IncludeStructmemberH -#include <structmember.h> #include <frameobject.h> #define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) @@ -1184,7 +1184,7 @@ static void __Pyx_Coroutine_dealloc(PyObject *self) { } #endif __Pyx_Coroutine_clear(self); - PyObject_GC_Del(gen); + __Pyx_PyHeapTypeObject_GC_Del(gen); } static void __Pyx_Coroutine_del(PyObject *self) { @@ -1443,7 +1443,7 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( static void __Pyx_CoroutineAwait_dealloc(PyObject *self) { PyObject_GC_UnTrack(self); Py_CLEAR(((__pyx_CoroutineAwaitObject*)self)->coroutine); - PyObject_GC_Del(self); + __Pyx_PyHeapTypeObject_GC_Del(self); } static int __Pyx_CoroutineAwait_traverse(__pyx_CoroutineAwaitObject *self, visitproc visit, void *arg) { @@ -1494,6 +1494,29 @@ static PyMethodDef __pyx_CoroutineAwait_methods[] = { {0, 0, 0, 0} }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CoroutineAwaitType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CoroutineAwait_dealloc}, + {Py_tp_traverse, (void *)__Pyx_CoroutineAwait_traverse}, + {Py_tp_clear, (void *)__Pyx_CoroutineAwait_clear}, +#if !CYTHON_COMPILING_IN_PYPY + {Py_tp_new, (void *)__Pyx_CoroutineAwait_no_new}, +#endif + {Py_tp_methods, (void *)__pyx_CoroutineAwait_methods}, + {Py_tp_iter, (void *)__Pyx_CoroutineAwait_self}, + {Py_tp_iternext, (void *)__Pyx_CoroutineAwait_Next}, + {0, 0}, +}; + +static PyType_Spec __pyx_CoroutineAwaitType_spec = { + __PYX_TYPE_MODULE_PREFIX "coroutine_wrapper", + sizeof(__pyx_CoroutineAwaitObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + __pyx_CoroutineAwaitType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + static PyTypeObject __pyx_CoroutineAwaitType_type = { PyVarObject_HEAD_INIT(0, 0) __PYX_TYPE_MODULE_PREFIX "coroutine_wrapper", /*tp_name*/ @@ -1559,6 +1582,7 @@ static PyTypeObject __pyx_CoroutineAwaitType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ #if PY_VERSION_HEX < 0x030500B1 || defined(__Pyx_IterableCoroutine_USED) || CYTHON_USE_ASYNC_SLOTS static CYTHON_INLINE PyObject *__Pyx__Coroutine_await(PyObject *coroutine) { @@ -1620,7 +1644,10 @@ static PyMemberDef __pyx_Coroutine_memberlist[] = { {(char*) "cr_await", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, (char*) PyDoc_STR("object being awaited, or None")}, {(char*) "cr_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, - {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), PY_WRITE_RESTRICTED, 0}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif {0, 0, 0, 0, 0} }; @@ -1634,6 +1661,30 @@ static PyGetSetDef __pyx_Coroutine_getsets[] = { {0, 0, 0, 0, 0} }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CoroutineType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_am_await, (void *)&__Pyx_Coroutine_await}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_methods, (void *)__pyx_Coroutine_methods}, + {Py_tp_members, (void *)__pyx_Coroutine_memberlist}, + {Py_tp_getset, (void *)__pyx_Coroutine_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; + +static PyType_Spec __pyx_CoroutineType_spec = { + __PYX_TYPE_MODULE_PREFIX "coroutine", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + __pyx_CoroutineType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + #if CYTHON_USE_ASYNC_SLOTS static __Pyx_PyAsyncMethodsStruct __pyx_Coroutine_as_async = { __Pyx_Coroutine_await, /*am_await*/ @@ -1719,20 +1770,30 @@ static PyTypeObject __pyx_CoroutineType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ -static int __pyx_Coroutine_init(void) { +static int __pyx_Coroutine_init(PyObject *module) { // on Windows, C-API functions can't be used in slots statically +#if CYTHON_USE_TYPE_SPECS + __pyx_CoroutineType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CoroutineType_spec, NULL); +#else + (void) module; __pyx_CoroutineType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx_CoroutineType = __Pyx_FetchCommonType(&__pyx_CoroutineType_type); +#endif if (unlikely(!__pyx_CoroutineType)) return -1; #ifdef __Pyx_IterableCoroutine_USED - if (unlikely(__pyx_IterableCoroutine_init() == -1)) + if (unlikely(__pyx_IterableCoroutine_init(module) == -1)) return -1; #endif +#if CYTHON_USE_TYPE_SPECS + __pyx_CoroutineAwaitType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CoroutineAwaitType_spec, NULL); +#else __pyx_CoroutineAwaitType = __Pyx_FetchCommonType(&__pyx_CoroutineAwaitType_type); +#endif if (unlikely(!__pyx_CoroutineAwaitType)) return -1; return 0; @@ -1751,13 +1812,39 @@ static PyTypeObject *__pyx_IterableCoroutineType = 0; #define __Pyx_IterableCoroutine_New(body, code, closure, name, qualname, module_name) \ __Pyx__Coroutine_New(__pyx_IterableCoroutineType, body, code, closure, name, qualname, module_name) -static int __pyx_IterableCoroutine_init(void);/*proto*/ +static int __pyx_IterableCoroutine_init(PyObject *module);/*proto*/ //////////////////// IterableCoroutine //////////////////// //@requires: Coroutine //@requires: CommonStructures.c::FetchCommonType +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_IterableCoroutineType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_am_await, (void *)&__Pyx_Coroutine_await}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)__Pyx_Coroutine_await}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Coroutine_methods}, + {Py_tp_members, (void *)__pyx_Coroutine_memberlist}, + {Py_tp_getset, (void *)__pyx_Coroutine_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; + +static PyType_Spec __pyx_IterableCoroutineType_spec = { + __PYX_TYPE_MODULE_PREFIX "iterable_coroutine", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + __pyx_IterableCoroutineType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + static PyTypeObject __pyx_IterableCoroutineType_type = { PyVarObject_HEAD_INIT(0, 0) __PYX_TYPE_MODULE_PREFIX "iterable_coroutine", /*tp_name*/ @@ -1833,11 +1920,17 @@ static PyTypeObject __pyx_IterableCoroutineType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ -static int __pyx_IterableCoroutine_init(void) { +static int __pyx_IterableCoroutine_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_IterableCoroutineType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_IterableCoroutineType_spec, NULL); +#else + (void) module; __pyx_IterableCoroutineType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx_IterableCoroutineType = __Pyx_FetchCommonType(&__pyx_IterableCoroutineType_type); +#endif if (unlikely(!__pyx_IterableCoroutineType)) return -1; return 0; @@ -1864,6 +1957,10 @@ static PyMemberDef __pyx_Generator_memberlist[] = { {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif {0, 0, 0, 0, 0} }; @@ -1873,10 +1970,35 @@ static PyGetSetDef __pyx_Generator_getsets[] = { {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, (char*) PyDoc_STR("qualified name of the generator"), 0}, {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, - (char*) PyDoc_STR("Frame of the coroutine"), 0}, + (char*) PyDoc_STR("Frame of the generator"), 0}, {0, 0, 0, 0, 0} }; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; + +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + __pyx_GeneratorType_slots +}; +#else /* CYTHON_USE_TYPE_SPECS */ + static PyTypeObject __pyx_GeneratorType_type = { PyVarObject_HEAD_INIT(0, 0) __PYX_TYPE_MODULE_PREFIX "generator", /*tp_name*/ @@ -1886,7 +2008,7 @@ static PyTypeObject __pyx_GeneratorType_type = { 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_compare / tp_as_async*/ + 0, /*tp_as_async*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -1944,13 +2066,18 @@ static PyTypeObject __pyx_GeneratorType_type = { 0, /*tp_pypy_flags*/ #endif }; +#endif /* CYTHON_USE_TYPE_SPECS */ -static int __pyx_Generator_init(void) { +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + (void) module; // on Windows, C-API functions can't be used in slots statically __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; - __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif if (unlikely(!__pyx_GeneratorType)) { return -1; } @@ -2283,11 +2410,15 @@ old_types.add(_cython_generator_type) #define __Pyx_StopAsyncIteration_USED static PyObject *__Pyx_PyExc_StopAsyncIteration; -static int __pyx_StopAsyncIteration_init(void); /*proto*/ +static int __pyx_StopAsyncIteration_init(PyObject *module); /*proto*/ //////////////////// StopAsyncIteration //////////////////// #if PY_VERSION_HEX < 0x030500B1 +#if CYTHON_USE_TYPE_SPECS +#error Using async coroutines with type specs requires Python 3.5 or later. +#else + static PyTypeObject __Pyx__PyExc_StopAsyncIteration_type = { PyVarObject_HEAD_INIT(0, 0) "StopAsyncIteration", /*tp_name*/ @@ -2344,9 +2475,11 @@ static PyTypeObject __Pyx__PyExc_StopAsyncIteration_type = { #endif }; #endif +#endif -static int __pyx_StopAsyncIteration_init(void) { +static int __pyx_StopAsyncIteration_init(PyObject *module) { #if PY_VERSION_HEX >= 0x030500B1 + (void) module; __Pyx_PyExc_StopAsyncIteration = PyExc_StopAsyncIteration; #else PyObject *builtins = PyEval_GetBuiltins(); @@ -2364,6 +2497,7 @@ static int __pyx_StopAsyncIteration_init(void) { __Pyx__PyExc_StopAsyncIteration_type.tp_dictoffset = ((PyTypeObject*)PyExc_BaseException)->tp_dictoffset; __Pyx__PyExc_StopAsyncIteration_type.tp_base = (PyTypeObject*)PyExc_Exception; + (void) module; __Pyx_PyExc_StopAsyncIteration = (PyObject*) __Pyx_FetchCommonType(&__Pyx__PyExc_StopAsyncIteration_type); if (unlikely(!__Pyx_PyExc_StopAsyncIteration)) return -1; diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c index 69e325e12..b3021b944 100644 --- a/Cython/Utility/CythonFunction.c +++ b/Cython/Utility/CythonFunction.c @@ -10,8 +10,16 @@ #define __Pyx_CyFunction_GetClosure(f) \ (((__pyx_CyFunctionObject *) (f))->func_closure) -#define __Pyx_CyFunction_GetClassObj(f) \ - (((__pyx_CyFunctionObject *) (f))->func_classobj) + +#if PY_VERSION_HEX < 0x030900B1 + #define __Pyx_CyFunction_GetClassObj(f) \ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f) \ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj) \ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) #define __Pyx_CyFunction_Defaults(type, f) \ ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) @@ -20,7 +28,12 @@ typedef struct { +#if PY_VERSION_HEX < 0x030900B1 PyCFunctionObject func; +#else + // PEP-573: PyCFunctionObject + mm_class + PyCMethodObject func; +#endif #if CYTHON_BACKPORT_VECTORCALL __pyx_vectorcallfunc func_vectorcall; #endif @@ -34,9 +47,10 @@ typedef struct { PyObject *func_globals; PyObject *func_code; PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 // No-args super() class cell PyObject *func_classobj; - +#endif // Dynamic default args and annotations void *defaults; int defaults_pyobjects; @@ -53,7 +67,7 @@ typedef struct { PyObject *func_is_coroutine; } __pyx_CyFunctionObject; -#if !CYTHON_COMPILING_IN_LIMITED_API +#if !CYTHON_USE_MODULE_STATE static PyTypeObject *__pyx_CyFunctionType = 0; #endif @@ -67,6 +81,7 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef * PyObject *module, PyObject *globals, PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, size_t size, int pyobjects); @@ -78,16 +93,17 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, PyObject *dict); -static int __pyx_CyFunction_init(void); +static int __pyx_CyFunction_init(PyObject *module); #if CYTHON_METH_FASTCALL static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); #if CYTHON_BACKPORT_VECTORCALL #define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) #else -#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func.vectorcall) +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) #endif #endif @@ -96,19 +112,31 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, //@requires: CommonStructures.c::FetchCommonType //@requires: ObjectHandling.c::PyMethodNew //@requires: ObjectHandling.c::PyVectorcallFastCallDict +//@requires: ModuleSetupCode.c::IncludeStructmemberH //@requires: ObjectHandling.c::PyObjectGetAttrStr -#include <structmember.h> +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { + __Pyx_Py_XDECREF_SET( +#if PY_VERSION_HEX < 0x030900B1 + __Pyx_CyFunction_GetClassObj(f), +#else + // assigning to "mm_class", which is a "PyTypeObject*" + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*) +#endif + ((classobj) ? __Pyx_NewRef(classobj) : NULL) + ); +} static PyObject * __Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure) { if (unlikely(op->func_doc == NULL)) { - if (op->func.m_ml->ml_doc) { + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { #if PY_MAJOR_VERSION >= 3 - op->func_doc = PyUnicode_FromString(op->func.m_ml->ml_doc); + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); #else - op->func_doc = PyString_FromString(op->func.m_ml->ml_doc); + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); #endif if (unlikely(op->func_doc == NULL)) return NULL; @@ -138,9 +166,9 @@ __Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *contex { if (unlikely(op->func_name == NULL)) { #if PY_MAJOR_VERSION >= 3 - op->func_name = PyUnicode_InternFromString(op->func.m_ml->ml_name); + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); #else - op->func_name = PyString_InternFromString(op->func.m_ml->ml_name); + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); #endif if (unlikely(op->func_name == NULL)) return NULL; @@ -437,9 +465,16 @@ static PyGetSetDef __pyx_CyFunction_getsets[] = { }; static PyMemberDef __pyx_CyFunction_members[] = { - {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), PY_WRITE_RESTRICTED, 0}, -#if CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#if CYTHON_USE_TYPE_SPECS {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif #if PY_VERSION_HEX < 0x030500A0 {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, #else @@ -456,7 +491,7 @@ __Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, CYTHON_UNUSED PyObject *args) Py_INCREF(m->func_qualname); return m->func_qualname; #else - return PyString_FromString(m->func.m_ml->ml_name); + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); #endif } @@ -469,27 +504,32 @@ static PyMethodDef __pyx_CyFunction_methods[] = { #if PY_VERSION_HEX < 0x030500A0 #define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) #else -#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist) +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) #endif static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyCFunctionObject *cf = (PyCFunctionObject*) op; if (unlikely(op == NULL)) return NULL; op->flags = flags; __Pyx_CyFunction_weakreflist(op) = NULL; - op->func.m_ml = ml; - op->func.m_self = (PyObject *) op; + cf->m_ml = ml; + cf->m_self = (PyObject *) op; Py_XINCREF(closure); op->func_closure = closure; Py_XINCREF(module); - op->func.m_module = module; + cf->m_module = module; op->func_dict = NULL; op->func_name = NULL; Py_INCREF(qualname); op->func_qualname = qualname; op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif op->func_globals = globals; Py_INCREF(op->func_globals); Py_XINCREF(code); @@ -504,7 +544,7 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * op->func_annotations = NULL; op->func_is_coroutine = NULL; #if CYTHON_METH_FASTCALL - switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS)) { + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_NOARGS: __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; break; @@ -512,6 +552,9 @@ static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef * __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; break; // case METH_FASTCALL is not used + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; case METH_FASTCALL | METH_KEYWORDS: __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; break; @@ -532,14 +575,22 @@ static int __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) { Py_CLEAR(m->func_closure); - Py_CLEAR(m->func.m_module); + Py_CLEAR(((PyCFunctionObject*)m)->m_module); Py_CLEAR(m->func_dict); Py_CLEAR(m->func_name); Py_CLEAR(m->func_qualname); Py_CLEAR(m->func_doc); Py_CLEAR(m->func_globals); Py_CLEAR(m->func_code); - Py_CLEAR(m->func_classobj); +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif Py_CLEAR(m->defaults_tuple); Py_CLEAR(m->defaults_kwdict); Py_CLEAR(m->func_annotations); @@ -564,7 +615,7 @@ static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) if (__Pyx_CyFunction_weakreflist(m) != NULL) PyObject_ClearWeakRefs((PyObject *) m); __Pyx_CyFunction_clear(m); - PyObject_GC_Del(m); + __Pyx_PyHeapTypeObject_GC_Del(m); } static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) @@ -576,14 +627,14 @@ static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) { Py_VISIT(m->func_closure); - Py_VISIT(m->func.m_module); + Py_VISIT(((PyCFunctionObject*)m)->m_module); Py_VISIT(m->func_dict); Py_VISIT(m->func_name); Py_VISIT(m->func_qualname); Py_VISIT(m->func_doc); Py_VISIT(m->func_globals); Py_VISIT(m->func_code); - Py_VISIT(m->func_classobj); + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); Py_VISIT(m->defaults_tuple); Py_VISIT(m->defaults_kwdict); Py_VISIT(m->func_is_coroutine); @@ -727,14 +778,14 @@ static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionO if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { if (unlikely(nargs < 1)) { PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", - cyfunc->func.m_ml->ml_name); + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); return -1; } ret = 1; } if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", cyfunc->func.m_ml->ml_name); + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); return -1; } return ret; @@ -743,7 +794,7 @@ static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionO static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; - PyMethodDef* def = cyfunc->func.m_ml; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; #if CYTHON_BACKPORT_VECTORCALL Py_ssize_t nargs = (Py_ssize_t)nargsf; #else @@ -757,7 +808,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c nargs -= 1; break; case 0: - self = cyfunc->func.m_self; + self = ((PyCFunctionObject*)cyfunc)->m_self; break; default: return NULL; @@ -775,7 +826,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; - PyMethodDef* def = cyfunc->func.m_ml; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; #if CYTHON_BACKPORT_VECTORCALL Py_ssize_t nargs = (Py_ssize_t)nargsf; #else @@ -789,7 +840,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const nargs -= 1; break; case 0: - self = cyfunc->func.m_self; + self = ((PyCFunctionObject*)cyfunc)->m_self; break; default: return NULL; @@ -807,7 +858,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; - PyMethodDef* def = cyfunc->func.m_ml; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; #if CYTHON_BACKPORT_VECTORCALL Py_ssize_t nargs = (Py_ssize_t)nargsf; #else @@ -821,7 +872,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, nargs -= 1; break; case 0: - self = cyfunc->func.m_self; + self = ((PyCFunctionObject*)cyfunc)->m_self; break; default: return NULL; @@ -829,9 +880,36 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, return ((_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); } + +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); #endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } -#if CYTHON_COMPILING_IN_LIMITED_API + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, nargs, kwnames); +} +#endif + +#if CYTHON_USE_TYPE_SPECS static PyType_Slot __pyx_CyFunctionType_slots[] = { {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, @@ -849,11 +927,17 @@ static PyType_Spec __pyx_CyFunctionType_spec = { __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", sizeof(__pyx_CyFunctionObject), 0, - // TODO: Support _Py_TPFLAGS_HAVE_VECTORCALL and _Py_TPFLAGS_HAVE_VECTORCALL - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#ifdef _Py_TPFLAGS_HAVE_VECTORCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /*tp_flags*/ __pyx_CyFunctionType_slots }; -#else +#else /* CYTHON_USE_TYPE_SPECS */ + static PyTypeObject __pyx_CyFunctionType_type = { PyVarObject_HEAD_INIT(0, 0) __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", /*tp_name*/ @@ -865,7 +949,7 @@ static PyTypeObject __pyx_CyFunctionType_type = { #elif CYTHON_BACKPORT_VECTORCALL (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), /*tp_vectorcall_offset backported into tp_print*/ #else - offsetof(__pyx_CyFunctionObject, func.vectorcall), /*tp_vectorcall_offset*/ + offsetof(PyCFunctionObject, vectorcall), /*tp_vectorcall_offset*/ #endif 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -890,7 +974,7 @@ static PyTypeObject __pyx_CyFunctionType_type = { #ifdef _Py_TPFLAGS_HAVE_VECTORCALL _Py_TPFLAGS_HAVE_VECTORCALL | #endif - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 0, /*tp_doc*/ (traverseproc) __Pyx_CyFunction_traverse, /*tp_traverse*/ (inquiry) __Pyx_CyFunction_clear, /*tp_clear*/ @@ -935,13 +1019,14 @@ static PyTypeObject __pyx_CyFunctionType_type = { 0, /*tp_pypy_flags*/ #endif }; -#endif /* CYTHON_COMPILING_IN_LIMITED_API */ +#endif /* CYTHON_USE_TYPE_SPECS */ -static int __pyx_CyFunction_init(void) { -#if CYTHON_COMPILING_IN_LIMITED_API - __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(&__pyx_CyFunctionType_spec, NULL); +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); #else + (void) module; __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); #endif if (unlikely(__pyx_CyFunctionType == NULL)) { @@ -1023,8 +1108,7 @@ static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *class if (unlikely(!m)) return -1; #endif - Py_INCREF(classobj); - m->func_classobj = classobj; + __Pyx_CyFunction_SetClassObj(m, classobj); #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) Py_DECREF((PyObject*)m); #endif @@ -1047,10 +1131,10 @@ static PyObject *__pyx_FusedFunction_New(PyMethodDef *ml, int flags, PyObject *code); static int __pyx_FusedFunction_clear(__pyx_FusedFunctionObject *self); -#if !CYTHON_COMPILING_IN_LIMITED_API +#if !CYTHON_USE_MODULE_STATE static PyTypeObject *__pyx_FusedFunctionType = NULL; #endif -static int __pyx_FusedFunction_init(void); +static int __pyx_FusedFunction_init(PyObject *module); #define __Pyx_FusedFunction_USED @@ -1153,8 +1237,7 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) Py_XINCREF(pydefaults[i]); } - Py_XINCREF(func->func.func_classobj); - meth->func.func_classobj = func->func.func_classobj; + __Pyx_CyFunction_SetClassObj(meth, __Pyx_CyFunction_GetClassObj(func)); Py_XINCREF(func->__signatures__); meth->__signatures__ = func->__signatures__; @@ -1238,8 +1321,7 @@ __pyx_err:; __pyx_FusedFunctionObject *unbound = (__pyx_FusedFunctionObject *) unbound_result_func; // TODO: move this to InitClassCell - Py_XINCREF(self->func.func_classobj); - __Pyx_Py_XDECREF_SET(unbound->func.func_classobj, self->func.func_classobj); + __Pyx_CyFunction_SetClassObj(unbound, __Pyx_CyFunction_GetClassObj(self)); result_func = __pyx_FusedFunction_descr_get(unbound_result_func, self->self, self->self); @@ -1334,8 +1416,7 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) if (unlikely(!new_func)) goto bad; - Py_XINCREF(binding_func->func.func_classobj); - __Pyx_Py_XDECREF_SET(new_func->func.func_classobj, binding_func->func.func_classobj); + __Pyx_CyFunction_SetClassObj(new_func, __Pyx_CyFunction_GetClassObj(binding_func)); func = (PyObject *) new_func; } @@ -1377,7 +1458,7 @@ static PyGetSetDef __pyx_FusedFunction_getsets[] = { {0, 0, 0, 0, 0} }; -#if CYTHON_COMPILING_IN_LIMITED_API +#if CYTHON_USE_TYPE_SPECS static PyType_Slot __pyx_FusedFunctionType_slots[] = { {Py_tp_dealloc, (void *)__pyx_FusedFunction_dealloc}, {Py_tp_call, (void *)__pyx_FusedFunction_call}, @@ -1398,7 +1479,7 @@ static PyType_Spec __pyx_FusedFunctionType_spec = { __pyx_FusedFunctionType_slots }; -#else /* !CYTHON_COMPILING_IN_LIMITED_API */ +#else /* !CYTHON_USE_TYPE_SPECS */ static PyMappingMethods __pyx_FusedFunction_mapping_methods = { 0, @@ -1474,15 +1555,16 @@ static PyTypeObject __pyx_FusedFunctionType_type = { }; #endif -static int __pyx_FusedFunction_init(void) { -#if CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_FusedFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS PyObject *bases = PyTuple_Pack(1, __pyx_CyFunctionType); if (unlikely(!bases)) { return -1; } - __pyx_FusedFunctionType = __Pyx_FetchCommonTypeFromSpec(&__pyx_FusedFunctionType_spec, bases); + __pyx_FusedFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_FusedFunctionType_spec, bases); Py_DECREF(bases); #else + (void) module; // Set base from __Pyx_FetchCommonTypeFromSpec, in case it's different from the local static value. __pyx_FusedFunctionType_type.tp_base = __pyx_CyFunctionType; __pyx_FusedFunctionType = __Pyx_FetchCommonType(&__pyx_FusedFunctionType_type); diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c index 26bc2d9d9..e19df8578 100644 --- a/Cython/Utility/ExtensionTypes.c +++ b/Cython/Utility/ExtensionTypes.c @@ -1,13 +1,104 @@ -/////////////// PyType_Ready.proto /////////////// +/////////////// FixUpExtensionType.proto /////////////// -static int __Pyx_PyType_Ready(PyTypeObject *t); +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); /*proto*/ +#endif -/////////////// PyType_Ready /////////////// -//@requires: ObjectHandling.c::PyObjectCallNoArg +/////////////// FixUpExtensionType /////////////// +//@requires:ModuleSetupCode.c::IncludeStructmemberH +//@requires:StringTools.c::IncludeStringH -// Wrapper around PyType_Ready() with some runtime checks and fixes -// to deal with multiple inheritance. -static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + (void) spec; + (void) type; +#else + // Set tp_weakreflist, tp_dictoffset, tp_vectorcalloffset + // Copied and adapted from https://bugs.python.org/issue38140 + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + // The PyMemberDef must be a Py_ssize_t and readonly. + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + // FIXME: is it even worth calling PyType_Modified() here? + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + // The PyMemberDef must be a Py_ssize_t and readonly. + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + // FIXME: is it even worth calling PyType_Modified() here? + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + // The PyMemberDef must be a Py_ssize_t and readonly. + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + // FIXME: is it even worth calling PyType_Modified() here? + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + // PyType_FromSpec() in CPython <= 3.9b1 overwrites this field with a constant string. + // See https://bugs.python.org/issue40703 + PyObject *descr; + // The PyMemberDef must be an object and normally readable, possibly writable. + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + + +/////////////// ValidateBasesTuple.proto /////////////// + +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); /*proto*/ + +/////////////// ValidateBasesTuple /////////////// + +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { // Loop over all bases (except the first) and check that those // really are heap types. Otherwise, it would not be safe to // subclass them. @@ -18,49 +109,63 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { // tp_dictoffset (i.e. there is no __dict__ attribute in the object // structure), we need to check that none of the base classes sets // it either. - int r; - PyObject *bases = t->tp_bases; - if (bases) + Py_ssize_t i, n = PyTuple_GET_SIZE(bases); + for (i = 1; i < n; i++) /* Skip first base */ { - Py_ssize_t i, n = PyTuple_GET_SIZE(bases); - for (i = 1; i < n; i++) /* Skip first base */ - { - PyObject *b0 = PyTuple_GET_ITEM(bases, i); - PyTypeObject *b; + PyObject *b0 = PyTuple_GET_ITEM(bases, i); + PyTypeObject *b; #if PY_MAJOR_VERSION < 3 - /* Disallow old-style classes */ - if (PyClass_Check(b0)) - { - PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", - PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); - return -1; - } + /* Disallow old-style classes */ + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); + return -1; + } #endif - b = (PyTypeObject*)b0; - if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) - { - __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); - PyErr_Format(PyExc_TypeError, - "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); - __Pyx_DECREF_TypeName(b_name); - return -1; - } - if (t->tp_dictoffset == 0 && b->tp_dictoffset) - { - __Pyx_TypeName t_name = __Pyx_PyType_GetName(t); - __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); - PyErr_Format(PyExc_TypeError, - "extension type '" __Pyx_FMT_TYPENAME "' has no __dict__ slot, " - "but base type '" __Pyx_FMT_TYPENAME "' has: " - "either add 'cdef dict __dict__' to the extension type " - "or add '__slots__ = [...]' to the base type", - t_name, b_name); - __Pyx_DECREF_TypeName(t_name); - __Pyx_DECREF_TypeName(b_name); - return -1; - } + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); + return -1; + } + if (dictoffset == 0 && b->tp_dictoffset) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + return -1; } } + return 0; +} + + +/////////////// PyType_Ready.proto /////////////// + +#if !CYTHON_USE_TYPE_SPECS +static int __Pyx_PyType_Ready(PyTypeObject *t); +#endif + +/////////////// PyType_Ready /////////////// +//@requires: ObjectHandling.c::PyObjectCallNoArg +//@requires: ValidateBasesTuple + +// Wrapper around PyType_Ready() with some runtime checks and fixes +// to deal with multiple inheritance. +#if !CYTHON_USE_TYPE_SPECS +static int __Pyx_PyType_Ready(PyTypeObject *t) { + int r; + if (t->tp_bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, t->tp_bases) == -1)) + return -1; #if PY_VERSION_HEX >= 0x03050000 { @@ -136,6 +241,7 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { return r; } +#endif /////////////// PyTrashcan.proto /////////////// diff --git a/Cython/Utility/ImportExport.c b/Cython/Utility/ImportExport.c index 655781ee1..523de2010 100644 --- a/Cython/Utility/ImportExport.c +++ b/Cython/Utility/ImportExport.c @@ -693,22 +693,18 @@ bad: /////////////// SetVTable.proto /////////////// -static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); /*proto*/ /////////////// SetVTable /////////////// -#if CYTHON_COMPILING_IN_LIMITED_API -static int __Pyx_SetVtable(PyObject *type, void *vtable) { -#else -static int __Pyx_SetVtable(PyObject *dict, void *vtable) { -#endif +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { PyObject *ob = PyCapsule_New(vtable, 0, 0); - if (!ob) + if (unlikely(!ob)) goto bad; #if CYTHON_COMPILING_IN_LIMITED_API - if (PyObject_SetAttr(type, PYIDENT("__pyx_vtable__"), ob) < 0) + if (unlikely(PyObject_SetAttr((PyObject *) type, PYIDENT("__pyx_vtable__"), ob) < 0)) #else - if (PyDict_SetItem(dict, PYIDENT("__pyx_vtable__"), ob) < 0) + if (unlikely(PyDict_SetItem(type->tp_dict, PYIDENT("__pyx_vtable__"), ob) < 0)) #endif goto bad; Py_DECREF(ob); diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c index 3929bc64b..4ddc9da05 100644 --- a/Cython/Utility/ModuleSetupCode.c +++ b/Cython/Utility/ModuleSetupCode.c @@ -61,6 +61,8 @@ #undef CYTHON_USE_TYPE_SLOTS #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 #undef CYTHON_USE_PYTYPE_LOOKUP #define CYTHON_USE_PYTYPE_LOOKUP 0 #if PY_VERSION_HEX < 0x03050000 @@ -96,6 +98,8 @@ #endif #undef CYTHON_PEP489_MULTI_PHASE_INIT #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 #undef CYTHON_USE_TP_FINALIZE #define CYTHON_USE_TP_FINALIZE 0 #undef CYTHON_USE_DICT_VERSIONS @@ -112,6 +116,8 @@ #ifndef CYTHON_USE_TYPE_SLOTS #define CYTHON_USE_TYPE_SLOTS 1 #endif + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 #undef CYTHON_USE_PYTYPE_LOOKUP #define CYTHON_USE_PYTYPE_LOOKUP 0 #undef CYTHON_USE_ASYNC_SLOTS @@ -146,6 +152,8 @@ #define CYTHON_PEP487_INIT_SUBCLASS 0 #undef CYTHON_PEP489_MULTI_PHASE_INIT #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 #undef CYTHON_USE_TP_FINALIZE #define CYTHON_USE_TP_FINALIZE 0 #undef CYTHON_USE_DICT_VERSIONS @@ -154,6 +162,7 @@ #define CYTHON_USE_EXC_INFO_STACK 0 #elif defined(CYTHON_LIMITED_API) + // EXPERIMENTAL !! #define CYTHON_COMPILING_IN_PYPY 0 #define CYTHON_COMPILING_IN_PYSTON 0 #define CYTHON_COMPILING_IN_CPYTHON 0 @@ -161,6 +170,8 @@ #undef CYTHON_USE_TYPE_SLOTS #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 #undef CYTHON_USE_PYTYPE_LOOKUP #define CYTHON_USE_PYTYPE_LOOKUP 0 #undef CYTHON_USE_ASYNC_SLOTS @@ -194,6 +205,8 @@ #endif #undef CYTHON_PEP489_MULTI_PHASE_INIT #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 #ifndef CYTHON_USE_TP_FINALIZE #define CYTHON_USE_TP_FINALIZE 1 #endif @@ -211,6 +224,9 @@ #ifndef CYTHON_USE_TYPE_SLOTS #define CYTHON_USE_TYPE_SLOTS 1 #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif #ifndef CYTHON_USE_PYTYPE_LOOKUP #define CYTHON_USE_PYTYPE_LOOKUP 1 #endif @@ -262,17 +278,33 @@ #ifndef CYTHON_PEP487_INIT_SUBCLASS #define CYTHON_PEP487_INIT_SUBCLASS 1 #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) + #ifndef CYTHON_USE_MODULE_STATE + // EXPERIMENTAL !! + #define CYTHON_USE_MODULE_STATE 0 #endif - #ifndef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1) + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS 1 #endif - #ifndef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3) + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 #endif #endif @@ -565,6 +597,18 @@ class __Pyx_FakeReference { #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) #endif +// PEP-573: PyCFunction holds reference to defining class (PyCMethodObject) +#if PY_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif + #if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) #define PyObject_Malloc(s) PyMem_Malloc(s) #define PyObject_Free(p) PyMem_Free(p) @@ -604,7 +648,7 @@ class __Pyx_FakeReference { #endif #if CYTHON_COMPILING_IN_LIMITED_API -static inline void *__Pyx_PyModule_GetState(PyObject *op) +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) { void *result; @@ -704,20 +748,30 @@ static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, #endif /* Type slots */ -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) -#else - #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) -#endif #if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) #else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next #endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +// In Py3.8+, instances of heap types need to decref their type on deallocation. +// https://bugs.python.org/issue35810 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) { \ + PyTypeObject *type = Py_TYPE(obj); \ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)); \ + PyObject_GC_Del(obj); \ + Py_DECREF(type); \ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif + #if CYTHON_COMPILING_IN_LIMITED_API #define CYTHON_PEP393_ENABLED 1 #define __Pyx_PyUnicode_READY(op) (0) @@ -902,6 +956,12 @@ static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, } __Pyx_PyAsyncMethodsStruct; #endif + +/////////////// IncludeStructmemberH.proto /////////////// + +#include <structmember.h> + + /////////////// SmallCodeConfig.proto /////////////// #ifndef CYTHON_SMALL_CODE diff --git a/Cython/Utility/ObjectHandling.c b/Cython/Utility/ObjectHandling.c index 903c03833..bd6e438da 100644 --- a/Cython/Utility/ObjectHandling.c +++ b/Cython/Utility/ObjectHandling.c @@ -1575,6 +1575,7 @@ static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) #endif { PyObject *result; +// FIXME: clean up the macro guard order here: limited API first, then borrowed refs, then cpython #if !CYTHON_AVOID_BORROWED_REFS #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 // Identifier names are always interned and have a pre-calculated hash value. diff --git a/appveyor.yml b/appveyor.yml index a6ad04ea7..8148e517c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,7 @@ environment: WITH_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd" BACKEND: c PARALLEL: "-j4" + EXTRA_CFLAGS: "" matrix: - PYTHON: "C:\\Python27" @@ -38,6 +39,11 @@ environment: - PYTHON: "C:\\Python38-x64" PYTHON_VERSION: "3.8" PYTHON_ARCH: "64" + EXTRA_CFLAGS: "-DCYTHON_USE_TYPE_SPECS=1" + + - PYTHON: "C:\\Python38-x64" + PYTHON_VERSION: "3.8" + PYTHON_ARCH: "64" BACKEND: c,cpp - PYTHON: "C:\\Python37" @@ -49,6 +55,16 @@ environment: PYTHON_VERSION: "3.7" PYTHON_ARCH: "64" + - PYTHON: "C:\\Python37-x64" + PYTHON_VERSION: "3.7" + PYTHON_ARCH: "64" + EXTRA_CFLAGS: "-DCYTHON_USE_TYPE_SPECS=1" + + - PYTHON: "C:\\Python37-x64" + PYTHON_VERSION: "3.7" + PYTHON_ARCH: "64" + BACKEND: cpp + - PYTHON: "C:\\Python36" PYTHON_VERSION: "3.6" PYTHON_ARCH: "32" @@ -108,7 +124,7 @@ test: off test_script: - "%PYTHON%\\Scripts\\pip.exe install -r test-requirements.txt" - "%PYTHON%\\Scripts\\pip.exe install win_unicode_console" - - "set CFLAGS=/Od /W3" + - "set CFLAGS=/Od /W3 %EXTRA_CFLAGS%" - "%WITH_ENV% %PYTHON%\\python.exe runtests.py -vv --backend=%BACKEND% --no-code-style -j5" artifacts: diff --git a/tests/compile/types_and_names.pyx b/tests/compile/types_and_names.pyx index 8ded94e4d..2637d4ba6 100644 --- a/tests/compile/types_and_names.pyx +++ b/tests/compile/types_and_names.pyx @@ -23,3 +23,16 @@ cdef A a foo(2, 3, [], [], P, P, &P) a.point("something", 3, "anything", [], "an object", P, &P) + +# Test that internally generated names do not conflict. +cdef class A_spec: + pass + +cdef class A_members: + pass + +cdef class A_methods: + pass + +cdef class A_slots: + pass diff --git a/tests/limited_api_bugs.txt b/tests/limited_api_bugs.txt index 60baf6eb4..b98ff76c0 100644 --- a/tests/limited_api_bugs.txt +++ b/tests/limited_api_bugs.txt @@ -6,3 +6,6 @@ dict_animal not_none queue3 test_queue +memoryview +memview +buffer diff --git a/tests/run/cdef_multiple_inheritance_errors.srctree b/tests/run/cdef_multiple_inheritance_errors.srctree index dd4aaa200..4f49184f4 100644 --- a/tests/run/cdef_multiple_inheritance_errors.srctree +++ b/tests/run/cdef_multiple_inheritance_errors.srctree @@ -65,31 +65,31 @@ import sys try: import notheaptype - assert False + assert False, "notheaptype" except TypeError as msg: assert str(msg) == "base class 'object' is not a heap type" try: import wrongbase - assert False + assert False, "wrongbase" except TypeError as msg: assert str(msg) == "best base 'str' must be equal to first base 'wrongbase.Base'" try: import badmro - assert False + assert False, "badmro" except TypeError as msg: assert str(msg).startswith("Cannot create a consistent method resolution") try: import nodict - assert False + assert False, "nodict" except TypeError as msg: assert str(msg) == "extension type 'nodict.X' has no __dict__ slot, but base type 'Py' has: either add 'cdef dict __dict__' to the extension type or add '__slots__ = [...]' to the base type" try: # This should work on Python 3 but fail on Python 2 import oldstyle - assert sys.version_info[0] >= 3 + assert sys.version_info[0] >= 3, "oldstyle" except TypeError as msg: assert str(msg) == "base class 'OldStyle' is an old-style class" |