diff -r 41300fa6a67c -r f7bc934e204c util/tests/auto/compiler/tst_compiler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/tests/auto/compiler/tst_compiler.cpp Wed Mar 31 11:06:36 2010 +0300 @@ -0,0 +1,656 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +#include + +#define BASECLASS_NOT_ABSTRACT +#include "baseclass.h" +#include "derivedclass.h" + +QT_USE_NAMESPACE + +class tst_Compiler : public QObject +{ +Q_OBJECT + +private slots: + void template_methods(); + void template_constructors(); + void template_subclasses(); + void methodSpecialization(); + void constructorSpecialization(); + void staticTemplateMethods(); + void staticTemplateMethodSpecialization(); + void detectDataStream(); + void detectEnums(); + void overrideCFunction(); + void stdSortQList(); + void stdSortQVector(); + void templateCallOrder(); + void virtualFunctionNoLongerPureVirtual(); + void charSignedness() const; + void privateStaticTemplateMember() const; + void staticConstUnionWithInitializerList() const; +}; + +#if defined(Q_CC_MSVC) && _MSC_VER < 1300 +#define MSVC6 +#endif + +#if defined(Q_CC_MSVC) && _MSC_VER == 1300 +#define MSVC2002 +#endif + +#if defined(MSVC6) +# define DONT_TEST_TEMPLATE_METHODS +# define DONT_TEST_TEMPLATE_CONSTRUCTORS +# define DONT_TEST_METHOD_SPECIALIZATION +# define DONT_TEST_CONSTRUCTOR_SPECIALIZATION +# define DONT_TEST_STATIC_TEMPLATE_METHODS +# define DONT_TEST_STATIC_TEMPLATE_METHOD_SPECIALIZATION +# define DONT_TEST_STL_SORTING +# define DONT_TEST_SIGNEDNESS +#endif + +#if defined(MSVC2002) +# define DONT_TEST_TEMPLATE_METHODS +# define DONT_TEST_DETECT_ENUMS +# define DONT_TEST_METHOD_SPECIALIZATION +# define DONT_TEST_CONSTRUCTOR_SPECIALIZATION +# define DONT_TEST_STATIC_TEMPLATE_METHOD_SPECIALIZATION +# define DONT_TEST_STL_SORTING +#endif + +#if defined(Q_CC_HPACC) +# define DONT_TEST_TEMPLATE_CONSTRUCTORS +# define DONT_TEST_CONSTRUCTOR_SPECIALIZATION +# define DONT_TEST_DATASTREAM_DETECTION +#endif + +#if defined(Q_CC_SUN) +# define DONT_TEST_STL_SORTING +#endif + +#ifndef DONT_TEST_TEMPLATE_METHODS +class TemplateMethodClass +{ +public: + template + T foo() { return 42; } +}; + +void tst_Compiler::template_methods() +{ + TemplateMethodClass t; + + QCOMPARE(t.foo(), 42); + QCOMPARE(t.foo(), 42l); + QCOMPARE(t.foo(), 42.0); +} +#else +void tst_Compiler::template_methods() +{ QSKIP("Compiler doesn't do template methods", SkipAll); } +#endif + +#ifndef DONT_TEST_TEMPLATE_CONSTRUCTORS +class TemplateConstructorClass +{ +public: + template + TemplateConstructorClass(const T& t) { i = int(t); } + + int i; +}; + +void tst_Compiler::template_constructors() +{ + TemplateConstructorClass t1(42); + TemplateConstructorClass t2(42l); + TemplateConstructorClass t3(42.0); + + QCOMPARE(t1.i, 42); + QCOMPARE(t2.i, 42); + QCOMPARE(t3.i, 42); +} +#else +void tst_Compiler::template_constructors() +{ QSKIP("Compiler doesn't do template constructors", SkipAll); } +#endif + +template +struct OuterClass +{ + template + struct InnerClass + { + U convert(const T &t) { return static_cast(t); } + }; +}; + +void tst_Compiler::template_subclasses() +{ + OuterClass::InnerClass c1; + QCOMPARE(c1.convert('a'), int('a')); + + OuterClass::InnerClass c2; + QCOMPARE(c2.convert(QRect(1, 2, 3, 4)), QRectF(QRect(1, 2, 3, 4))); +} + +#ifndef DONT_TEST_METHOD_SPECIALIZATION +class TemplateMethodClass2 +{ +public: + template + T foo() { return 42; } +}; + +template<> +int TemplateMethodClass2::foo() +{ return 43; } + +void tst_Compiler::methodSpecialization() +{ + TemplateMethodClass2 t; + + QCOMPARE(t.foo(), 43); + QCOMPARE(t.foo(), 42l); + QCOMPARE(t.foo(), 42.0); +} +#else +void tst_Compiler::methodSpecialization() +{ QSKIP("Compiler doesn't do template specialization", SkipAll); } +#endif + +#ifndef DONT_TEST_CONSTRUCTOR_SPECIALIZATION +class TemplateConstructorClass2 +{ +public: + template + TemplateConstructorClass2(const T &t) { i = int(t); } + + int i; +}; + +template<> +TemplateConstructorClass2::TemplateConstructorClass2(const int &t) { i = t + 1; } + +void tst_Compiler::constructorSpecialization() +{ + TemplateConstructorClass2 t1(42); + TemplateConstructorClass2 t2(42l); + TemplateConstructorClass2 t3(42.0); + + QCOMPARE(t1.i, 43); + QCOMPARE(t2.i, 42); + QCOMPARE(t3.i, 42); +} +#else +void tst_Compiler::constructorSpecialization() +{ QSKIP("Compiler doesn't do constructor specialization", SkipAll); } +#endif + +#ifndef DONT_TEST_STATIC_TEMPLATE_METHODS +class StaticTemplateClass +{ +public: + template + static T foo() { return 42; } +}; + +void tst_Compiler::staticTemplateMethods() +{ + QCOMPARE(StaticTemplateClass::foo(), 42); + QCOMPARE(StaticTemplateClass::foo(), 42u); +} +#else +void tst_Compiler::staticTemplateMethods() +{ QSKIP("Compiler doesn't do static template methods", SkipAll); } +#endif + +#ifndef DONT_TEST_STATIC_TEMPLATE_METHOD_SPECIALIZATION +class StaticTemplateClass2 +{ +public: + template + static T foo() { return 42; } +}; + +template<> +double StaticTemplateClass2::foo() { return 18.5; } + +void tst_Compiler::staticTemplateMethodSpecialization() +{ + QCOMPARE(StaticTemplateClass2::foo(), 42); + QCOMPARE(StaticTemplateClass2::foo(), 42u); + QCOMPARE(StaticTemplateClass2::foo(), 18.5); +} +#else +void tst_Compiler::staticTemplateMethodSpecialization() +{ QSKIP("Compiler doesn't do static template method specialization", SkipAll); } +#endif + +#ifndef DONT_TEST_DATASTREAM_DETECTION +/******* DataStream tester *********/ +namespace QtTestInternal +{ + struct EmptyStruct {}; + struct LowPreferenceStruct { LowPreferenceStruct(...); }; + + EmptyStruct operator<<(QDataStream &, const LowPreferenceStruct &); + EmptyStruct operator>>(QDataStream &, const LowPreferenceStruct &); + + template + struct DataStreamChecker + { + static EmptyStruct hasStreamHelper(const EmptyStruct &); + static QDataStream hasStreamHelper(const QDataStream &); + static QDataStream &dsDummy(); + static T &dummy(); + +#ifdef BROKEN_COMPILER + static const bool HasDataStream = + sizeof(hasStreamHelper(dsDummy() << dummy())) == sizeof(QDataStream) + && sizeof(hasStreamHelper(dsDummy() >> dummy())) == sizeof(QDataStream); +#else + enum { + HasOutDataStream = sizeof(hasStreamHelper(dsDummy() >> dummy())) == sizeof(QDataStream), + HasInDataStream = sizeof(hasStreamHelper(dsDummy() << dummy())) == sizeof(QDataStream), + HasDataStream = HasOutDataStream & HasInDataStream + }; +#endif + }; + + template + struct DataStreamOpHelper + { + template + struct Getter { + static QMetaType::SaveOperator saveOp() { return 0; } + }; + }; + + template<> + struct DataStreamOpHelper + { + template + struct Getter { + static QMetaType::SaveOperator saveOp() + { + typedef void(*SavePtr)(QDataStream &, const T *); + SavePtr op = ::qMetaTypeSaveHelper; + return reinterpret_cast(op); + } + }; + + }; + + template + inline QMetaType::SaveOperator getSaveOperator(T * = 0) + { + typedef typename DataStreamOpHelper::HasDataStream>::template Getter GetterHelper; + return GetterHelper::saveOp(); + } +}; + +struct MyString: public QString {}; +struct Qxxx {}; + +void tst_Compiler::detectDataStream() +{ + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasInDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasOutDataStream == false); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == false); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == true); + QVERIFY(QtTestInternal::DataStreamChecker::HasDataStream == false); + + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() != 0); + QVERIFY(QtTestInternal::getSaveOperator() == 0); +} +#else +void tst_Compiler::detectDataStream() +{ QSKIP("Compiler doesn't evaluate templates correctly", SkipAll); } +#endif + +#ifndef DONT_TEST_DETECT_ENUMS +enum Enum1 { Foo = 0, Bar = 1 }; +enum Enum2 {}; +enum Enum3 { Something = 1 }; + +template char QTypeInfoEnumHelper(T); +template void *QTypeInfoEnumHelper(...); + +#if defined(MSVC6) + +template +struct QTestTypeInfoHelper +{ + enum { IsE = 0 }; +}; + +template <> +struct QTestTypeInfoHelper +{ + enum { IsE = 1 }; +}; + + +template +struct QTestTypeInfo +{ + typedef typename QTestTypeInfoHelper(0))> TIHelper; + enum { IsEnum = TIHelper::IsE }; +}; +#else +template +struct QTestTypeInfo +{ + enum { IsEnum = sizeof(QTypeInfoEnumHelper(0)) == sizeof(void*) }; +}; +#endif + +void tst_Compiler::detectEnums() +{ + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); + QVERIFY(QTestTypeInfo::IsEnum); + QVERIFY(!QTestTypeInfo::IsEnum); +} +#else +void tst_Compiler::detectEnums() +{ QSKIP("Compiler doesn't evaluate templates correctly", SkipAll); } +#endif + +static int indicator = 0; + + +// this is a silly C function +extern "C" { + void someCFunc(void *) { indicator = 42; } +} + +// this is the catch-template that will be called if the C function doesn't exist +template +void someCFunc(T *) { indicator = 10; } + +void tst_Compiler::overrideCFunction() +{ + someCFunc((void*)0); + QCOMPARE(indicator, 42); +} + +#ifndef DONT_TEST_STL_SORTING +void tst_Compiler::stdSortQList() +{ + QList list; + list << 4 << 2; + std::sort(list.begin(), list.end()); + QCOMPARE(list.value(0), 2); + QCOMPARE(list.value(1), 4); + + QList slist; + slist << "b" << "a"; + std::sort(slist.begin(), slist.end()); + QCOMPARE(slist.value(0), QString("a")); + QCOMPARE(slist.value(1), QString("b")); +} + +void tst_Compiler::stdSortQVector() +{ + QVector vector; + vector << 4 << 2; + std::sort(vector.begin(), vector.end()); + QCOMPARE(vector.value(0), 2); + QCOMPARE(vector.value(1), 4); + + QVector strvec; + strvec << "b" << "a"; + std::sort(strvec.begin(), strvec.end()); + QCOMPARE(strvec.value(0), QString("a")); + QCOMPARE(strvec.value(1), QString("b")); +} +#else +void tst_Compiler::stdSortQList() +{ QSKIP("Compiler's STL broken", SkipAll); } +void tst_Compiler::stdSortQVector() +{ QSKIP("Compiler's STL broken", SkipAll); } +#endif + +// the C func will set it to 1, the template to 2 +static int whatWasCalled = 0; + +void callOrderFunc(void *) +{ + whatWasCalled = 1; +} + +template +void callOrderFunc(T *) +{ + whatWasCalled = 2; +} + +template +void callOrderNoCFunc(T *) +{ + whatWasCalled = 3; +} + +/* + This test will check what will get precendence - the C function + or the template. + + It also makes sure this template "override" will compile on all systems + and not result in ambiguities. +*/ +void tst_Compiler::templateCallOrder() +{ + QCOMPARE(whatWasCalled, 0); + + // call it with a void * + void *f = 0; + callOrderFunc(f); + QCOMPARE(whatWasCalled, 1); + whatWasCalled = 0; + + char *c = 0; + /* call it with a char * - AMBIGOUS, fails on several compilers + callOrderFunc(c); + QCOMPARE(whatWasCalled, 1); + whatWasCalled = 0; + */ + + // now try the case when there is no C function + callOrderNoCFunc(f); + QCOMPARE(whatWasCalled, 3); + whatWasCalled = 0; + + callOrderNoCFunc(c); + QCOMPARE(whatWasCalled, 3); + whatWasCalled = 0; +} + +// test to see if removing =0 from a pure virtual function is BC +void tst_Compiler::virtualFunctionNoLongerPureVirtual() +{ +#ifdef BASECLASS_NOT_ABSTRACT + // has a single virtual function, not pure virtual, can call it + BaseClass baseClass; + QTest::ignoreMessage(QtDebugMsg, "BaseClass::wasAPureVirtualFunction()"); + baseClass.wasAPureVirtualFunction(); +#endif + + // DerivedClass inherits from BaseClass, and function is declared + // pure virtual, make sure we can still call it + DerivedClass derivedClass; + QTest::ignoreMessage(QtDebugMsg, "DerivedClass::wasAPureVirtualFunction()"); + derivedClass.wasAPureVirtualFunction(); +} + +template const char *resolveCharSignedness(); + +template<> +const char *resolveCharSignedness() +{ + return "char"; +} + +template<> +const char *resolveCharSignedness() +{ + return "unsigned char"; +} + +template<> +const char *resolveCharSignedness() +{ + return "signed char"; +} + +void tst_Compiler::charSignedness() const +{ +#ifdef DONT_TEST_SIGNEDNESS + QSKIP("MS VC 6.0 instantiates the char function for type unsigned char.", SkipSingle); +#else + QCOMPARE("char", resolveCharSignedness()); + QCOMPARE("unsigned char", resolveCharSignedness()); + QCOMPARE("signed char", resolveCharSignedness()); +#endif +} + +class PrivateStaticTemplateMember +{ +public: + long regularMember() + { + return helper(3); + } + +private: + template + static A helper(const B b) + { + return A(b); + } +}; + +void tst_Compiler::privateStaticTemplateMember() const +{ + PrivateStaticTemplateMember v; + + QCOMPARE(long(3), v.regularMember()); +} + + +#if !defined(Q_CC_MIPS) + +// make sure we can use a static initializer with a union and then use +// the second member of the union +static const union { unsigned char c[8]; double d; } qt_be_inf_bytes = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } }; +static const union { unsigned char c[8]; double d; } qt_le_inf_bytes = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } }; +static const union { unsigned char c[8]; double d; } qt_armfpa_inf_bytes = { { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } }; +static inline double qt_inf() +{ +#ifdef QT_ARMFPA + return qt_armfpa_inf_bytes.d; +#else + return (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? qt_be_inf_bytes.d + : qt_le_inf_bytes.d); +#endif +} + +#else + +static const unsigned char qt_be_inf_bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; +static const unsigned char qt_le_inf_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; +static const unsigned char qt_armfpa_inf_bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }; +static inline double qt_inf() +{ + const uchar *bytes; +#ifdef QT_ARMFPA + bytes = qt_armfpa_inf_bytes; +#else + bytes = (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? qt_be_inf_bytes + : qt_le_inf_bytes); +#endif + + union { uchar c[8]; double d; } returnValue; + qMemCopy(returnValue.c, bytes, sizeof(returnValue.c)); + return returnValue.d; +} + +#endif + +void tst_Compiler::staticConstUnionWithInitializerList() const +{ + double d = qt_inf(); + QVERIFY(qIsInf(d)); +} + +QTEST_MAIN(tst_Compiler) +#include "tst_compiler.moc"