Repository: pallets/click

Issue:
windows argument expansion is failing with a regex parsing error
I'm using pipenv to run pytest which is calling into click and attempting to expand arguments and failing.

The command I'm running in context is
```text
pipenv run pytest tests/test_thing.py::test_something[e-a]
```
but it can replicated without using pipenv or pytest and produce the same exception. 

Running
```python
from click.utils import _expand_args
_expand_args(['tests/test_thing.py::test_something[e-a]'])
```
results in
```text
  File "C:\Users\xxx\.virtualenvs\xxx-3g_HEZBh\lib\site-packages\click\utils.py", line 572, in _expand_args
    matches = glob(arg, recursive=glob_recursive)
  File "C:\Program Files\Python39\lib\glob.py", line 22, in glob
    return list(iglob(pathname, recursive=recursive))
  File "C:\Program Files\Python39\lib\glob.py", line 75, in _iglob
    for name in glob_in_dir(dirname, basename, dironly):
  File "C:\Program Files\Python39\lib\glob.py", line 86, in _glob1
    return fnmatch.filter(names, pattern)
  File "C:\Program Files\Python39\lib\fnmatch.py", line 58, in filter
    match = _compile_pattern(pat)
  File "C:\Program Files\Python39\lib\fnmatch.py", line 52, in _compile_pattern
    return re.compile(res).match
  File "C:\Program Files\Python39\lib\re.py", line 252, in compile
    return _compile(pattern, flags)
  File "C:\Program Files\Python39\lib\re.py", line 304, in _compile
    p = sre_compile.compile(pattern, flags)
  File "C:\Program Files\Python39\lib\sre_compile.py", line 764, in compile
    p = sre_parse.parse(p, flags)
  File "C:\Program Files\Python39\lib\sre_parse.py", line 948, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
  File "C:\Program Files\Python39\lib\sre_parse.py", line 443, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
  File "C:\Program Files\Python39\lib\sre_parse.py", line 834, in _parse
    p = _parse_sub(source, state, sub_verbose, nested + 1)
  File "C:\Program Files\Python39\lib\sre_parse.py", line 443, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
  File "C:\Program Files\Python39\lib\sre_parse.py", line 598, in _parse
    raise source.error(msg, len(this) + 1 + len(that))
re.error: bad character range e-a at position 35
```

Expected behavior - if expansion fails, treat it as an empty glob match. Something like this but without the bare except catch.
```python
def _expand_args(args):
    from glob import glob

    out = []

    for arg in args:
        if user:
            arg = os.path.expanduser(arg)

        if env:
            arg = os.path.expandvars(arg)

        try:
            matches = glob(arg, recursive=glob_recursive)
        except:
            matches = []

        if not matches:
            out.append(arg)
        else:
            out.extend(matches)

    return out
```

Environment:

- Python version: 3.9.7
- Click version: 8.0.3



Discussion:
Related to #1901 and #2135

Resolving patch:
diff --git a/src/click/utils.py b/src/click/utils.py
--- a/src/click/utils.py
+++ b/src/click/utils.py
@@ -1,4 +1,5 @@
 import os
+import re
 import sys
 import typing as t
 from functools import update_wrapper
@@ -536,7 +537,7 @@ def _expand_args(
     See :func:`glob.glob`, :func:`os.path.expanduser`, and
     :func:`os.path.expandvars`.
 
-    This intended for use on Windows, where the shell does not do any
+    This is intended for use on Windows, where the shell does not do any
     expansion. It may not exactly match what a Unix shell would do.
 
     :param args: List of command line arguments to expand.
@@ -544,6 +545,10 @@ def _expand_args(
     :param env: Expand environment variables.
     :param glob_recursive: ``**`` matches directories recursively.
 
+    .. versionchanged:: 8.1
+        Invalid glob patterns are treated as empty expansions rather
+        than raising an error.
+
     .. versionadded:: 8.0
 
     :meta private:
@@ -559,7 +564,10 @@ def _expand_args(
         if env:
             arg = os.path.expandvars(arg)
 
-        matches = glob(arg, recursive=glob_recursive)
+        try:
+            matches = glob(arg, recursive=glob_recursive)
+        except re.error:
+            matches = []
 
         if not matches:
             out.append(arg)


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -468,6 +468,8 @@ def test_expand_args(monkeypatch):
     assert "setup.cfg" in click.utils._expand_args(["*.cfg"])
     assert os.path.join("docs", "conf.py") in click.utils._expand_args(["**/conf.py"])
     assert "*.not-found" in click.utils._expand_args(["*.not-found"])
+    # a bad glob pattern, such as a pytest identifier, should return itself
+    assert click.utils._expand_args(["test.py::test_bad"])[0] == "test.py::test_bad"
 
 
 @pytest.mark.parametrize(