diff --git a/CMakeLists.txt b/CMakeLists.txt index 31dcd85cd..b82f45706 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,6 @@ set(PYBIND11_HEADERS include/pybind11/detail/smart_holder_sfinae_hooks_only.h include/pybind11/detail/smart_holder_type_casters.h include/pybind11/detail/type_caster_base.h - include/pybind11/detail/type_caster_odr_guard.h include/pybind11/detail/typeid.h include/pybind11/detail/value_and_holder.h include/pybind11/attr.h diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e02cb6175..5c49e8b29 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -14,7 +14,6 @@ #include "detail/descr.h" #include "detail/smart_holder_sfinae_hooks_only.h" #include "detail/type_caster_base.h" -#include "detail/type_caster_odr_guard.h" #include "detail/typeid.h" #include "pytypes.h" @@ -48,20 +47,8 @@ class type_caster_for_class_ : public type_caster_base {}; template class type_caster : public type_caster_for_class_ {}; -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) - template -using make_caster_for_intrinsic = type_caster_odr_guard>; - -#else - -template -using make_caster_for_intrinsic = type_caster; - -#endif - -template -using make_caster = make_caster_for_intrinsic>; +using make_caster = type_caster>; template struct type_uses_smart_holder_type_caster { @@ -1179,8 +1166,8 @@ struct return_value_policy_override< }; // Basic python -> C++ casting; throws if casting fails -template -make_caster_for_intrinsic &load_type(make_caster_for_intrinsic &conv, const handle &handle) { +template +type_caster &load_type(type_caster &conv, const handle &handle) { static_assert(!detail::is_pyobject::value, "Internal error: type_caster should only be used for C++ types"); if (!conv.load(handle, true)) { diff --git a/include/pybind11/detail/descr.h b/include/pybind11/detail/descr.h index 5b20c8843..7d546311e 100644 --- a/include/pybind11/detail/descr.h +++ b/include/pybind11/detail/descr.h @@ -1,6 +1,3 @@ -// Copyright (c) 2022 The Pybind Development Team. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. /* pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time @@ -23,106 +20,21 @@ PYBIND11_NAMESPACE_BEGIN(detail) # define PYBIND11_DESCR_CONSTEXPR const #endif -// struct src_loc below is to support type_caster_odr_guard.h -// (see https://github.com/pybind/pybind11/pull/4022). -// The ODR guard creates ODR violations itself (see WARNING below & in type_caster_odr_guard.h), -// but is currently the only tool available. -// The ODR is useful to know *for sure* what is safe and what is not, but that is only a -// subset of what actually works in practice, in a specific environment. The implementation -// here exploits the gray area (similar to a white hat hacker). -// The dedicated test_type_caster_odr_guard_1, test_type_caster_odr_guard_2 pair of unit tests -// passes reliably on almost all platforms that meet the compiler requirements (C++17, C++20), -// except one (gcc 9.4.0 debug build). -// In the pybind11 unit tests we want to test the ODR guard in as many environments as possible, -// but it is NOT recommended to enable the guard in regular builds, production, or -// debug. The guard is meant to be used similar to a sanitizer, to check for type_caster ODR -// violations in binaries that are otherwise already fully tested and assumed to be healthy. -// -// * MSVC 2017 does not support __builtin_FILE(), __builtin_LINE(). -// * MSVC 193732825 C++17 windows-2020 is failing for unknown reasons. -// * Intel 2021.6.0.20220226 (g++ 9.4 mode) __builtin_LINE() is unreliable -// (line numbers vary between translation units). -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD_IF_AVAILABLE) \ - && !defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) && defined(PYBIND11_CPP17) \ - && !defined(__INTEL_COMPILER) \ - && (!defined(_MSC_VER) \ - || (_MSC_VER >= 1920 /* MSVC 2019 or newer */ \ - && (_MSC_FULL_VER < 193732825 || _MSC_FULL_VER > 193732826 \ - || defined(PYBIND11_CPP20)))) -# define PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD -#endif - -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) - -// Not using std::source_location because: -// 1. "It is unspecified whether the copy/move constructors and the copy/move -// assignment operators of source_location are trivial and/or constexpr." -// (https://en.cppreference.com/w/cpp/utility/source_location). -// 2. A matching no-op stub is needed (below) to avoid code duplication. -struct src_loc { - const char *file; - unsigned line; - - constexpr src_loc(const char *file, unsigned line) : file(file), line(line) {} - - static constexpr src_loc here(const char *file = __builtin_FILE(), - unsigned line = __builtin_LINE()) { - return src_loc(file, line); - } - - constexpr src_loc if_known_or(const src_loc &other) const { - if (file != nullptr) { - return *this; - } - return other; - } -}; - -#else - -// No-op stub, to avoid code duplication, expected to be optimized out completely. -struct src_loc { - constexpr src_loc(const char *, unsigned) {} - - static constexpr src_loc here(const char * = nullptr, unsigned = 0) { - return src_loc(nullptr, 0); - } - - constexpr src_loc if_known_or(const src_loc &) const { return *this; } -}; - -#endif - -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) -namespace { // WARNING: This creates an ODR violation in the ODR guard itself, - // but we do not have any alternative at the moment. -// The ODR violation here is a difference in constexpr between multiple TUs. -// All definitions have the same data layout, the only difference is the -// text const char* pointee (the pointees are identical in value), -// src_loc const char* file pointee (the pointees are different in value), -// src_loc unsigned line value. -// See also: Comment above; WARNING in type_caster_odr_guard.h -#endif - /* Concatenate type signatures at compile time */ template struct descr { char text[N + 1]{'\0'}; - const src_loc sloc; - explicit constexpr descr(src_loc sloc) : sloc(sloc) {} + constexpr descr() = default; // NOLINTNEXTLINE(google-explicit-constructor) - constexpr descr(char const (&s)[N + 1], src_loc sloc = src_loc::here()) - : descr(s, make_index_sequence(), sloc) {} + constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence()) {} template - constexpr descr(char const (&s)[N + 1], index_sequence, src_loc sloc = src_loc::here()) - : text{s[Is]..., '\0'}, sloc(sloc) {} + constexpr descr(char const (&s)[N + 1], index_sequence) : text{s[Is]..., '\0'} {} template // NOLINTNEXTLINE(google-explicit-constructor) - constexpr descr(src_loc sloc, char c, Chars... cs) - : text{c, static_cast(cs)..., '\0'}, sloc(sloc) {} + constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} {} static constexpr std::array types() { return {{&typeid(Ts)..., nullptr}}; @@ -135,8 +47,7 @@ constexpr descr plus_impl(const descr &a, index_sequence, index_sequence) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); - return descr{ - a.sloc.if_known_or(b.sloc), a.text[Is1]..., b.text[Is2]...}; + return {a.text[Is1]..., b.text[Is2]...}; } template @@ -146,33 +57,27 @@ constexpr descr operator+(const descr &a, } template -constexpr descr const_name(char const (&text)[N], src_loc sloc = src_loc::here()) { - return descr(text, sloc); -} -constexpr descr<0> const_name(char const (&)[1], src_loc sloc = src_loc::here()) { - return descr<0>(sloc); +constexpr descr const_name(char const (&text)[N]) { + return descr(text); } +constexpr descr<0> const_name(char const (&)[1]) { return {}; } template struct int_to_str : int_to_str {}; template struct int_to_str<0, Digits...> { // WARNING: This only works with C++17 or higher. - // src_loc not tracked (not needed in this situation, at least at the moment). - static constexpr auto digits - = descr(src_loc{nullptr, 0}, ('0' + Digits)...); + static constexpr auto digits = descr(('0' + Digits)...); }; // Ternary description (like std::conditional) template -constexpr enable_if_t> -const_name(char const (&text1)[N1], char const (&)[N2], src_loc sloc = src_loc::here()) { - return const_name(text1, sloc); +constexpr enable_if_t> const_name(char const (&text1)[N1], char const (&)[N2]) { + return const_name(text1); } template -constexpr enable_if_t> -const_name(char const (&)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { - return const_name(text2, sloc); +constexpr enable_if_t> const_name(char const (&)[N1], char const (&text2)[N2]) { + return const_name(text2); } template @@ -186,13 +91,12 @@ constexpr enable_if_t const_name(const T1 &, const T2 &d) { template auto constexpr const_name() -> remove_cv_t::digits)> { - // src_loc not tracked (not needed in this situation, at least at the moment). return int_to_str::digits; } template -constexpr descr<1, Type> const_name(src_loc sloc = src_loc::here()) { - return {sloc, '%'}; +constexpr descr<1, Type> const_name() { + return {'%'}; } // If "_" is defined as a macro, py::detail::_ cannot be provided. @@ -202,18 +106,16 @@ constexpr descr<1, Type> const_name(src_loc sloc = src_loc::here()) { #ifndef _ # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY template -constexpr descr _(char const (&text)[N], src_loc sloc = src_loc::here()) { - return const_name(text, sloc); +constexpr descr _(char const (&text)[N]) { + return const_name(text); } template -constexpr enable_if_t> -_(char const (&text1)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { - return const_name(text1, text2, sloc); +constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { + return const_name(text1, text2); } template -constexpr enable_if_t> -_(char const (&text1)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { - return const_name(text1, text2, sloc); +constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { + return const_name(text1, text2); } template constexpr enable_if_t _(const T1 &d1, const T2 &d2) { @@ -226,16 +128,15 @@ constexpr enable_if_t _(const T1 &d1, const T2 &d2) { template auto constexpr _() -> remove_cv_t::digits)> { - // src_loc not tracked (not needed in this situation, at least at the moment). return const_name(); } template -constexpr descr<1, Type> _(src_loc sloc = src_loc::here()) { - return const_name(sloc); +constexpr descr<1, Type> _() { + return const_name(); } #endif // #ifndef _ -constexpr descr<0> concat(src_loc sloc = src_loc::here()) { return descr<0>{sloc}; } +constexpr descr<0> concat() { return {}; } template constexpr descr concat(const descr &descr) { @@ -246,8 +147,7 @@ constexpr descr concat(const descr &descr) { template constexpr descr operator,(const descr &a, const descr &b) { - // Ensure that src_loc of existing descr is used. - return a + const_name(", ", src_loc{nullptr, 0}) + b; + return a + const_name(", ") + b; } template @@ -259,20 +159,14 @@ template constexpr auto concat(const descr &d, const Args &...args) -> decltype(std::declval>() + concat(args...)) { - // Ensure that src_loc of existing descr is used. - return d + const_name(", ", src_loc{nullptr, 0}) + concat(args...); + return d + const_name(", ") + concat(args...); } #endif template constexpr descr type_descr(const descr &descr) { - // Ensure that src_loc of existing descr is used. - return const_name("{", src_loc{nullptr, 0}) + descr + const_name("}"); + return const_name("{") + descr + const_name("}"); } -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) -} // namespace -#endif - PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/type_caster_odr_guard.h b/include/pybind11/detail/type_caster_odr_guard.h deleted file mode 100644 index 71d074d1d..000000000 --- a/include/pybind11/detail/type_caster_odr_guard.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2022 The Pybind Development Team. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#pragma once - -#include "descr.h" - -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) - -# if !defined(PYBIND11_CPP20) && defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic ignored "-Wsubobject-linkage" -# endif - -# include "../pytypes.h" -# include "common.h" -# include "typeid.h" - -# include -# include -# include -# include -# include -# include -# include -# include - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -PYBIND11_NAMESPACE_BEGIN(detail) - -using type_caster_odr_guard_registry_type = std::unordered_map; - -inline type_caster_odr_guard_registry_type &type_caster_odr_guard_registry() { - // Using the no-destructor idiom (maximizes safety). - static auto *reg = new type_caster_odr_guard_registry_type(); - return *reg; -} - -inline unsigned &type_caster_odr_violation_detected_counter() { - static unsigned counter = 0; - return counter; -} - -inline std::string source_file_line_basename(const char *sfl) { - unsigned i_base = 0; - for (unsigned i = 0; sfl[i] != '\0'; i++) { - if (sfl[i] == '/' || sfl[i] == '\\') { - i_base = i + 1; - } - } - return std::string(sfl + i_base); -} - -// This macro is for cooperation with test_type_caster_odr_guard_?.cpp -# ifndef PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_THROW_DISABLED -# define PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_THROW_DISABLED false -# endif - -inline void type_caster_odr_guard_impl(const std::type_info &intrinsic_type_info, - const src_loc &sloc, - bool throw_disabled) { - std::string source_file_line_from_sloc - = std::string(sloc.file) + ':' + std::to_string(sloc.line); -// This macro is purely for debugging. -# if defined(PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_IMPL_DEBUG) - // std::cout cannot be used here: static initialization could be incomplete. - std::fprintf(stdout, - "\nTYPE_CASTER_ODR_GUARD_IMPL %s %s\n", - clean_type_id(intrinsic_type_info.name()).c_str(), - source_file_line_from_sloc.c_str()); - std::fflush(stdout); -# endif - auto ins = type_caster_odr_guard_registry().insert( - {std::type_index(intrinsic_type_info), source_file_line_from_sloc}); - auto reg_iter = ins.first; - auto added = ins.second; - if (!added - && source_file_line_basename(reg_iter->second.c_str()) - != source_file_line_basename(source_file_line_from_sloc.c_str())) { - std::string msg("ODR VIOLATION DETECTED: pybind11::detail::type_caster<" - + clean_type_id(intrinsic_type_info.name()) + ">: SourceLocation1=\"" - + reg_iter->second + "\", SourceLocation2=\"" + source_file_line_from_sloc - + "\""); - if (throw_disabled) { -# if defined(PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_IMPL_DEBUG) - std::fprintf(stderr, "\nDISABLED std::system_error: %s\n", msg.c_str()); - std::fflush(stderr); -# endif - type_caster_odr_violation_detected_counter()++; - } else { - throw std::system_error(std::make_error_code(std::errc::state_not_recoverable), msg); - } - } -} - -namespace { // WARNING: This creates an ODR violation in the ODR guard itself, - // but we do not have any alternative at the moment. -// The ODR violation here does not involve any data at all. -// See also: Comment near top of descr.h & WARNING in descr.h - -struct tu_local_no_data_always_false { - explicit operator bool() const noexcept { return false; } -}; - -} // namespace - -template -struct type_caster_odr_guard : TypeCasterType { - static tu_local_no_data_always_false translation_unit_local; - - type_caster_odr_guard() { - // Possibly, good optimizers will elide this `if` (and below) completely. - // It is needed only to trigger the TU-local mechanisms. - if (translation_unit_local) { - } - } - - // The original author of this function is @amauryfa - template - static handle cast(CType &&src, return_value_policy policy, handle parent, Arg &&...arg) { - if (translation_unit_local) { - } - return TypeCasterType::cast( - std::forward(src), policy, parent, std::forward(arg)...); - } -}; - -template -tu_local_no_data_always_false - type_caster_odr_guard::translation_unit_local - = []() { - // Executed only once per process (e.g. when a PYBIND11_MODULE is initialized). - // Conclusively tested vi test_type_caster_odr_guard_1, test_type_caster_odr_guard_2: - // those tests will fail if the sloc here is not working as intended (TU-local). - type_caster_odr_guard_impl(typeid(IntrinsicType), - TypeCasterType::name.sloc, - PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_THROW_DISABLED); - return tu_local_no_data_always_false(); - }(); - -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) - -#endif // PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 39ce97b1e..1007d6d82 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -176,8 +176,6 @@ set(PYBIND11_TEST_FILES test_stl_binders test_tagbased_polymorphic test_thread - test_type_caster_odr_guard_1 - test_type_caster_odr_guard_2 test_type_caster_pyobject_ptr test_union test_unnamed_namespace_a @@ -492,9 +490,6 @@ foreach(target ${test_targets}) target_compile_options(${target} PRIVATE /utf-8) endif() - target_compile_definitions(${target} - PRIVATE -DPYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD_IF_AVAILABLE) - if(EIGEN3_FOUND) target_link_libraries(${target} PRIVATE Eigen3::Eigen) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index e993e37b2..a61b42840 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -63,7 +63,6 @@ detail_headers = { "include/pybind11/detail/smart_holder_sfinae_hooks_only.h", "include/pybind11/detail/smart_holder_type_casters.h", "include/pybind11/detail/type_caster_base.h", - "include/pybind11/detail/type_caster_odr_guard.h", "include/pybind11/detail/typeid.h", "include/pybind11/detail/value_and_holder.h", } diff --git a/tests/test_descr_src_loc.cpp b/tests/test_descr_src_loc.cpp deleted file mode 100644 index 8032f318d..000000000 --- a/tests/test_descr_src_loc.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2022 The Pybind Development Team. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#include "pybind11_tests.h" - -// This test actually works with almost all C++17 compilers, but is currently -// only needed (and tested) for type_caster_odr_guard.h, for simplicity. - -#ifndef PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD - -TEST_SUBMODULE(descr_src_loc, m) { m.attr("block_descr_offset") = py::none(); } - -#else - -namespace pybind11_tests { -namespace descr_src_loc { - -using py::detail::const_name; -using py::detail::src_loc; - -struct block_descr { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = py::detail::descr<0>(src_loc::here()); - static constexpr auto c1 = py::detail::descr<3>("Abc"); - static constexpr auto c2 = py::detail::descr<1>(src_loc::here(), 'D'); - static constexpr auto c3 = py::detail::descr<2>(src_loc::here(), 'E', 'f'); -}; - -struct block_const_name { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = const_name("G"); - static constexpr auto c1 = const_name("Hi"); - static constexpr auto c2 = const_name<0>(); - static constexpr auto c3 = const_name<1>(); - static constexpr auto c4 = const_name<23>(); - static constexpr auto c5 = const_name(); - static constexpr auto c6 = const_name("J", "K"); - static constexpr auto c7 = const_name("L", "M"); -}; - -# if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY) -struct block_underscore { - static constexpr unsigned offset = __LINE__; - // Using a macro to avoid copying the block_const_name code garbles the src_loc.line numbers. - static constexpr auto c0 = const_name("G"); - static constexpr auto c1 = const_name("Hi"); - static constexpr auto c2 = const_name<0>(); - static constexpr auto c3 = const_name<1>(); - static constexpr auto c4 = const_name<23>(); - static constexpr auto c5 = const_name(); - static constexpr auto c6 = const_name("J", "K"); - static constexpr auto c7 = const_name("L", "M"); -}; -# endif - -struct block_plus { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = const_name("N") + // critical line break - const_name("O"); - static constexpr auto c1 = const_name("P", src_loc(nullptr, 0)) + // critical line break - const_name("Q"); -}; - -struct block_concat { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = py::detail::concat(const_name("R")); - static constexpr auto c1 = py::detail::concat(const_name("S"), // critical line break - const_name("T")); - static constexpr auto c2 - = py::detail::concat(const_name("U", src_loc(nullptr, 0)), // critical line break - const_name("V")); -}; - -struct block_type_descr { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = py::detail::type_descr(const_name("W")); -}; - -struct block_int_to_str { - static constexpr unsigned offset = __LINE__; - static constexpr auto c0 = py::detail::int_to_str<0>::digits; - static constexpr auto c1 = py::detail::int_to_str<4>::digits; - static constexpr auto c2 = py::detail::int_to_str<56>::digits; -}; - -} // namespace descr_src_loc -} // namespace pybind11_tests - -TEST_SUBMODULE(descr_src_loc, m) { - using namespace pybind11_tests::descr_src_loc; - -# define ATTR_OFFS(B) m.attr(#B "_offset") = B::offset; -# define ATTR_BLKC(B, C) \ - m.attr(#B "_" #C) = py::make_tuple(B::C.text, B::C.sloc.file, B::C.sloc.line); - - ATTR_OFFS(block_descr) - ATTR_BLKC(block_descr, c0) - ATTR_BLKC(block_descr, c1) - ATTR_BLKC(block_descr, c2) - ATTR_BLKC(block_descr, c3) - - ATTR_OFFS(block_const_name) - ATTR_BLKC(block_const_name, c0) - ATTR_BLKC(block_const_name, c1) - ATTR_BLKC(block_const_name, c2) - ATTR_BLKC(block_const_name, c3) - ATTR_BLKC(block_const_name, c4) - ATTR_BLKC(block_const_name, c5) - ATTR_BLKC(block_const_name, c6) - ATTR_BLKC(block_const_name, c7) - - ATTR_OFFS(block_underscore) - ATTR_BLKC(block_underscore, c0) - ATTR_BLKC(block_underscore, c1) - ATTR_BLKC(block_underscore, c2) - ATTR_BLKC(block_underscore, c3) - ATTR_BLKC(block_underscore, c4) - ATTR_BLKC(block_underscore, c5) - ATTR_BLKC(block_underscore, c6) - ATTR_BLKC(block_underscore, c7) - - ATTR_OFFS(block_plus) - ATTR_BLKC(block_plus, c0) - ATTR_BLKC(block_plus, c1) - - ATTR_OFFS(block_concat) - ATTR_BLKC(block_concat, c0) - ATTR_BLKC(block_concat, c1) - ATTR_BLKC(block_concat, c2) - - ATTR_OFFS(block_type_descr) - ATTR_BLKC(block_type_descr, c0) - - ATTR_OFFS(block_int_to_str) - ATTR_BLKC(block_int_to_str, c0) - ATTR_BLKC(block_int_to_str, c1) - ATTR_BLKC(block_int_to_str, c2) -} - -#endif // PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD diff --git a/tests/test_descr_src_loc.py b/tests/test_descr_src_loc.py deleted file mode 100644 index cf16f7141..000000000 --- a/tests/test_descr_src_loc.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -import pytest - -from pybind11_tests import descr_src_loc as m - -if m.block_descr_offset is None: - block_parametrize = (("all_blocks", None),) -else: - block_parametrize = ( - ("block_descr", (("", 1), ("Abc", 2), ("D", 3), ("Ef", 4))), - ( - "block_const_name", - ( - ("G", 1), - ("Hi", 2), - ("0", 0), - ("1", 0), - ("23", 0), - ("%", 6), - ("J", 7), - ("M", 8), - ), - ), - ( - "block_underscore", - ( - ("G", 2), - ("Hi", 3), - ("0", 0), - ("1", 0), - ("23", 0), - ("%", 7), - ("J", 8), - ("M", 9), - ), - ), - ("block_plus", (("NO", 1), ("PQ", 4))), - ("block_concat", (("R", 1), ("S, T", 2), ("U, V", 6))), - ("block_type_descr", (("{W}", 1),)), - ("block_int_to_str", (("", 0), ("4", 0), ("56", 0))), - ) - - -@pytest.mark.skipif(m.block_descr_offset is None, reason="Not enabled.") -@pytest.mark.parametrize(("block_name", "expected_text_line"), block_parametrize) -def test_block(block_name, expected_text_line): - offset = getattr(m, f"{block_name}_offset") - for ix, (expected_text, expected_line) in enumerate(expected_text_line): - text, file, line = getattr(m, f"{block_name}_c{ix}") - assert text == expected_text - if expected_line: - assert file is not None, expected_text_line - assert file.endswith("test_descr_src_loc.cpp") - assert line == offset + expected_line - else: - assert file is None - assert line == 0 diff --git a/tests/test_type_caster_odr_guard_1.cpp b/tests/test_type_caster_odr_guard_1.cpp deleted file mode 100644 index 13a533c82..000000000 --- a/tests/test_type_caster_odr_guard_1.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#define PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_THROW_DISABLED true -#include "pybind11_tests.h" - -// For test of real-world issue. -#include "pybind11/stl.h" - -#include - -namespace mrc_ns { // minimal real caster - -struct type_mrc { - explicit type_mrc(int v = -9999) : value(v) {} - int value; -}; - -struct minimal_real_caster { - static constexpr auto name = py::detail::const_name(); - - static py::handle - cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { - return py::int_(src.value + 1010).release(); // ODR violation. - } - - // Maximizing simplicity. This will go terribly wrong for other arg types. - template - using cast_op_type = const type_mrc &; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator type_mrc const &() { - static type_mrc obj; - obj.value = 11; // ODR violation. - return obj; - } - - bool load(py::handle src, bool /*convert*/) { - // Only accepts str, but the value is ignored. - return py::isinstance(src); - } -}; - -// Intentionally not called from Python: this test is to exercise the ODR guard, -// not stl.h or stl_bind.h. -inline void pass_vector_type_mrc(const std::vector &) {} - -} // namespace mrc_ns - -namespace pybind11 { -namespace detail { -template <> -struct type_caster : mrc_ns::minimal_real_caster {}; -} // namespace detail -} // namespace pybind11 - -TEST_SUBMODULE(type_caster_odr_guard_1, m) { - m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc(101); }); - m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 100; }); - m.def("type_caster_odr_guard_registry_values", []() { -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) - py::list values; - for (const auto ®_iter : py::detail::type_caster_odr_guard_registry()) { - values.append(py::str(reg_iter.second)); - } - return values; -#else - return py::none(); -#endif - }); - m.def("type_caster_odr_violation_detected_count", []() { -#if defined(PYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD) - return py::detail::type_caster_odr_violation_detected_counter(); -#else - return py::none(); -#endif - }); - - // See comment near the bottom of test_type_caster_odr_guard_2.cpp. - m.def("pass_vector_type_mrc", mrc_ns::pass_vector_type_mrc); - - m.attr("if_defined__NO_INLINE__") = -#if defined(__NO_INLINE__) - true; -#else - false; -#endif - - m.attr("CUDACC") = -#if defined(__CUDACC_VER_MAJOR__) - PYBIND11_TOSTRING(__CUDACC_VER_MAJOR__) "." PYBIND11_TOSTRING( - __CUDACC_VER_MINOR__) "." PYBIND11_TOSTRING(__CUDACC_VER_BUILD__); -#else - py::none(); -#endif - m.attr("NVCOMPILER") = -#if defined(__NVCOMPILER_MAJOR__) - PYBIND11_TOSTRING(__NVCOMPILER_MAJOR__) "." PYBIND11_TOSTRING( - __NVCOMPILER_MINOR__) "." PYBIND11_TOSTRING(__NVCOMPILER_PATCHLEVEL__); -#else - py::none(); -#endif -} diff --git a/tests/test_type_caster_odr_guard_1.py b/tests/test_type_caster_odr_guard_1.py deleted file mode 100644 index 88a89bd0b..000000000 --- a/tests/test_type_caster_odr_guard_1.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import pytest - -import pybind11_tests -import pybind11_tests.type_caster_odr_guard_1 as m - - -def test_type_mrc_to_python(): - val = m.type_mrc_to_python() - if val == 101 + 2020: - pytest.skip( - "UNEXPECTED: test_type_caster_odr_guard_2.cpp prevailed (to_python)." - ) - else: - assert val == 101 + 1010 - - -def test_type_mrc_from_python(): - val = m.type_mrc_from_python("ignored") - if val == 100 + 22: - pytest.skip( - "UNEXPECTED: test_type_caster_odr_guard_2.cpp prevailed (from_python)." - ) - else: - assert val == 100 + 11 - - -def test_type_caster_odr_registry_values(): - reg_values = m.type_caster_odr_guard_registry_values() - if reg_values is None: - pytest.skip("type_caster_odr_guard_registry_values() is None") - else: - assert "test_type_caster_odr_guard_" in "\n".join(reg_values) - - -def _count_0_message(tail): - return ( - "type_caster_odr_violation_detected_count() == 0:" - f" {pybind11_tests.compiler_info}, {pybind11_tests.cpp_std}, " + tail - ) - - -def test_type_caster_odr_violation_detected_counter(): - num_violations = m.type_caster_odr_violation_detected_count() - if num_violations is None: - pytest.skip("type_caster_odr_violation_detected_count() is None") - if num_violations == 0: - if m.if_defined__NO_INLINE__: - pytest.skip(_count_0_message("__NO_INLINE__")) - if m.CUDACC is not None: - pytest.skip(_count_0_message(f"CUDACC = {m.CUDACC}")) - if m.NVCOMPILER is not None: - pytest.skip(_count_0_message(f"NVCOMPILER = {m.NVCOMPILER}")) - assert num_violations == 1 diff --git a/tests/test_type_caster_odr_guard_2.cpp b/tests/test_type_caster_odr_guard_2.cpp deleted file mode 100644 index e0d5054df..000000000 --- a/tests/test_type_caster_odr_guard_2.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#define PYBIND11_DETAIL_TYPE_CASTER_ODR_GUARD_THROW_DISABLED true -#include "pybind11_tests.h" - -// For test of real-world issue. -#include "pybind11/stl_bind.h" - -#include - -namespace mrc_ns { // minimal real caster - -struct type_mrc { - explicit type_mrc(int v = -9999) : value(v) {} - int value; -}; - -struct minimal_real_caster { - static constexpr auto name = py::detail::const_name(); - - static py::handle - cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { - return py::int_(src.value + 2020).release(); // ODR violation. - } - - // Maximizing simplicity. This will go terribly wrong for other arg types. - template - using cast_op_type = const type_mrc &; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator type_mrc const &() { - static type_mrc obj; - obj.value = 22; // ODR violation. - return obj; - } - - bool load(py::handle src, bool /*convert*/) { - // Only accepts str, but the value is ignored. - return py::isinstance(src); - } -}; - -// Intentionally not called from Python: this test is to exercise the ODR guard, -// not stl.h or stl_bind.h. -inline void pass_vector_type_mrc(const std::vector &) {} - -} // namespace mrc_ns - -PYBIND11_MAKE_OPAQUE(std::vector); - -namespace pybind11 { -namespace detail { -template <> -struct type_caster : mrc_ns::minimal_real_caster {}; -} // namespace detail -} // namespace pybind11 - -TEST_SUBMODULE(type_caster_odr_guard_2, m) { - m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc(202); }); - m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 200; }); - - // Uncomment and run test_type_caster_odr_guard_1.py to verify that the - // test_type_caster_odr_violation_detected_counter subtest fails - // (num_violations 2 instead of 1). - // Unlike the "controlled ODR violation" for the minimal_real_caster, this ODR violation is - // completely unsafe, therefore it cannot portably be exercised with predictable results. - // m.def("pass_vector_type_mrc", mrc_ns::pass_vector_type_mrc); -} diff --git a/tests/test_type_caster_odr_guard_2.py b/tests/test_type_caster_odr_guard_2.py deleted file mode 100644 index 29aeb832e..000000000 --- a/tests/test_type_caster_odr_guard_2.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -import pytest - -import pybind11_tests.type_caster_odr_guard_2 as m - - -def test_type_mrc_to_python(): - val = m.type_mrc_to_python() - if val == 202 + 2020: - pytest.skip( - "UNEXPECTED: test_type_caster_odr_guard_2.cpp prevailed (to_python)." - ) - else: - assert val == 202 + 1010 - - -def test_type_mrc_from_python(): - val = m.type_mrc_from_python("ignored") - if val == 200 + 22: - pytest.skip( - "UNEXPECTED: test_type_caster_odr_guard_2.cpp prevailed (from_python)." - ) - else: - assert val == 200 + 11