bpo-32684: Fix gather to propagate cancel of itself with return_exceptions (GH-7209) (#7222)

(cherry picked from commit 863b6749093a86810c4077112a857363410cc221)

Co-authored-by: Yury Selivanov <yury@magic.io>
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 67fb57c..6cef33d 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -591,6 +591,7 @@
     def __init__(self, children, *, loop=None):
         super().__init__(loop=loop)
         self._children = children
+        self._cancel_requested = False
 
     def cancel(self):
         if self.done():
@@ -599,6 +600,11 @@
         for child in self._children:
             if child.cancel():
                 ret = True
+        if ret:
+            # If any child tasks were actually cancelled, we should
+            # propagate the cancellation request regardless of
+            # *return_exceptions* argument.  See issue 32684.
+            self._cancel_requested = True
         return ret
 
 
@@ -673,7 +679,13 @@
                         res = fut.result()
                 results.append(res)
 
-            outer.set_result(results)
+            if outer._cancel_requested:
+                # If gather is being cancelled we must propagate the
+                # cancellation regardless of *return_exceptions* argument.
+                # See issue 32684.
+                outer.set_exception(futures.CancelledError())
+            else:
+                outer.set_result(results)
 
     arg_to_fut = {}
     children = []