From 5ebc78164db47772d9c57948b3668edae1e273be Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Fri, 2 Oct 2020 15:39:22 +0200 Subject: [PATCH] Allow raw unions without base classes in is_accessible_base_of (#2320) Co-authored-by: Henry Schreiner --- docs/changelog.rst | 6 +++++- include/pybind11/detail/common.h | 3 ++- tests/pybind11_tests.h | 6 ++++++ tests/test_opaque_types.cpp | 6 ++++++ tests/test_opaque_types.py | 8 ++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8f95c1274..56dc10eaf 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -98,6 +98,11 @@ See :ref:`upgrade-guide-2.6` for help upgrading to the new version. ``get_type_overload`` is deprecated. `#2325 `_ +* `py::class_` is now supported. Note that writing to one data + member of the union and reading another (type punning) is UB in C++. Thus + pybind11-bound enums should never be used for such conversion. + `#2320 `_. + Smaller or developer focused features: * Moved ``mkdoc.py`` to a new repo, `pybind11-mkdoc`_. @@ -164,7 +169,6 @@ Smaller or developer focused features: .. _pre-commit: https://pre-commit.com - v2.5.0 (Mar 31, 2020) ----------------------------------------------------- diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 7220532cd..474e00629 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -631,8 +631,9 @@ template using is_strict_base_of = bool_consta /// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer /// can be converted to a Base pointer) +/// For unions, `is_base_of::value` is False, so we need to check `is_same` as well. template using is_accessible_base_of = bool_constant< - std::is_base_of::value && std::is_convertible::value>; + (std::is_same::value || std::is_base_of::value) && std::is_convertible::value>; template class Base> struct is_template_base_of_impl { diff --git a/tests/pybind11_tests.h b/tests/pybind11_tests.h index 1e4741627..247f799ce 100644 --- a/tests/pybind11_tests.h +++ b/tests/pybind11_tests.h @@ -50,6 +50,12 @@ public: IncType &operator=(IncType &&) = delete; }; +/// A simple union for basic testing +union IntFloat { + int i; + float f; +}; + /// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context. /// Used to test recursive casters (e.g. std::tuple, stl containers). struct RValueCaster {}; diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp index 594c45a08..5a2343163 100644 --- a/tests/test_opaque_types.cpp +++ b/tests/test_opaque_types.cpp @@ -64,4 +64,10 @@ TEST_SUBMODULE(opaque_types, m) { result->push_back("some value"); return std::unique_ptr(result); }); + + // test unions + py::class_(m, "IntFloat") + .def(py::init<>()) + .def_readwrite("i", &IntFloat::i) + .def_readwrite("f", &IntFloat::f); } diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py index 3f2392775..ac6a8560e 100644 --- a/tests/test_opaque_types.py +++ b/tests/test_opaque_types.py @@ -45,3 +45,11 @@ def test_pointers(msg): ptr = m.return_unique_ptr() assert "StringList" in repr(ptr) assert m.print_opaque_list(ptr) == "Opaque list: [some value]" + + +def test_unions(): + int_float_union = m.IntFloat() + int_float_union.i = 42 + assert int_float_union.i == 42 + int_float_union.f = 3.0 + assert int_float_union.f == 3.0