fix: throwing repr caused a segfault (#2389)

* fix: throwing repr caused a segfault

* fixup! ci: include Python 3.9 RC1 (#2387)
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index d34c92c..3a7d7b8 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -776,7 +776,11 @@
             for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
                 if (!some_args) some_args = true;
                 else msg += ", ";
-                msg += pybind11::repr(args_[ti]);
+                try {
+                    msg += pybind11::repr(args_[ti]);
+                } catch (const error_already_set&) {
+                    msg += "<repr raised Error>";
+                }
             }
             if (kwargs_in) {
                 auto kwargs = reinterpret_borrow<dict>(kwargs_in);
@@ -787,7 +791,12 @@
                     for (auto kwarg : kwargs) {
                         if (first) first = false;
                         else msg += ", ";
-                        msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
+                        msg += pybind11::str("{}=").format(kwarg.first);
+                        try {
+                            msg += pybind11::repr(kwarg.second);
+                        } catch (const error_already_set&) {
+                            msg += "<repr raised Error>";
+                        }
                     }
                 }
             }
diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp
index 372d0ae..537819d 100644
--- a/tests/test_exceptions.cpp
+++ b/tests/test_exceptions.cpp
@@ -218,4 +218,7 @@
         }
     });
 
+    // Test repr that cannot be displayed
+    m.def("simple_bool_passthrough", [](bool x) {return x;});
+
 }
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index 83a46bf..7d7088d 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -178,3 +178,14 @@
     with pytest.raises(m.MyException5) as excinfo:
         m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
     assert str(excinfo.value) == "this is a helper-defined translated exception"
+
+
+# This can often happen if you wrap a pybind11 class in a Python wrapper
+def test_invalid_repr():
+
+    class MyRepr(object):
+        def __repr__(self):
+            raise AttributeError("Example error")
+
+    with pytest.raises(TypeError):
+        m.simple_bool_passthrough(MyRepr())