From: Kurt Smith Date: Tue, 17 Mar 2009 05:02:46 +0000 (-0500) Subject: Bug 158 -- raise error if cdef variable declared after it's used. X-Git-Tag: 0.11.1.alpha~52 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=162584a48b4d6a11ef8a2dcb897e7f4358014f71;p=cython.git Bug 158 -- raise error if cdef variable declared after it's used. --- diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 3f92d738..d9f37c07 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -658,6 +658,8 @@ class DecoratorTransform(CythonTransform, SkipDeclarations): rhs = decorator_result) return [func_node, reassignment] + +ERR_DEC_AFTER = "cdef variable '%s' declared after it's used." class AnalyseDeclarationsTransform(CythonTransform): basic_property = TreeFragment(u""" @@ -670,14 +672,23 @@ property NAME: def __call__(self, root): 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) + def visit_NameNode(self, node): + self.local_scope_stack[-1].add(node.name) + return node + def visit_ModuleNode(self, node): + self.local_scope_stack.append(set()) node.analyse_declarations(self.env_stack[-1]) self.visitchildren(node) + self.local_scope_stack.pop() return node def visit_FuncDefNode(self, node): + self.local_scope_stack.append(set()) lenv = node.create_local_scope(self.env_stack[-1]) node.body.analyse_control_flow(lenv) # this will be totally refactored node.declare_arguments(lenv) @@ -692,6 +703,7 @@ property NAME: self.env_stack.append(lenv) self.visitchildren(node) self.env_stack.pop() + self.local_scope_stack.pop() return node # Some nodes are no longer needed after declaration @@ -699,6 +711,8 @@ property NAME: # on these nodes in a seperate recursive process from the # enclosing function or module, so we can simply drop them. def visit_CDeclaratorNode(self, node): + # necessary to ensure that all CNameDeclaratorNodes are visited. + self.visitchildren(node) return node def visit_CTypeDefNode(self, node): @@ -713,7 +727,18 @@ property NAME: def visit_CStructOrUnionDefNode(self, node): 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): + + # to ensure all CNameDeclaratorNodes are visited. + self.visitchildren(node) + if node.need_properties: # cdef public attributes may need type testing on # assignment, so we create a property accesss diff --git a/tests/errors/declareafteruse_T158.pyx b/tests/errors/declareafteruse_T158.pyx new file mode 100644 index 00000000..364c9421 --- /dev/null +++ b/tests/errors/declareafteruse_T158.pyx @@ -0,0 +1,65 @@ +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. +"""