From da104a9efd0357b5c144c67eb641ae0b9e23012d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 9 Oct 2022 21:50:35 -0700 Subject: [PATCH] Reproducer and fix for issue encountered in smart_holder update. (#4228) * Reproducer for issue encountered in smart_holder update. * clang-tidy compatibility (untested). * Add `enable_if_t` to workaround. * Bug fix: Move `PYBIND11_USING_WORKAROUND_FOR_CUDA_11_4_THROUGH_8` determination to detail/common.h So that it actually is defined in pybind11.h * Try using the workaround (which is nicer than the original code) universally. * Reduce reproducer for CUDA 11.7 issue encountered in smart_holder update. This commit tested in isolation on top of current master + first version of reproducer (62311eb431849d135a5db84f6c75ec390f2ede7c). Succeeds with Debian Clang 14.0.6 C++17 (and probably all other compilers). Fails for CUDA 11.7: ``` cd /build/tests && /usr/local/cuda/bin/nvcc -forward-unknown-to-host-compiler -Dpybind11_tests_EXPORTS -I/mounted_pybind11/include -isystem=/usr/include/python3.10 -g --generate-code=arch=compute_52,code=[compute_52,sm_52] -Xcompiler=-fPIC -Xcompiler=-fvisibility=hidden -Werror all-warnings -std=c++17 -MD -MT tests/CMakeFiles/pybind11_tests.dir/test_class.cpp.o -MF CMakeFiles/pybind11_tests.dir/test_class.cpp.o.d -x cu -c /mounted_pybind11/tests/test_class.cpp -o CMakeFiles/pybind11_tests.dir/test_class.cpp.o /mounted_pybind11/tests/test_class.cpp(53): error: more than one instance of overloaded function "pybind11::class_::def [with type_=test_class::pr4220_tripped_over_this::Empty0, options=<>]" matches the argument list: function template "pybind11::class_ &pybind11::class_::def(const char *, Func &&, const Extra &...) [with type_=test_class::pr4220_tripped_over_this::Empty0, options=<>]" /mounted_pybind11/include/pybind11/pybind11.h(1557): here function template "pybind11::class_ &pybind11::class_::def(const T &, const Extra &...) [with type_=test_class::pr4220_tripped_over_this::Empty0, options=<>]" /mounted_pybind11/include/pybind11/pybind11.h(1586): here argument types are: (const char [8], ) object type is: pybind11::class_ 1 error detected in the compilation of "/mounted_pybind11/tests/test_class.cpp". ``` --- include/pybind11/operators.h | 1 + include/pybind11/pybind11.h | 21 ++------------------- tests/test_class.cpp | 22 ++++++++++++++++++++++ tests/test_class.py | 7 +++++++ 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/pybind11/operators.h b/include/pybind11/operators.h index a0c3b78d6..16a88ae17 100644 --- a/include/pybind11/operators.h +++ b/include/pybind11/operators.h @@ -84,6 +84,7 @@ struct op_impl {}; /// Operator implementation generator template struct op_ { + static constexpr bool op_enable_if_hook = true; template void execute(Class &cl, const Extra &...extra) const { using Base = typename Class::type; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 3f6e27b75..fb4b7578d 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1578,34 +1578,17 @@ public: return *this; } -// Nvidia's NVCC is broken between 11.4.0 and 11.8.0 -// https://github.com/pybind/pybind11/issues/4193 -#if defined(__CUDACC__) && (__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 4) \ - && (__CUDACC_VER_MINOR__ <= 8) - template + template = 0> class_ &def(const T &op, const Extra &...extra) { op.execute(*this, extra...); return *this; } - template + template = 0> class_ &def_cast(const T &op, const Extra &...extra) { op.execute_cast(*this, extra...); return *this; } -#else - template - class_ &def(const detail::op_ &op, const Extra &...extra) { - op.execute(*this, extra...); - return *this; - } - - template - class_ &def_cast(const detail::op_ &op, const Extra &...extra) { - op.execute_cast(*this, extra...); - return *this; - } -#endif template class_ &def(const detail::initimpl::constructor &init, const Extra &...extra) { diff --git a/tests/test_class.cpp b/tests/test_class.cpp index c8b8071dc..18c8d358b 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -36,6 +36,26 @@ struct NoBraceInitialization { std::vector vec; }; +namespace test_class { +namespace pr4220_tripped_over_this { // PR #4227 + +template +struct SoEmpty {}; + +template +std::string get_msg(const T &) { + return "This is really only meant to exercise successful compilation."; +} + +using Empty0 = SoEmpty<0x0>; + +void bind_empty0(py::module_ &m) { + py::class_(m, "Empty0").def(py::init<>()).def("get_msg", get_msg); +} + +} // namespace pr4220_tripped_over_this +} // namespace test_class + TEST_SUBMODULE(class_, m) { // test_instance struct NoConstructor { @@ -517,6 +537,8 @@ TEST_SUBMODULE(class_, m) { py::class_(gt, "OtherDuplicateNested"); py::class_(gt, "YetAnotherDuplicateNested"); }); + + test_class::pr4220_tripped_over_this::bind_empty0(m); } template diff --git a/tests/test_class.py b/tests/test_class.py index ff9196f0f..47ba450fc 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -469,3 +469,10 @@ def test_register_duplicate_class(): m.register_duplicate_nested_class_type(ClassScope) expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!' assert str(exc_info.value) == expected + + +def test_pr4220_tripped_over_this(): + assert ( + m.Empty0().get_msg() + == "This is really only meant to exercise successful compilation." + )