bpo-32094: Update subprocess for -X dev (#4480)

Modify subprocess._args_from_interpreter_flags() to handle -X dev
option.

Add also unit tests for test.support.args_from_interpreter_flags()
and test.support.optim_args_from_interpreter_flags().
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 43be1f9..97b4493 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -260,8 +260,29 @@
         v = getattr(sys.flags, flag)
         if v > 0:
             args.append('-' + opt * v)
-    for opt in sys.warnoptions:
+
+    # -W options
+    warnoptions = sys.warnoptions
+    xoptions = getattr(sys, '_xoptions', {})
+    if 'dev' in xoptions and warnoptions and warnoptions[-1] == 'default':
+        # special case: -X dev adds 'default' to sys.warnoptions
+        warnoptions = warnoptions[:-1]
+    for opt in warnoptions:
         args.append('-W' + opt)
+
+    # -X options
+    if 'dev' in xoptions:
+        args.extend(('-X', 'dev'))
+    for opt in ('faulthandler', 'tracemalloc', 'importtime',
+                'showalloccount', 'showrefcount'):
+        if opt in xoptions:
+            value = xoptions[opt]
+            if value is True:
+                arg = opt
+            else:
+                arg = '%s=%s' % (opt, value)
+            args.extend(('-X', arg))
+
     return args
 
 
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 8632837..4a577ef 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -6,6 +6,7 @@
 import shutil
 import socket
 import stat
+import subprocess
 import sys
 import tempfile
 import time
@@ -426,6 +427,62 @@
         # pending child process
         support.reap_children()
 
+    def check_options(self, args, func):
+        code = f'from test.support import {func}; print(repr({func}()))'
+        cmd = [sys.executable, *args, '-c', code]
+        env = {key: value for key, value in os.environ.items()
+               if not key.startswith('PYTHON')}
+        proc = subprocess.run(cmd,
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.DEVNULL,
+                              universal_newlines=True,
+                              env=env)
+        self.assertEqual(proc.stdout.rstrip(), repr(args))
+        self.assertEqual(proc.returncode, 0)
+
+    def test_args_from_interpreter_flags(self):
+        # Test test.support.args_from_interpreter_flags()
+        for opts in (
+            # no option
+            [],
+            # single option
+            ['-B'],
+            ['-s'],
+            ['-S'],
+            ['-E'],
+            ['-v'],
+            ['-b'],
+            ['-q'],
+            # same option multiple times
+            ['-bb'],
+            ['-vvv'],
+            # -W options
+            ['-Wignore'],
+            # -X options
+            ['-X', 'dev'],
+            ['-Wignore', '-X', 'dev'],
+            ['-X', 'faulthandler'],
+            ['-X', 'importtime'],
+            ['-X', 'showalloccount'],
+            ['-X', 'showrefcount'],
+            ['-X', 'tracemalloc'],
+            ['-X', 'tracemalloc=3'],
+        ):
+            with self.subTest(opts=opts):
+                self.check_options(opts, 'args_from_interpreter_flags')
+
+    def test_optim_args_from_interpreter_flags(self):
+        # Test test.support.optim_args_from_interpreter_flags()
+        for opts in (
+            # no option
+            [],
+            ['-O'],
+            ['-OO'],
+            ['-OOOO'],
+        ):
+            with self.subTest(opts=opts):
+                self.check_options(opts, 'optim_args_from_interpreter_flags')
+
     # XXX -follows a list of untested API
     # make_legacy_pyc
     # is_resource_enabled
@@ -447,7 +504,6 @@
     # threading_cleanup
     # reap_threads
     # strip_python_stderr
-    # args_from_interpreter_flags
     # can_symlink
     # skip_unless_symlink
     # SuppressCrashReport