improved thread safety of the LRUCache and fixed a bug in for loops

--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index e0f02f3..d643d39 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -352,6 +352,10 @@
         # the current indentation
         self._indentation = 0
 
+    def fail(self, msg, lineno):
+        """Fail with a `TemplateAssertionError`."""
+        raise TemplateAssertionError(msg, lineno, self.name, self.filename)
+
     def temporary_identifier(self):
         """Get a new unique identifier."""
         self._last_identifier += 1
@@ -359,9 +363,8 @@
 
     def buffer(self, frame):
         """Enable buffering for the frame from that point onwards."""
-        frame.buffer = buf = self.temporary_identifier()
-        self.writeline('%s = []' % buf)
-        return buf
+        frame.buffer = self.temporary_identifier()
+        self.writeline('%s = []' % frame.buffer)
 
     def return_buffer_contents(self, frame):
         """Return the buffer contents of the frame."""
@@ -543,12 +546,9 @@
              func_frame.identifiers.declared_parameter)
         )
         if overriden_closure_vars:
-            vars = ', '.join(sorted(overriden_closure_vars))
-            raise TemplateAssertionError('It\'s not possible to set and '
-                                         'access variables derived from '
-                                         'an outer scope! (affects: %s' %
-                                         vars, node.lineno, self.name,
-                                         self.filename)
+            self.fail('It\'s not possible to set and access variables '
+                      'derived from an outer scope! (affects: %s' %
+                      ', '.join(sorted(overriden_closure_vars)), node.lineno)
 
         # remove variables from a closure from the frame's undeclared
         # identifiers.
@@ -597,9 +597,7 @@
         # find all blocks
         for block in node.find_all(nodes.Block):
             if block.name in self.blocks:
-                raise TemplateAssertionError('block %r defined twice' %
-                                             block.name, block.lineno,
-                                             self.name, self.filename)
+                self.fail('block %r defined twice' % block.name, block.lineno)
             self.blocks[block.name] = block
 
         # find all imports and import them
@@ -700,9 +698,8 @@
     def visit_Extends(self, node, frame):
         """Calls the extender."""
         if not frame.toplevel:
-            raise TemplateAssertionError('cannot use extend from a non '
-                                         'top-level scope', node.lineno,
-                                         self.name, self.filename)
+            self.fail('cannot use extend from a non top-level scope',
+                      node.lineno)
 
         # if the number of extends statements in general is zero so
         # far, we don't have to add a check if something extended
@@ -831,7 +828,7 @@
     def visit_For(self, node, frame):
         # when calculating the nodes for the inner frame we have to exclude
         # the iterator contents from it
-        children = node.iter_child_nodes(exclude=('iter',))
+        children = list(node.iter_child_nodes(exclude=('iter',)))
 
         if node.recursive:
             loop_frame = self.function_scoping(node, frame, children,
@@ -840,8 +837,8 @@
             loop_frame = frame.inner()
             loop_frame.inspect(children)
 
-        extended_loop = node.recursive or node.else_ or \
-                        'loop' in loop_frame.identifiers.undeclared
+        undeclared = find_undeclared(children, ('loop',))
+        extended_loop = node.recursive or node.else_ or 'loop' in undeclared
         if extended_loop:
             loop_frame.identifiers.add_special('loop')
 
@@ -1294,9 +1291,7 @@
         self.write(self.filters[node.name] + '(')
         func = self.environment.filters.get(node.name)
         if func is None:
-            raise TemplateAssertionError('no filter named %r' % node.name,
-                                         node.lineno, self.name,
-                                         self.filename)
+            self.fail('no filter named %r' % node.name, node.lineno)
         if getattr(func, 'contextfilter', False):
             self.write('context, ')
         elif getattr(func, 'environmentfilter', False):
@@ -1313,9 +1308,7 @@
     def visit_Test(self, node, frame):
         self.write(self.tests[node.name] + '(')
         if node.name not in self.environment.tests:
-            raise TemplateAssertionError('no test named %r' % node.name,
-                                         node.lineno, self.name,
-                                         self.filename)
+            self.fail('no test named %r' % node.name, node.lineno)
         self.visit(node.node, frame)
         self.signature(node, frame)
         self.write(')')