diff options
-rw-r--r-- | src/corelib/global/qglobal.h | 50 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobjectbuilder.cpp | 4 | ||||
-rw-r--r-- | src/corelib/tools/qcontiguouscache.h | 4 | ||||
-rw-r--r-- | src/corelib/tools/qhash.h | 5 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 4 | ||||
-rw-r--r-- | tests/auto/corelib/global/qglobal/tst_qglobal.cpp | 111 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 34 |
7 files changed, 165 insertions, 47 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index d0d6e851ad..ee577a7563 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -248,6 +248,56 @@ typedef quint64 qulonglong; #if defined(__cplusplus) +namespace QtPrivate { + template <class T> + struct AlignOfHelper + { + char c; + T type; + + AlignOfHelper(); + ~AlignOfHelper(); + }; + + template <class T> + struct AlignOf_Default + { + enum { Value = sizeof(AlignOfHelper<T>) - sizeof(T) }; + }; + + template <class T> struct AlignOf : AlignOf_Default<T> { }; + template <class T> struct AlignOf<T &> : AlignOf<T> {}; + template <size_t N, class T> struct AlignOf<T[N]> : AlignOf<T> {}; + +#ifdef Q_COMPILER_RVALUE_REFS + template <class T> struct AlignOf<T &&> : AlignOf<T> {}; +#endif + +#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN) + template <class T> struct AlignOf_WorkaroundForI386Abi { enum { Value = sizeof(T) }; }; + + // x86 ABI weirdness + // Alignment of naked type is 8, but inside struct has alignment 4. + template <> struct AlignOf<double> : AlignOf_WorkaroundForI386Abi<double> {}; + template <> struct AlignOf<qint64> : AlignOf_WorkaroundForI386Abi<qint64> {}; + template <> struct AlignOf<quint64> : AlignOf_WorkaroundForI386Abi<quint64> {}; +#ifdef Q_CC_CLANG + // GCC and Clang seem to disagree wrt to alignment of arrays + template <size_t N> struct AlignOf<double[N]> : AlignOf_Default<double> {}; + template <size_t N> struct AlignOf<qint64[N]> : AlignOf_Default<qint64> {}; + template <size_t N> struct AlignOf<quint64[N]> : AlignOf_Default<quint64> {}; +#endif +#endif +} // namespace QtPrivate + +#define QT_EMULATED_ALIGNOF(T) \ + (size_t(QT_PREPEND_NAMESPACE(QtPrivate)::AlignOf<T>::Value)) + +#ifndef Q_ALIGNOF +#define Q_ALIGNOF(T) QT_EMULATED_ALIGNOF(T) +#endif + + /* quintptr and qptrdiff is guaranteed to be the same size as a pointer, i.e. diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 59740960c9..8d6d7cbe91 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1095,11 +1095,7 @@ int QMetaStringTable::enter(const QByteArray &value) int QMetaStringTable::preferredAlignment() { -#ifdef Q_ALIGNOF return Q_ALIGNOF(QByteArrayData); -#else - return sizeof(void *); -#endif } // Returns the size (in bytes) required for serializing this string table. diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 4dc763f35d..4e01d7b586 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -170,11 +170,7 @@ private: } int alignOfTypedData() const { -#ifdef Q_ALIGNOF return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); -#else - return 0; -#endif } }; diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 73162b6cf1..ef003c8a71 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -257,13 +257,8 @@ class QHash return reinterpret_cast<Node *>(node); } -#ifdef Q_ALIGNOF static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); } static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); } -#else - static inline int alignOfNode() { return 0; } - static inline int alignOfDummyNode() { return 0; } -#endif public: inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { } diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 226d0bb258..04ab9e6e80 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -331,11 +331,7 @@ private: } static Q_DECL_CONSTEXPR int alignOfTypedData() { -#ifdef Q_ALIGNOF return Q_ALIGNOF(AlignmentDummy); -#else - return sizeof(void *); -#endif } }; diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index b3d76bef8a..529bafaa7a 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -56,6 +56,7 @@ private slots: void qstaticassert(); void qConstructorFunction(); void isEnum(); + void qAlignOf(); }; void tst_QGlobal::qIsNull() @@ -415,5 +416,115 @@ void tst_QGlobal::isEnum() #undef IS_ENUM_FALSE } +struct Empty {}; +template <class T> struct AlignmentInStruct { T dummy; }; + +typedef int (*fun) (); +typedef int (Empty::*memFun) (); + +#define TEST_AlignOf(type, alignment) \ + do { \ + TEST_AlignOf_impl(type, alignment); \ + \ + TEST_AlignOf_impl(type &, alignment); \ + TEST_AlignOf_RValueRef(type &&, alignment); \ + \ + TEST_AlignOf_impl(type [5], alignment); \ + TEST_AlignOf_impl(type (&) [5], alignment); \ + \ + TEST_AlignOf_impl(AlignmentInStruct<type>, alignment); \ + \ + /* Some internal sanity validation, just for fun */ \ + TEST_AlignOf_impl(AlignmentInStruct<type [5]>, alignment); \ + TEST_AlignOf_impl(AlignmentInStruct<type &>, Q_ALIGNOF(void *)); \ + TEST_AlignOf_impl(AlignmentInStruct<type (&) [5]>, \ + Q_ALIGNOF(void *)); \ + TEST_AlignOf_RValueRef(AlignmentInStruct<type &&>, \ + Q_ALIGNOF(void *)); \ + } while (false) \ + /**/ + +#ifdef Q_COMPILER_RVALUE_REFS +#define TEST_AlignOf_RValueRef(type, alignment) \ + TEST_AlignOf_impl(type, alignment) +#else +#define TEST_AlignOf_RValueRef(type, alignment) do {} while (false) +#endif + +#define TEST_AlignOf_impl(type, alignment) \ + do { \ + QCOMPARE(Q_ALIGNOF(type), size_t(alignment)); \ + /* Compare to native operator for compilers that support it, + otherwise... erm... check consistency! :-) */ \ + QCOMPARE(QT_EMULATED_ALIGNOF(type), Q_ALIGNOF(type)); \ + } while (false) + /**/ + +void tst_QGlobal::qAlignOf() +{ + // Built-in types, except 64-bit integers and double + TEST_AlignOf(char, 1); + TEST_AlignOf(signed char, 1); + TEST_AlignOf(unsigned char, 1); + TEST_AlignOf(qint8, 1); + TEST_AlignOf(quint8, 1); + TEST_AlignOf(qint16, 2); + TEST_AlignOf(quint16, 2); + TEST_AlignOf(qint32, 4); + TEST_AlignOf(quint32, 4); + TEST_AlignOf(void *, sizeof(void *)); + + // Depends on platform and compiler, disabling test for now + // TEST_AlignOf(long double, 16); + + // Empty struct + TEST_AlignOf(Empty, 1); + + // Function pointers + TEST_AlignOf(fun, Q_ALIGNOF(void *)); + TEST_AlignOf(memFun, Q_ALIGNOF(void *)); + + + // 64-bit integers and double + TEST_AlignOf_impl(qint64, 8); + TEST_AlignOf_impl(quint64, 8); + TEST_AlignOf_impl(double, 8); + + TEST_AlignOf_impl(qint64 &, 8); + TEST_AlignOf_impl(quint64 &, 8); + TEST_AlignOf_impl(double &, 8); + + TEST_AlignOf_RValueRef(qint64 &&, 8); + TEST_AlignOf_RValueRef(quint64 &&, 8); + TEST_AlignOf_RValueRef(double &&, 8); + + // 32-bit x86 ABI idiosyncrasies +#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN) + TEST_AlignOf_impl(AlignmentInStruct<qint64>, 4); +#else + TEST_AlignOf_impl(AlignmentInStruct<qint64>, 8); +#endif + + TEST_AlignOf_impl(AlignmentInStruct<quint64>, Q_ALIGNOF(AlignmentInStruct<qint64>)); + TEST_AlignOf_impl(AlignmentInStruct<double>, Q_ALIGNOF(AlignmentInStruct<qint64>)); + + // 32-bit x86 ABI, Clang disagrees with gcc +#if !defined(Q_PROCESSOR_X86_32) || !defined(Q_CC_CLANG) + TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(qint64)); +#else + TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(AlignmentInStruct<qint64>)); +#endif + + TEST_AlignOf_impl(qint64 (&) [5], Q_ALIGNOF(qint64 [5])); + TEST_AlignOf_impl(quint64 [5], Q_ALIGNOF(quint64 [5])); + TEST_AlignOf_impl(quint64 (&) [5], Q_ALIGNOF(quint64 [5])); + TEST_AlignOf_impl(double [5], Q_ALIGNOF(double [5])); + TEST_AlignOf_impl(double (&) [5], Q_ALIGNOF(double [5])); +} + +#undef TEST_AlignOf +#undef TEST_AlignOf_RValueRef +#undef TEST_AlignOf_impl + QTEST_MAIN(tst_QGlobal) #include "tst_qglobal.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 72ad3080d6..9f4944b44b 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -868,41 +868,15 @@ void tst_QMetaType::construct_data() create_data(); } -#ifndef Q_ALIGNOF -template<uint N> -struct RoundToNextHighestPowerOfTwo -{ -private: - enum { V1 = N-1 }; - enum { V2 = V1 | (V1 >> 1) }; - enum { V3 = V2 | (V2 >> 2) }; - enum { V4 = V3 | (V3 >> 4) }; - enum { V5 = V4 | (V4 >> 8) }; - enum { V6 = V5 | (V5 >> 16) }; -public: - enum { Value = V6 + 1 }; -}; -#endif - -template<class T> -struct TypeAlignment -{ -#ifdef Q_ALIGNOF - enum { Value = Q_ALIGNOF(T) }; -#else - enum { Value = RoundToNextHighestPowerOfTwo<sizeof(T)>::Value }; -#endif -}; - template<int ID> static void testConstructHelper() { typedef typename MetaEnumToType<ID>::Type Type; QMetaType info(ID); int size = info.sizeOf(); - void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value); + void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0); - void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value); + void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual2 = info.construct(storage2, /*copy=*/0); QCOMPARE(actual1, storage1); QCOMPARE(actual2, storage2); @@ -971,9 +945,9 @@ static void testConstructCopyHelper() QMetaType info(ID); int size = QMetaType::sizeOf(ID); QCOMPARE(info.sizeOf(), size); - void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value); + void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual1 = QMetaType::construct(ID, storage1, expected); - void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value); + void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type)); void *actual2 = info.construct(storage2, expected); QCOMPARE(actual1, storage1); QCOMPARE(actual2, storage2); |