Commit 33707f2e authored by Stefan Behnel's avatar Stefan Behnel

Avoid generating a tp_new() function for extension types that do not need their own one.

See #1555.
parent 85d2424f
...@@ -60,6 +60,11 @@ Bugs fixed ...@@ -60,6 +60,11 @@ Bugs fixed
semantics. It now passes through the Mapping protocol first when supported. semantics. It now passes through the Mapping protocol first when supported.
(Github issue #1807) (Github issue #1807)
* Extension types that do not need their own ``tp_new`` implementation (because
they have no object attributes etc.) directly inherit the implementation of
their parent type if that is available in the same module.
(Github issue #1555)
* The ``Py_hash_t`` type failed to accept arbitrary "index" values. * The ``Py_hash_t`` type failed to accept arbitrary "index" values.
(Github issue #2752) (Github issue #2752)
......
...@@ -1270,8 +1270,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1270,8 +1270,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.empty_declaration_code())) type.empty_declaration_code()))
def generate_new_function(self, scope, code, cclass_entry): def generate_new_function(self, scope, code, cclass_entry):
tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__') tp_slot = TypeSlots.ConstructorSlot("tp_new", "__cinit__")
slot_func = scope.mangle_internal("tp_new") slot_func = scope.mangle_internal("tp_new")
if tp_slot.slot_code(scope) != slot_func:
return # never used
type = scope.parent_type type = scope.parent_type
base_type = type.base_type base_type = type.base_type
...@@ -1554,7 +1557,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1554,7 +1557,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_usr_dealloc_call(self, scope, code): def generate_usr_dealloc_call(self, scope, code):
entry = scope.lookup_here("__dealloc__") entry = scope.lookup_here("__dealloc__")
if not entry: if not entry or not entry.is_special:
return return
code.putln("{") code.putln("{")
......
...@@ -362,17 +362,17 @@ class GCClearReferencesSlot(GCDependentSlot): ...@@ -362,17 +362,17 @@ class GCClearReferencesSlot(GCDependentSlot):
class ConstructorSlot(InternalMethodSlot): class ConstructorSlot(InternalMethodSlot):
# Descriptor for tp_new and tp_dealloc. # Descriptor for tp_new and tp_dealloc.
def __init__(self, slot_name, method, **kargs): def __init__(self, slot_name, method=None, **kargs):
InternalMethodSlot.__init__(self, slot_name, **kargs) InternalMethodSlot.__init__(self, slot_name, **kargs)
self.method = method self.method = method
def slot_code(self, scope): def slot_code(self, scope):
entry = scope.lookup_here(self.method) entry = scope.lookup_here(self.method) if self.method else None
if (self.slot_name != 'tp_new' if (scope.parent_type.base_type
and scope.parent_type.base_type
and not scope.has_pyobject_attrs and not scope.has_pyobject_attrs
and not scope.has_memoryview_attrs and not scope.has_memoryview_attrs
and not scope.has_cpp_class_attrs and not scope.has_cpp_class_attrs
and not (self.slot_name == 'tp_new' and scope.parent_type.vtabslot_cname)
and not (entry and entry.is_special)): and not (entry and entry.is_special)):
# if the type does not have object attributes, it can # if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent # delegate GC methods to its parent - iff the parent
...@@ -382,8 +382,6 @@ class ConstructorSlot(InternalMethodSlot): ...@@ -382,8 +382,6 @@ class ConstructorSlot(InternalMethodSlot):
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern': if entry.visibility != 'extern':
return self.slot_code(parent_type_scope) return self.slot_code(parent_type_scope)
if entry and not entry.is_special:
return "0"
return InternalMethodSlot.slot_code(self, scope) return InternalMethodSlot.slot_code(self, scope)
...@@ -877,7 +875,7 @@ slot_table = ( ...@@ -877,7 +875,7 @@ slot_table = (
MethodSlot(initproc, "tp_init", "__init__"), MethodSlot(initproc, "tp_init", "__init__"),
EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"), EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
InternalMethodSlot("tp_new"), ConstructorSlot("tp_new", "__cinit__"),
EmptySlot("tp_free"), EmptySlot("tp_free"),
EmptySlot("tp_is_gc"), EmptySlot("tp_is_gc"),
......
# mode: run
# tag: exttype, tpnew
from __future__ import print_function
from cpython.object cimport PyTypeObject
cdef gobble(a, b): cdef gobble(a, b):
print a, b print(a, b)
def tp_new_ptr(exttype):
assert isinstance(exttype, type)
tp = <PyTypeObject*> exttype
return <unsigned long long><void*>tp.tp_new
cdef class Empty:
"""
>>> n = Empty()
>>> isinstance(n, Empty)
True
>>> tp_new_ptr(Empty) != 0
True
"""
cdef class EmptySubclass(Empty):
"""
>>> n = EmptySubclass()
>>> isinstance(n, EmptySubclass)
True
>>> tp_new_ptr(EmptySubclass) != 0
True
>>> tp_new_ptr(EmptySubclass) == tp_new_ptr(Empty)
True
"""
cdef class CInit:
"""
>>> c = CInit()
>>> isinstance(c, CInit)
True
"""
def __cinit__(self):
assert self is not None
cdef class Spam: cdef class Spam:
""" """
...@@ -21,6 +67,7 @@ cdef class Spam: ...@@ -21,6 +67,7 @@ cdef class Spam:
def eat(self): def eat(self):
gobble(self.eggs, self.ham) gobble(self.eggs, self.ham)
def f(Spam spam): def f(Spam spam):
""" """
>>> s = Spam(12) >>> s = Spam(12)
......
# mode: run
# tag: exttype, tpnew
# ticket: 808 # ticket: 808
cimport cython cimport cython
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment