Commit 01321f7b authored by Stefan Behnel's avatar Stefan Behnel

enable control flow analysis for stack allocated structured variables (struct,...

enable control flow analysis for stack allocated structured variables (struct, union, array, C++ class)
parent 0ac2fa8a
......@@ -16,7 +16,8 @@ from Errors import error, warning, InternalError
class TypedExprNode(ExprNodes.ExprNode):
# Used for declaring assignments of a specified type without a known entry.
def __init__(self, type, may_be_none=None):
def __init__(self, type, may_be_none=None, pos=None):
self.pos = pos
self.type = type
self._may_be_none = may_be_none
......@@ -147,13 +148,19 @@ class ControlFlow(object):
def is_tracked(self, entry):
if entry.is_anonymous:
return False
if (entry.type.is_array or entry.type.is_struct_or_union or
entry.type.is_cpp_class):
return False
return (entry.is_local or entry.is_pyclass_attr or entry.is_arg or
entry.from_closure or entry.in_closure or
entry.error_on_uninitialized)
def is_statically_assigned(self, entry):
if (entry.is_local and entry.is_variable and
(entry.type.is_struct_or_union or
entry.type.is_array or
entry.type.is_cpp_class)):
# stack allocated structured variable => never uninitialised
return True
return False
def mark_position(self, node):
"""Mark position, will be used to draw graph nodes."""
if self.block:
......@@ -252,7 +259,9 @@ class ControlFlow(object):
ret = set()
assmts = self.assmts[entry]
if istate & assmts.bit:
if entry.from_closure:
if self.is_statically_assigned(entry):
ret.add(StaticAssignment(entry))
elif entry.from_closure:
ret.add(Unknown)
else:
ret.add(Uninitialized)
......@@ -320,6 +329,24 @@ class NameAssignment(object):
return self.rhs.type_dependencies(scope)
class StaticAssignment(NameAssignment):
"""Initialised at declaration time, e.g. stack allocation."""
def __init__(self, entry):
if not entry.type.is_pyobject:
may_be_none = False
else:
may_be_none = None # unknown
lhs = TypedExprNode(
entry.type, may_be_none=may_be_none, pos=entry.pos)
super(StaticAssignment, self).__init__(lhs, lhs, entry)
def infer_type(self, scope):
return self.entry.type
def type_dependencies(self, scope):
return []
class Argument(NameAssignment):
def __init__(self, lhs, rhs, entry):
NameAssignment.__init__(self, lhs, rhs, entry)
......
# mode: run
# tag: werror, control-flow
# cython: warn.unused=True, warn.unused_arg=True, warn.unused_result=True
cdef struct S:
int x
float y
cdef stack_alloc_test(int[2] array_arg, S struct_arg):
cdef int[2] array_var
cdef S struct_var, struct_var_by_value
for i in range(2):
array_var[i] = array_arg[i]
struct_var.x, struct_var.y = struct_arg.x, struct_arg.y
struct_var_by_value = struct_var
return [ i for i in array_var ], struct_var_by_value
def test():
"""
>>> test()
([0, 1], {'y': 2.0, 'x': 1})
"""
cdef int[2] array_var
cdef S struct_var
for i in range(2):
array_var[i] = i
struct_var = [1, 2.0]
return stack_alloc_test(array_var, struct_var)
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