-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Cleanup cast_safe<void> specialization #3861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Replace explicit specialization of cast_safe<void> with SFINAE. It's better for SFINAE cases to cover all type-sets rather than mixing SFINAE and explicit specialization. Extracted from #3674
for more information, see https://pre-commit.ci
Use detail::none_of<> as suggested
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strictly optional, and strictly speaking unrelated to this change, but because this code is touched:
I'd find the code easier to read if lines 1157-1163 were moved down to 1170.
To have this pattern:
if A
if B
if not (A or B)
Reorder: If TEMP_REF If VOID if (!VOID && !TEMP_REF)
Updated for @rwgk suggested order. |
This broke code like this: #include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
using std::cout;
using std::endl;
class Animal {
public:
virtual ~Animal() { }
virtual void* go() = 0;
};
class PyAnimal : public Animal {
public:
/* Inherit the constructors */
using Animal::Animal;
/* Trampoline (need one for each virtual function) */
void* go() override {
PYBIND11_OVERRIDE_PURE(
void*, /* Return type */
Animal, /* Parent class */
go, /* Name of function in C++ (must match Python name) */
);
}
};
PYBIND11_MODULE(example, m) {
py::class_<Animal, PyAnimal /* <--- trampoline*/>(m, "Animal")
.def(py::init<>())
.def("go", &Animal::go);
} Example projects that were broken by this are Nvidia's TensorRT. Can it be fixed quickly or should we revert? |
Wow, 6 months later. |
$ clang++ -I/usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.10/include/python3.10 -I/usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.10/include/python3.10 -I/Users/henryschreiner/git/software/pybind11/include -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk -std=c++11 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk -undefined dynamic_lookup example.cpp -o example.cpython-310-darwin.so
example.cpp:18:9: error: cannot initialize return object of type 'void *' with an rvalue of type 'enable_if_t<std::is_same<void, intrinsic_t<void *>>::value, void>' (aka 'void')
PYBIND11_OVERRIDE_PURE(
^~~~~~~~~~~~~~~~~~~~~~~
/Users/henryschreiner/git/software/pybind11/include/pybind11/pybind11.h:2808:5: note: expanded from macro 'PYBIND11_OVERRIDE_PURE'
PYBIND11_OVERRIDE_PURE_NAME( \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/henryschreiner/git/software/pybind11/include/pybind11/pybind11.h:2770:9: note: expanded from macro 'PYBIND11_OVERRIDE_PURE_NAME'
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/henryschreiner/git/software/pybind11/include/pybind11/pybind11.h:2736:20: note: expanded from macro 'PYBIND11_OVERRIDE_IMPL'
return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated. And this was opened about two weeks after releasing 2.10.0, it's been sitting in the issues for over two months, and it's been linked in my 2.10.1 wishlist for nearly as long; I've been busy teaching and no one else bothered to look. It looks like it used to treat |
Thanks, I'll try to reproduce that.
Ouch. Maybe we need to encourage people more to send a PR with a reproducer, to lower the bar for someone to jump in debugging. I'm unable to look at all issues. |
This PR had a reproducer, which is one reason it took about 2 minutes to find the bad comment via |
Oh, the link was up there. I missed it before. |
Confirmed (clang 14, although it looks like the compiler doesn't even matter).
|
It can be fixed, diff below (I don't want to trigger the CI with what I have right now), but is it better than the rollback? I need to make the test complete, and TBH understand how the overriding Python function can meaningfully return a diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 5699d4fb..8b8ef696 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -1178,16 +1178,33 @@ template <typename T>
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked");
}
+
+#ifdef PR3861_ROLLBACK
+
template <typename T>
-enable_if_t<std::is_same<void, intrinsic_t<T>>::value, void> cast_safe(object &&) {}
+enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) {
+ return pybind11::cast<T>(std::move(o));
+}
+
+template <>
+inline void cast_safe<void>(object &&) {}
+
+#else
+
+template <typename T>
+enable_if_t<std::is_same<void, intrinsic_t<T>>::value && !std::is_pointer<T>::value, void>
+cast_safe(object &&) {}
+
template <typename T>
-enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
- std::is_same<void, intrinsic_t<T>>>::value,
+enable_if_t<!cast_is_temporary_value_reference<T>::value
+ && !(std::is_same<void, intrinsic_t<T>>::value && !std::is_pointer<T>::value),
T>
cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o));
}
+#endif
+
PYBIND11_NAMESPACE_END(detail)
// The overloads could coexist, i.e. the #if is not strictly speaking needed, |
I think that the issue is the code used Try replacing this:
with
(The test below should be the same. Apparently we have similar comments crossing paths.). |
It looks like detail/common.h has a remove_cvref_t; use that instead of intrinsic_t. Like this:
|
The new code should be:
|
Though arguably since you cannot form a reference to |
Confirmed, @laramiel's fix works. Tested locally, all unit tests pass. |
We need to add the failing test and the fix for it - will one of you do it, or do you want me to do it? |
Replace explicit specialization of cast_safe with SFINAE.
It's better for SFINAE cases to cover all type-sets rather than mixing SFINAE and explicit specialization.
Extracted from #3674