diff --git a/include/pybind11/detail/descr.h b/include/pybind11/detail/descr.h index e7a5e2c14..e4baa383b 100644 --- a/include/pybind11/detail/descr.h +++ b/include/pybind11/detail/descr.h @@ -20,21 +20,69 @@ PYBIND11_NAMESPACE_BEGIN(detail) # define PYBIND11_DESCR_CONSTEXPR const #endif +// * MSVC 2017 does not support __builtin_FILE(), __builtin_LINE(). +// * Intel 2021.6.0.20220226 (g++ 9.4 mode) __builtin_LINE() is unreliable +// (line numbers vary between translation units). +#if !defined(PYBIND11_DETAIL_DESCR_SRC_LOC_ON) && !defined(PYBIND11_DETAIL_DESCR_SRC_LOC_OFF) \ + && !defined(__INTEL_COMPILER) \ + && ((defined(_MSC_VER) && _MSC_VER >= 1920) || defined(PYBIND11_CPP17)) +# define PYBIND11_DETAIL_DESCR_SRC_LOC_ON +#endif + +#ifdef PYBIND11_DETAIL_DESCR_SRC_LOC_ON + +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 + +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 + /* Concatenate type signatures at compile time */ template struct descr { char text[N + 1]{'\0'}; + src_loc sloc; - constexpr descr() = default; + explicit constexpr descr(src_loc sloc) : sloc(sloc) {} // NOLINTNEXTLINE(google-explicit-constructor) - constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence()) {} + constexpr descr(char const (&s)[N + 1], src_loc sloc = src_loc::here()) + : descr(s, make_index_sequence(), sloc) {} template - constexpr descr(char const (&s)[N + 1], index_sequence) : text{s[Is]..., '\0'} {} + constexpr descr(char const (&s)[N + 1], index_sequence, src_loc sloc = src_loc::here()) + : text{s[Is]..., '\0'}, sloc(sloc) {} template // NOLINTNEXTLINE(google-explicit-constructor) - constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} {} + constexpr descr(src_loc sloc, char c, Chars... cs) + : text{c, static_cast(cs)..., '\0'}, sloc(sloc) {} static constexpr std::array types() { return {{&typeid(Ts)..., nullptr}}; @@ -47,7 +95,8 @@ constexpr descr plus_impl(const descr &a, index_sequence, index_sequence) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); - return {a.text[Is1]..., b.text[Is2]...}; + return descr{ + a.sloc.if_known_or(b.sloc), a.text[Is1]..., b.text[Is2]...}; } template @@ -57,27 +106,31 @@ constexpr descr operator+(const descr &a, } template -constexpr descr const_name(char const (&text)[N]) { - return descr(text); +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<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. - static constexpr auto digits = descr(('0' + Digits)...); + static constexpr auto digits = descr(src_loc::here(), ('0' + Digits)...); }; // Ternary description (like std::conditional) template -constexpr enable_if_t> const_name(char const (&text1)[N1], char const (&)[N2]) { - return const_name(text1); +constexpr enable_if_t> +const_name(char const (&text1)[N1], char const (&)[N2], src_loc sloc = src_loc::here()) { + return const_name(text1, sloc); } template -constexpr enable_if_t> const_name(char const (&)[N1], char const (&text2)[N2]) { - return const_name(text2); +constexpr enable_if_t> +const_name(char const (&)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { + return const_name(text2, sloc); } template @@ -91,12 +144,13 @@ constexpr enable_if_t const_name(const T1 &, const T2 &d) { template auto constexpr const_name() -> remove_cv_t::digits)> { + // src_loc not tracked (irrelevant in this situation, at least at the moment). return int_to_str::digits; } template -constexpr descr<1, Type> const_name() { - return {'%'}; +constexpr descr<1, Type> const_name(src_loc sloc = src_loc::here()) { + return {sloc, '%'}; } // If "_" is defined as a macro, py::detail::_ cannot be provided. @@ -106,16 +160,18 @@ constexpr descr<1, Type> const_name() { #ifndef _ # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY template -constexpr descr _(char const (&text)[N]) { - return const_name(text); +constexpr descr _(char const (&text)[N], src_loc sloc = src_loc::here()) { + return const_name(text, sloc); } template -constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { - return const_name(text1, text2); +constexpr enable_if_t> +_(char const (&text1)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { + return const_name(text1, text2, sloc); } template -constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { - return const_name(text1, text2); +constexpr enable_if_t> +_(char const (&text1)[N1], char const (&text2)[N2], src_loc sloc = src_loc::here()) { + return const_name(text1, text2, sloc); } template constexpr enable_if_t _(const T1 &d1, const T2 &d2) { @@ -128,15 +184,16 @@ constexpr enable_if_t _(const T1 &d1, const T2 &d2) { template auto constexpr _() -> remove_cv_t::digits)> { + // src_loc not tracked (irrelevant in this situation, at least at the moment). return const_name(); } template -constexpr descr<1, Type> _() { - return const_name(); +constexpr descr<1, Type> _(src_loc sloc = src_loc::here()) { + return const_name(sloc); } #endif // #ifndef _ -constexpr descr<0> concat() { return {}; } +constexpr descr<0> concat(src_loc sloc = src_loc::here()) { return descr<0>{sloc}; } template constexpr descr concat(const descr &descr) { @@ -151,7 +208,8 @@ constexpr auto concat(const descr &d, const Args &...args) template constexpr descr type_descr(const descr &descr) { - return const_name("{") + descr + const_name("}"); + // Ensure that src_loc of existing descr is used. + return const_name("{", src_loc{nullptr, 0}) + descr + const_name("}"); } PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/detail/type_caster_odr_guard.h b/include/pybind11/detail/type_caster_odr_guard.h index 97092e0ab..4ae6d91fe 100644 --- a/include/pybind11/detail/type_caster_odr_guard.h +++ b/include/pybind11/detail/type_caster_odr_guard.h @@ -4,18 +4,16 @@ #pragma once +#include "descr.h" + // The type_caster ODR guard feature requires Translation-Unit-local entities // (https://en.cppreference.com/w/cpp/language/tu_local), a C++20 feature, but // almost all tested C++17 compilers support this feature already. +// This highly correlates with the preconditions for PYBIND11_DETAIL_DESCR_SRC_LOC_ON. #if !defined(PYBIND11_TYPE_CASTER_ODR_GUARD_ON) && !defined(PYBIND11_TYPE_CASTER_ODR_GUARD_OFF) \ - && !defined(__INTEL_COMPILER) \ - && ((defined(_MSC_VER) && _MSC_VER >= 1920) || defined(PYBIND11_CPP17)) + && defined(PYBIND11_DETAIL_DESCR_SRC_LOC_ON) # define PYBIND11_TYPE_CASTER_ODR_GUARD_ON #endif -// To explain the above: -// * MSVC 2017 does not support __builtin_FILE(), __builtin_LINE(). -// * Intel 2021.6.0.20220226 (g++ 9.4 mode) __builtin_LINE() is unreliable -// (line numbers vary between translation units). #ifndef PYBIND11_TYPE_CASTER_ODR_GUARD_ON @@ -31,7 +29,6 @@ # include "../pytypes.h" # include "common.h" -# include "descr.h" # include "typeid.h" # include @@ -46,19 +43,6 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) -struct src_loc { - const char *file; - unsigned line; - - // constexpr src_loc() : file(nullptr), line(0) {} - 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); - } -}; - inline std::unordered_map &type_caster_odr_guard_registry() { static std::unordered_map reg; return reg;