From a2cec17407b83aed23b01065f4e10d32008552e1 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 17 Aug 2020 08:46:56 +0200 Subject: [PATCH] QMetaType: specialize typenameHelper for std::pair The string representation of std::pair is now always "std::pair". This is in line with how we translate QPair, avoiding typename mismatches that would previoulsy occur, because the full name of pair on libc++ was "std::__1::pair". Fixes: QTBUG-84924 Change-Id: Ia6c044a7327d69e4b4f4a31496c6b2408d85ebb9 Reviewed-by: Qt CI Bot Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetatype.h | 95 +++++++++++++------ .../kernel/qmetaobject/tst_qmetaobject.cpp | 4 - 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index a7916cfb137..ced3444020c 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1636,6 +1636,7 @@ struct QMetaTypeId : public QMetaTypeIdQObject template struct QMetaTypeId2 { + using NameAsArrayType = void; enum { Defined = QMetaTypeId::Defined, IsBuiltIn=false }; static inline constexpr int qt_metatype_id() { return QMetaTypeId::qt_metatype_id(); } }; @@ -1935,9 +1936,10 @@ inline int qRegisterMetaTypeStreamOperators() QT_BEGIN_NAMESPACE \ template<> struct QMetaTypeId2 \ { \ + using NameAsArrayType = std::array; \ enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \ static inline constexpr int qt_metatype_id() { return METATYPEID; } \ - static constexpr const char * const name = #NAME; \ + static constexpr NameAsArrayType nameAsArray = { #NAME }; \ }; \ QT_END_NAMESPACE @@ -2468,11 +2470,7 @@ public: if (skipToken(begin, end, "QPair")) { // replace QPair by std::pair -#ifdef _LIBCPP_VERSION - appendStr("std::" QT_STRINGIFY(_LIBCPP_ABI_NAMESPACE) "::pair"); -#else appendStr("std::pair"); -#endif } if (!hasMiddleConst) { @@ -2576,43 +2574,86 @@ constexpr int qNormalizeType(const char *begin, const char *end, char *output) return QTypeNormalizer { output }.normalizeType(begin, end); } +template +struct is_std_pair : std::false_type {}; + +template +struct is_std_pair> : std::true_type { + using T1 = T1_; + using T2 = T2_; +}; + template constexpr auto typenameHelper() { - constexpr auto prefix = sizeof( + if constexpr (is_std_pair::value) { + using T1 = typename is_std_pair::T1; + using T2 = typename is_std_pair::T2; + std::remove_const_t::IsBuiltIn), typename QMetaTypeId2::NameAsArrayType, decltype(typenameHelper())>> t1Name {}; + std::remove_const_t::IsBuiltIn), typename QMetaTypeId2::NameAsArrayType, decltype(typenameHelper())>> t2Name {}; + if constexpr (bool (QMetaTypeId2::IsBuiltIn) ) { + t1Name = QMetaTypeId2::nameAsArray; + } else { + t1Name = typenameHelper(); + } + if constexpr (bool (QMetaTypeId2::IsBuiltIn) ) { + t2Name = QMetaTypeId2::nameAsArray; + } else { + t2Name = typenameHelper(); + } + constexpr auto nonTypeDependentLen = sizeof("std::pair<,>"); + constexpr auto t1Len = t1Name.size() - 1; + constexpr auto t2Len = t2Name.size() - 1; + constexpr auto length = nonTypeDependentLen + t1Len + t2Len; + std::array result {}; + constexpr auto prefix = "std::pair<"; + int currentLength = 0; + for (; currentLength < int(sizeof("std::pair<")-1); ++currentLength) + result[currentLength] = prefix[currentLength]; + for (int i = 0; i < int(t1Len); ++currentLength, ++i) + result[currentLength] = t1Name[i]; + result[currentLength++] = ','; + for (int i = 0; i < int(t2Len); ++currentLength, ++i) + result[currentLength] = t2Name[i]; + result[currentLength++] = '>'; + result[currentLength++] = '\0'; + return result; + } else { + constexpr auto prefix = sizeof( #ifdef QT_NAMESPACE - QT_STRINGIFY(QT_NAMESPACE) "::" + QT_STRINGIFY(QT_NAMESPACE) "::" #endif #ifdef Q_CC_MSVC - "auto __cdecl QtPrivate::typenameHelper<" + "auto __cdecl QtPrivate::typenameHelper<" #elif defined(Q_CC_CLANG) - "auto QtPrivate::typenameHelper() [T = " + "auto QtPrivate::typenameHelper() [T = " #else - "constexpr auto QtPrivate::typenameHelper() [with T = " + "constexpr auto QtPrivate::typenameHelper() [with T = " #endif - ) - 1; + ) - 1; #ifdef Q_CC_MSVC - constexpr int suffix = sizeof(">(void)"); + constexpr int suffix = sizeof(">(void)"); #else - constexpr int suffix = sizeof("]"); + constexpr int suffix = sizeof("]"); #endif #if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)) - constexpr auto func = Q_FUNC_INFO; - constexpr const char *begin = func + prefix; - constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix; - constexpr int len = qNormalizeType(begin, end, nullptr); + constexpr auto func = Q_FUNC_INFO; + constexpr const char *begin = func + prefix; + constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + constexpr int len = qNormalizeType(begin, end, nullptr); #else // GCC < 8.1 did not have Q_FUNC_INFO as constexpr, and GCC 9 has a precompiled header bug - auto func = Q_FUNC_INFO; - const char *begin = func + prefix; - const char *end = func + sizeof(Q_FUNC_INFO) - suffix; - // This is an upper bound of the size since the normalized signature should always be smaller - // (Unless there is a QList -> QVector change, but that should not happen) - constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix; + auto func = Q_FUNC_INFO; + const char *begin = func + prefix; + const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + // This is an upper bound of the size since the normalized signature should always be smaller + // (Unless there is a QList -> QVector change, but that should not happen) + constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix; #endif - std::array result {}; - qNormalizeType(begin, end, result.data()); - return result; + std::array result {}; + qNormalizeType(begin, end, result.data()); + return result; + } } template @@ -2712,7 +2753,7 @@ class QMetaTypeForType static constexpr const char *getName() { if constexpr (bool(QMetaTypeId2::IsBuiltIn)) { - return QMetaTypeId2::name; + return QMetaTypeId2::nameAsArray.data(); } else { return name.data(); } diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 5f099f64582..06e586322fb 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -1382,11 +1382,7 @@ void tst_QMetaObject::normalizedType_data() QTest::newRow("template7") << "QList >" << "QList>"; QTest::newRow("template8") << "QMap" << "QMap"; QTest::newRow("template9") << "QPair , QPair > >" -#ifdef _LIBCPP_VERSION - << "std::__1::pair,std::__1::pair>>"; -#else << "std::pair,std::pair>>"; -#endif QTest::newRow("template10") << "QVector const" << "QList"; QTest::newRow("template11") << " QSharedPointer> 2 )> > const & " << "QSharedPointer>2)>>";