Skip to content

Commit f3aaad0

Browse files
committed
Make tests pass for the first time
1 parent 42b131f commit f3aaad0

File tree

4 files changed

+44
-25
lines changed

4 files changed

+44
-25
lines changed

include/pybind11/cast.h

+3-9
Original file line numberDiff line numberDiff line change
@@ -1014,9 +1014,7 @@ template <typename CharT> using is_std_char_type = any_of<
10141014

10151015
template <typename T>
10161016
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
1017-
using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
1018-
using _py_type_1 = conditional_t<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>;
1019-
using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;
1017+
using py_type = conditional_t<std::is_floating_point<T>::value, double, py_int_type_for<T>>;
10201018
public:
10211019

10221020
bool load(handle src, bool convert) {
@@ -1042,12 +1040,8 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
10421040
return false;
10431041
} else if (!convert && !index_check(src.ptr()) && !PYBIND11_LONG_CHECK(src.ptr())) {
10441042
return false;
1045-
} else if (std::is_unsigned<py_type>::value) {
1046-
py_value = as_unsigned<py_type>(src.ptr());
1047-
} else { // signed integer:
1048-
py_value = sizeof(T) <= sizeof(long)
1049-
? (py_type) PyLong_AsLong(src.ptr())
1050-
: (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
1043+
} else {
1044+
py_value = as_integer<py_type>(src.ptr());
10511045
}
10521046

10531047
// Python API reported an error

include/pybind11/detail/common.h

+2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
#define PYBIND11_BYTES_SIZE PyBytes_Size
176176
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
177177
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
178+
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o)
178179
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o)
179180
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o)
180181
#define PYBIND11_BYTES_NAME "bytes"
@@ -203,6 +204,7 @@
203204
#define PYBIND11_BYTES_SIZE PyString_Size
204205
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
205206
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
207+
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o))
206208
#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
207209
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
208210
#define PYBIND11_BYTES_NAME "str"

include/pybind11/pytypes.h

+35-14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#pragma once
1111

1212
#include "detail/common.h"
13+
#include "detail/typeid.h"
1314
#include "buffer_info.h"
1415
#include <utility>
1516
#include <type_traits>
@@ -1091,23 +1092,36 @@ class bool_ : public object {
10911092
};
10921093

10931094
PYBIND11_NAMESPACE_BEGIN(detail)
1095+
template <typename T>
1096+
using py_signed_int_type_for = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
1097+
1098+
template <typename T>
1099+
using py_unsigned_int_type_for = typename std::make_unsigned<py_signed_int_type_for<T>>::type;
1100+
1101+
template <typename T>
1102+
using py_int_type_for = conditional_t<std::is_signed<T>::value, py_signed_int_type_for<T>, py_unsigned_int_type_for<T>>;
1103+
10941104
// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1;
10951105
// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).
10961106
// (The distinction is critically important when casting a returned -1 error value to some other
10971107
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
10981108
template <typename Unsigned>
10991109
Unsigned as_unsigned(PyObject *o) {
1100-
if (sizeof(Unsigned) <= sizeof(unsigned long)
1101-
#if PY_VERSION_HEX < 0x03000000
1102-
|| PyInt_Check(o)
1103-
#endif
1104-
) {
1105-
unsigned long v = PyLong_AsUnsignedLong(o);
1106-
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
1110+
py_unsigned_int_type_for<Unsigned> v = (sizeof(Unsigned) <= sizeof(unsigned long))
1111+
? PyLong_AsUnsignedLong(o)
1112+
: PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o);
1113+
return v == (py_unsigned_int_type_for<Unsigned>) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
1114+
}
1115+
1116+
template <typename Int>
1117+
Int as_integer(PyObject *o) {
1118+
if (std::is_unsigned<Int>::value) {
1119+
return as_unsigned<Int>(o);
11071120
}
11081121
else {
1109-
unsigned long long v = PyLong_AsUnsignedLongLong(o);
1110-
return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
1122+
return sizeof(Int) <= sizeof(long)
1123+
? (Int) PyLong_AsLong(o)
1124+
: (Int) PYBIND11_LONG_AS_LONGLONG(o);
11111125
}
11121126
}
11131127
PYBIND11_NAMESPACE_END(detail)
@@ -1137,11 +1151,18 @@ class int_ : public object {
11371151
template <typename T,
11381152
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
11391153
operator T() const {
1140-
return std::is_unsigned<T>::value
1141-
? detail::as_unsigned<T>(m_ptr)
1142-
: sizeof(T) <= sizeof(long)
1143-
? (T) PyLong_AsLong(m_ptr)
1144-
: (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
1154+
using py_type = detail::py_int_type_for<T>;
1155+
auto value = detail::as_integer<py_type>(m_ptr);
1156+
if (PyErr_Occurred())
1157+
throw error_already_set();
1158+
if (sizeof(py_type) != sizeof(T) && value != (py_type) (T) value)
1159+
#if defined(NDEBUG)
1160+
throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
1161+
#else
1162+
throw cast_error("Unable to cast Python instance of type " +
1163+
(std::string) pybind11::str(type::handle_of(*this)) + " to C++ type '" + type_id<T>() + "'");
1164+
#endif
1165+
return (T) value;
11451166
}
11461167
};
11471168

tests/test_pytypes.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -333,11 +333,13 @@ def test_implicit_casting():
333333

334334
assert m.implicitly_cast_to_int32(42) == 42
335335
assert m.implicitly_cast_to_int32(2 ** 31 - 1) == 2 ** 31 - 1
336-
assert m.implicitly_cast_to_int32(2 ** 31)
336+
with pytest.raises(RuntimeError, match="Unable to cast Python instance"):
337+
m.implicitly_cast_to_int32(2 ** 31)
337338

338339
assert m.implicitly_cast_to_uint32(42) == 42
339340
assert m.implicitly_cast_to_uint32(2 ** 32 - 1) == 2 ** 32 - 1
340-
assert m.implicitly_cast_to_uint32(2 ** 32)
341+
with pytest.raises(RuntimeError, match="Unable to cast Python instance"):
342+
m.implicitly_cast_to_uint32(2 ** 32)
341343

342344

343345
def test_print(capture):

0 commit comments

Comments
 (0)