Commit 3d918433 authored by Xavier Thompson's avatar Xavier Thompson

Defer declaration analysis of cpp classes until all bases have been analysed

parent 034a53fd
...@@ -1507,6 +1507,8 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1507,6 +1507,8 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
# decorators [DecoratorNode] or None # decorators [DecoratorNode] or None
decorators = None decorators = None
scope = None
template_types = None
def declare(self, env): def declare(self, env):
if not env.is_cpp(): if not env.is_cpp():
...@@ -1519,6 +1521,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1519,6 +1521,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
num_optional_templates = sum(not required for _, required in self.templates) num_optional_templates = sum(not required for _, required in self.templates)
if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]): if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]):
error(self.pos, "Required template parameters must precede optional template parameters.") error(self.pos, "Required template parameters must precede optional template parameters.")
self.template_types = template_types
self.entry = env.declare_cpp_class( self.entry = env.declare_cpp_class(
self.name, None, self.pos, self.cname, self.name, None, self.pos, self.cname,
base_classes=[], visibility=self.visibility, templates=template_types, base_classes=[], visibility=self.visibility, templates=template_types,
...@@ -1526,37 +1529,55 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1526,37 +1529,55 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
def analyse_declarations(self, env): def analyse_declarations(self, env):
if self.templates is None: if self.templates is None:
template_types = template_names = None template_names = None
else: else:
template_names = [template_name for template_name, _ in self.templates] template_names = [template_name for template_name, _ in self.templates]
template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) if self.template_types is None:
for template_name, required in self.templates] self.template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required)
scope = None for template_name, required in self.templates]
if self.attributes is not None:
template_types = self.template_types
if self.scope is None and self.attributes is not None:
scope = CppClassScope(self.name, env, templates=template_names) scope = CppClassScope(self.name, env, templates=template_names)
self.scope = scope
scope = self.scope
def base_ok(base_class): def base_ok(base_class):
if base_class.is_cpp_class or base_class.is_struct: if base_class.is_cpp_class or base_class.is_struct:
return True return True
else: else:
error(self.pos, "Base class '%s' not a struct or class." % base_class) error(self.pos, "Base class '%s' not a struct or class." % base_class)
base_types_list = [b.analyse(scope or env) for b in self.base_classes] base_types_list = [b.analyse(scope or env) for b in self.base_classes]
base_class_types = list(filter(base_ok, base_types_list))
# if this is not just a forward declaration, defer analysis until all base classes are analysed
if scope:
for base_type in base_class_types:
if not base_type.scope:
base_type.deferred_declarations.append(lambda: self.analyse_declarations(env))
return
# add implicit cyobject or acthon base if this cypclass has no explicit cypclass bases
if self.cypclass: if self.cypclass:
if self.activable: if self.activable:
activable_base = False activable_base = False
for base_type in base_types_list: for base_type in base_class_types:
if not base_type.activable: if not base_type.activable:
error(self.pos, "Activable class cannot inherit from not activable one.") error(self.pos, "Activable class cannot inherit from not activable one.")
activable_base = activable_base or base_type.activable activable_base = activable_base or base_type.activable
if not activable_base: if not activable_base:
from . import Builtin from . import Builtin
base_types_list.append(Builtin.acthon_activable_type) base_class_types.append(Builtin.acthon_activable_type)
cyobject_base = False cyobject_base = False
for base_type in base_types_list: for base_type in base_class_types:
cyobject_base = cyobject_base or base_type.is_cyp_class cyobject_base = cyobject_base or base_type.is_cyp_class
if not cyobject_base: if not cyobject_base:
base_types_list.append(cy_object_type) base_class_types.append(cy_object_type)
base_class_types = filter(base_ok, base_types_list)
self.entry = env.declare_cpp_class( self.entry = env.declare_cpp_class(
self.name, scope, self.pos, self.name, scope, self.pos,
self.cname, base_class_types, visibility=self.visibility, templates=template_types, self.cname, base_class_types, visibility=self.visibility, templates=template_types,
...@@ -1590,7 +1611,10 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1590,7 +1611,10 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
if self.templates is not None: if self.templates is not None:
func.template_declaration = "template <typename %s>" % ", typename ".join(template_names) func.template_declaration = "template <typename %s>" % ", typename ".join(template_names)
self.body = StatListNode(self.pos, stats=defined_funcs) self.body = StatListNode(self.pos, stats=defined_funcs)
self.scope = scope
# analyse the subclasses that were waiting for this class (their base) to be analysed
for thunk in self.entry.type.deferred_declarations:
thunk()
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.body = self.body.analyse_expressions(self.entry.type.scope) self.body = self.body.analyse_expressions(self.entry.type.scope)
......
...@@ -3494,12 +3494,14 @@ class CStructOrUnionType(CType): ...@@ -3494,12 +3494,14 @@ class CStructOrUnionType(CType):
# scope StructOrUnionScope, or None if incomplete # scope StructOrUnionScope, or None if incomplete
# typedef_flag boolean # typedef_flag boolean
# packed boolean # packed boolean
# deferred_declarations [thunk] or None Used to declare class hierarchies in order (None when this type is an union)
# entry Entry # entry Entry
is_struct_or_union = 1 is_struct_or_union = 1
has_attributes = 1 has_attributes = 1
exception_check = True exception_check = True
deferred_declarations = None
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False): def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name self.name = name
...@@ -3508,6 +3510,8 @@ class CStructOrUnionType(CType): ...@@ -3508,6 +3510,8 @@ class CStructOrUnionType(CType):
self.scope = scope self.scope = scope
self.typedef_flag = typedef_flag self.typedef_flag = typedef_flag
self.is_struct = kind == 'struct' self.is_struct = kind == 'struct'
if self.is_struct:
self.deferred_declarations = []
self.to_py_function = "%s_to_py_%s" % ( self.to_py_function = "%s_to_py_%s" % (
Naming.convert_func_prefix, self.specialization_name()) Naming.convert_func_prefix, self.specialization_name())
self.from_py_function = "%s_from_py_%s" % ( self.from_py_function = "%s_from_py_%s" % (
...@@ -3683,6 +3687,7 @@ class CppClassType(CType): ...@@ -3683,6 +3687,7 @@ class CppClassType(CType):
# cname string # cname string
# scope CppClassScope # scope CppClassScope
# templates [string] or None # templates [string] or None
# deferred_declarations [thunk] Used to declare class hierarchies in order
is_cpp_class = 1 is_cpp_class = 1
has_attributes = 1 has_attributes = 1
...@@ -3701,6 +3706,7 @@ class CppClassType(CType): ...@@ -3701,6 +3706,7 @@ class CppClassType(CType):
self.cname = cname self.cname = cname
self.scope = scope self.scope = scope
self.base_classes = base_classes self.base_classes = base_classes
self.deferred_declarations = []
self.operators = [] self.operators = []
self.templates = templates self.templates = templates
self.template_type = template_type self.template_type = template_type
......
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