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>
This commit is contained in:
Fabian Kosmale 2020-08-17 08:46:56 +02:00
parent 2df41e2c48
commit a2cec17407
2 changed files with 68 additions and 31 deletions

View File

@ -1636,6 +1636,7 @@ struct QMetaTypeId : public QMetaTypeIdQObject<T>
template <typename T> template <typename T>
struct QMetaTypeId2 struct QMetaTypeId2
{ {
using NameAsArrayType = void;
enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false }; enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false };
static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); } static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
}; };
@ -1935,9 +1936,10 @@ inline int qRegisterMetaTypeStreamOperators()
QT_BEGIN_NAMESPACE \ QT_BEGIN_NAMESPACE \
template<> struct QMetaTypeId2<NAME> \ template<> struct QMetaTypeId2<NAME> \
{ \ { \
using NameAsArrayType = std::array<char, sizeof(#NAME)>; \
enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \ enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \
static inline constexpr int qt_metatype_id() { return 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 QT_END_NAMESPACE
@ -2468,11 +2470,7 @@ public:
if (skipToken(begin, end, "QPair")) { if (skipToken(begin, end, "QPair")) {
// replace QPair by std::pair // replace QPair by std::pair
#ifdef _LIBCPP_VERSION
appendStr("std::" QT_STRINGIFY(_LIBCPP_ABI_NAMESPACE) "::pair");
#else
appendStr("std::pair"); appendStr("std::pair");
#endif
} }
if (!hasMiddleConst) { if (!hasMiddleConst) {
@ -2576,43 +2574,86 @@ constexpr int qNormalizeType(const char *begin, const char *end, char *output)
return QTypeNormalizer { output }.normalizeType(begin, end); return QTypeNormalizer { output }.normalizeType(begin, end);
} }
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> template<typename T>
constexpr auto typenameHelper() 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 #ifdef QT_NAMESPACE
QT_STRINGIFY(QT_NAMESPACE) "::" QT_STRINGIFY(QT_NAMESPACE) "::"
#endif #endif
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
"auto __cdecl QtPrivate::typenameHelper<" "auto __cdecl QtPrivate::typenameHelper<"
#elif defined(Q_CC_CLANG) #elif defined(Q_CC_CLANG)
"auto QtPrivate::typenameHelper() [T = " "auto QtPrivate::typenameHelper() [T = "
#else #else
"constexpr auto QtPrivate::typenameHelper() [with T = " "constexpr auto QtPrivate::typenameHelper() [with T = "
#endif #endif
) - 1; ) - 1;
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
constexpr int suffix = sizeof(">(void)"); constexpr int suffix = sizeof(">(void)");
#else #else
constexpr int suffix = sizeof("]"); constexpr int suffix = sizeof("]");
#endif #endif
#if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)) #if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG))
constexpr auto func = Q_FUNC_INFO; constexpr auto func = Q_FUNC_INFO;
constexpr const char *begin = func + prefix; constexpr const char *begin = func + prefix;
constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix; constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
constexpr int len = qNormalizeType(begin, end, nullptr); 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 #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; auto func = Q_FUNC_INFO;
const char *begin = func + prefix; const char *begin = func + prefix;
const char *end = func + sizeof(Q_FUNC_INFO) - suffix; 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 // 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) // (Unless there is a QList -> QVector change, but that should not happen)
constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix; constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix;
#endif #endif
std::array<char, len + 1> result {}; std::array<char, len + 1> result {};
qNormalizeType(begin, end, result.data()); qNormalizeType(begin, end, result.data());
return result; return result;
}
} }
template<typename T, typename = void> template<typename T, typename = void>
@ -2712,7 +2753,7 @@ class QMetaTypeForType
static constexpr const char *getName() static constexpr const char *getName()
{ {
if constexpr (bool(QMetaTypeId2<S>::IsBuiltIn)) { if constexpr (bool(QMetaTypeId2<S>::IsBuiltIn)) {
return QMetaTypeId2<S>::name; return QMetaTypeId2<S>::nameAsArray.data();
} else { } else {
return name.data(); return name.data();
} }

View File

@ -1382,11 +1382,7 @@ void tst_QMetaObject::normalizedType_data()
QTest::newRow("template7") << "QList<QList<int> >" << "QList<QList<int>>"; QTest::newRow("template7") << "QList<QList<int> >" << "QList<QList<int>>";
QTest::newRow("template8") << "QMap<const int, const short*>" << "QMap<const int,const short*>"; 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*> > >" 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*>>>"; << "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("template10") << "QVector<int const * const> const" << "QList<const int*const>";
QTest::newRow("template11") << " QSharedPointer<QVarLengthArray< QString const, ( 16>> 2 )> > const & " QTest::newRow("template11") << " QSharedPointer<QVarLengthArray< QString const, ( 16>> 2 )> > const & "
<< "QSharedPointer<QVarLengthArray<const QString,(16>>2)>>"; << "QSharedPointer<QVarLengthArray<const QString,(16>>2)>>";