Commit 81e51c9d authored by Robert Bradshaw's avatar Robert Bradshaw

More nullary C++ class constructor checks.

parent b640de61
...@@ -2048,6 +2048,8 @@ class CFuncDefNode(FuncDefNode): ...@@ -2048,6 +2048,8 @@ class CFuncDefNode(FuncDefNode):
if self.return_type.is_array and self.visibility != 'extern': if self.return_type.is_array and self.visibility != 'extern':
error(self.pos, error(self.pos,
"Function cannot return an array") "Function cannot return an array")
if self.return_type.is_cpp_class:
self.return_type.check_nullary_constructor(self.pos, "used as a return value")
if self.overridable and not env.is_module_scope: if self.overridable and not env.is_module_scope:
if len(self.args) < 1 or not self.args[0].type.is_pyobject: if len(self.args) < 1 or not self.args[0].type.is_pyobject:
......
...@@ -3205,6 +3205,11 @@ class CppClassType(CType): ...@@ -3205,6 +3205,11 @@ class CppClassType(CType):
func_type = func_type.base_type func_type = func_type.base_type
return func_type.return_type return func_type.return_type
def check_nullary_constructor(self, pos, msg="stack allocated"):
constructor = self.scope.lookup(u'<init>')
if constructor is not None and best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have a nullary constructor to be %s" % msg)
class TemplatePlaceholderType(CType): class TemplatePlaceholderType(CType):
......
...@@ -569,9 +569,7 @@ class Scope(object): ...@@ -569,9 +569,7 @@ class Scope(object):
else: else:
cname = self.mangle(Naming.var_prefix, name) cname = self.mangle(Naming.var_prefix, name)
if type.is_cpp_class and visibility != 'extern': if type.is_cpp_class and visibility != 'extern':
constructor = type.scope.lookup(u'<init>') type.check_nullary_constructor(pos)
if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have a no-arg constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
if in_pxd and visibility != 'extern': if in_pxd and visibility != 'extern':
...@@ -1782,10 +1780,7 @@ class CClassScope(ClassScope): ...@@ -1782,10 +1780,7 @@ class CClassScope(ClassScope):
if visibility == 'private': if visibility == 'private':
cname = c_safe_identifier(cname) cname = c_safe_identifier(cname)
if type.is_cpp_class and visibility != 'extern': if type.is_cpp_class and visibility != 'extern':
constructor = type.scope.lookup(u'<init>') type.check_nullary_constructor(pos)
if constructor is not None and \
PyrexTypes.best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have a no-arg constructor to be a member of an extension type; use a pointer instead")
self.use_utility_code(Code.UtilityCode("#include <new>")) self.use_utility_code(Code.UtilityCode("#include <new>"))
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
......
...@@ -390,7 +390,7 @@ class SimpleAssignmentTypeInferer(object): ...@@ -390,7 +390,7 @@ class SimpleAssignmentTypeInferer(object):
types = [assmt.rhs.infer_type(scope) types = [assmt.rhs.infer_type(scope)
for assmt in entry.cf_assignments] for assmt in entry.cf_assignments]
if types and Utils.all(types): if types and Utils.all(types):
entry.type = spanning_type(types, entry.might_overflow) entry.type = spanning_type(types, entry.might_overflow, entry.pos)
else: else:
# FIXME: raise a warning? # FIXME: raise a warning?
# print "No assignments", entry.pos, entry # print "No assignments", entry.pos, entry
...@@ -405,10 +405,10 @@ class SimpleAssignmentTypeInferer(object): ...@@ -405,10 +405,10 @@ class SimpleAssignmentTypeInferer(object):
for assmt in entry.cf_assignments for assmt in entry.cf_assignments
if assmt.type_dependencies(scope) == ()] if assmt.type_dependencies(scope) == ()]
if types: if types:
entry.type = spanning_type(types, entry.might_overflow) entry.type = spanning_type(types, entry.might_overflow, entry.pos)
types = [assmt.infer_type(scope) types = [assmt.infer_type(scope)
for assmt in entry.cf_assignments] for assmt in entry.cf_assignments]
entry.type = spanning_type(types, entry.might_overflow) # might be wider... entry.type = spanning_type(types, entry.might_overflow, entry.pos) # might be wider...
resolve_dependancy(entry) resolve_dependancy(entry)
del dependancies_by_entry[entry] del dependancies_by_entry[entry]
if ready_to_infer: if ready_to_infer:
...@@ -438,16 +438,20 @@ def find_spanning_type(type1, type2): ...@@ -438,16 +438,20 @@ def find_spanning_type(type1, type2):
return PyrexTypes.c_double_type return PyrexTypes.c_double_type
return result_type return result_type
def aggressive_spanning_type(types, might_overflow): def aggressive_spanning_type(types, might_overflow, pos):
result_type = reduce(find_spanning_type, types) result_type = reduce(find_spanning_type, types)
if result_type.is_reference: if result_type.is_reference:
result_type = result_type.ref_base_type result_type = result_type.ref_base_type
if result_type.is_cpp_class:
result_type.check_nullary_constructor(pos)
return result_type return result_type
def safe_spanning_type(types, might_overflow): def safe_spanning_type(types, might_overflow, pos):
result_type = reduce(find_spanning_type, types) result_type = reduce(find_spanning_type, types)
if result_type.is_reference: if result_type.is_reference:
result_type = result_type.ref_base_type result_type = result_type.ref_base_type
if result_type.is_cpp_class:
result_type.check_nullary_constructor(pos)
if result_type.is_pyobject: if result_type.is_pyobject:
# In theory, any specific Python type is always safe to # In theory, any specific Python type is always safe to
# infer. However, inferring str can cause some existing code # infer. However, inferring str can cause some existing code
......
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