Issue #23243, asyncio: Emit a ResourceWarning when an event loop or a transport
is not explicitly closed. Close also explicitly transports in test_sslproto.
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index e40d3ad..7108f25 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -26,6 +26,7 @@
 import time
 import traceback
 import sys
+import warnings
 
 from . import coroutines
 from . import events
@@ -333,6 +334,16 @@
         """Returns True if the event loop was closed."""
         return self._closed
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if not self.is_closed():
+                warnings.warn("unclosed event loop %r" % self, ResourceWarning)
+                if not self.is_running():
+                    self.close()
+
     def is_running(self):
         """Returns True if the event loop is running."""
         return (self._owner is not None)
diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py
index 81c6f1a..651a9a2 100644
--- a/Lib/asyncio/base_subprocess.py
+++ b/Lib/asyncio/base_subprocess.py
@@ -1,5 +1,7 @@
 import collections
 import subprocess
+import sys
+import warnings
 
 from . import protocols
 from . import transports
@@ -13,6 +15,7 @@
                  stdin, stdout, stderr, bufsize,
                  extra=None, **kwargs):
         super().__init__(extra)
+        self._closed = False
         self._protocol = protocol
         self._loop = loop
         self._pid = None
@@ -40,7 +43,10 @@
                          program, self._pid)
 
     def __repr__(self):
-        info = [self.__class__.__name__, 'pid=%s' % self._pid]
+        info = [self.__class__.__name__]
+        if self._closed:
+            info.append('closed')
+        info.append('pid=%s' % self._pid)
         if self._returncode is not None:
             info.append('returncode=%s' % self._returncode)
 
@@ -70,6 +76,7 @@
         raise NotImplementedError
 
     def close(self):
+        self._closed = True
         for proto in self._pipes.values():
             if proto is None:
                 continue
@@ -77,6 +84,15 @@
         if self._returncode is None:
             self.terminate()
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if not self._closed:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self.close()
+
     def get_pid(self):
         return self._pid
 
@@ -104,6 +120,7 @@
         Function called when an exception is raised during the creation
         of a subprocess.
         """
+        self._closed = True
         if self._loop.get_debug():
             logger.warning('Exception during subprocess creation, '
                            'kill the subprocess %r',
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 19212a9..2c741fd 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -195,9 +195,9 @@
         info = self._repr_info()
         return '<%s %s>' % (self.__class__.__name__, ' '.join(info))
 
-    # On Python 3.3 or older, objects with a destructor part of a reference
-    # cycle are never destroyed. It's not more the case on Python 3.4 thanks to
-    # the PEP 442.
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
     if _PY34:
         def __del__(self):
             if not self._log_traceback:
diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py
index 0f533a5..65de926 100644
--- a/Lib/asyncio/proactor_events.py
+++ b/Lib/asyncio/proactor_events.py
@@ -7,6 +7,8 @@
 __all__ = ['BaseProactorEventLoop']
 
 import socket
+import sys
+import warnings
 
 from . import base_events
 from . import constants
@@ -74,6 +76,15 @@
             self._read_fut.cancel()
             self._read_fut = None
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if self._sock is not None:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self.close()
+
     def _fatal_error(self, exc, message='Fatal error on pipe transport'):
         if isinstance(exc, (BrokenPipeError, ConnectionResetError)):
             if self._loop.get_debug():
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 9147832..4bd6dc8 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -10,6 +10,8 @@
 import errno
 import functools
 import socket
+import sys
+import warnings
 try:
     import ssl
 except ImportError:  # pragma: no cover
@@ -499,6 +501,11 @@
 
     _buffer_factory = bytearray  # Constructs initial value for self._buffer.
 
+    # Attribute used in the destructor: it must be set even if the constructor
+    # is not called (see _SelectorSslTransport which may start by raising an
+    # exception)
+    _sock = None
+
     def __init__(self, loop, sock, protocol, extra=None, server=None):
         super().__init__(extra, loop)
         self._extra['socket'] = sock
@@ -559,6 +566,15 @@
             self._conn_lost += 1
             self._loop.call_soon(self._call_connection_lost, None)
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if self._sock is not None:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self._sock.close()
+
     def _fatal_error(self, exc, message='Fatal error on transport'):
         # Should be called from exception handler only.
         if isinstance(exc, (BrokenPipeError,
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index fc809b9..235855e 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -1,4 +1,6 @@
 import collections
+import sys
+import warnings
 try:
     import ssl
 except ImportError:  # pragma: no cover
@@ -295,6 +297,7 @@
         self._loop = loop
         self._ssl_protocol = ssl_protocol
         self._app_protocol = app_protocol
+        self._closed = False
 
     def get_extra_info(self, name, default=None):
         """Get optional transport information."""
@@ -308,8 +311,18 @@
         protocol's connection_lost() method will (eventually) called
         with None as its argument.
         """
+        self._closed = True
         self._ssl_protocol._start_shutdown()
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if not self._closed:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self.close()
+
     def pause_reading(self):
         """Pause the receiving end.
 
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index 7e1265a..b06f1b2 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -8,6 +8,7 @@
 import subprocess
 import sys
 import threading
+import warnings
 
 
 from . import base_events
@@ -353,6 +354,15 @@
         if not self._closing:
             self._close(None)
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if self._pipe is not None:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self._pipe.close()
+
     def _fatal_error(self, exc, message='Fatal error on pipe transport'):
         # should be called by exception handler only
         if (isinstance(exc, OSError) and exc.errno == errno.EIO):
@@ -529,6 +539,15 @@
             # write_eof is all what we needed to close the write pipe
             self.write_eof()
 
+    # On Python 3.3 and older, objects with a destructor part of a reference
+    # cycle are never destroyed. It's not more the case on Python 3.4 thanks
+    # to the PEP 442.
+    if sys.version_info >= (3, 4):
+        def __del__(self):
+            if self._pipe is not None:
+                warnings.warn("unclosed transport %r" % self, ResourceWarning)
+                self._pipe.close()
+
     def abort(self):
         self._close(None)
 
diff --git a/Lib/asyncio/windows_utils.py b/Lib/asyncio/windows_utils.py
index 5f8327e..870cd13 100644
--- a/Lib/asyncio/windows_utils.py
+++ b/Lib/asyncio/windows_utils.py
@@ -14,6 +14,7 @@
 import socket
 import subprocess
 import tempfile
+import warnings
 
 
 __all__ = ['socketpair', 'pipe', 'Popen', 'PIPE', 'PipeHandle']
@@ -156,7 +157,10 @@
             CloseHandle(self._handle)
             self._handle = None
 
-    __del__ = close
+    def __del__(self):
+        if self._handle is not None:
+            warnings.warn("unclosed %r" % self, ResourceWarning)
+            self.close()
 
     def __enter__(self):
         return self