mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-26 07:02:11 +00:00
1bafd5db5f
* Adding test_unique_ptr_member (for desired PyCLIF behavior). See also: https://github.com/pybind/pybind11/issues/2583 Does not build with upstream master or https://github.com/pybind/pybind11/pull/2047, but builds with https://github.com/RobotLocomotion/pybind11 and almost runs: ``` Running tests in directory "/usr/local/google/home/rwgk/forked/EricCousineau-TRI/pybind11/tests": ================================================================================= test session starts ================================================================================= platform linux -- Python 3.8.5, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: /usr/local/google/home/rwgk/forked/EricCousineau-TRI/pybind11/tests, inifile: pytest.ini collected 2 items test_unique_ptr_member.py .F [100%] ====================================================================================== FAILURES ======================================================================================= _____________________________________________________________________________ test_pointee_and_ptr_owner ______________________________________________________________________________ def test_pointee_and_ptr_owner(): obj = m.pointee() assert obj.get_int() == 213 m.ptr_owner(obj) with pytest.raises(ValueError) as exc_info: > obj.get_int() E Failed: DID NOT RAISE <class 'ValueError'> test_unique_ptr_member.py:17: Failed ============================================================================= 1 failed, 1 passed in 0.06s ============================================================================= ``` * unique_ptr or shared_ptr return * new test_variant_unique_shared with vptr_holder prototype * moving prototype code to pybind11/vptr_holder.h, adding type_caster specialization to make the bindings involving unique_ptr passing compile, but load and cast implementations are missing * disabling GitHub Actions on pull_request (for this PR) * disabling AppVeyor (for this PR) * TRIGGER_SEGSEV macro, annotations for GET_STACK (vptr::get), GET_INT_STACK (pointee) * adding test_promotion_of_disowned_to_shared * Copying tests as-is from xxx_value_ptr_xxx_holder branch. https://github.com/rwgk/pybind11/tree/xxx_value_ptr_xxx_holder Systematically exercising returning and passing unique_ptr<T>, shared_ptr<T> with unique_ptr, shared_ptr holder. Observations: test_holder_unique_ptr: make_unique_pointee OK pass_unique_pointee BUILD_FAIL (as documented) make_shared_pointee Abort free(): double free detected pass_shared_pointee RuntimeError: Unable to load a custom holder type from a default-holder instance test_holder_shared_ptr: make_unique_pointee Segmentation fault (#1138) pass_unique_pointee BUILD_FAIL (as documented) make_shared_pointee OK pass_shared_pointee OK * Copying tests as-is from xxx_value_ptr_xxx_holder branch. https://github.com/rwgk/pybind11/tree/xxx_value_ptr_xxx_holder Systematically exercising casting between shared_ptr<base>, shared_ptr<derived>. * Demonstration of Undefined Behavior in handling of shared_ptr holder. Based on https://godbolt.org/z/4fdjaW by jorgbrown@ (thanks Jorg!). * Additional demonstration of Undefined Behavior in handling of shared_ptr holder. * fixing up-down mixup in comment * Demonstration of Undefined Behavior in handling of polymorphic pointers. (This demo does NOT involve smart pointers at all, unlike the otherwise similar test_smart_ptr_private_first_base.) * minor test_private_first_base.cpp simplification (after discovering that this can be wrapped with Boost.Python, using boost::noncopyable) * pybind11 equivalent of Boost.Python test similar to reproducer under #1333 * Snapshot of WIP, TODO: shared_ptr deleter with on/off switch * Adding vptr_deleter. * Adding from/as unique_ptr<T> and unique_ptr<T, D>. * Adding from_shared_ptr. Some polishing. * New tests/core/smart_holder_poc_test.cpp, using Catch2. * Adding in vptr_deleter_guard_flag. * Improved labeling of TEST_CASEs. * Shuffling existing TEST_CASEs into systematic matrix. * Implementing all [S]uccess tests. * Implementing all [E]xception tests. * Testing of exceptions not covered by the from-as matrix. * Adding top-level comment. * Converting from methods to factory functions (no functional change). * Removing obsolete and very incomplete test (replaced by Catch2-based test). * Removing stray file. * Adding type_caster_bare_interface_demo. * Adding shared_ptr<mpty>, shared_ptr<mpty const> casters. * Adding unique_ptr<mpty>, unique_ptr<mpty const> casters. * Pure copy of `class class_` implementation in pybind11.h (master commit98f1bbb800
). * classh.h: renaming of class_ to classh + namespace; forking test_classh_wip from test_type_caster_bare_interface_demo. * Hard-coding smart_holder into classh. * Adding mpty::mtxt string member. * Adding isinstance<mpty> in type_caster::load functions. * Adding rvalue_ref, renaming const_value_ref to lvalue_ref & removing const. * Retrieving smart_holder pointer in type_caster<mpty>::load, and using it cast_op operators. * Factoring out smart_holder_type_caster_load. * Retrieving smart_holder pointer in type_caster<std::shared_ptr<mpty[ const]>>::load, and using it cast_op operators. * Improved error messaging: Cannot disown nullptr (as_unique_ptr). * Retrieving smart_holder pointer in type_caster<std::unique_ptr<mpty[ const]>>::load, and using it cast_op operators. * Pure `clang-format --style=file -i` change. * Pure `clang-format --style=file -i` change, with two `clang-format off` directives. * Fixing oversight (discovered by flake8). * flake8 cleanup * Systematically setting mtxt for all rtrn_mpty_* functions (preparation, the values are not actually used yet). * static cast handle for rtrn_cptr works by simply dropping in code from type_caster_base (marked with comments). * static cast handle for rtrn_cref works by simply dropping in code from type_caster_base (marked with comments). rtrn_mref and rtrn_mptr work via const_cast (to add const). * static cast handle for rtrn_valu works by simply dropping in code from type_caster_base (marked with comments). rtrn_rref raises a RuntimeError, to be investigated. * Copying type_caster_generic::cast into type_caster<mpty> as-is (preparation for handling smart pointers). * Pure clang-format change (applied to original type_caster_generic::cast). * Adding comment re potential use_count data race. * static handle cast implementations for rtrn_shmp, rtrn_shcp. * Adding MISSING comments in operator std::unique_ptr<mpty[ const]>. * static handle cast implementations for rtrn_uqmp, rtrn_uqcp. * Bug fix: vptr_deleter_armed_flag_ptr has to live on the heap. See new bullet point in comment section near the top. The variable was also renamed to reflect its function more accurately. * Fixing bugs discovered by ASAN. The code is now ASAN, MSAN, UBSAN clean. * Making test_type_caster_bare_interface_demo.cpp slightly more realistic, ASAN, MSAN, UBSAN clean. * Calling deregister_instance after disowning via unique_ptr. * Removing enable_shared_from_this stub, simplifying existing code, clang-format. Open question, with respect to the original code:76a160070b/include/pybind11/pybind11.h (L1510)
To me it looks like the exact situation marked as `std::shared_ptr<Good> gp1 = not_so_good.getptr();` here: https://en.cppreference.com/w/cpp/memory/enable_shared_from_this The comment there is: `// undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17)` Does the existing code have UB pre C++17? I'll leave handling of enable_shared_from_this for later, as the need arises. * Cosmetical change around helper functions. * Using type_caster_base<mpty>::src_and_type directly, removing copy. Also renaming one cast to cast_const_raw_ptr, for clarity. * Fixing clang-format oversight. * Using factored-out make_constructor (PR #2798), removing duplicate code. * Inserting additional assert to ensure a returned unique_ptr is always a new Python instance. * Adding minor comment (change to internals needed to distinguish uninitialized/disowned in error message). * Factoring out find_existing_python_instance(). * Moving factored-out make_constructor to test_classh_wip.cpp, restoring previous version of cast.h. This is currently the most practical approach. See PR #2798 for background. * Copying classh type_casters from test_classh_wip.cpp UNMODIFIED, as a baseline for generalizing the code. * Using pybind11/detail/classh_type_casters.h from test_classh_wip.cpp. * Adding & using PYBIND11_CLASSH_TYPE_CASTERS define. * Adding test_classh_inheritance, currently failing (passes with class_). * Removing .clang-format before git rebase master (where the file was added). * Bringing back .clang-format, the previous rm was a bad idea. * Folding in modified_type_caster_generic_load_impl, just enough to pass test_class_wip. test_classh_inheritance is still failing, but with a different error: [RuntimeError: Incompatible type (as_raw_ptr_unowned).] * Minimal changes needed to pass test_classh_inheritance. * First pass adjusting try_implicit_casts and try_load_foreign_module_local to capture loaded_v_h, but untested and guarded with pybind11_failure("Untested"). This was done mainly to determine general feasibility. Note the TODO in pybind11.h, where type_caster_generic::local_load is currently hard-coded. test_classh_wip and test_classh_inheritance still pass, as before. * Decoupling generic_type from type_caster_generic. * Changes and tests covering classh_type_casters try_implicit_casts. * Minimal test covering classh_type_casters load_impl Case 2b. * Removing stray isinstance<T>(src): it interferes with the py::module_local feature. Adding missing #includes. * Tests for classh py::module_local() feature. * Pure renaming of function names in test_classh_inheritance, similar to the systematic approach used in test_class_wip. NO functional changes. * Pure renaming of function and variable names, for better generalization when convoluting with inheritance. NO functional changes. * Adopting systematic naming scheme from test_classh_wip. NO functional changes. * Moving const after type name, for functions that cover a systematic scheme. NO functional changes. * Adding smart_holder_type_caster_load::loaded_as_shared_ptr, currently bypassing smart_holder shared_ptr tracking completely, but the tests pass and are sanitizer clean. * Removing rtti_held from smart_holder. See updated comment. * Cleaning up loaded_as_raw_ptr_unowned, loaded_as_shared_ptr. * Factoring out convert_type and folding into loaded_as_unique_ptr. * Folding convert_type into lvalue_ref and rvalue_ref paths. Some smart_holder_type_caster_load cleanup. * Using unique_ptr in local_load to replace static variable. Also adding local_load_safety_guard. * Converting test_unique_ptr_member to using classh: fully working, ASAN, MSAN, UBSAN clean. * Removing debugging comments (GET_STACK, GET_INT_STACK). cast.h is identical to current master again, pybind11.h only has the generic_type::initialize(..., &type_caster_generic::local_load) change. * Purging obsolete pybind11/vptr_holder.h and associated test. * Moving several tests to github.com/rwgk/rwgk_tbx/tree/main/pybind11_testsa2c2f88174
These tests are from experimenting, and for demonstrating UB in pybind11 multiple inheritance handling ("first_base"), to be fixed later. * Adding py::smart_holder support to py::class_, purging py::classh completely. * Renaming files in include directory, creating pybind11/smart_holder.h. * Renaming all "classh" to "smart_holder" in pybind11/detail/smart_holder_type_casters.h. The user-facing macro is now PYBIND11_SMART_HOLDER_TYPE_CASTERS. * Systematically renaming tests to use "class_sh" in the name. * Renaming test_type_caster_bare_interface_demo to test_type_caster_bare_interface. * Renaming new tests/core subdirectory to tests/pure_cpp. * Adding new tests to CMake config, resetting CI config. * Changing CMake file so that test_class_sh_module_local.py actually runs. * clang-tidy fixes. * 32-bit compatibility. * Reusing type_caster_base make_copy_constructor, make_move_constructor with a trick. * CMake COMPARE NATURAL is not available with older versions. * Adding copyright notices to new header files. * Explicitly define copy/move constructors/assignments. * Adding new header files to tests/extra_python_package/test_files.py. * Adding tests/pure_cpp/CMakeLists.txt. * Making use of the new find_existing_python_instance() function factored out with PR #2822. * Moving define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) down in the file. NO functional changes. Preparation for follow-up work (to keep that diff smaller). * Reintroducing py::classh, this time as a simple alias for py::class_<U, py::smart_holder>. * Replacing detail::is_smart_holder<H> in cast.h with detail::is_smart_holder_type_caster<T>. Moving get_local_load_function_ptr, init_instance_for_type to smart_holder_type_caster_class_hooks. Expanding static_assert in py::type::handle_of<> to accommodate smart_holder_type_casters. * Fixing oversight. * Adding classu alias for class_<U, std::unique_ptr<U>>. * Giving up on idea to use legacy init_instance only if is_base_of<type_caster_generic, type_caster<T>. There are use cases in the wild that define both a custom type_caster and class_. * Removing test_type_caster_bare_interface, which was moved to the separate PR #2834. * Moving up is_smart_holder_type_caster, to also use in cast_is_temporary_value_reference. * Adding smart_holder_type_casters for unique_ptr with custom deleter. SEVERE CODE DUPLICATION. This commit is to establish a baseline for consolidating the unique_ptr code. * Unification of unique_ptr, unique_ptr_with_deleter code in smart_holder_poc.h. Leads to more fitting error messages. Enables use of unique_ptr<T, D> smart_holder_type_casters also for unique_ptr<T>. * Copying files as-is from branch test_unique_ptr_member (PR #2672). * Adding comment, simplifying naming, cmake addition. * Introducing PYBIND11_USE_SMART_HOLDER_AS_DEFAULT macro (tested only undefined; there are many errors with the macro defined). * Removing test_type_caster_bare_interface, which was moved to the separate PR #2834. * Fixing oversight introduced with commit95425f13d6
. * Setting record.default_holder correctly for PYBIND11_USE_SMART_HOLDER_AS_DEFAULT. With this test_class.cpp builds and even mostly runs, except `test_multiple_instances_with_same_pointer`, which segfaults because it is using a `unique_ptr` holder but `smart_holder` `type_caster`. Also adding `static_assert`s to generate build errors for such situations, but guarding with `#if 0` to first pivot to test_factory_constructors.cpp. * Fixing up cast.h and smart_holder.h after rebase. * Removing detail/smart_holder_type_casters.h in separate commit. * Commenting out const in def_buffer(... const). With this, test_buffers builds and runs with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT. Explanation why the const needs to be removed, or fix elsewhere, is still needed, but left for later. * Adding test_class_sh_factory_constructors, reproducing test_factory_constructors failure. Using py::class_ in this commit, to be changed to py::classh for debugging. * Removing include/pybind11/detail/smart_holder_type_casters.h from CMakeLists.txt, test_files.py (since it does not exist in this branch). * Adding // DANGER ZONE reminders. * Converting as many py::class_ to py::classh as possible, not breaking tests. * Adding initimpl::construct() overloads, resulting in test_class_sh_factory_constructors feature parity for py::class_ and py::classh. * Adding enable_if !is_smart_holder_type_caster to existing initimpl::construct(). With this test_factory_constructors.cpp builds with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT. * Disabling shared_ptr&, shared_ptr* tests when building with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT for now, pending work on smart_holder_type_caster<shared_ptr>. * Factoring out struct and class definitions into anonymous namespace. Preparation for building with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT. * Simplifying from_unique_ptr(): typename D = std::default_delete<T> is not needed. Factoring out is_std_default_delete<T>() for consistentcy between ensure_compatible_rtti_uqp_del() and from_unique_ptr(). * Introducing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS. Using it in test_smart_ptr.cpp. With this test_smart_ptr builds with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT and all but one test run successfully. * Introducing 1. type_caster_for_class_, used in PYBIND11_MAKE_OPAQUE, and 2. default_holder_type, used in stl_bind.h. * Using __VA_ARGS__ in PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS. * Replacing condense_for_macro with much simpler approach. * Softening static_assert, to only check specifically that smart_holder is not mixed with type_caster_base, and unique_ptr/shared_ptr holders are not mixed with smart_holder_type_casters. * Adding PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS in test_class.cpp (with this all but one test succeed with PYBIND11_USE_SMART_HOLDER_AS_DEFAULT). * Adding remaining PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS. static_assert for "necessary conditions" for both types of default holder, static_assert for "strict conditions" guarded by new PYBIND11_STRICT_ASSERTS_CLASS_HOLDER_VS_TYPE_CASTER_MIX. All tests build & run as before with unique_ptr as the default holder, all tests build for smart_holder as the default holder, even with the strict static_assert. * Introducing check_is_smart_holder_type_caster() function for runtime check, and reinterpreting record.default_holder as "uses_unique_ptr_holder". With this test_smart_ptr succeeds. (All 42 tests build, 35 tests succeed, 5 run but have some failures, 2 segfault.) * Bug fix: Adding have_value() to smart_holder_type_caster_load. With this test_builtin_casters succeeds. (All 42 tests build, 36 tests succeed, 5 run but have some failures, 1 segfault.) * Adding unowned_void_ptr_from_direct_conversion to modified_type_caster_generic_load_impl. This fixes the last remaining segfault (test_numpy_dtypes). New stats for all tests combined: 12 failed, 458 passed. * Adding "Lazy allocation for unallocated values" (for old-style __init__) into load_value_and_holder. Deferring destruction of disowned holder until clear_instance, to remain inspectable for "uninitialized" or "disowned" detection. New stats for all tests combined: 5 failed, 465 passed. * Changing std::shared_ptr pointer/reference to const pointer/reference. New stats for all tests combined: 4 failed, 466 passed. * Adding return_value_policy::move to permissible policies for unique_ptr returns. New stats for all tests combined: 3 failed, 467 passed. * Overlooked flake8 fixes. * Manipulating failing ConstructorStats test to pass, to be able to run all tests with ASAN. This version of the code is ASAN clean with unique_ptr or smart_holder as the default. This change needs to be reverted after adopting the existing move-only-if-refcount-is-1 logic used by type_caster_base. * Adding copy constructor and move constructor tracking to atyp. Preparation for a follow-up change in smart_holder_type_caster, to make this test sensitive to the changing behavior. [skip ci] * Removing `operator T&&() &&` from smart_holder_type_caster, for compatibility with the behavior of type_caster_base. Enables reverting 2 of 3 test manipulations applied under commit249df7cbdb
. The manipulation in test_factory_constructors.py is NOT reverted in this commit. [skip ci] * Fixing unfortunate editing mishap. This reverts the last remaining test manipulation in commit249df7cbdb
and makes all existing unit tests pass with smart_holder as default holder. * GitHub CI clang-tidy fixes. * Adding messages to terse `static_assert`s, for pre-C++17 compatibility. * Using @pytest.mark.parametrize to run each assert separately (to see all errors, not just the first). * Systematically removing _atyp from function names, to make the test code simpler. * Using re.match to accommodate variable number of intermediate MvCtor. * Also removing `operator T()` from smart_holder_type_caster, to fix gcc compilation errors. The only loss is pass_rref in test_class_sh_basic. * Systematically replacing `detail::enable_if_t<...smart_holder...>` with `typename std::enable_if<...smart_holder...>::type`. Attempt to work around MSVC 2015 issues, to be tested via GitHub CI. The idea for this change originates from this comment: https://github.com/pybind/pybind11/issues/1616#issuecomment-444536813 * Importing re before pytest after observing a PyPy CI flake when importing pytest first. * Copying MSVC 2015 compatibility change from branch pr2672_use_smart_holder_as_default. * Introducing is_smart_holder_type_caster_base_tag, to keep smart_holder code more disconnected. * Working around MSVC 2015 bug. * Expanding comment for MSVC 2015 workaround. * Systematically changing std::enable_if back to detail::enable_if_t, effectively reverting commit5d4b6890a3
. * Removing unused smart_holder_type_caster_load::loaded_as_rvalue_ref (it was an oversight that it was not removed with commit23036a45eb
). * Removing py::classu, because it does not seem useful enough. * Reverting commit6349531306
by un-commenting `const` in `def_buffer(...)`. To make this possible, `operator T const&` and `operator T const*` in `smart_holder_type_caster` need to be marked as `const` member functions. * Adding construct() overloads for constructing smart_holder from alias unique_ptr, shared_ptr returns. * Adding test_class_sh_factory_constructors.cpp to tests/CMakeLists.txt (fixes oversight, this should have been added long before). * Compatibility with old clang versions (clang 3.6, 3.7 C++11). * Cleaning up changes to existing unit tests. * Systematically adding SMART_HOLDER_WIP tag. Removing minor UNTESTED tags (only the throw are not actually exercised, investing time there has a high cost but very little benefit). * Splitting out smart_holder_type_casters again, into new detail/smart_holder_type_casters_inline_include.h. * Splitting out smart_holder_init_inline_include.h. * Adding additional new include files to CMakeLists.txt, tests/extra_python_package/test_files.py. * clang-format cleanup of most smart_holder code. * Adding source code comments in response to review. * Simple micro-benchmark ("ubench") comparing runtime performance for several holders. Tested using github.com/rwgk/pybind11_scons and Google-internal build system. Sorry, no cmake support at the moment. First results: https://docs.google.com/spreadsheets/d/1InapCYws2Gt-stmFf_Bwl33eOMo3aLE_gc9adveY7RU/edit#gid=0 * Breaking out number_bucket.h, adding hook for also collecting performance data for PyCLIF. * Accounting for ubench in MANIFEST.in (simply prune, for now). * Smarter determination of call_repetitions. [skip ci] * Also scaling performance data to PyCLIF. [skip ci] * Adding ubench/python/number_bucket.clif here for general visibility. * Fix after rebase * Merging detail/smart_holder_init_inline_include.h into detail/init.h. * Renaming detail/is_smart_holder_type_caster.h -> detail/smart_holder_sfinae_hooks_only.h. * Renaming is_smart_holder_type_caster -> type_uses_smart_holder_type_caster for clarity. * Renaming type_caster_type_is_smart_holder_type_caster -> wrapped_type_uses_smart_holder_type_caster for clarity. * Renaming is_smart_holder_type_caster_base_tag -> smart_holder_type_caster_base_tag for simplicity. * Adding copyright notices and minor colateral cleanup. * iwyu cleanup (comprehensive only for cast.h and smart_holder*.h files). * Fixing `git rebase master` accident. * Moving large `pragma warning` block from pybind11.h to detail/common.h. * Fixing another `git rebase master` accident.
557 lines
22 KiB
C++
557 lines
22 KiB
C++
/*
|
|
tests/test_class.cpp -- test py::class_ definitions and basic functionality
|
|
|
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
|
|
All rights reserved. Use of this source code is governed by a
|
|
BSD-style license that can be found in the LICENSE file.
|
|
*/
|
|
|
|
#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
|
|
// Intel compiler requires a separate header file to support aligned new operators
|
|
// and does not set the __cpp_aligned_new feature macro.
|
|
// This header needs to be included before pybind11.
|
|
#include <aligned_new>
|
|
#endif
|
|
|
|
#include "pybind11_tests.h"
|
|
#include "constructor_stats.h"
|
|
#include "local_bindings.h"
|
|
#include <pybind11/stl.h>
|
|
|
|
#if defined(_MSC_VER)
|
|
# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
// test_brace_initialization
|
|
struct NoBraceInitialization {
|
|
NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
|
template <typename T>
|
|
NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
|
|
|
|
std::vector<int> vec;
|
|
};
|
|
|
|
// test_mismatched_holder
|
|
struct MismatchBase1 { };
|
|
struct MismatchDerived1 : MismatchBase1 { };
|
|
struct MismatchBase2 { };
|
|
struct MismatchDerived2 : MismatchBase2 { };
|
|
|
|
// test_multiple_instances_with_same_pointer
|
|
struct SamePointer {};
|
|
|
|
} // namespace
|
|
|
|
PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(MismatchBase1, std::shared_ptr<MismatchBase1>)
|
|
PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(MismatchDerived1, std::unique_ptr<MismatchDerived1>)
|
|
PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(MismatchBase2, std::unique_ptr<MismatchBase2>)
|
|
PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(MismatchDerived2, std::shared_ptr<MismatchDerived2>)
|
|
PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(SamePointer, std::unique_ptr<SamePointer>)
|
|
|
|
TEST_SUBMODULE(class_, m) {
|
|
// test_instance
|
|
struct NoConstructor {
|
|
NoConstructor() = default;
|
|
NoConstructor(const NoConstructor &) = default;
|
|
NoConstructor(NoConstructor &&) = default;
|
|
static NoConstructor *new_instance() {
|
|
auto *ptr = new NoConstructor();
|
|
print_created(ptr, "via new_instance");
|
|
return ptr;
|
|
}
|
|
~NoConstructor() { print_destroyed(this); }
|
|
};
|
|
|
|
py::class_<NoConstructor>(m, "NoConstructor")
|
|
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
|
|
|
|
// test_inheritance
|
|
class Pet {
|
|
public:
|
|
Pet(const std::string &name, const std::string &species)
|
|
: m_name(name), m_species(species) {}
|
|
std::string name() const { return m_name; }
|
|
std::string species() const { return m_species; }
|
|
private:
|
|
std::string m_name;
|
|
std::string m_species;
|
|
};
|
|
|
|
class Dog : public Pet {
|
|
public:
|
|
Dog(const std::string &name) : Pet(name, "dog") {}
|
|
std::string bark() const { return "Woof!"; }
|
|
};
|
|
|
|
class Rabbit : public Pet {
|
|
public:
|
|
Rabbit(const std::string &name) : Pet(name, "parrot") {}
|
|
};
|
|
|
|
class Hamster : public Pet {
|
|
public:
|
|
Hamster(const std::string &name) : Pet(name, "rodent") {}
|
|
};
|
|
|
|
class Chimera : public Pet {
|
|
Chimera() : Pet("Kimmy", "chimera") {}
|
|
};
|
|
|
|
py::class_<Pet> pet_class(m, "Pet");
|
|
pet_class
|
|
.def(py::init<std::string, std::string>())
|
|
.def("name", &Pet::name)
|
|
.def("species", &Pet::species);
|
|
|
|
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
|
py::class_<Dog>(m, "Dog", pet_class)
|
|
.def(py::init<std::string>());
|
|
|
|
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
|
py::class_<Rabbit, Pet>(m, "Rabbit")
|
|
.def(py::init<std::string>());
|
|
|
|
/* And another: list parent in class template arguments */
|
|
py::class_<Hamster, Pet>(m, "Hamster")
|
|
.def(py::init<std::string>());
|
|
|
|
/* Constructors are not inherited by default */
|
|
py::class_<Chimera, Pet>(m, "Chimera");
|
|
|
|
m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
|
|
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
|
|
|
|
// test_automatic_upcasting
|
|
struct BaseClass {
|
|
BaseClass() = default;
|
|
BaseClass(const BaseClass &) = default;
|
|
BaseClass(BaseClass &&) = default;
|
|
virtual ~BaseClass() = default;
|
|
};
|
|
struct DerivedClass1 : BaseClass { };
|
|
struct DerivedClass2 : BaseClass { };
|
|
|
|
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
|
|
py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
|
|
py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
|
|
|
|
m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); });
|
|
m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); });
|
|
m.def("return_class_n", [](int n) -> BaseClass* {
|
|
if (n == 1) return new DerivedClass1();
|
|
if (n == 2) return new DerivedClass2();
|
|
return new BaseClass();
|
|
});
|
|
m.def("return_none", []() -> BaseClass* { return nullptr; });
|
|
|
|
// test_isinstance
|
|
m.def("check_instances", [](py::list l) {
|
|
return py::make_tuple(
|
|
py::isinstance<py::tuple>(l[0]),
|
|
py::isinstance<py::dict>(l[1]),
|
|
py::isinstance<Pet>(l[2]),
|
|
py::isinstance<Pet>(l[3]),
|
|
py::isinstance<Dog>(l[4]),
|
|
py::isinstance<Rabbit>(l[5]),
|
|
py::isinstance<UnregisteredType>(l[6])
|
|
);
|
|
});
|
|
|
|
struct Invalid {};
|
|
|
|
// test_type
|
|
m.def("check_type", [](int category) {
|
|
// Currently not supported (via a fail at compile time)
|
|
// See https://github.com/pybind/pybind11/issues/2486
|
|
// if (category == 2)
|
|
// return py::type::of<int>();
|
|
if (category == 1)
|
|
return py::type::of<DerivedClass1>();
|
|
else
|
|
return py::type::of<Invalid>();
|
|
});
|
|
|
|
m.def("get_type_of", [](py::object ob) {
|
|
return py::type::of(ob);
|
|
});
|
|
|
|
m.def("get_type_classic", [](py::handle h) {
|
|
return h.get_type();
|
|
});
|
|
|
|
m.def("as_type", [](py::object ob) {
|
|
return py::type(ob);
|
|
});
|
|
|
|
// test_mismatched_holder
|
|
m.def("mismatched_holder_1", []() {
|
|
auto mod = py::module_::import("__main__");
|
|
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
|
py::class_<MismatchDerived1, std::unique_ptr<MismatchDerived1>,
|
|
MismatchBase1>(mod, "MismatchDerived1");
|
|
});
|
|
m.def("mismatched_holder_2", []() {
|
|
auto mod = py::module_::import("__main__");
|
|
py::class_<MismatchBase2, std::unique_ptr<MismatchBase2>>(mod, "MismatchBase2");
|
|
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,
|
|
MismatchBase2>(mod, "MismatchDerived2");
|
|
});
|
|
|
|
// test_override_static
|
|
// #511: problem with inheritance + overwritten def_static
|
|
struct MyBase {
|
|
static std::unique_ptr<MyBase> make() {
|
|
return std::unique_ptr<MyBase>(new MyBase());
|
|
}
|
|
};
|
|
|
|
struct MyDerived : MyBase {
|
|
static std::unique_ptr<MyDerived> make() {
|
|
return std::unique_ptr<MyDerived>(new MyDerived());
|
|
}
|
|
};
|
|
|
|
py::class_<MyBase>(m, "MyBase")
|
|
.def_static("make", &MyBase::make);
|
|
|
|
py::class_<MyDerived, MyBase>(m, "MyDerived")
|
|
.def_static("make", &MyDerived::make)
|
|
.def_static("make2", &MyDerived::make);
|
|
|
|
// test_implicit_conversion_life_support
|
|
struct ConvertibleFromUserType {
|
|
int i;
|
|
|
|
ConvertibleFromUserType(UserType u) : i(u.value()) { }
|
|
};
|
|
|
|
py::class_<ConvertibleFromUserType>(m, "AcceptsUserType")
|
|
.def(py::init<UserType>());
|
|
py::implicitly_convertible<UserType, ConvertibleFromUserType>();
|
|
|
|
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
|
|
m.def("implicitly_convert_variable", [](py::object o) {
|
|
// `o` is `UserType` and `r` is a reference to a temporary created by implicit
|
|
// conversion. This is valid when called inside a bound function because the temp
|
|
// object is attached to the same life support system as the arguments.
|
|
const auto &r = o.cast<const ConvertibleFromUserType &>();
|
|
return r.i;
|
|
});
|
|
m.add_object("implicitly_convert_variable_fail", [&] {
|
|
auto f = [](PyObject *, PyObject *args) -> PyObject * {
|
|
auto o = py::reinterpret_borrow<py::tuple>(args)[0];
|
|
try { // It should fail here because there is no life support.
|
|
o.cast<const ConvertibleFromUserType &>();
|
|
} catch (const py::cast_error &e) {
|
|
return py::str(e.what()).release().ptr();
|
|
}
|
|
return py::str().release().ptr();
|
|
};
|
|
|
|
auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
|
|
py::capsule def_capsule(def, [](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
|
|
return py::reinterpret_steal<py::object>(PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr()));
|
|
}());
|
|
|
|
// test_operator_new_delete
|
|
struct HasOpNewDel {
|
|
std::uint64_t i;
|
|
static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); }
|
|
static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; }
|
|
static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); }
|
|
};
|
|
struct HasOpNewDelSize {
|
|
std::uint32_t i;
|
|
static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); }
|
|
static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; }
|
|
static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); }
|
|
};
|
|
struct AliasedHasOpNewDelSize {
|
|
std::uint64_t i;
|
|
static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); }
|
|
static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; }
|
|
static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); }
|
|
virtual ~AliasedHasOpNewDelSize() = default;
|
|
AliasedHasOpNewDelSize() = default;
|
|
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize&) = delete;
|
|
};
|
|
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
|
|
PyAliasedHasOpNewDelSize() = default;
|
|
PyAliasedHasOpNewDelSize(int) { }
|
|
std::uint64_t j;
|
|
};
|
|
struct HasOpNewDelBoth {
|
|
std::uint32_t i[8];
|
|
static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); }
|
|
static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; }
|
|
static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); }
|
|
static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); }
|
|
};
|
|
py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
|
|
py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
|
|
py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
|
|
py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m, "AliasedHasOpNewDelSize");
|
|
aliased.def(py::init<>());
|
|
aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
|
|
aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
|
|
|
|
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
|
|
// definition in a different compilation unit within the same module:
|
|
bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local());
|
|
|
|
// test_bind_protected_functions
|
|
class ProtectedA {
|
|
protected:
|
|
int foo() const { return value; }
|
|
|
|
private:
|
|
int value = 42;
|
|
};
|
|
|
|
class PublicistA : public ProtectedA {
|
|
public:
|
|
using ProtectedA::foo;
|
|
};
|
|
|
|
py::class_<ProtectedA>(m, "ProtectedA")
|
|
.def(py::init<>())
|
|
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
|
.def("foo", &PublicistA::foo);
|
|
#else
|
|
.def("foo", static_cast<int (ProtectedA::*)() const>(&PublicistA::foo));
|
|
#endif
|
|
|
|
class ProtectedB {
|
|
public:
|
|
virtual ~ProtectedB() = default;
|
|
ProtectedB() = default;
|
|
ProtectedB(const ProtectedB &) = delete;
|
|
|
|
protected:
|
|
virtual int foo() const { return value; }
|
|
|
|
private:
|
|
int value = 42;
|
|
};
|
|
|
|
class TrampolineB : public ProtectedB {
|
|
public:
|
|
int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
|
|
};
|
|
|
|
class PublicistB : public ProtectedB {
|
|
public:
|
|
// [workaround(intel)] = default does not work here
|
|
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
|
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
|
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
|
|
using ProtectedB::foo;
|
|
};
|
|
|
|
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
|
.def(py::init<>())
|
|
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
|
.def("foo", &PublicistB::foo);
|
|
#else
|
|
.def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo));
|
|
#endif
|
|
|
|
// test_brace_initialization
|
|
struct BraceInitialization {
|
|
int field1;
|
|
std::string field2;
|
|
};
|
|
|
|
py::class_<BraceInitialization>(m, "BraceInitialization")
|
|
.def(py::init<int, const std::string &>())
|
|
.def_readwrite("field1", &BraceInitialization::field1)
|
|
.def_readwrite("field2", &BraceInitialization::field2);
|
|
// We *don't* want to construct using braces when the given constructor argument maps to a
|
|
// constructor, because brace initialization could go to the wrong place (in particular when
|
|
// there is also an `initializer_list<T>`-accept constructor):
|
|
py::class_<NoBraceInitialization>(m, "NoBraceInitialization")
|
|
.def(py::init<std::vector<int>>())
|
|
.def_readonly("vec", &NoBraceInitialization::vec);
|
|
|
|
// test_reentrant_implicit_conversion_failure
|
|
// #1035: issue with runaway reentrant implicit conversion
|
|
struct BogusImplicitConversion {
|
|
BogusImplicitConversion(const BogusImplicitConversion &) = default;
|
|
};
|
|
|
|
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
|
.def(py::init<const BogusImplicitConversion &>());
|
|
|
|
py::implicitly_convertible<int, BogusImplicitConversion>();
|
|
|
|
// test_qualname
|
|
// #1166: nested class docstring doesn't show nested name
|
|
// Also related: tests that __qualname__ is set properly
|
|
struct NestBase {};
|
|
struct Nested {};
|
|
py::class_<NestBase> base(m, "NestBase");
|
|
base.def(py::init<>());
|
|
py::class_<Nested>(base, "Nested")
|
|
.def(py::init<>())
|
|
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
|
.def("fa", [](Nested &, int, NestBase &, Nested &) {},
|
|
"a"_a, "b"_a, "c"_a);
|
|
base.def("g", [](NestBase &, Nested &) {});
|
|
base.def("h", []() { return NestBase(); });
|
|
|
|
// test_error_after_conversion
|
|
// The second-pass path through dispatcher() previously didn't
|
|
// remember which overload was used, and would crash trying to
|
|
// generate a useful error message
|
|
|
|
struct NotRegistered {};
|
|
struct StringWrapper { std::string str; };
|
|
m.def("test_error_after_conversions", [](int) {});
|
|
m.def("test_error_after_conversions",
|
|
[](StringWrapper) -> NotRegistered { return {}; });
|
|
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
|
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
|
|
|
|
// test_final
|
|
struct IsFinal final {};
|
|
py::class_<IsFinal>(m, "IsFinal", py::is_final());
|
|
|
|
// test_non_final_final
|
|
struct IsNonFinalFinal {};
|
|
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
|
|
|
// test_exception_rvalue_abort
|
|
struct PyPrintDestructor {
|
|
PyPrintDestructor() = default;
|
|
~PyPrintDestructor() {
|
|
py::print("Print from destructor");
|
|
}
|
|
void throw_something() { throw std::runtime_error("error"); }
|
|
};
|
|
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
|
|
.def(py::init<>())
|
|
.def("throw_something", &PyPrintDestructor::throw_something);
|
|
|
|
// test_multiple_instances_with_same_pointer
|
|
static SamePointer samePointer;
|
|
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
|
|
.def(py::init([]() { return &samePointer; }));
|
|
|
|
struct Empty {};
|
|
py::class_<Empty>(m, "Empty")
|
|
.def(py::init<>());
|
|
|
|
// test_base_and_derived_nested_scope
|
|
struct BaseWithNested {
|
|
struct Nested {};
|
|
};
|
|
|
|
struct DerivedWithNested : BaseWithNested {
|
|
struct Nested {};
|
|
};
|
|
|
|
py::class_<BaseWithNested> baseWithNested_class(m, "BaseWithNested");
|
|
py::class_<DerivedWithNested, BaseWithNested> derivedWithNested_class(m, "DerivedWithNested");
|
|
py::class_<BaseWithNested::Nested>(baseWithNested_class, "Nested")
|
|
.def_static("get_name", []() { return "BaseWithNested::Nested"; });
|
|
py::class_<DerivedWithNested::Nested>(derivedWithNested_class, "Nested")
|
|
.def_static("get_name", []() { return "DerivedWithNested::Nested"; });
|
|
|
|
// test_register_duplicate_class
|
|
struct Duplicate {};
|
|
struct OtherDuplicate {};
|
|
struct DuplicateNested {};
|
|
struct OtherDuplicateNested {};
|
|
m.def("register_duplicate_class_name", [](py::module_ m) {
|
|
py::class_<Duplicate>(m, "Duplicate");
|
|
py::class_<OtherDuplicate>(m, "Duplicate");
|
|
});
|
|
m.def("register_duplicate_class_type", [](py::module_ m) {
|
|
py::class_<OtherDuplicate>(m, "OtherDuplicate");
|
|
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
|
|
});
|
|
m.def("register_duplicate_nested_class_name", [](py::object gt) {
|
|
py::class_<DuplicateNested>(gt, "DuplicateNested");
|
|
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
|
|
});
|
|
m.def("register_duplicate_nested_class_type", [](py::object gt) {
|
|
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
|
|
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
|
|
});
|
|
}
|
|
|
|
template <int N> class BreaksBase { public:
|
|
virtual ~BreaksBase() = default;
|
|
BreaksBase() = default;
|
|
BreaksBase(const BreaksBase&) = delete;
|
|
};
|
|
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
|
// These should all compile just fine:
|
|
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
|
|
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
|
|
using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>;
|
|
using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>;
|
|
using DoesntBreak5 = py::class_<BreaksBase<5>>;
|
|
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
|
|
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
|
|
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
|
|
#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<N>>::value, \
|
|
"DoesntBreak" #N " has wrong type!")
|
|
CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8);
|
|
#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<N>>::value, \
|
|
"DoesntBreak" #N " has wrong type_alias!")
|
|
#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void<typename DoesntBreak##N::type_alias>::value, \
|
|
"DoesntBreak" #N " has type alias, but shouldn't!")
|
|
CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8);
|
|
#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same<typename DoesntBreak##N::holder_type, std::TYPE##_ptr<BreaksBase<N>>>::value, \
|
|
"DoesntBreak" #N " has wrong holder_type!")
|
|
#define CHECK_SMART_HOLDER(N) static_assert(std::is_same<typename DoesntBreak##N::holder_type, py::smart_holder>::value, \
|
|
"DoesntBreak" #N " has wrong holder_type!")
|
|
CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique);
|
|
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
|
|
CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique);
|
|
#else
|
|
CHECK_SMART_HOLDER(4); CHECK_SMART_HOLDER(5);
|
|
#endif
|
|
CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared);
|
|
|
|
// There's no nice way to test that these fail because they fail to compile; leave them here,
|
|
// though, so that they can be manually tested by uncommenting them (and seeing that compilation
|
|
// failures occurs).
|
|
|
|
// We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
|
|
#define CHECK_BROKEN(N) static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-N>>::value, \
|
|
"Breaks1 has wrong type!");
|
|
|
|
//// Two holder classes:
|
|
//typedef py::class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>> Breaks1;
|
|
//CHECK_BROKEN(1);
|
|
//// Two aliases:
|
|
//typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
|
|
//CHECK_BROKEN(2);
|
|
//// Holder + 2 aliases
|
|
//typedef py::class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3;
|
|
//CHECK_BROKEN(3);
|
|
//// Alias + 2 holders
|
|
//typedef py::class_<BreaksBase<-4>, std::unique_ptr<BreaksBase<-4>>, BreaksTramp<-4>, std::shared_ptr<BreaksBase<-4>>> Breaks4;
|
|
//CHECK_BROKEN(4);
|
|
//// Invalid option (not a subclass or holder)
|
|
//typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
|
|
//CHECK_BROKEN(5);
|
|
//// Invalid option: multiple inheritance not supported:
|
|
//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
|
|
//typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
|
|
//CHECK_BROKEN(8);
|