/**************************************************************************** ** ** Copyright (C) 2012 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$ ** GNU Lesser General Public License Usage ** 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. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $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; memcpy(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"