diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-08-17 08:46:56 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-08-19 19:17:46 +0200 |
commit | a2cec17407b83aed23b01065f4e10d32008552e1 (patch) | |
tree | 24971e413706df129512789e68f78146d73b941c | |
parent | 2df41e2c4876cb692bf575d9d0d1cc798e09237c (diff) |
QMetaType: specialize typenameHelper for std::pair
The string representation of std::pair<T1,T2> is now always
"std::pair<T1,T2>". 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 <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 95 | ||||
-rw-r--r-- | tests/auto/corelib/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 a7916cfb13..ced3444020 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1636,6 +1636,7 @@ struct QMetaTypeId : public QMetaTypeIdQObject<T> template <typename T> struct QMetaTypeId2 { + using NameAsArrayType = void; enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false }; static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); } }; @@ -1935,9 +1936,10 @@ inline int qRegisterMetaTypeStreamOperators() QT_BEGIN_NAMESPACE \ template<> struct QMetaTypeId2<NAME> \ { \ + using NameAsArrayType = std::array<char, sizeof(#NAME)>; \ 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) { @@ -2577,42 +2575,85 @@ constexpr int qNormalizeType(const char *begin, const char *end, char *output) } template<typename T> +struct is_std_pair : std::false_type {}; + +template <typename T1_, typename T2_> +struct is_std_pair<std::pair<T1_, T2_>> : std::true_type { + using T1 = T1_; + using T2 = T2_; +}; + +template<typename T> constexpr auto typenameHelper() { - constexpr auto prefix = sizeof( + if constexpr (is_std_pair<T>::value) { + using T1 = typename is_std_pair<T>::T1; + using T2 = typename is_std_pair<T>::T2; + std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T1>::IsBuiltIn), typename QMetaTypeId2<T1>::NameAsArrayType, decltype(typenameHelper<T1>())>> t1Name {}; + std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T2>::IsBuiltIn), typename QMetaTypeId2<T2>::NameAsArrayType, decltype(typenameHelper<T2>())>> t2Name {}; + if constexpr (bool (QMetaTypeId2<T1>::IsBuiltIn) ) { + t1Name = QMetaTypeId2<T1>::nameAsArray; + } else { + t1Name = typenameHelper<T1>(); + } + if constexpr (bool (QMetaTypeId2<T2>::IsBuiltIn) ) { + t2Name = QMetaTypeId2<T2>::nameAsArray; + } else { + t2Name = typenameHelper<T2>(); + } + 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<char, length + 1> 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<char, len + 1> result {}; - qNormalizeType(begin, end, result.data()); - return result; + std::array<char, len + 1> result {}; + qNormalizeType(begin, end, result.data()); + return result; + } } template<typename T, typename = void> @@ -2712,7 +2753,7 @@ class QMetaTypeForType static constexpr const char *getName() { if constexpr (bool(QMetaTypeId2<S>::IsBuiltIn)) { - return QMetaTypeId2<S>::name; + return QMetaTypeId2<S>::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 5f099f6458..06e586322f 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<int> >" << "QList<QList<int>>"; QTest::newRow("template8") << "QMap<const int, const short*>" << "QMap<const int,const short*>"; QTest::newRow("template9") << "QPair<const QPair<int, int const *> , QPair<QHash<int, const char*> > >" -#ifdef _LIBCPP_VERSION - << "std::__1::pair<const std::__1::pair<int,const int*>,std::__1::pair<QHash<int,const char*>>>"; -#else << "std::pair<const std::pair<int,const int*>,std::pair<QHash<int,const char*>>>"; -#endif QTest::newRow("template10") << "QVector<int const * const> const" << "QList<const int*const>"; QTest::newRow("template11") << " QSharedPointer<QVarLengthArray< QString const, ( 16>> 2 )> > const & " << "QSharedPointer<QVarLengthArray<const QString,(16>>2)>>"; |