Report type names in return value policy-related cast exceptions (#1965)


diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index efc10d6..e1bbf03 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -533,9 +533,17 @@
             case return_value_policy::copy:
                 if (copy_constructor)
                     valueptr = copy_constructor(src);
-                else
-                    throw cast_error("return_value_policy = copy, but the "
-                                     "object is non-copyable!");
+                else {
+#if defined(NDEBUG)
+                    throw cast_error("return_value_policy = copy, but type is "
+                                     "non-copyable! (compile in debug mode for details)");
+#else
+                    std::string type_name(tinfo->cpptype->name());
+                    detail::clean_type_id(type_name);
+                    throw cast_error("return_value_policy = copy, but type " +
+                                     type_name + " is non-copyable!");
+#endif
+                }
                 wrapper->owned = true;
                 break;
 
@@ -544,9 +552,18 @@
                     valueptr = move_constructor(src);
                 else if (copy_constructor)
                     valueptr = copy_constructor(src);
-                else
-                    throw cast_error("return_value_policy = move, but the "
-                                     "object is neither movable nor copyable!");
+                else {
+#if defined(NDEBUG)
+                    throw cast_error("return_value_policy = move, but type is neither "
+                                     "movable nor copyable! "
+                                     "(compile in debug mode for details)");
+#else
+                    std::string type_name(tinfo->cpptype->name());
+                    detail::clean_type_id(type_name);
+                    throw cast_error("return_value_policy = move, but type " +
+                                     type_name + " is neither movable nor copyable!");
+#endif
+                }
                 wrapper->owned = true;
                 break;
 
diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py
index aff2d99..0e671d9 100644
--- a/tests/test_copy_move.py
+++ b/tests/test_copy_move.py
@@ -5,13 +5,13 @@
 def test_lacking_copy_ctor():
     with pytest.raises(RuntimeError) as excinfo:
         m.lacking_copy_ctor.get_one()
-    assert "the object is non-copyable!" in str(excinfo.value)
+    assert "is non-copyable!" in str(excinfo.value)
 
 
 def test_lacking_move_ctor():
     with pytest.raises(RuntimeError) as excinfo:
         m.lacking_move_ctor.get_one()
-    assert "the object is neither movable nor copyable!" in str(excinfo.value)
+    assert "is neither movable nor copyable!" in str(excinfo.value)
 
 
 def test_move_and_copy_casts():
@@ -98,7 +98,7 @@
 
     with pytest.raises(RuntimeError) as excinfo:
         m.private_op_new_value()
-    assert "the object is neither movable nor copyable" in str(excinfo.value)
+    assert "is neither movable nor copyable" in str(excinfo.value)
 
     assert m.private_op_new_reference().value == 1