mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Support C++17 aligned new statement (#1582)
* Support C++17 aligned new statement This patch makes pybind11 aware of nonstandard alignment requirements in bound types and passes on this information to C++17 aligned 'new' operator. Pre-C++17, the behavior is unchanged.
This commit is contained in:
parent
adc2cdd5c4
commit
e2eca4f8f8
@ -214,11 +214,14 @@ struct type_record {
|
|||||||
/// How large is the underlying C++ type?
|
/// How large is the underlying C++ type?
|
||||||
size_t type_size = 0;
|
size_t type_size = 0;
|
||||||
|
|
||||||
|
/// What is the alignment of the underlying C++ type?
|
||||||
|
size_t type_align = 0;
|
||||||
|
|
||||||
/// How large is the type's holder?
|
/// How large is the type's holder?
|
||||||
size_t holder_size = 0;
|
size_t holder_size = 0;
|
||||||
|
|
||||||
/// The global operator new can be overridden with a class-specific variant
|
/// The global operator new can be overridden with a class-specific variant
|
||||||
void *(*operator_new)(size_t) = ::operator new;
|
void *(*operator_new)(size_t) = nullptr;
|
||||||
|
|
||||||
/// Function pointer to class_<..>::init_instance
|
/// Function pointer to class_<..>::init_instance
|
||||||
void (*init_instance)(instance *, const void *) = nullptr;
|
void (*init_instance)(instance *, const void *) = nullptr;
|
||||||
|
@ -571,7 +571,17 @@ public:
|
|||||||
// Lazy allocation for unallocated values:
|
// Lazy allocation for unallocated values:
|
||||||
if (vptr == nullptr) {
|
if (vptr == nullptr) {
|
||||||
auto *type = v_h.type ? v_h.type : typeinfo;
|
auto *type = v_h.type ? v_h.type : typeinfo;
|
||||||
vptr = type->operator_new(type->type_size);
|
if (type->operator_new) {
|
||||||
|
vptr = type->operator_new(type->type_size);
|
||||||
|
} else {
|
||||||
|
#if defined(PYBIND11_CPP17)
|
||||||
|
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||||
|
vptr = ::operator new(type->type_size,
|
||||||
|
(std::align_val_t) type->type_align);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
vptr = ::operator new(type->type_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
value = vptr;
|
value = vptr;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ struct internals {
|
|||||||
struct type_info {
|
struct type_info {
|
||||||
PyTypeObject *type;
|
PyTypeObject *type;
|
||||||
const std::type_info *cpptype;
|
const std::type_info *cpptype;
|
||||||
size_t type_size, holder_size_in_ptrs;
|
size_t type_size, type_align, holder_size_in_ptrs;
|
||||||
void *(*operator_new)(size_t);
|
void *(*operator_new)(size_t);
|
||||||
void (*init_instance)(instance *, const void *);
|
void (*init_instance)(instance *, const void *);
|
||||||
void (*dealloc)(value_and_holder &v_h);
|
void (*dealloc)(value_and_holder &v_h);
|
||||||
@ -138,7 +138,7 @@ struct type_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
||||||
#define PYBIND11_INTERNALS_VERSION 2
|
#define PYBIND11_INTERNALS_VERSION 3
|
||||||
|
|
||||||
#if defined(WITH_THREAD)
|
#if defined(WITH_THREAD)
|
||||||
# define PYBIND11_INTERNALS_KIND ""
|
# define PYBIND11_INTERNALS_KIND ""
|
||||||
|
@ -896,6 +896,7 @@ protected:
|
|||||||
tinfo->type = (PyTypeObject *) m_ptr;
|
tinfo->type = (PyTypeObject *) m_ptr;
|
||||||
tinfo->cpptype = rec.type;
|
tinfo->cpptype = rec.type;
|
||||||
tinfo->type_size = rec.type_size;
|
tinfo->type_size = rec.type_size;
|
||||||
|
tinfo->type_align = rec.type_align;
|
||||||
tinfo->operator_new = rec.operator_new;
|
tinfo->operator_new = rec.operator_new;
|
||||||
tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);
|
tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);
|
||||||
tinfo->init_instance = rec.init_instance;
|
tinfo->init_instance = rec.init_instance;
|
||||||
@ -987,11 +988,21 @@ template <typename T> struct has_operator_delete_size<T, void_t<decltype(static_
|
|||||||
: std::true_type { };
|
: std::true_type { };
|
||||||
/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
|
/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
|
||||||
template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
|
template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
|
||||||
void call_operator_delete(T *p, size_t) { T::operator delete(p); }
|
void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); }
|
||||||
template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
|
template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
|
||||||
void call_operator_delete(T *p, size_t s) { T::operator delete(p, s); }
|
void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); }
|
||||||
|
|
||||||
inline void call_operator_delete(void *p, size_t) { ::operator delete(p); }
|
inline void call_operator_delete(void *p, size_t s, size_t a) {
|
||||||
|
(void)s; (void)a;
|
||||||
|
#if defined(PYBIND11_CPP17)
|
||||||
|
if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||||
|
::operator delete(p, s, std::align_val_t(a));
|
||||||
|
else
|
||||||
|
::operator delete(p, s);
|
||||||
|
#else
|
||||||
|
::operator delete(p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
@ -1054,6 +1065,7 @@ public:
|
|||||||
record.name = name;
|
record.name = name;
|
||||||
record.type = &typeid(type);
|
record.type = &typeid(type);
|
||||||
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
|
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
|
||||||
|
record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
|
||||||
record.holder_size = sizeof(holder_type);
|
record.holder_size = sizeof(holder_type);
|
||||||
record.init_instance = init_instance;
|
record.init_instance = init_instance;
|
||||||
record.dealloc = dealloc;
|
record.dealloc = dealloc;
|
||||||
@ -1329,7 +1341,10 @@ private:
|
|||||||
v_h.set_holder_constructed(false);
|
v_h.set_holder_constructed(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
detail::call_operator_delete(v_h.value_ptr<type>(), v_h.type->type_size);
|
detail::call_operator_delete(v_h.value_ptr<type>(),
|
||||||
|
v_h.type->type_size,
|
||||||
|
v_h.type->type_align
|
||||||
|
);
|
||||||
}
|
}
|
||||||
v_h.value_ptr() = nullptr;
|
v_h.value_ptr() = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include "local_bindings.h"
|
#include "local_bindings.h"
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
|
||||||
|
#endif
|
||||||
|
|
||||||
// test_brace_initialization
|
// test_brace_initialization
|
||||||
struct NoBraceInitialization {
|
struct NoBraceInitialization {
|
||||||
NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
||||||
@ -354,6 +358,15 @@ TEST_SUBMODULE(class_, m) {
|
|||||||
[](StringWrapper) -> NotRegistered { return {}; });
|
[](StringWrapper) -> NotRegistered { return {}; });
|
||||||
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
||||||
py::implicitly_convertible<std::string, StringWrapper>();
|
py::implicitly_convertible<std::string, StringWrapper>();
|
||||||
|
|
||||||
|
#if defined(PYBIND11_CPP17)
|
||||||
|
struct alignas(1024) Aligned {
|
||||||
|
std::uintptr_t ptr() const { return (uintptr_t) this; }
|
||||||
|
};
|
||||||
|
py::class_<Aligned>(m, "Aligned")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("ptr", &Aligned::ptr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };
|
template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };
|
||||||
|
@ -273,3 +273,9 @@ def test_error_after_conversions():
|
|||||||
m.test_error_after_conversions("hello")
|
m.test_error_after_conversions("hello")
|
||||||
assert str(exc_info.value).startswith(
|
assert str(exc_info.value).startswith(
|
||||||
"Unable to convert function return value to a Python type!")
|
"Unable to convert function return value to a Python type!")
|
||||||
|
|
||||||
|
|
||||||
|
def test_aligned():
|
||||||
|
if hasattr(m, "Aligned"):
|
||||||
|
p = m.Aligned().ptr()
|
||||||
|
assert p % 1024 == 0
|
||||||
|
Loading…
Reference in New Issue
Block a user