[2.7] bpo-10544: Deprecate "yield" in comprehensions and generator expressions in Py3k mode. (GH-4579) (#4676)

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 0f0da72..cabf548 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -847,8 +847,8 @@
         file.close()
         unlink(TESTFN)
 
-def check_syntax_error(testcase, statement, lineno=None, offset=None):
-    with testcase.assertRaises(SyntaxError) as cm:
+def check_syntax_error(testcase, statement, errtext='', lineno=None, offset=None):
+    with testcase.assertRaisesRegexp(SyntaxError, errtext) as cm:
         compile(statement, '<test string>', 'exec')
     err = cm.exception
     if lineno is not None:
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 5e1a3e5..0f7bf19 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -1524,13 +1524,7 @@
 [None]
 
 
-
-An obscene abuse of a yield expression within a generator expression:
-
->>> list((yield 21) for i in range(4))
-[21, None, 21, None, 21, None, 21, None]
-
-And a more sane, but still weird usage:
+Yield is allowed only in the outermost iterable in generator expression:
 
 >>> def f(): list(i for i in [(yield 26)])
 >>> type(f())
@@ -1571,7 +1565,7 @@
 >>> def f(): return lambda x=(yield): 1
 Traceback (most recent call last):
   ...
-SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.coroutine[22]>, line 1)
+SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.coroutine[21]>, line 1)
 
 >>> def f(): x = yield = y
 Traceback (most recent call last):
@@ -1784,7 +1778,7 @@
 >>> type(f())
 <type 'generator'>
 
->>> def f(): x=(i for i in (yield) if (yield))
+>>> def f(): x=(i for i in (yield) if i)
 >>> type(f())
 <type 'generator'>
 
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 5f77c1d..fc675c3 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -493,6 +493,46 @@
     def testYield(self):
         check_syntax_error(self, "class foo:yield 1")
 
+    def test_yield_in_comprehensions(self):
+        # Check yield in comprehensions
+        def g(): [x for x in [(yield 1)]]
+
+        def check(code, warntext):
+            with check_py3k_warnings((warntext, DeprecationWarning)):
+                compile(code, '<test string>', 'exec')
+            if sys.py3kwarning:
+                import warnings
+                with warnings.catch_warnings():
+                    warnings.filterwarnings('error', category=DeprecationWarning)
+                    with self.assertRaises(SyntaxError) as cm:
+                        compile(code, '<test string>', 'exec')
+                    self.assertIn(warntext, str(cm.exception))
+
+        check("def g(): [(yield x) for x in ()]",
+              "'yield' inside list comprehension")
+        check("def g(): [x for x in () if not (yield x)]",
+              "'yield' inside list comprehension")
+        check("def g(): [y for x in () for y in [(yield x)]]",
+              "'yield' inside list comprehension")
+        check("def g(): {(yield x) for x in ()}",
+              "'yield' inside set comprehension")
+        check("def g(): {(yield x): x for x in ()}",
+              "'yield' inside dict comprehension")
+        check("def g(): {x: (yield x) for x in ()}",
+              "'yield' inside dict comprehension")
+        check("def g(): ((yield x) for x in ())",
+              "'yield' inside generator expression")
+        with check_py3k_warnings(("'yield' inside list comprehension",
+                                  DeprecationWarning)):
+            check_syntax_error(self, "class C: [(yield x) for x in ()]")
+        check("class C: ((yield x) for x in ())",
+              "'yield' inside generator expression")
+        with check_py3k_warnings(("'yield' inside list comprehension",
+                                  DeprecationWarning)):
+            check_syntax_error(self, "[(yield x) for x in ()]")
+        check("((yield x) for x in ())",
+              "'yield' inside generator expression")
+
     def testRaise(self):
         # 'raise' test [',' test]
         try: raise RuntimeError, 'just testing'