Merge pull request #394 from jagerman/fix-ref-heap-casts

Fix ref heap casts
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 8ec0aa4..b30b5be 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -106,12 +106,17 @@
 }
 
 PYBIND11_NOINLINE inline std::string error_string() {
-   PyObject *type, *value, *traceback;
-   PyErr_Fetch(&type, &value, &traceback);
+    if (!PyErr_Occurred()) {
+        PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
+        return "Unknown internal error occurred";
+    }
 
-   std::string errorString;
+    PyObject *type, *value, *traceback;
+    PyErr_Fetch(&type, &value, &traceback);
+
+    std::string errorString;
     if (type) {
-        errorString += (std::string) handle(type).str();
+        errorString += handle(type).attr("__name__").cast<std::string>();
         errorString += ": ";
     }
     if (value)
@@ -155,7 +160,7 @@
     PYBIND11_NOINLINE bool load(handle src, bool convert) {
         if (!src || !typeinfo)
             return false;
-        if (src.ptr() == Py_None) {
+        if (src.is_none()) {
             value = nullptr;
             return true;
         } else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
@@ -180,7 +185,7 @@
                                          const void *existing_holder = nullptr) {
         void *src = const_cast<void *>(_src);
         if (src == nullptr)
-            return handle(Py_None).inc_ref();
+            return none();
 
         auto &internals = get_internals();
 
@@ -409,7 +414,7 @@
 public:
     bool load(handle, bool) { return false; }
     static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) {
-        return handle(Py_None).inc_ref();
+        return none();
     }
     PYBIND11_TYPE_CASTER(void_type, _("None"));
 };
@@ -421,7 +426,7 @@
     bool load(handle h, bool) {
         if (!h) {
             return false;
-        } else if (h.ptr() == Py_None) {
+        } else if (h.is_none()) {
             value = nullptr;
             return true;
         }
@@ -447,7 +452,7 @@
         if (ptr)
             return capsule(ptr).release();
         else
-            return handle(Py_None).inc_ref();
+            return none();
     }
 
     template <typename T> using cast_op_type = void*&;
@@ -559,12 +564,12 @@
 template <> class type_caster<char> : public type_caster<std::string> {
 public:
     bool load(handle src, bool convert) {
-        if (src.ptr() == Py_None) return true;
+        if (src.is_none()) return true;
         return type_caster<std::string>::load(src, convert);
     }
 
     static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
-        if (src == nullptr) return handle(Py_None).inc_ref();
+        if (src == nullptr) return none();
         return PyUnicode_FromString(src);
     }
 
@@ -582,12 +587,12 @@
 template <> class type_caster<wchar_t> : public type_caster<std::wstring> {
 public:
     bool load(handle src, bool convert) {
-        if (src.ptr() == Py_None) return true;
+        if (src.is_none()) return true;
         return type_caster<std::wstring>::load(src, convert);
     }
 
     static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) {
-        if (src == nullptr) return handle(Py_None).inc_ref();
+        if (src == nullptr) return none();
         return PyUnicode_FromWideChar(src, (ssize_t) wcslen(src));
     }
 
@@ -758,7 +763,7 @@
     bool load(handle src, bool convert) {
         if (!src || !typeinfo) {
             return false;
-        } else if (src.ptr() == Py_None) {
+        } else if (src.is_none()) {
             value = nullptr;
             return true;
         } else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h
index 0df8129..7f032fc 100644
--- a/include/pybind11/functional.h
+++ b/include/pybind11/functional.h
@@ -20,7 +20,7 @@
     typedef typename std::conditional<std::is_same<Return, void>::value, void_type, Return>::type retval_type;
 public:
     bool load(handle src_, bool) {
-        if (src_.ptr() == Py_None)
+        if (src_.is_none())
             return true;
 
         src_ = detail::get_function(src_);
@@ -62,7 +62,7 @@
     template <typename Func>
     static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
         if (!f_)
-            return handle(Py_None).inc_ref();
+            return none();
 
         auto result = f_.template target<Return (*)(Args...)>();
         if (result)
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 0d16c7a..dd04e95 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -1143,7 +1143,7 @@
     if (!nurse || !patient)
         pybind11_fail("Could not activate keep_alive!");
 
-    if (patient.ptr() == Py_None || nurse.ptr() == Py_None)
+    if (patient.is_none() || nurse.is_none())
         return; /* Nothing to keep alive or nothing to be kept alive by */
 
     cpp_function disable_lifesupport(
diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h
index 51f1629..ba5d2c4 100644
--- a/include/pybind11/pytypes.h
+++ b/include/pybind11/pytypes.h
@@ -40,6 +40,7 @@
     inline detail::accessor attr(const char *key) const;
     inline pybind11::str str() const;
     inline pybind11::str repr() const;
+    bool is_none() const { return m_ptr == Py_None; }
     template <typename T> T cast() const;
     template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
     #if __cplusplus > 201103L
diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp
index 534f23b..67133a6 100644
--- a/tests/test_exceptions.cpp
+++ b/tests/test_exceptions.cpp
@@ -104,5 +104,23 @@
     m.def("throws3", &throws3);
     m.def("throws4", &throws4);
     m.def("throws_logic_error", &throws_logic_error);
-});
 
+    m.def("throw_already_set", [](bool err) {
+        if (err)
+            PyErr_SetString(PyExc_ValueError, "foo");
+        try {
+            throw py::error_already_set();
+        } catch (const std::runtime_error& e) {
+            if ((err && e.what() != std::string("ValueError: foo")) ||
+                (!err && e.what() != std::string("Unknown internal error occurred")))
+            {
+                PyErr_Clear();
+                throw std::runtime_error("error message mismatch");
+            }
+        }
+        PyErr_Clear();
+        if (err)
+            PyErr_SetString(PyExc_ValueError, "foo");
+        throw py::error_already_set();
+    });
+});
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index 24f9769..a92300c 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -1,6 +1,18 @@
 import pytest
 
 
+def test_error_already_set(msg):
+    from pybind11_tests import throw_already_set
+
+    with pytest.raises(RuntimeError) as excinfo:
+        throw_already_set(False)
+    assert msg(excinfo.value) == "Unknown internal error occurred"
+
+    with pytest.raises(ValueError) as excinfo:
+        throw_already_set(True)
+    assert msg(excinfo.value) == "foo"
+
+
 def test_custom(msg):
     from pybind11_tests import (MyException, throws1, throws2, throws3, throws4,
                                 throws_logic_error)