Commit 760bdc3c authored by scoder's avatar scoder

Merge pull request #29 from vitek/unreachable_code

Unreachable code removal
parents a6ec5007 82357f1c
...@@ -109,6 +109,7 @@ class Context(object): ...@@ -109,6 +109,7 @@ class Context(object):
from ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform from ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform
from TypeInference import MarkAssignments, MarkOverflowingArithmetic from TypeInference import MarkAssignments, MarkOverflowingArithmetic
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
from ParseTreeTransforms import RemoveUnreachableCode
from AnalysedTreeTransforms import AutoTestDictTransform from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
...@@ -138,6 +139,7 @@ class Context(object): ...@@ -138,6 +139,7 @@ class Context(object):
ParallelRangeTransform(self), ParallelRangeTransform(self),
MarkClosureVisitor(self), MarkClosureVisitor(self),
_align_function_definitions, _align_function_definitions,
RemoveUnreachableCode(self),
ConstantFolding(), ConstantFolding(),
FlattenInListTransform(), FlattenInListTransform(),
WithTransform(self), WithTransform(self),
......
...@@ -128,6 +128,7 @@ class Node(object): ...@@ -128,6 +128,7 @@ class Node(object):
is_name = 0 is_name = 0
is_literal = 0 is_literal = 0
is_terminator = 0
temps = None temps = None
# All descandants should set child_attrs to a list of the attributes # All descandants should set child_attrs to a list of the attributes
...@@ -4049,6 +4050,7 @@ class PassStatNode(StatNode): ...@@ -4049,6 +4050,7 @@ class PassStatNode(StatNode):
class BreakStatNode(StatNode): class BreakStatNode(StatNode):
child_attrs = [] child_attrs = []
is_terminator = True
def analyse_expressions(self, env): def analyse_expressions(self, env):
pass pass
...@@ -4063,6 +4065,7 @@ class BreakStatNode(StatNode): ...@@ -4063,6 +4065,7 @@ class BreakStatNode(StatNode):
class ContinueStatNode(StatNode): class ContinueStatNode(StatNode):
child_attrs = [] child_attrs = []
is_terminator = True
def analyse_expressions(self, env): def analyse_expressions(self, env):
pass pass
...@@ -4083,6 +4086,7 @@ class ReturnStatNode(StatNode): ...@@ -4083,6 +4086,7 @@ class ReturnStatNode(StatNode):
# return_type PyrexType # return_type PyrexType
child_attrs = ["value"] child_attrs = ["value"]
is_terminator = True
def analyse_expressions(self, env): def analyse_expressions(self, env):
return_type = env.return_type return_type = env.return_type
...@@ -4156,6 +4160,7 @@ class RaiseStatNode(StatNode): ...@@ -4156,6 +4160,7 @@ class RaiseStatNode(StatNode):
# cause ExprNode or None # cause ExprNode or None
child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"] child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"]
is_terminator = True
def analyse_expressions(self, env): def analyse_expressions(self, env):
if self.exc_type: if self.exc_type:
...@@ -4250,6 +4255,7 @@ class RaiseStatNode(StatNode): ...@@ -4250,6 +4255,7 @@ class RaiseStatNode(StatNode):
class ReraiseStatNode(StatNode): class ReraiseStatNode(StatNode):
child_attrs = [] child_attrs = []
is_terminator = True
def analyse_expressions(self, env): def analyse_expressions(self, env):
env.use_utility_code(restore_exception_utility_code) env.use_utility_code(restore_exception_utility_code)
......
...@@ -94,6 +94,10 @@ directive_defaults = { ...@@ -94,6 +94,10 @@ directive_defaults = {
'warn': None, 'warn': None,
'warn.undeclared': False, 'warn.undeclared': False,
'warn.unreachable': True,
# remove unreachable code
'remove_unreachable': True,
# test support # test support
'test_assert_path_exists' : [], 'test_assert_path_exists' : [],
......
...@@ -1666,6 +1666,43 @@ class AlignFunctionDefinitions(CythonTransform): ...@@ -1666,6 +1666,43 @@ class AlignFunctionDefinitions(CythonTransform):
return node return node
class RemoveUnreachableCode(CythonTransform):
def visit_Node(self, node):
self.visitchildren(node)
return node
def visit_StatListNode(self, node):
if not self.current_directives['remove_unreachable']:
return node
self.visitchildren(node)
for idx, stat in enumerate(node.stats):
idx += 1
if stat.is_terminator:
if idx < len(node.stats):
if self.current_directives['warn.unreachable']:
warning(node.stats[idx].pos, "Unreachable code", 2)
node.stats = node.stats[:idx]
node.is_terminator = True
break
return node
def visit_IfClauseNode(self, node):
self.visitchildren(node)
if node.body.is_terminator:
node.is_terminator = True
return node
def visit_IfStatNode(self, node):
self.visitchildren(node)
if node.else_clause and node.else_clause.is_terminator:
for clause in node.if_clauses:
if not clause.is_terminator:
break
else:
node.is_terminator = True
return node
class YieldNodeCollector(TreeVisitor): class YieldNodeCollector(TreeVisitor):
def __init__(self): def __init__(self):
......
# cython: remove_unreachable=False
# mode: error # mode: error
break break
...@@ -27,11 +28,11 @@ def bool_result(): ...@@ -27,11 +28,11 @@ def bool_result():
_ERRORS = u''' _ERRORS = u'''
3:0: break statement not inside loop 4:0: break statement not inside loop
6:4: break statement not inside loop 7:4: break statement not inside loop
9:4: break statement not inside loop 10:4: break statement not inside loop
12:4: break statement not inside loop 13:4: break statement not inside loop
17:5: break statement not inside loop 18:5: break statement not inside loop
21:4: break statement not inside loop 22:4: break statement not inside loop
23:4: break statement not inside loop 24:4: break statement not inside loop
''' '''
# cython: remove_unreachable=False
# mode: error # mode: error
continue continue
...@@ -26,11 +27,11 @@ def bool_result(): ...@@ -26,11 +27,11 @@ def bool_result():
return True return True
_ERRORS = u''' _ERRORS = u'''
3:0: continue statement not inside loop 4:0: continue statement not inside loop
6:4: continue statement not inside loop 7:4: continue statement not inside loop
9:4: continue statement not inside loop 10:4: continue statement not inside loop
12:4: continue statement not inside loop 13:4: continue statement not inside loop
17:5: continue statement not inside loop 18:5: continue statement not inside loop
21:4: continue statement not inside loop 22:4: continue statement not inside loop
23:4: continue statement not inside loop 24:4: continue statement not inside loop
''' '''
# cython: remove_unreachable=False
# mode: error # mode: error
cdef void g(): cdef void g():
...@@ -9,7 +10,7 @@ cdef int h(): ...@@ -9,7 +10,7 @@ cdef int h():
return # error return # error
return p # error return p # error
_ERRORS = u""" _ERRORS = u"""
5:17: Return with value in void function 6:17: Return with value in void function
9:1: Return value required 10:1: Return value required
10:17: Cannot assign type 'int *' to 'int' 11:17: Cannot assign type 'int *' to 'int'
""" """
# cython: remove_unreachable=False
# mode: error # mode: error
def f(a, b): def f(a, b):
...@@ -5,6 +6,6 @@ def f(a, b): ...@@ -5,6 +6,6 @@ def f(a, b):
break # error break # error
continue # error continue # error
_ERRORS = u""" _ERRORS = u"""
5:1: break statement not inside loop 6:1: break statement not inside loop
6:1: continue statement not inside loop 7:1: continue statement not inside loop
""" """
# cython: remove_unreachable=False
# mode: error # mode: error
cdef object f(object x) nogil: cdef object f(object x) nogil:
...@@ -92,71 +93,71 @@ def bare_pyvar_name(object x): ...@@ -92,71 +93,71 @@ def bare_pyvar_name(object x):
# except these: 29, 34, 44, 56, 58, 60, 62-64 # except these: 29, 34, 44, 56, 58, 60, 62-64
_ERRORS = u""" _ERRORS = u"""
3:5: Function with Python return type cannot be declared nogil 4:5: Function with Python return type cannot be declared nogil
6:5: Function declared nogil has Python locals or temporaries 7:5: Function declared nogil has Python locals or temporaries
8:6: Assignment of Python object not allowed without gil 9:6: Assignment of Python object not allowed without gil
11:5: Discarding owned Python object not allowed without gil 12:5: Discarding owned Python object not allowed without gil
13:5: Function with Python return type cannot be declared nogil 14:5: Function with Python return type cannot be declared nogil
17:5: Calling gil-requiring function not allowed without gil 18:5: Calling gil-requiring function not allowed without gil
26:9: Calling gil-requiring function not allowed without gil 27:9: Calling gil-requiring function not allowed without gil
28:12: Assignment of Python object not allowed without gil 29:12: Assignment of Python object not allowed without gil
30:8: Discarding owned Python object not allowed without gil 31:8: Discarding owned Python object not allowed without gil
30:16: Constructing complex number not allowed without gil 31:16: Constructing complex number not allowed without gil
32:8: Backquote expression not allowed without gil 33:8: Backquote expression not allowed without gil
32:8: Discarding owned Python object not allowed without gil 33:8: Discarding owned Python object not allowed without gil
32:9: Operation not allowed without gil 33:9: Operation not allowed without gil
33:15: Assignment of Python object not allowed without gil 34:15: Assignment of Python object not allowed without gil
33:15: Operation not allowed without gil 34:15: Operation not allowed without gil
33:15: Python import not allowed without gil 34:15: Python import not allowed without gil
34:8: Operation not allowed without gil 35:8: Operation not allowed without gil
34:13: Python import not allowed without gil 35:13: Python import not allowed without gil
34:25: Constructing Python list not allowed without gil 35:25: Constructing Python list not allowed without gil
34:25: Operation not allowed without gil 35:25: Operation not allowed without gil
35:17: Iterating over Python object not allowed without gil 36:17: Iterating over Python object not allowed without gil
37:11: Discarding owned Python object not allowed without gil
37:11: Indexing Python object not allowed without gil
38:11: Discarding owned Python object not allowed without gil 38:11: Discarding owned Python object not allowed without gil
38:11: Slicing Python object not allowed without gil 38:11: Indexing Python object not allowed without gil
39:11: Constructing Python slice object not allowed without gil
39:11: Discarding owned Python object not allowed without gil 39:11: Discarding owned Python object not allowed without gil
39:11: Indexing Python object not allowed without gil 39:11: Slicing Python object not allowed without gil
39:13: Converting to Python object not allowed without gil 40:11: Constructing Python slice object not allowed without gil
39:15: Converting to Python object not allowed without gil
39:17: Converting to Python object not allowed without gil
40:11: Accessing Python attribute not allowed without gil
40:11: Discarding owned Python object not allowed without gil 40:11: Discarding owned Python object not allowed without gil
41:9: Constructing Python tuple not allowed without gil 40:11: Indexing Python object not allowed without gil
41:9: Discarding owned Python object not allowed without gil 40:13: Converting to Python object not allowed without gil
42:8: Constructing Python list not allowed without gil 40:15: Converting to Python object not allowed without gil
42:8: Discarding owned Python object not allowed without gil 40:17: Converting to Python object not allowed without gil
43:8: Constructing Python dict not allowed without gil 41:11: Accessing Python attribute not allowed without gil
41:11: Discarding owned Python object not allowed without gil
42:9: Constructing Python tuple not allowed without gil
42:9: Discarding owned Python object not allowed without gil
43:8: Constructing Python list not allowed without gil
43:8: Discarding owned Python object not allowed without gil 43:8: Discarding owned Python object not allowed without gil
44:12: Discarding owned Python object not allowed without gil 44:8: Constructing Python dict not allowed without gil
44:12: Truth-testing Python object not allowed without gil 44:8: Discarding owned Python object not allowed without gil
45:13: Python type test not allowed without gil 45:12: Discarding owned Python object not allowed without gil
47:10: Discarding owned Python object not allowed without gil 45:12: Truth-testing Python object not allowed without gil
47:10: Operation not allowed without gil 46:13: Python type test not allowed without gil
48:8: Discarding owned Python object not allowed without gil 48:10: Discarding owned Python object not allowed without gil
48:8: Operation not allowed without gil 48:10: Operation not allowed without gil
49:10: Assignment of Python object not allowed without gil 49:8: Discarding owned Python object not allowed without gil
49:14: Assignment of Python object not allowed without gil 49:8: Operation not allowed without gil
50:9: Assignment of Python object not allowed without gil 50:10: Assignment of Python object not allowed without gil
50:13: Assignment of Python object not allowed without gil 50:14: Assignment of Python object not allowed without gil
50:16: Creating temporary Python reference not allowed without gil 51:9: Assignment of Python object not allowed without gil
50:19: Creating temporary Python reference not allowed without gil 51:13: Assignment of Python object not allowed without gil
51:11: Assignment of Python object not allowed without gil 51:16: Creating temporary Python reference not allowed without gil
51:11: Indexing Python object not allowed without gil 51:19: Creating temporary Python reference not allowed without gil
52:11: Accessing Python attribute not allowed without gil
52:11: Assignment of Python object not allowed without gil 52:11: Assignment of Python object not allowed without gil
53:8: Constructing Python tuple not allowed without gil 52:11: Indexing Python object not allowed without gil
53:8: Python print statement not allowed without gil 53:11: Accessing Python attribute not allowed without gil
54:8: Deleting Python object not allowed without gil 53:11: Assignment of Python object not allowed without gil
55:8: Returning Python object not allowed without gil 54:8: Constructing Python tuple not allowed without gil
56:8: Raising exception not allowed without gil 54:8: Python print statement not allowed without gil
57:14: Truth-testing Python object not allowed without gil 55:8: Deleting Python object not allowed without gil
59:17: Truth-testing Python object not allowed without gil 56:8: Returning Python object not allowed without gil
61:8: For-loop using object bounds or target not allowed without gil 57:8: Raising exception not allowed without gil
63:8: Try-except statement not allowed without gil 58:14: Truth-testing Python object not allowed without gil
67:8: Try-finally statement not allowed without gil 60:17: Truth-testing Python object not allowed without gil
84:8: For-loop using object bounds or target not allowed without gil 62:8: For-loop using object bounds or target not allowed without gil
64:8: Try-except statement not allowed without gil
68:8: Try-finally statement not allowed without gil
85:8: For-loop using object bounds or target not allowed without gil
""" """
# cython: remove_unreachable=False
# ticket: 135 # ticket: 135
# mode: error # mode: error
...@@ -31,13 +32,13 @@ else: ...@@ -31,13 +32,13 @@ else:
_ERRORS = u''' _ERRORS = u'''
7:0: Return not inside a function body 8:0: Return not inside a function body
10:4: Return not inside a function body 11:4: Return not inside a function body
13:4: Return not inside a function body 14:4: Return not inside a function body
15:5: Return not inside a function body 16:5: Return not inside a function body
18:5: Return not inside a function body 19:5: Return not inside a function body
22:4: Return not inside a function body 23:4: Return not inside a function body
25:4: Return not inside a function body 26:4: Return not inside a function body
28:4: Return not inside a function body 29:4: Return not inside a function body
30:4: Return not inside a function body 31:4: Return not inside a function body
''' '''
# mode: error
# tag: werror
def simple_return():
return
print 'Where am I?'
def simple_loops(*args):
for i in args:
continue
print 'Never be here'
while True:
break
print 'Never be here'
def conditional(a, b):
if a:
return 1
elif b:
return 2
else:
return 3
print 'oops'
_ERRORS = """
6:4: Unreachable code
11:8: Unreachable code
15:8: Unreachable code
24:4: Unreachable 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