Fix a long-standing bug in the handling of Python multiple inheritance (#4762)
* Equivalent of https://github.com/google/clif/commit/5718e4d0807fd3b6a8187dde140069120b81ecef
* Resolve clang-tidy errors.
* Moving test_PPCCInit() first changes the behavior!
* Resolve new Clang dev C++11 errors:
```
The CXX compiler identification is Clang 17.0.0
```
```
pytypes.h:1615:23: error: identifier '_s' preceded by whitespace in a literal operator declaration is deprecated [-Werror,-Wdeprecated-literal-operator]
```
```
cast.h:1380:26: error: identifier '_a' preceded by whitespace in a literal operator declaration is deprecated [-Werror,-Wdeprecated-literal-operator]
```
* Resolve gcc 4.8.5 error:
```
pytypes.h:1615:12: error: missing space between '""' and suffix identifier
```
* Specifically exclude `__clang__`
* Snapshot of debugging code (does NOT pass pre-commit checks).
* Revert "Snapshot of debugging code (does NOT pass pre-commit checks)."
This reverts commit 1d4f9ff2632b32ddcb0dc7ecd0ab7a4ce4c15a4e.
* [ci skip] Order Dependence Demo
* Revert "[ci skip] Order Dependence Demo"
This reverts commit d37b5409d4e5b835620ccbb321a4e1ba89af315c.
* One way to deal with the order dependency issue. This is not the best way, more like a proof of concept.
* Move test_PC() first again.
* Add `all_type_info_add_base_most_derived_first()`, use in `all_type_info_populate()`
* Revert "One way to deal with the order dependency issue. This is not the best way, more like a proof of concept."
This reverts commit eb09c6c1b978208ceee40f05bbe75491b6ff8ad6.
* clang-tidy fixes (automatic)
* Add `is_redundant_value_and_holder()` and use to avoid forcing `__init__` overrides when they are not needed.
* Streamline implementation and avoid unsafe `reinterpret_cast<instance *>()` introduced with PR #2152
The `reinterpret_cast<instance *>(self)` is unsafe if `__new__` is mocked,
which was actually found in the wild: the mock returned `None` for `self`.
This was inconsequential because `inst` is currently cast straight back to
`PyObject *` to compute `all_type_info()`, which is empty if `self` is not
a pybind11 `instance`, and then `inst` is never dereferenced. However, the
unsafe detour through `instance *` is easily avoided and the updated
implementation is less prone to accidents while debugging or refactoring.
* Fix actual undefined behavior exposed by previous changes.
It turns out the previous commit message is incorrect, the `inst` pointer is actually dereferenced, in the `value_and_holder` ctor here:
https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/detail/type_caster_base.h#L262-L263
```
259 // Main constructor for a found value/holder:
260 value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
261 : inst{i}, index{index}, type{type},
262 vh{inst->simple_layout ? inst->simple_value_holder
263 : &inst->nonsimple.values_and_holders[vpos]} {}
```
* Add test_mock_new()
* Experiment: specify indirect bases
* Revert "Experiment: specify indirect bases"
This reverts commit 4f90d85f9fc15290d6be54d5ae9417bd131b84d9.
* Add `all_type_info_check_for_divergence()` and some tests.
* Call `all_type_info_check_for_divergence()` also from `type_caster_generic::load_impl<>`
* Resolve clang-tidy error:
```
include/pybind11/detail/type_caster_base.h:795:21: error: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty,-warnings-as-errors]
if (matching_bases.size() != 0) {
^~~~~~~~~~~~~~~~~~~~~~~~~~
!matching_bases.empty()
```
* Revert "Resolve clang-tidy error:"
This reverts commit df27188dc6d6cf333145755543f56b2f6657aa5e.
* Revert "Call `all_type_info_check_for_divergence()` also from `type_caster_generic::load_impl<>`"
This reverts commit 5f5fd6a68e3cff1726628f6dea8e1c0754636a23.
* Revert "Add `all_type_info_check_for_divergence()` and some tests."
This reverts commit 0a9599f775bfd3ca196c5e23a3fcf2890cbf6e82.
2023-11-08 20:44:04 +00:00
|
|
|
# Adapted from:
|
|
|
|
# https://github.com/google/clif/blob/5718e4d0807fd3b6a8187dde140069120b81ecef/clif/testing/python/python_multiple_inheritance_test.py
|
2024-06-22 04:55:00 +00:00
|
|
|
from __future__ import annotations
|
Fix a long-standing bug in the handling of Python multiple inheritance (#4762)
* Equivalent of https://github.com/google/clif/commit/5718e4d0807fd3b6a8187dde140069120b81ecef
* Resolve clang-tidy errors.
* Moving test_PPCCInit() first changes the behavior!
* Resolve new Clang dev C++11 errors:
```
The CXX compiler identification is Clang 17.0.0
```
```
pytypes.h:1615:23: error: identifier '_s' preceded by whitespace in a literal operator declaration is deprecated [-Werror,-Wdeprecated-literal-operator]
```
```
cast.h:1380:26: error: identifier '_a' preceded by whitespace in a literal operator declaration is deprecated [-Werror,-Wdeprecated-literal-operator]
```
* Resolve gcc 4.8.5 error:
```
pytypes.h:1615:12: error: missing space between '""' and suffix identifier
```
* Specifically exclude `__clang__`
* Snapshot of debugging code (does NOT pass pre-commit checks).
* Revert "Snapshot of debugging code (does NOT pass pre-commit checks)."
This reverts commit 1d4f9ff2632b32ddcb0dc7ecd0ab7a4ce4c15a4e.
* [ci skip] Order Dependence Demo
* Revert "[ci skip] Order Dependence Demo"
This reverts commit d37b5409d4e5b835620ccbb321a4e1ba89af315c.
* One way to deal with the order dependency issue. This is not the best way, more like a proof of concept.
* Move test_PC() first again.
* Add `all_type_info_add_base_most_derived_first()`, use in `all_type_info_populate()`
* Revert "One way to deal with the order dependency issue. This is not the best way, more like a proof of concept."
This reverts commit eb09c6c1b978208ceee40f05bbe75491b6ff8ad6.
* clang-tidy fixes (automatic)
* Add `is_redundant_value_and_holder()` and use to avoid forcing `__init__` overrides when they are not needed.
* Streamline implementation and avoid unsafe `reinterpret_cast<instance *>()` introduced with PR #2152
The `reinterpret_cast<instance *>(self)` is unsafe if `__new__` is mocked,
which was actually found in the wild: the mock returned `None` for `self`.
This was inconsequential because `inst` is currently cast straight back to
`PyObject *` to compute `all_type_info()`, which is empty if `self` is not
a pybind11 `instance`, and then `inst` is never dereferenced. However, the
unsafe detour through `instance *` is easily avoided and the updated
implementation is less prone to accidents while debugging or refactoring.
* Fix actual undefined behavior exposed by previous changes.
It turns out the previous commit message is incorrect, the `inst` pointer is actually dereferenced, in the `value_and_holder` ctor here:
https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/detail/type_caster_base.h#L262-L263
```
259 // Main constructor for a found value/holder:
260 value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
261 : inst{i}, index{index}, type{type},
262 vh{inst->simple_layout ? inst->simple_value_holder
263 : &inst->nonsimple.values_and_holders[vpos]} {}
```
* Add test_mock_new()
* Experiment: specify indirect bases
* Revert "Experiment: specify indirect bases"
This reverts commit 4f90d85f9fc15290d6be54d5ae9417bd131b84d9.
* Add `all_type_info_check_for_divergence()` and some tests.
* Call `all_type_info_check_for_divergence()` also from `type_caster_generic::load_impl<>`
* Resolve clang-tidy error:
```
include/pybind11/detail/type_caster_base.h:795:21: error: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty,-warnings-as-errors]
if (matching_bases.size() != 0) {
^~~~~~~~~~~~~~~~~~~~~~~~~~
!matching_bases.empty()
```
* Revert "Resolve clang-tidy error:"
This reverts commit df27188dc6d6cf333145755543f56b2f6657aa5e.
* Revert "Call `all_type_info_check_for_divergence()` also from `type_caster_generic::load_impl<>`"
This reverts commit 5f5fd6a68e3cff1726628f6dea8e1c0754636a23.
* Revert "Add `all_type_info_check_for_divergence()` and some tests."
This reverts commit 0a9599f775bfd3ca196c5e23a3fcf2890cbf6e82.
2023-11-08 20:44:04 +00:00
|
|
|
|
|
|
|
from pybind11_tests import python_multiple_inheritance as m
|
|
|
|
|
|
|
|
|
|
|
|
class PC(m.CppBase):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class PPCC(PC, m.CppDrvd):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def test_PC():
|
|
|
|
d = PC(11)
|
|
|
|
assert d.get_base_value() == 11
|
|
|
|
d.reset_base_value(13)
|
|
|
|
assert d.get_base_value() == 13
|
|
|
|
|
|
|
|
|
|
|
|
def test_PPCC():
|
|
|
|
d = PPCC(11)
|
|
|
|
assert d.get_drvd_value() == 33
|
|
|
|
d.reset_drvd_value(55)
|
|
|
|
assert d.get_drvd_value() == 55
|
|
|
|
|
|
|
|
assert d.get_base_value() == 11
|
|
|
|
assert d.get_base_value_from_drvd() == 11
|
|
|
|
d.reset_base_value(20)
|
|
|
|
assert d.get_base_value() == 20
|
|
|
|
assert d.get_base_value_from_drvd() == 20
|
|
|
|
d.reset_base_value_from_drvd(30)
|
|
|
|
assert d.get_base_value() == 30
|
|
|
|
assert d.get_base_value_from_drvd() == 30
|