Commit 162584a4 authored by Kurt Smith's avatar Kurt Smith

Bug 158 -- raise error if cdef variable declared after it's used.

parent cff8447f
...@@ -658,6 +658,8 @@ class DecoratorTransform(CythonTransform, SkipDeclarations): ...@@ -658,6 +658,8 @@ class DecoratorTransform(CythonTransform, SkipDeclarations):
rhs = decorator_result) rhs = decorator_result)
return [func_node, reassignment] return [func_node, reassignment]
ERR_DEC_AFTER = "cdef variable '%s' declared after it's used."
class AnalyseDeclarationsTransform(CythonTransform): class AnalyseDeclarationsTransform(CythonTransform):
basic_property = TreeFragment(u""" basic_property = TreeFragment(u"""
...@@ -670,14 +672,23 @@ property NAME: ...@@ -670,14 +672,23 @@ property NAME:
def __call__(self, root): def __call__(self, root):
self.env_stack = [root.scope] self.env_stack = [root.scope]
# needed to determine if a cdef var is declared after it's used.
self.local_scope_stack = []
return super(AnalyseDeclarationsTransform, self).__call__(root) return super(AnalyseDeclarationsTransform, self).__call__(root)
def visit_NameNode(self, node):
self.local_scope_stack[-1].add(node.name)
return node
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
self.local_scope_stack.append(set())
node.analyse_declarations(self.env_stack[-1]) node.analyse_declarations(self.env_stack[-1])
self.visitchildren(node) self.visitchildren(node)
self.local_scope_stack.pop()
return node return node
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
self.local_scope_stack.append(set())
lenv = node.create_local_scope(self.env_stack[-1]) lenv = node.create_local_scope(self.env_stack[-1])
node.body.analyse_control_flow(lenv) # this will be totally refactored node.body.analyse_control_flow(lenv) # this will be totally refactored
node.declare_arguments(lenv) node.declare_arguments(lenv)
...@@ -692,6 +703,7 @@ property NAME: ...@@ -692,6 +703,7 @@ property NAME:
self.env_stack.append(lenv) self.env_stack.append(lenv)
self.visitchildren(node) self.visitchildren(node)
self.env_stack.pop() self.env_stack.pop()
self.local_scope_stack.pop()
return node return node
# Some nodes are no longer needed after declaration # Some nodes are no longer needed after declaration
...@@ -699,6 +711,8 @@ property NAME: ...@@ -699,6 +711,8 @@ property NAME:
# on these nodes in a seperate recursive process from the # on these nodes in a seperate recursive process from the
# enclosing function or module, so we can simply drop them. # enclosing function or module, so we can simply drop them.
def visit_CDeclaratorNode(self, node): def visit_CDeclaratorNode(self, node):
# necessary to ensure that all CNameDeclaratorNodes are visited.
self.visitchildren(node)
return node return node
def visit_CTypeDefNode(self, node): def visit_CTypeDefNode(self, node):
...@@ -713,7 +727,18 @@ property NAME: ...@@ -713,7 +727,18 @@ property NAME:
def visit_CStructOrUnionDefNode(self, node): def visit_CStructOrUnionDefNode(self, node):
return None return None
def visit_CNameDeclaratorNode(self, node):
if node.name in self.local_scope_stack[-1]:
# cdef variable declared after it's used.
error(node.pos, ERR_DEC_AFTER % node.name)
self.visitchildren(node)
return node
def visit_CVarDefNode(self, node): def visit_CVarDefNode(self, node):
# to ensure all CNameDeclaratorNodes are visited.
self.visitchildren(node)
if node.need_properties: if node.need_properties:
# cdef public attributes may need type testing on # cdef public attributes may need type testing on
# assignment, so we create a property accesss # assignment, so we create a property accesss
......
def mult_decl_test():
print "%s" % vv
print "%s" % s
cdef str s, vv = "Test"
def def_test():
cdef int j = 10
i[0] = j
cdef int *i = NULL # pointer variables are special case
cdef cdef_test():
cdef int j = 10
i[0] = j
print "%d" % i[0]
cdef int *i = NULL
cpdef cpdef_test():
cdef int j = 10
i[0] = j
print "%d" % i[0]
cdef int *i = NULL
s.upper()
cdef str s = "Test"
class Foo(object):
def bar(self, x, y):
cdef unsigned long w = 20
z = w + t
cdef int t = 10
cdef class Foo2(object):
print '%s' % r # check error inside class scope
cdef str r
def bar(self, x, y):
cdef unsigned long w = 20
self.r = c'r'
print self.r
z = w + g(t)
cdef int t = 10
def g(x):
return x
cdef int d = 20
baz[0] = d
cdef int *baz
print var[0][0]
cdef unsigned long long var[100][100]
_ERRORS = u"""
4:13: cdef variable 's' declared after it's used.
4:16: cdef variable 'vv' declared after it's used.
9:14: cdef variable 'i' declared after it's used.
15:14: cdef variable 'i' declared after it's used.
21:14: cdef variable 'i' declared after it's used.
24:9: cdef variable 's' declared after it's used.
30:17: cdef variable 't' declared after it's used.
34:13: cdef variable 'r' declared after it's used.
40:17: cdef variable 't' declared after it's used.
47:10: cdef variable 'baz' declared after it's used.
50:24: cdef variable 'var' declared after it's used.
"""
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