Expand the compiler test with C++11 and C++14 compiler tests

This allows us to quickly test if a compiler actually supports what it
claims to support.

Change-Id: Ia32212a11774aa7947ddffae30837c53665374f3
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
bb10
Thiago Macieira 2014-06-18 14:30:50 -07:00
parent 416c112aea
commit eab7ec586d
3 changed files with 811 additions and 2 deletions

View File

@ -1,9 +1,9 @@
CONFIG += testcase
TARGET = tst_compiler
SOURCES += tst_compiler.cpp baseclass.cpp derivedclass.cpp
SOURCES += tst_compiler.cpp baseclass.cpp derivedclass.cpp othersource.cpp
HEADERS += baseclass.h derivedclass.h
QT = core testlib
contains(QT_CONFIG, c++11): CONFIG += c++14 c++11
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0

View File

@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2014 Intel Corporation.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights. These rights are described in the Digia 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.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qglobal.h>
#ifdef Q_COMPILER_EXTERN_TEMPLATES
template <typename T> T externTemplate();
template<> int externTemplate<int>()
{
return 42;
}
#endif

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Intel Corporation
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@ -48,12 +49,17 @@
#include "baseclass.h"
#include "derivedclass.h"
#ifdef Q_COMPILER_ATOMICS
# include <atomic>
#endif
QT_USE_NAMESPACE
class tst_Compiler : public QObject
{
Q_OBJECT
private slots:
/* C++98 & C++03 base functionality */
void template_methods();
void template_constructors();
void template_subclasses();
@ -71,6 +77,57 @@ private slots:
void charSignedness() const;
void privateStaticTemplateMember() const;
void staticConstUnionWithInitializerList() const;
void templateFriends();
/* C++11 features */
void cxx11_alignas();
void cxx11_alignof();
void cxx11_alignas_alignof();
void cxx11_atomics();
void cxx11_attributes();
void cxx11_auto_function();
void cxx11_auto_type();
void cxx11_class_enum();
void cxx11_constexpr();
void cxx11_decltype();
void cxx11_default_members();
void cxx11_delete_members();
void cxx11_delegating_constructors();
void cxx11_explicit_conversions();
void cxx11_explicit_overrides();
void cxx11_extern_templates();
void cxx11_inheriting_constructors();
void cxx11_initializer_lists();
void cxx11_lambda();
void cxx11_nonstatic_member_init();
void cxx11_noexcept();
void cxx11_nullptr();
void cxx11_range_for();
void cxx11_raw_strings();
void cxx11_ref_qualifiers();
void cxx11_rvalue_refs();
void cxx11_static_assert();
void cxx11_template_alias();
void cxx11_thread_local();
void cxx11_udl();
void cxx11_unicode_strings();
void cxx11_uniform_init();
void cxx11_unrestricted_unions();
void cxx11_variadic_macros();
void cxx11_variadic_templates();
/* C++14 compiler features */
void cxx14_binary_literals();
void cxx14_init_captures();
void cxx14_generic_lambdas();
void cxx14_constexpr();
void cxx14_decltype_auto();
void cxx14_return_type_deduction();
void cxx14_aggregate_nsdmi();
void cxx14_variable_templates();
/* Future / Technical specification compiler features */
void runtimeArrays();
};
#if defined(Q_CC_HPACC)
@ -556,5 +613,706 @@ void tst_Compiler::staticConstUnionWithInitializerList() const
QVERIFY(qIsInf(d));
}
#ifndef Q_NO_TEMPLATE_FRIENDS
template <typename T> class TemplateFriends
{
T value;
public:
TemplateFriends(T value) : value(value) {}
template <typename X> void copy(TemplateFriends<X> other)
{ value = other.value; }
template <typename X> friend class TemplateFriends;
};
void tst_Compiler::templateFriends()
{
TemplateFriends<int> ti(42);
TemplateFriends<long> tl(0);
tl.copy(ti);
}
#else
void tst_Compiler::templateFriends()
{
QSKIP("Compiler does not support template friends");
}
#endif
void tst_Compiler::cxx11_alignas()
{
#ifndef Q_COMPILER_ALIGNAS
QSKIP("Compiler does not support C++11 feature");
#else
alignas(double) char c;
QVERIFY(Q_ALIGNOF(c) == Q_ALIGNOF(double));
#endif
}
void tst_Compiler::cxx11_alignof()
{
#ifndef Q_COMPILER_ALIGNOF
QSKIP("Compiler does not support C++11 feature");
#else
size_t alignchar = alignof(char);
size_t aligndouble = alignof(double);
QVERIFY(alignchar >= 1);
QVERIFY(alignchar <= aligndouble);
#endif
}
void tst_Compiler::cxx11_alignas_alignof()
{
#if !defined(Q_COMPILER_ALIGNAS) && !defined(Q_COMPILER_ALIGNOF)
QSKIP("Compiler does not support C++11 feature");
#else
alignas(alignof(double)) char c;
Q_UNUSED(c);
#endif
}
void tst_Compiler::cxx11_atomics()
{
#ifndef Q_COMPILER_ATOMICS
QSKIP("Compiler does not support C++11 feature");
#else
std::atomic<int> i;
i.store(42, std::memory_order_seq_cst);
QCOMPARE(i.load(std::memory_order_acquire), 42);
std::atomic<short> s;
s.store(42);
QCOMPARE(s.load(), short(42));
std::atomic_flag flag;
flag.clear();
QVERIFY(!flag.test_and_set());
QVERIFY(flag.test_and_set());
#endif
}
void tst_Compiler::cxx11_attributes()
{
#ifndef Q_COMPILER_ATTRIBUTES
QSKIP("Compiler does not support C++11 feature");
#else
struct [[deprecated]] C {};
[[gnu::unused]] struct D {} d;
[[noreturn]] void f();
struct D e [[gnu::used, gnu::unused]];
[[gnu::aligned(8)]] int i;
[[gnu::unused]] end:
;
Q_UNUSED(d);
Q_UNUSED(e);
Q_UNUSED(i);
#endif
}
#ifdef Q_COMPILER_AUTO_FUNCTION
auto autoFunction() -> unsigned
{
return 1;
}
#endif
void tst_Compiler::cxx11_auto_function()
{
#ifndef Q_COMPILER_AUTO_FUNCTION
QSKIP("Compiler does not support C++11 feature");
#else
QCOMPARE(autoFunction(), 1u);
#endif
}
void tst_Compiler::cxx11_auto_type()
{
#ifndef Q_COMPILER_AUTO_TYPE
QSKIP("Compiler does not support C++11 feature");
#else
auto i = 1;
auto x = qrand();
auto l = 1L;
auto s = QStringLiteral("Hello World");
QCOMPARE(i, 1);
Q_UNUSED(x);
QCOMPARE(l, 1L);
QCOMPARE(s.toLower(), QString("hello world"));
#endif
}
void tst_Compiler::cxx11_class_enum()
{
#ifndef Q_COMPILER_CLASS_ENUM
QSKIP("Compiler does not support C++11 feature");
#else
enum class X { EnumValue };
X x = X::EnumValue;
QCOMPARE(x, X::EnumValue);
enum class Y : short { Val = 2 };
enum Z : long { ValLong = LONG_MAX };
#endif
}
#ifdef Q_COMPILER_CONSTEXPR
constexpr int constexprValue()
{
return 42;
}
#endif
void tst_Compiler::cxx11_constexpr()
{
#ifndef Q_COMPILER_CONSTEXPR
QSKIP("Compiler does not support C++11 feature");
#else
static constexpr QBasicAtomicInt atomic = Q_BASIC_ATOMIC_INITIALIZER(1);
static constexpr int i = constexprValue();
QCOMPARE(i, constexprValue());
QCOMPARE(atomic.load(), 1);
#endif
}
void tst_Compiler::cxx11_decltype()
{
#ifndef Q_COMPILER_DECLTYPE
QSKIP("Compiler does not support C++11 feature");
#else
decltype(qrand()) i = 0;
QCOMPARE(i, 0);
#endif
}
void tst_Compiler::cxx11_default_members()
{
#ifndef Q_COMPILER_DEFAULT_MEMBERS
QSKIP("Compiler does not support C++11 feature");
#else
struct DefaultMembers
{
DefaultMembers() = default;
DefaultMembers(int) {}
};
DefaultMembers dm;
Q_UNUSED(dm);
#endif
}
void tst_Compiler::cxx11_delete_members()
{
#ifndef Q_COMPILER_DELETE_MEMBERS
QSKIP("Compiler does not support C++11 feature");
#else
struct DeleteMembers
{
DeleteMembers() = delete;
DeleteMembers(const DeleteMembers &) = delete;
~DeleteMembers() = delete;
};
#endif
}
void tst_Compiler::cxx11_delegating_constructors()
{
#ifndef Q_COMPILER_DELEGATING_CONSTRUCTORS
QSKIP("Compiler does not support C++11 feature");
#else
struct DC {
DC(int i) : i(i) {}
DC() : DC(0) {}
int i;
};
DC dc;
QCOMPARE(dc.i, 0);
#endif
}
void tst_Compiler::cxx11_explicit_conversions()
{
#ifndef Q_COMPILER_EXPLICIT_CONVERSIONS
QSKIP("Compiler does not support C++11 feature");
#else
struct EC {
explicit operator int() const { return 0; }
operator long long() const { return 1; }
};
EC ec;
int i(ec);
QCOMPARE(i, 0);
int i2 = ec;
QCOMPARE(i2, 1);
#endif
}
void tst_Compiler::cxx11_explicit_overrides()
{
#ifndef Q_COMPILER_EXPLICIT_OVERRIDES
QSKIP("Compiler does not support C++11 feature");
#else
struct Base {
virtual ~Base() {}
virtual void f() {}
};
struct Derived final : public Base {
virtual void f() final override {}
};
#endif
}
#ifdef Q_COMPILER_EXTERN_TEMPLATES
template <typename T> T externTemplate() { return T(0); }
extern template int externTemplate<int>();
#endif
void tst_Compiler::cxx11_extern_templates()
{
#ifndef Q_COMPILER_EXTERN_TEMPLATES
QSKIP("Compiler does not support C++11 feature");
#else
QCOMPARE(externTemplate<int>(), 42);
#endif
}
void tst_Compiler::cxx11_inheriting_constructors()
{
#ifndef Q_COMPILER_INHERITING_CONSTRUCTORS
QSKIP("Compiler does not support C++11 feature");
#else
struct Base {
int i;
Base() : i(0) {}
Base(int i) : i(i) {}
};
struct Derived : public Base {
using Base::Base;
};
Derived d(1);
QCOMPARE(d.i, 1);
#endif
}
void tst_Compiler::cxx11_initializer_lists()
{
#ifndef Q_COMPILER_INITIALIZER_LISTS
QSKIP("Compiler does not support C++11 feature");
#else
QList<int> l = { 1, 2, 3, 4, 5 };
QCOMPARE(l.length(), 5);
QCOMPARE(l.at(0), 1);
QCOMPARE(l.at(4), 5);
#endif
}
struct CallFunctor
{
template <typename Functor> static int f(Functor f)
{ return f();}
};
void tst_Compiler::cxx11_lambda()
{
#ifndef Q_COMPILER_LAMBDA
QSKIP("Compiler does not support C++11 feature");
#else
QCOMPARE(CallFunctor::f([]() { return 42; }), 42);
#endif
}
void tst_Compiler::cxx11_nonstatic_member_init()
{
#ifndef Q_COMPILER_NONSTATIC_MEMBER_INIT
QSKIP("Compiler does not support C++11 feature");
#else
struct S {
int i = 42;
long l = 47;
char c;
S() : l(-47), c(0) {}
};
S s;
QCOMPARE(s.i, 42);
QCOMPARE(s.l, -47L);
QCOMPARE(s.c, '\0');
#endif
}
void tst_Compiler::cxx11_noexcept()
{
#ifndef Q_COMPILER_NOEXCEPT
QSKIP("Compiler does not support C++11 feature");
#else
extern void noexcept_f() noexcept;
extern void g() noexcept(noexcept(noexcept_f()));
QCOMPARE(noexcept(cxx11_noexcept()), false);
QCOMPARE(noexcept(noexcept_f), true);
QCOMPARE(noexcept(g), true);
#endif
}
void tst_Compiler::cxx11_nullptr()
{
#ifndef Q_COMPILER_NULLPTR
QSKIP("Compiler does not support C++11 feature");
#else
void *v = nullptr;
char *c = nullptr;
const char *cc = nullptr;
volatile char *vc = nullptr;
std::nullptr_t np = nullptr;
v = np;
Q_UNUSED(v);
Q_UNUSED(c);
Q_UNUSED(cc);
Q_UNUSED(vc);
#endif
}
void tst_Compiler::cxx11_range_for()
{
#ifndef Q_COMPILER_RANGE_FOR
QSKIP("Compiler does not support C++11 feature");
#else
QList<int> l;
l << 1 << 2 << 3;
for (int i : l)
Q_UNUSED(i);
l.clear();
l << 1;
for (int i : l)
QCOMPARE(i, 1);
QList<long> ll;
l << 2;
for (int i : ll)
QCOMPARE(i, 2);
#endif
}
void tst_Compiler::cxx11_raw_strings()
{
#ifndef Q_COMPILER_RAW_STRINGS
QSKIP("Compiler does not support C++11 feature");
#else
static const char xml[] = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
static const char raw[] = R"***(*"*)***";
QCOMPARE(strlen(raw), size_t(3));
QCOMPARE(raw[1], '"');
Q_UNUSED(xml);
#endif
}
void tst_Compiler::cxx11_ref_qualifiers()
{
#ifndef Q_COMPILER_REF_QUALIFIERS
QSKIP("Compiler does not support C++11 feature");
#else
# ifndef Q_COMPILER_RVALUE_REFS
# error "Impossible condition: ref qualifiers are supported but not rvalue refs"
# endif
// also applies to function pointers
QByteArray (QString:: *lvalueref)() const & = &QString::toLatin1;
QByteArray (QString:: *rvalueref)() && = &QString::toLatin1;
QString s("Hello");
QCOMPARE((s.*lvalueref)(), QByteArray("Hello"));
QCOMPARE((std::move(s).*rvalueref)(), QByteArray("Hello"));
// tests internal behavior:
QVERIFY(s.isEmpty());
#endif
}
void tst_Compiler::cxx11_rvalue_refs()
{
#ifndef Q_COMPILER_RVALUE_REFS
QSKIP("Compiler does not support C++11 feature");
#else
int i = 1;
i = std::move(i);
QString s = "Hello";
QString t = std::move(s);
QCOMPARE(t, QString("Hello"));
s = t;
t = std::move(s);
QCOMPARE(t, QString("Hello"));
QString &&r = std::move(s);
QCOMPARE(r, QString("Hello"));
#endif
}
void tst_Compiler::cxx11_static_assert()
{
#ifndef Q_COMPILER_STATIC_ASSERT
QSKIP("Compiler does not support C++11 feature");
#else
static_assert(true, "Message");
#endif
}
#ifdef Q_COMPILER_TEMPLATE_ALIAS
template <typename T> using Map = QMap<QString, T>;
#endif
void tst_Compiler::cxx11_template_alias()
{
#ifndef Q_COMPILER_TEMPLATE_ALIAS
QSKIP("Compiler does not support C++11 feature");
#else
Map<QVariant> m;
m.insert("Hello", "World");
QCOMPARE(m.value("Hello").toString(), QString("World"));
using X = int;
X i = 0;
Q_UNUSED(i);
#endif
}
#ifdef Q_COMPILER_THREAD_LOCAL
static thread_local int stl = 42;
thread_local int gtl = 42;
#endif
void tst_Compiler::cxx11_thread_local()
{
#ifndef Q_COMPILER_THREAD_LOCAL
QSKIP("Compiler does not support C++11 feature");
#else
thread_local int v = 1;
QVERIFY(v);
QVERIFY(stl);
QVERIFY(gtl);
thread_local QString s = "Hello";
QVERIFY(!s.isEmpty());
#endif
}
#ifdef Q_COMPILER_UDL
QString operator"" _tstqstring(const char *str, size_t len)
{
return QString::fromUtf8(str, len) + " UDL";
}
#endif
void tst_Compiler::cxx11_udl()
{
#ifndef Q_COMPILER_UDL
QSKIP("Compiler does not support C++11 feature");
#else
QString s = "Hello World"_tstqstring;
QCOMPARE(s, QString("Hello World UDL"));
#endif
}
void tst_Compiler::cxx11_unicode_strings()
{
#ifndef Q_COMPILER_UNICODE_STRINGS
QSKIP("Compiler does not support C++11 feature");
#else
static const char16_t u[] = u"\u200BHello\u00A0World";
QCOMPARE(u[0], char16_t(0x200B));
static const char32_t U[] = U"\ufffe";
QCOMPARE(U[0], char32_t(0xfffe));
QCOMPARE(u"\U00010000"[0], char16_t(0xD800));
QCOMPARE(u"\U00010000"[1], char16_t(0xDC00));
#endif
}
static void noop(QPair<int, int>) {}
void tst_Compiler::cxx11_uniform_init()
{
#ifndef Q_COMPILER_UNIFORM_INIT
QSKIP("Compiler does not support C++11 feature");
noop(QPair<int,int>());
#else
QString s{"Hello"};
int i{};
noop(QPair<int,int>{1,1});
noop({i,1});
#endif
}
void tst_Compiler::cxx11_unrestricted_unions()
{
#ifndef Q_COMPILER_UNRESTRICTED_UNIONS
QSKIP("Compiler does not support C++11 feature");
#else
union U {
QString s;
U() {}
U(const QString &s) : s(s) {}
~U() {}
};
U u;
std::aligned_storage<sizeof(QString), Q_ALIGNOF(QString)> as;
Q_UNUSED(u);
Q_UNUSED(as);
U u2("hello");
u2.s.~QString();
#endif
}
void tst_Compiler::cxx11_variadic_macros()
{
#ifndef Q_COMPILER_VARIADIC_MACROS
QSKIP("Compiler does not support C++11 feature");
#else
# define TEST_VARARG(x, ...) __VA_ARGS__
QCOMPARE(TEST_VARARG(0, 1), 1);
#endif
}
#ifdef Q_COMPILER_VARIADIC_TEMPLATES
template <typename... Args> struct VariadicTemplate {};
#endif
void tst_Compiler::cxx11_variadic_templates()
{
#ifndef Q_COMPILER_VARIADIC_TEMPLATES
QSKIP("Compiler does not support C++11 feature");
#else
VariadicTemplate<> v0;
VariadicTemplate<int> v1;
VariadicTemplate<int, int, int, int,
int, int, int, int> v8;
Q_UNUSED(v0);
Q_UNUSED(v1);
Q_UNUSED(v8);
#endif
}
void tst_Compiler::cxx14_binary_literals()
{
#if __cpp_binary_literals-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
int i = 0b11001001;
QCOMPARE(i, 0xC9);
#endif
}
void tst_Compiler::cxx14_init_captures()
{
#if __cpp_init_captures-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
QCOMPARE([x = 42]() { return x; }(), 42);
#endif
}
void tst_Compiler::cxx14_generic_lambdas()
{
#if __cpp_generic_lambdas-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
auto identity = [](auto x) { return x; };
QCOMPARE(identity(42), 42);
QCOMPARE(identity(42U), 42U);
QCOMPARE(identity(42L), 42L);
#endif
}
#if __cpp_constexpr-0 >= 201304
constexpr int relaxedConstexpr(int i)
{
i *= 2;
i += 2;
return i;
}
#endif
void tst_Compiler::cxx14_constexpr()
{
#if __cpp_constexpr-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
QCOMPARE(relaxedConstexpr(0), 2);
QCOMPARE(relaxedConstexpr(2), 6);
#endif
}
void tst_Compiler::cxx14_decltype_auto()
{
#if __cpp_decltype_auto-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
QList<int> l;
l << 1;
decltype(auto) value = l[0];
value = 2;
QCOMPARE(l.at(0), 2);
#endif
}
#if __cpp_return_type_deduction >= 201304
auto returnTypeDeduction()
{
return 1U;
}
#endif
void tst_Compiler::cxx14_return_type_deduction()
{
#if __cpp_return_type_deduction-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
QCOMPARE(returnTypeDeduction(), 1U);
#endif
}
void tst_Compiler::cxx14_aggregate_nsdmi()
{
#if __cpp_aggregate_nsdmi-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
struct S { int i, j = i; };
S s = { 1 };
QCOMPARE(s.j, 1);
#endif
}
#if __cpp_variable_templates >= 201304
template <typename T> constexpr T variableTemplate = T(42);
#endif
void tst_Compiler::cxx14_variable_templates()
{
#if __cpp_variable_templates-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
QCOMPARE(variableTemplate<int>, 42);
QCOMPARE(variableTemplate<long>, 42L);
QCOMPARE(variableTemplate<unsigned>, 42U);
QCOMPARE(variableTemplate<unsigned long long>, 42ULL);
#endif
}
void tst_Compiler::runtimeArrays()
{
#if __cpp_runtime_arrays-0 < 201304
QSKIP("Compiler does not support this C++14 feature");
#else
int i[qrand() & 0x1f];
Q_UNUSED(i);
#endif
}
QTEST_MAIN(tst_Compiler)
#include "tst_compiler.moc"