1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2017 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtCore/QtCore>
31#include <QtTest/QtTest>
32
33#include <algorithm>
34
35#define BASECLASS_NOT_ABSTRACT
36#include "baseclass.h"
37#include "derivedclass.h"
38
39#ifdef Q_COMPILER_ATOMICS
40# include <atomic>
41#endif
42
43QT_USE_NAMESPACE
44
45class tst_Compiler : public QObject
46{
47Q_OBJECT
48private slots:
49 /* C++98 & C++03 base functionality */
50 void template_methods();
51 void template_constructors();
52 void template_subclasses();
53 void methodSpecialization();
54 void constructorSpecialization();
55 void staticTemplateMethods();
56 void staticTemplateMethodSpecialization();
57 void detectDataStream();
58 void detectEnums();
59 void overrideCFunction();
60 void stdSortQList();
61 void stdSortQVector();
62 void templateCallOrder();
63 void virtualFunctionNoLongerPureVirtual();
64 void charSignedness() const;
65 void privateStaticTemplateMember() const;
66 void staticConstUnionWithInitializerList() const;
67 void templateFriends();
68
69 /* C++11 features */
70 void cxx11_alignas();
71 void cxx11_alignof();
72 void cxx11_alignas_alignof();
73 void cxx11_atomics();
74 void cxx11_attributes();
75 void cxx11_auto_function();
76 void cxx11_auto_type();
77 void cxx11_class_enum();
78 void cxx11_constexpr();
79 void cxx11_decltype();
80 void cxx11_default_members();
81 void cxx11_delete_members();
82 void cxx11_delegating_constructors();
83 void cxx11_explicit_conversions();
84 void cxx11_explicit_overrides();
85 void cxx11_extern_templates();
86 void cxx11_inheriting_constructors();
87 void cxx11_initializer_lists();
88 void cxx11_lambda();
89 void cxx11_nonstatic_member_init();
90 void cxx11_noexcept();
91 void cxx11_nullptr();
92 void cxx11_range_for();
93 void cxx11_raw_strings();
94 void cxx11_ref_qualifiers();
95 void cxx11_rvalue_refs();
96 void cxx11_static_assert();
97 void cxx11_template_alias();
98 void cxx11_thread_local();
99 void cxx11_udl();
100 void cxx11_unicode_strings();
101 void cxx11_uniform_init();
102 void cxx11_unrestricted_unions();
103 void cxx11_variadic_macros();
104 void cxx11_variadic_templates();
105
106 /* C++14 compiler features */
107 void cxx14_binary_literals();
108 void cxx14_init_captures();
109 void cxx14_generic_lambdas();
110 void cxx14_constexpr();
111 void cxx14_decltype_auto();
112 void cxx14_return_type_deduction();
113 void cxx14_aggregate_nsdmi();
114 void cxx14_variable_templates();
115
116 /* Future / Technical specification compiler features */
117 void runtimeArrays();
118};
119
120#if defined(Q_CC_HPACC)
121# define DONT_TEST_TEMPLATE_CONSTRUCTORS
122# define DONT_TEST_CONSTRUCTOR_SPECIALIZATION
123# define DONT_TEST_DATASTREAM_DETECTION
124#endif
125
126#if defined(Q_CC_SUN)
127# define DONT_TEST_STL_SORTING
128#endif
129
130class TemplateMethodClass
131{
132public:
133 template <class T>
134 T foo() { return 42; }
135};
136
137void tst_Compiler::template_methods()
138{
139 TemplateMethodClass t;
140
141 QCOMPARE(t.foo<int>(), 42);
142 QCOMPARE(t.foo<long>(), 42l);
143 QCOMPARE(t.foo<double>(), 42.0);
144}
145
146#ifndef DONT_TEST_TEMPLATE_CONSTRUCTORS
147class TemplateConstructorClass
148{
149public:
150 template <class T>
151 TemplateConstructorClass(const T& t) { i = int(t); }
152
153 int i;
154};
155
156void tst_Compiler::template_constructors()
157{
158 TemplateConstructorClass t1(42);
159 TemplateConstructorClass t2(42l);
160 TemplateConstructorClass t3(42.0);
161
162 QCOMPARE(t1.i, 42);
163 QCOMPARE(t2.i, 42);
164 QCOMPARE(t3.i, 42);
165}
166#else
167void tst_Compiler::template_constructors()
168{ QSKIP("Compiler doesn't do template constructors"); }
169#endif
170
171template <typename T>
172struct OuterClass
173{
174 template <typename U>
175 struct InnerClass
176 {
177 U convert(const T &t) { return static_cast<U>(t); }
178 };
179};
180
181void tst_Compiler::template_subclasses()
182{
183 OuterClass<char>::InnerClass<int> c1;
184 QCOMPARE(c1.convert('a'), int('a'));
185
186 OuterClass<QRect>::InnerClass<QRectF> c2;
187 QCOMPARE(c2.convert(QRect(1, 2, 3, 4)), QRectF(QRect(1, 2, 3, 4)));
188}
189
190class TemplateMethodClass2
191{
192public:
193 template <class T>
194 T foo() { return 42; }
195};
196
197template<>
198int TemplateMethodClass2::foo<int>()
199{ return 43; }
200
201void tst_Compiler::methodSpecialization()
202{
203 TemplateMethodClass2 t;
204
205 QCOMPARE(t.foo<int>(), 43);
206 QCOMPARE(t.foo<long>(), 42l);
207 QCOMPARE(t.foo<double>(), 42.0);
208}
209
210#ifndef DONT_TEST_CONSTRUCTOR_SPECIALIZATION
211class TemplateConstructorClass2
212{
213public:
214 template <class T>
215 TemplateConstructorClass2(const T &t) { i = int(t); }
216
217 int i;
218};
219
220template<>
221TemplateConstructorClass2::TemplateConstructorClass2(const int &t) { i = t + 1; }
222
223void tst_Compiler::constructorSpecialization()
224{
225 TemplateConstructorClass2 t1(42);
226 TemplateConstructorClass2 t2(42l);
227 TemplateConstructorClass2 t3(42.0);
228
229 QCOMPARE(t1.i, 43);
230 QCOMPARE(t2.i, 42);
231 QCOMPARE(t3.i, 42);
232}
233#else
234void tst_Compiler::constructorSpecialization()
235{ QSKIP("Compiler doesn't do constructor specialization"); }
236#endif
237
238class StaticTemplateClass
239{
240public:
241 template <class T>
242 static T foo() { return 42; }
243};
244
245void tst_Compiler::staticTemplateMethods()
246{
247 QCOMPARE(StaticTemplateClass::foo<int>(), 42);
248 QCOMPARE(StaticTemplateClass::foo<uint>(), 42u);
249}
250
251class StaticTemplateClass2
252{
253public:
254 template <class T>
255 static T foo() { return 42; }
256};
257
258template<>
259double StaticTemplateClass2::foo<double>() { return 18.5; }
260
261void tst_Compiler::staticTemplateMethodSpecialization()
262{
263 QCOMPARE(StaticTemplateClass2::foo<int>(), 42);
264 QCOMPARE(StaticTemplateClass2::foo<uint>(), 42u);
265 QCOMPARE(StaticTemplateClass2::foo<double>(), 18.5);
266}
267
268#ifndef DONT_TEST_DATASTREAM_DETECTION
269/******* DataStream tester *********/
270namespace QtTestInternal
271{
272 struct EmptyStruct {};
273 struct LowPreferenceStruct { LowPreferenceStruct(...); };
274
275 EmptyStruct operator<<(QDataStream &, const LowPreferenceStruct &);
276 EmptyStruct operator>>(QDataStream &, const LowPreferenceStruct &);
277
278 template<typename T>
279 struct DataStreamChecker
280 {
281 static EmptyStruct hasStreamHelper(const EmptyStruct &);
282 static QDataStream hasStreamHelper(const QDataStream &);
283 static QDataStream &dsDummy();
284 static T &dummy();
285
286#ifdef BROKEN_COMPILER
287 static const bool HasDataStream =
288 sizeof(hasStreamHelper(dsDummy() << dummy())) == sizeof(QDataStream)
289 && sizeof(hasStreamHelper(dsDummy() >> dummy())) == sizeof(QDataStream);
290#else
291 enum {
292 HasOutDataStream = sizeof(hasStreamHelper(dsDummy() >> dummy())) == sizeof(QDataStream),
293 HasInDataStream = sizeof(hasStreamHelper(dsDummy() << dummy())) == sizeof(QDataStream),
294 HasDataStream = HasOutDataStream & HasInDataStream
295 };
296#endif
297 };
298
299 template<bool>
300 struct DataStreamOpHelper
301 {
302 template <typename T>
303 struct Getter {
304 static QMetaType::SaveOperator saveOp() { return 0; }
305 };
306 };
307
308 template<>
309 struct DataStreamOpHelper<true>
310 {
311 template <typename T>
312 struct Getter {
313 static QMetaType::SaveOperator saveOp()
314 {
315 return ::QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Save;
316 }
317 };
318
319 };
320
321 template<typename T>
322 inline QMetaType::SaveOperator getSaveOperator(T * = 0)
323 {
324 typedef typename DataStreamOpHelper<DataStreamChecker<T>::HasDataStream>::template Getter<T> GetterHelper;
325 return GetterHelper::saveOp();
326 }
327};
328
329struct MyString: public QString {};
330struct Qxxx {};
331
332void tst_Compiler::detectDataStream()
333{
334 QVERIFY(QtTestInternal::DataStreamChecker<int>::HasDataStream);
335 QVERIFY(QtTestInternal::DataStreamChecker<uint>::HasDataStream);
336 QVERIFY(QtTestInternal::DataStreamChecker<char *>::HasDataStream == true);
337 QVERIFY(QtTestInternal::DataStreamChecker<const int>::HasInDataStream == true);
338 QVERIFY(QtTestInternal::DataStreamChecker<const int>::HasOutDataStream == false);
339 QVERIFY(QtTestInternal::DataStreamChecker<const int>::HasDataStream == false);
340 QVERIFY(QtTestInternal::DataStreamChecker<double>::HasDataStream);
341
342 QVERIFY(QtTestInternal::DataStreamChecker<QString>::HasDataStream);
343 QVERIFY(QtTestInternal::DataStreamChecker<MyString>::HasDataStream);
344 QVERIFY(!QtTestInternal::DataStreamChecker<Qxxx>::HasDataStream);
345
346 QVERIFY(QtTestInternal::getSaveOperator<int>() != 0);
347 QVERIFY(QtTestInternal::getSaveOperator<uint>() != 0);
348 QVERIFY(QtTestInternal::getSaveOperator<char *>() != 0);
349 QVERIFY(QtTestInternal::getSaveOperator<double>() != 0);
350 QVERIFY(QtTestInternal::getSaveOperator<QString>() != 0);
351 QVERIFY(QtTestInternal::getSaveOperator<MyString>() != 0);
352 QVERIFY(!QtTestInternal::getSaveOperator<Qxxx>());
353}
354#else
355void tst_Compiler::detectDataStream()
356{ QSKIP("Compiler doesn't evaluate templates correctly"); }
357#endif
358
359enum Enum1 { Foo = 0, Bar = 1 };
360enum Enum2 {};
361enum Enum3 { Something = 1 };
362
363template <typename T> char QTypeInfoEnumHelper(T);
364template <typename T> void *QTypeInfoEnumHelper(...);
365
366template <typename T>
367struct QTestTypeInfo
368{
369 enum { IsEnum = sizeof(QTypeInfoEnumHelper<T>(0)) == sizeof(void*) };
370};
371
372void tst_Compiler::detectEnums()
373{
374 QVERIFY(QTestTypeInfo<Enum1>::IsEnum);
375 QVERIFY(QTestTypeInfo<Enum2>::IsEnum);
376 QVERIFY(QTestTypeInfo<Enum3>::IsEnum);
377 QVERIFY(!QTestTypeInfo<int>::IsEnum);
378 QVERIFY(!QTestTypeInfo<char>::IsEnum);
379 QVERIFY(!QTestTypeInfo<uint>::IsEnum);
380 QVERIFY(!QTestTypeInfo<short>::IsEnum);
381 QVERIFY(!QTestTypeInfo<ushort>::IsEnum);
382 QVERIFY(!QTestTypeInfo<void*>::IsEnum);
383 QVERIFY(!QTestTypeInfo<QString>::IsEnum);
384 QVERIFY(QTestTypeInfo<Qt::Key>::IsEnum);
385 QVERIFY(QTestTypeInfo<Qt::ToolBarArea>::IsEnum);
386 QVERIFY(!QTestTypeInfo<Qt::ToolBarAreas>::IsEnum);
387 QVERIFY(QTestTypeInfo<Qt::MatchFlag>::IsEnum);
388 QVERIFY(!QTestTypeInfo<Qt::MatchFlags>::IsEnum);
389}
390static int indicator = 0;
391
392// this is a silly C function
393extern "C" {
394 void someCFunc(void *) { indicator = 42; }
395}
396
397// this is the catch-template that will be called if the C function doesn't exist
398template <typename T>
399void someCFunc(T *) { indicator = 10; }
400
401void tst_Compiler::overrideCFunction()
402{
403 someCFunc((void*)0);
404 QCOMPARE(indicator, 42);
405}
406
407#ifndef DONT_TEST_STL_SORTING
408void tst_Compiler::stdSortQList()
409{
410 QList<int> list;
411 list << 4 << 2;
412 std::sort(first: list.begin(), last: list.end());
413 QCOMPARE(list.value(0), 2);
414 QCOMPARE(list.value(1), 4);
415
416 QList<QString> slist;
417 slist << "b" << "a";
418 std::sort(first: slist.begin(), last: slist.end());
419 QCOMPARE(slist.value(0), QString("a"));
420 QCOMPARE(slist.value(1), QString("b"));
421}
422
423void tst_Compiler::stdSortQVector()
424{
425 QVector<int> vector;
426 vector << 4 << 2;
427 std::sort(first: vector.begin(), last: vector.end());
428 QCOMPARE(vector.value(0), 2);
429 QCOMPARE(vector.value(1), 4);
430
431 QVector<QString> strvec;
432 strvec << "b" << "a";
433 std::sort(first: strvec.begin(), last: strvec.end());
434 QCOMPARE(strvec.value(0), QString("a"));
435 QCOMPARE(strvec.value(1), QString("b"));
436}
437#else
438void tst_Compiler::stdSortQList()
439{ QSKIP("Compiler's STL broken"); }
440void tst_Compiler::stdSortQVector()
441{ QSKIP("Compiler's STL broken"); }
442#endif
443
444// the C func will set it to 1, the template to 2
445static int whatWasCalled = 0;
446
447void callOrderFunc(void *)
448{
449 whatWasCalled = 1;
450}
451
452template <typename T>
453void callOrderFunc(T *)
454{
455 whatWasCalled = 2;
456}
457
458template <typename T>
459void callOrderNoCFunc(T *)
460{
461 whatWasCalled = 3;
462}
463
464/*
465 This test will check what will get precendence - the C function
466 or the template.
467
468 It also makes sure this template "override" will compile on all systems
469 and not result in ambiguities.
470*/
471void tst_Compiler::templateCallOrder()
472{
473 QCOMPARE(whatWasCalled, 0);
474
475 // call it with a void *
476 void *f = 0;
477 callOrderFunc(f);
478 QCOMPARE(whatWasCalled, 1);
479 whatWasCalled = 0;
480
481 char *c = 0;
482 /* call it with a char * - AMBIGOUS, fails on several compilers
483 callOrderFunc(c);
484 QCOMPARE(whatWasCalled, 1);
485 whatWasCalled = 0;
486 */
487
488 // now try the case when there is no C function
489 callOrderNoCFunc(f);
490 QCOMPARE(whatWasCalled, 3);
491 whatWasCalled = 0;
492
493 callOrderNoCFunc(c);
494 QCOMPARE(whatWasCalled, 3);
495 whatWasCalled = 0;
496}
497
498// test to see if removing =0 from a pure virtual function is BC
499void tst_Compiler::virtualFunctionNoLongerPureVirtual()
500{
501#ifdef BASECLASS_NOT_ABSTRACT
502 // has a single virtual function, not pure virtual, can call it
503 BaseClass baseClass;
504 QTest::ignoreMessage(type: QtDebugMsg, message: "BaseClass::wasAPureVirtualFunction()");
505 baseClass.wasAPureVirtualFunction();
506#endif
507
508 // DerivedClass inherits from BaseClass, and function is declared
509 // pure virtual, make sure we can still call it
510 DerivedClass derivedClass;
511 QTest::ignoreMessage(type: QtDebugMsg, message: "DerivedClass::wasAPureVirtualFunction()");
512 derivedClass.wasAPureVirtualFunction();
513}
514
515template<typename T> const char *resolveCharSignedness();
516
517template<>
518const char *resolveCharSignedness<char>()
519{
520 return "char";
521}
522
523template<>
524const char *resolveCharSignedness<unsigned char>()
525{
526 return "unsigned char";
527}
528
529template<>
530const char *resolveCharSignedness<signed char>()
531{
532 return "signed char";
533}
534
535void tst_Compiler::charSignedness() const
536{
537 QCOMPARE("char", resolveCharSignedness<char>());
538 QCOMPARE("unsigned char", resolveCharSignedness<unsigned char>());
539 QCOMPARE("signed char", resolveCharSignedness<signed char>());
540}
541
542class PrivateStaticTemplateMember
543{
544public:
545 long regularMember()
546 {
547 return helper<long, int>(b: 3);
548 }
549
550private:
551 template<typename A, typename B>
552 static A helper(const B b)
553 {
554 return A(b);
555 }
556};
557
558void tst_Compiler::privateStaticTemplateMember() const
559{
560 PrivateStaticTemplateMember v;
561
562 QCOMPARE(long(3), v.regularMember());
563}
564
565
566#if !defined(Q_CC_MIPS)
567
568// make sure we can use a static initializer with a union and then use
569// the second member of the union
570static const union { unsigned char c[8]; double d; } qt_be_inf_bytes = { .c: { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
571static const union { unsigned char c[8]; double d; } qt_le_inf_bytes = { .c: { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
572static inline double qt_inf()
573{
574 return (QSysInfo::ByteOrder == QSysInfo::BigEndian
575 ? qt_be_inf_bytes.d
576 : qt_le_inf_bytes.d);
577}
578
579#else
580
581static const unsigned char qt_be_inf_bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
582static const unsigned char qt_le_inf_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
583static inline double qt_inf()
584{
585 const uchar *bytes;
586 bytes = (QSysInfo::ByteOrder == QSysInfo::BigEndian
587 ? qt_be_inf_bytes
588 : qt_le_inf_bytes);
589
590 union { uchar c[8]; double d; } returnValue;
591 memcpy(returnValue.c, bytes, sizeof(returnValue.c));
592 return returnValue.d;
593}
594
595#endif
596
597void tst_Compiler::staticConstUnionWithInitializerList() const
598{
599 double d = qt_inf();
600 QVERIFY(qIsInf(d));
601}
602
603#ifndef Q_NO_TEMPLATE_FRIENDS
604template <typename T> class TemplateFriends
605{
606 T value;
607public:
608 TemplateFriends(T value) : value(value) {}
609
610 template <typename X> void copy(TemplateFriends<X> other)
611 { value = other.value; }
612
613 template <typename X> friend class TemplateFriends;
614};
615
616void tst_Compiler::templateFriends()
617{
618 TemplateFriends<int> ti(42);
619 TemplateFriends<long> tl(0);
620 tl.copy(other: ti);
621}
622#else
623void tst_Compiler::templateFriends()
624{
625 QSKIP("Compiler does not support template friends");
626}
627#endif
628
629void tst_Compiler::cxx11_alignas()
630{
631#ifndef Q_COMPILER_ALIGNAS
632 QSKIP("Compiler does not support C++11 feature");
633#else
634 struct S {
635 alignas(double) char c;
636 };
637 QCOMPARE(Q_ALIGNOF(S), Q_ALIGNOF(double));
638#endif
639}
640
641void tst_Compiler::cxx11_alignof()
642{
643#ifndef Q_COMPILER_ALIGNOF
644 QSKIP("Compiler does not support C++11 feature");
645#else
646 size_t alignchar = alignof(char);
647 size_t aligndouble = alignof(double);
648 QVERIFY(alignchar >= 1);
649 QVERIFY(alignchar <= aligndouble);
650#endif
651}
652
653void tst_Compiler::cxx11_alignas_alignof()
654{
655#if !defined(Q_COMPILER_ALIGNAS) && !defined(Q_COMPILER_ALIGNOF)
656 QSKIP("Compiler does not support C++11 feature");
657#else
658 alignas(alignof(double)) char c;
659 Q_UNUSED(c);
660#endif
661}
662
663void tst_Compiler::cxx11_atomics()
664{
665#ifndef Q_COMPILER_ATOMICS
666 QSKIP("Compiler does not support C++11 feature");
667#else
668 std::atomic<int> i;
669 i.store(i: 42, m: std::memory_order_seq_cst);
670 QCOMPARE(i.load(std::memory_order_acquire), 42);
671
672 std::atomic<short> s;
673 s.store(i: 42);
674 QCOMPARE(s.load(), short(42));
675
676 std::atomic_flag flag;
677 flag.clear();
678 QVERIFY(!flag.test_and_set());
679 QVERIFY(flag.test_and_set());
680#endif
681}
682
683QT_WARNING_PUSH
684QT_WARNING_DISABLE_CLANG("-Wignored-attributes")
685QT_WARNING_DISABLE_CLANG("-Wunused-local-typedefs")
686QT_WARNING_DISABLE_GCC("-Wattributes")
687QT_WARNING_DISABLE_GCC("-Wunused-local-typedefs")
688
689#ifndef __has_cpp_attribute
690# define __has_cpp_attribute(x) 0
691#endif
692#ifdef Q_COMPILER_ATTRIBUTES
693[[noreturn]] void attribute_f1();
694void attribute_f2 [[noreturn]] ();
695# if (defined(__cpp_namespace_attributes) && __cpp_namespace_attributes >= 201411) && __has_cpp_attribute(deprecated)
696namespace [[deprecated]] NS { }
697# endif
698#endif
699
700void tst_Compiler::cxx11_attributes()
701{
702#ifndef Q_COMPILER_ATTRIBUTES
703 QSKIP("Compiler does not support C++11 feature");
704#else
705 // Attributes in function parameters and using clauses cause MSVC 2015 to crash
706 // https://connect.microsoft.com/VisualStudio/feedback/details/2011594
707# if (!defined(Q_CC_MSVC) || _MSC_FULL_VER >= 190023811) && !defined(Q_CC_INTEL)
708 void f([[ ]] int);
709 [[ ]] using namespace QtPrivate;
710 [[ ]] try {
711 } catch ([[]] int) {
712 }
713# endif
714
715 struct [[ ]] A { };
716 struct B : A {
717 [[ ]] int m_i : 32;
718 [[noreturn]] void f() const { ::exit(status: 0); }
719
720# ifdef Q_COMPILER_DEFAULT_DELETE_MEMBERS
721 [[ ]] ~B() = default;
722 [[ ]] B(const B &) = delete;
723# endif
724 };
725# if __has_cpp_attribute(deprecated)
726 struct [[deprecated]] C { };
727# endif
728 enum [[ ]] E { };
729 [[ ]] void [[ ]] * [[ ]] * [[ ]] ptr = 0;
730 int B::* [[ ]] pmm = 0;
731
732# if __has_cpp_attribute(deprecated)
733 enum [[deprecated]] E2 {
734# if defined(__cpp_enumerator_attributes) && __cpp_enumerator_attributes >= 201411
735 value [[deprecated]] = 0
736# endif
737 };
738# endif
739# ifdef Q_COMPILER_LAMBDA
740 []()[[ ]] {}();
741# endif
742# ifdef Q_COMPILER_TEMPLATE_ALIAS
743 using B2 [[ ]] = B;
744# endif
745
746 [[ ]] goto end;
747# ifdef Q_CC_GNU
748 // Attributes in gnu:: namespace
749 [[gnu::unused]] end:
750 ;
751 [[gnu::unused]] struct D {} d;
752 struct D e [[gnu::used, gnu::unused]];
753 [[gnu::aligned(8)]] int i [[ ]];
754 int array[][[]] = { 1 };
755# else
756 // Non GNU, so use an empty attribute
757 [[ ]] end:
758 ;
759 [[ ]] struct D {} d;
760 struct D e [[ ]];
761 [[ ]] int i [[ ]];
762 int array[][[]] = { 1 };
763# endif
764
765 int & [[ ]] lref = i;
766 int && [[ ]] rref = 1;
767 [[ ]] (void)1;
768 [[ ]] for (i = 0; i < 2; ++i)
769 ;
770
771 Q_UNUSED(ptr);
772 Q_UNUSED(pmm);
773 Q_UNUSED(d);
774 Q_UNUSED(e);
775 Q_UNUSED(i);
776 Q_UNUSED(array);
777 Q_UNUSED(lref);
778 Q_UNUSED(rref);
779#endif
780}
781QT_WARNING_POP
782
783#ifdef Q_COMPILER_AUTO_FUNCTION
784auto autoFunction() -> unsigned
785{
786 return 1;
787}
788#endif
789
790void tst_Compiler::cxx11_auto_function()
791{
792#ifndef Q_COMPILER_AUTO_FUNCTION
793 QSKIP("Compiler does not support C++11 feature");
794#else
795 QCOMPARE(autoFunction(), 1u);
796#endif
797}
798
799void tst_Compiler::cxx11_auto_type()
800{
801#ifndef Q_COMPILER_AUTO_TYPE
802 QSKIP("Compiler does not support C++11 feature");
803#else
804 auto i = 1;
805 auto x = QRandomGenerator::global()->generate();
806 auto l = 1L;
807 auto s = QStringLiteral("Hello World");
808
809 QCOMPARE(i, 1);
810 Q_UNUSED(x);
811 QCOMPARE(l, 1L);
812 QCOMPARE(s.toLower(), QString("hello world"));
813#endif
814}
815
816void tst_Compiler::cxx11_class_enum()
817{
818#ifndef Q_COMPILER_CLASS_ENUM
819 QSKIP("Compiler does not support C++11 feature");
820#else
821 enum class X { EnumValue };
822 X x = X::EnumValue;
823 QCOMPARE(x, X::EnumValue);
824
825 enum class Y : short { Val = 2 };
826 enum Z : long { ValLong = LONG_MAX };
827#endif
828}
829
830#ifdef Q_COMPILER_CONSTEXPR
831constexpr int constexprValue()
832{
833 return 42;
834}
835#endif
836
837void tst_Compiler::cxx11_constexpr()
838{
839#ifndef Q_COMPILER_CONSTEXPR
840 QSKIP("Compiler does not support C++11 feature");
841#else
842 static constexpr QBasicAtomicInt atomic = Q_BASIC_ATOMIC_INITIALIZER(1);
843 static constexpr int i = constexprValue();
844 QCOMPARE(i, constexprValue());
845 QCOMPARE(atomic.loadRelaxed(), 1);
846#endif
847}
848
849void tst_Compiler::cxx11_decltype()
850{
851#ifndef Q_COMPILER_DECLTYPE
852 QSKIP("Compiler does not support C++11 feature");
853#else
854 decltype(QRandomGenerator::global()->generate()) i = 0;
855 QCOMPARE(i, 0U);
856#endif
857}
858
859void tst_Compiler::cxx11_default_members()
860{
861#ifndef Q_COMPILER_DEFAULT_MEMBERS
862 QSKIP("Compiler does not support C++11 feature");
863#else
864 class DefaultMembers
865 {
866 protected:
867 DefaultMembers() = default;
868 public:
869 DefaultMembers(int) {}
870 };
871 class DefaultMembersChild: public DefaultMembers
872 {
873 DefaultMembersChild(const DefaultMembersChild &) : DefaultMembers() {}
874 public:
875 DefaultMembersChild():DefaultMembers() {};
876 DefaultMembersChild(DefaultMembersChild &&) = default;
877 };
878 DefaultMembersChild dm;
879 DefaultMembersChild dm2 = std::move(dm);
880 Q_UNUSED(dm2);
881#endif
882}
883
884void tst_Compiler::cxx11_delete_members()
885{
886#ifndef Q_COMPILER_DELETE_MEMBERS
887 QSKIP("Compiler does not support C++11 feature");
888#else
889 class DeleteMembers
890 {
891 protected:
892 DeleteMembers() = delete;
893 public:
894 DeleteMembers(const DeleteMembers &) = delete;
895 ~DeleteMembers() = delete;
896 };
897#endif
898}
899
900void tst_Compiler::cxx11_delegating_constructors()
901{
902#ifndef Q_COMPILER_DELEGATING_CONSTRUCTORS
903 QSKIP("Compiler does not support C++11 feature");
904#else
905 struct DC {
906 DC(int i) : i(i) {}
907 DC() : DC(0) {}
908 int i;
909 };
910
911 DC dc;
912 QCOMPARE(dc.i, 0);
913#endif
914}
915
916void tst_Compiler::cxx11_explicit_conversions()
917{
918#ifndef Q_COMPILER_EXPLICIT_CONVERSIONS
919 QSKIP("Compiler does not support C++11 feature");
920#else
921 struct EC {
922 explicit operator int() const { return 0; }
923 operator long long() const { return 1; }
924 };
925 EC ec;
926
927 int i(ec);
928 QCOMPARE(i, 0);
929
930 int i2 = ec;
931 QCOMPARE(i2, 1);
932#endif
933}
934
935void tst_Compiler::cxx11_explicit_overrides()
936{
937#ifndef Q_COMPILER_EXPLICIT_OVERRIDES
938 QSKIP("Compiler does not support C++11 feature");
939#else
940 struct Base {
941 virtual ~Base() {}
942 virtual void f() {}
943 };
944 struct Derived final : public Base {
945 virtual void f() final override {}
946 };
947#endif
948}
949
950#ifdef Q_COMPILER_EXTERN_TEMPLATES
951template <typename T> T externTemplate() { return T(0); }
952extern template int externTemplate<int>();
953#endif
954
955void tst_Compiler::cxx11_extern_templates()
956{
957#ifndef Q_COMPILER_EXTERN_TEMPLATES
958 QSKIP("Compiler does not support C++11 feature");
959#else
960 QCOMPARE(externTemplate<int>(), 42);
961#endif
962}
963
964void tst_Compiler::cxx11_inheriting_constructors()
965{
966#ifndef Q_COMPILER_INHERITING_CONSTRUCTORS
967 QSKIP("Compiler does not support C++11 feature");
968#else
969 struct Base {
970 int i;
971 Base() : i(0) {}
972 Base(int i) : i(i) {}
973 };
974 struct Derived : public Base {
975 using Base::Base;
976 };
977
978 Derived d(1);
979 QCOMPARE(d.i, 1);
980#endif
981}
982
983void tst_Compiler::cxx11_initializer_lists()
984{
985#ifndef Q_COMPILER_INITIALIZER_LISTS
986 QSKIP("Compiler does not support C++11 feature");
987#else
988 QList<int> l = { 1, 2, 3, 4, 5 };
989 QCOMPARE(l.length(), 5);
990 QCOMPARE(l.at(0), 1);
991 QCOMPARE(l.at(4), 5);
992#endif
993}
994
995struct CallFunctor
996{
997 template <typename Functor> static int f(Functor f)
998 { return f();}
999};
1000
1001void tst_Compiler::cxx11_lambda()
1002{
1003#ifndef Q_COMPILER_LAMBDA
1004 QSKIP("Compiler does not support C++11 feature");
1005#else
1006 QCOMPARE(CallFunctor::f([]() { return 42; }), 42);
1007#endif
1008}
1009
1010void tst_Compiler::cxx11_nonstatic_member_init()
1011{
1012#ifndef Q_COMPILER_NONSTATIC_MEMBER_INIT
1013 QSKIP("Compiler does not support C++11 feature");
1014#else
1015 struct S {
1016 int i = 42;
1017 long l = 47;
1018 char c;
1019 S() : l(-47), c(0) {}
1020 };
1021 S s;
1022
1023 QCOMPARE(s.i, 42);
1024 QCOMPARE(s.l, -47L);
1025 QCOMPARE(s.c, '\0');
1026#endif
1027}
1028
1029void tst_Compiler::cxx11_noexcept()
1030{
1031#ifndef Q_COMPILER_NOEXCEPT
1032 QSKIP("Compiler does not support C++11 feature");
1033#else
1034 extern void noexcept_f() noexcept;
1035 extern void g() noexcept(noexcept(noexcept_f()));
1036 QCOMPARE(noexcept(cxx11_noexcept()), false);
1037 QCOMPARE(noexcept(noexcept_f), true);
1038 QCOMPARE(noexcept(g), true);
1039#endif
1040}
1041
1042void tst_Compiler::cxx11_nullptr()
1043{
1044#ifndef Q_COMPILER_NULLPTR
1045 QSKIP("Compiler does not support C++11 feature");
1046#else
1047 void *v = nullptr;
1048 char *c = nullptr;
1049 const char *cc = nullptr;
1050 volatile char *vc = nullptr;
1051 std::nullptr_t np = nullptr;
1052 v = np;
1053
1054 Q_UNUSED(v);
1055 Q_UNUSED(c);
1056 Q_UNUSED(cc);
1057 Q_UNUSED(vc);
1058#endif
1059}
1060
1061namespace SomeNamespace {
1062class AdlOnly {
1063 QVector<int> v;
1064public:
1065 AdlOnly() : v(5) { std::fill_n(first: v.begin(), n: v.size(), value: 42); }
1066
1067private:
1068 friend QVector<int>::const_iterator begin(const AdlOnly &x) { return x.v.begin(); }
1069 friend QVector<int>::const_iterator end(const AdlOnly &x) { return x.v.end(); }
1070 friend QVector<int>::iterator begin(AdlOnly &x) { return x.v.begin(); }
1071 friend QVector<int>::iterator end(AdlOnly &x) { return x.v.end(); }
1072};
1073}
1074
1075void tst_Compiler::cxx11_range_for()
1076{
1077#ifndef Q_COMPILER_RANGE_FOR
1078 QSKIP("Compiler does not support C++11 feature");
1079#else
1080 QList<int> l;
1081 l << 1 << 2 << 3;
1082 for (int i : l)
1083 Q_UNUSED(i);
1084
1085 l.clear();
1086 l << 1;
1087 for (int i : l)
1088 QCOMPARE(i, 1);
1089
1090 QList<long> ll;
1091 l << 2;
1092 for (int i : ll)
1093 QCOMPARE(i, 2);
1094
1095 {
1096 const int array[] = { 0, 1, 2, 3, 4 };
1097 int i = 0;
1098 for (const int &e : array)
1099 QCOMPARE(e, array[i++]);
1100 i = 0;
1101 for (int e : array)
1102 QCOMPARE(e, array[i++]);
1103 i = 0;
1104 for (const int e : array)
1105 QCOMPARE(e, array[i++]);
1106#ifdef Q_COMPILER_AUTO_TYPE
1107 i = 0;
1108 for (const auto &e : array)
1109 QCOMPARE(e, array[i++]);
1110 i = 0;
1111 for (auto &e : array) // auto deducing const
1112 QCOMPARE(e, array[i++]);
1113 i = 0;
1114 for (auto e : array)
1115 QCOMPARE(e, array[i++]);
1116 i = 0;
1117 for (const auto e : array)
1118 QCOMPARE(e, array[i++]);
1119#endif
1120 }
1121
1122 {
1123 int array[] = { 0, 1, 2, 3, 4 };
1124 const int array2[] = { 10, 11, 12, 13, 14 };
1125 int i = 0;
1126 for (const int &e : array)
1127 QCOMPARE(e, array[i++]);
1128 i = 0;
1129 for (int &e : array)
1130 QCOMPARE(e, array[i++]);
1131 i = 0;
1132 for (int e : array)
1133 QCOMPARE(e, array[i++]);
1134 i = 0;
1135 for (const int e : array)
1136 QCOMPARE(e, array[i++]);
1137#ifdef Q_COMPILER_AUTO_TYPE
1138 i = 0;
1139 for (const auto &e : array)
1140 QCOMPARE(e, array[i++]);
1141 i = 0;
1142 for (auto &e : array)
1143 QCOMPARE(e, array[i++]);
1144 i = 0;
1145 for (auto e : array)
1146 QCOMPARE(e, array[i++]);
1147 i = 0;
1148 for (const auto e : array)
1149 QCOMPARE(e, array[i++]);
1150#endif
1151 for (int &e : array)
1152 e += 10;
1153 i = 0;
1154 for (const int &e : array)
1155 QCOMPARE(e, array2[i++]);
1156 }
1157
1158 {
1159 const SomeNamespace::AdlOnly x;
1160 for (const int &e : x)
1161 QCOMPARE(e, 42);
1162 }
1163
1164 {
1165 SomeNamespace::AdlOnly x;
1166 for (const int &e : x)
1167 QCOMPARE(e, 42);
1168 for (int &e : x)
1169 e += 10;
1170 for (const int &e : x)
1171 QCOMPARE(e, 52);
1172 }
1173#endif
1174}
1175
1176void tst_Compiler::cxx11_raw_strings()
1177{
1178#ifndef Q_COMPILER_RAW_STRINGS
1179 QSKIP("Compiler does not support C++11 feature");
1180#else
1181 static const char xml[] = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
1182 static const char raw[] = R"***(*"*)***";
1183 QCOMPARE(strlen(raw), size_t(3));
1184 QCOMPARE(raw[1], '"');
1185 Q_UNUSED(xml);
1186#endif
1187}
1188
1189void tst_Compiler::cxx11_ref_qualifiers()
1190{
1191#ifndef Q_COMPILER_REF_QUALIFIERS
1192 QSKIP("Compiler does not support C++11 feature");
1193#else
1194# ifndef Q_COMPILER_RVALUE_REFS
1195# error "Impossible condition: ref qualifiers are supported but not rvalue refs"
1196# endif
1197 // also applies to function pointers
1198 QByteArray (QString:: *lvalueref)() const & = &QString::toLatin1;
1199 QByteArray (QString:: *rvalueref)() && = &QString::toLatin1;
1200
1201 QString s("Hello");
1202 QCOMPARE((s.*lvalueref)(), QByteArray("Hello"));
1203 QCOMPARE((std::move(s).*rvalueref)(), QByteArray("Hello"));
1204
1205 // tests internal behavior:
1206 QVERIFY(s.isEmpty());
1207#endif
1208}
1209
1210class MoveDefinedQString {
1211 QString s;
1212public:
1213 MoveDefinedQString() : s() {}
1214 explicit MoveDefinedQString(const QString &s) : s(s) {}
1215 MoveDefinedQString(const MoveDefinedQString &other) : s(other.s) {}
1216#ifdef Q_COMPILER_RVALUE_REFS
1217 MoveDefinedQString(MoveDefinedQString &&other) : s(std::move(other.s)) { other.s.clear(); }
1218 MoveDefinedQString &operator=(MoveDefinedQString &&other)
1219 { s = std::move(other.s); other.s.clear(); return *this; }
1220#endif
1221 MoveDefinedQString &operator=(const MoveDefinedQString &other) { s = other.s; return *this; }
1222
1223private:
1224 friend bool operator==(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs)
1225 { return lhs.s == rhs.s; }
1226 friend bool operator!=(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs)
1227 { return !operator==(lhs, rhs); }
1228 friend char* toString(const MoveDefinedQString &mds)
1229 { using namespace QTest; return toString(str: mds.s); }
1230};
1231
1232void tst_Compiler::cxx11_rvalue_refs()
1233{
1234#ifndef Q_COMPILER_RVALUE_REFS
1235 QSKIP("Compiler does not support C++11 feature");
1236#else
1237 // we require std::move:
1238 {
1239 int i = 1;
1240 i = std::move(i);
1241
1242 MoveDefinedQString s("Hello");
1243 MoveDefinedQString t = std::move(s);
1244 QCOMPARE(t, MoveDefinedQString("Hello"));
1245 QCOMPARE(s, MoveDefinedQString());
1246
1247 s = t;
1248 t = std::move(s);
1249 QCOMPARE(t, MoveDefinedQString("Hello"));
1250 QCOMPARE(s, MoveDefinedQString());
1251
1252 MoveDefinedQString &&r = std::move(t); // no actual move!
1253 QCOMPARE(r, MoveDefinedQString("Hello"));
1254 QCOMPARE(t, MoveDefinedQString("Hello")); // so 't' is unchanged
1255 }
1256
1257 // we require std::forward:
1258 {
1259 MoveDefinedQString s("Hello");
1260 MoveDefinedQString s2 = std::forward<MoveDefinedQString>(t&: s); // forward as rvalue
1261 QCOMPARE(s2, MoveDefinedQString("Hello"));
1262 QCOMPARE(s, MoveDefinedQString());
1263
1264 MoveDefinedQString s3 = std::forward<MoveDefinedQString&>(t&: s2); // forward as lvalue
1265 QCOMPARE(s2, MoveDefinedQString("Hello"));
1266 QCOMPARE(s3, MoveDefinedQString("Hello"));
1267 }
1268
1269 // we require automatic generation of move special member functions:
1270 {
1271 struct M { MoveDefinedQString s1, s2; };
1272 M m1 = { .s1: MoveDefinedQString("Hello"), .s2: MoveDefinedQString("World") };
1273 QCOMPARE(m1.s1, MoveDefinedQString("Hello"));
1274 QCOMPARE(m1.s2, MoveDefinedQString("World"));
1275 M m2 = std::move(m1);
1276 QCOMPARE(m1.s1, MoveDefinedQString());
1277 QCOMPARE(m1.s2, MoveDefinedQString());
1278 QCOMPARE(m2.s1, MoveDefinedQString("Hello"));
1279 QCOMPARE(m2.s2, MoveDefinedQString("World"));
1280 M m3;
1281 QCOMPARE(m3.s1, MoveDefinedQString());
1282 QCOMPARE(m3.s2, MoveDefinedQString());
1283 m3 = std::move(m2);
1284 QCOMPARE(m2.s1, MoveDefinedQString());
1285 QCOMPARE(m2.s2, MoveDefinedQString());
1286 QCOMPARE(m3.s1, MoveDefinedQString("Hello"));
1287 QCOMPARE(m3.s2, MoveDefinedQString("World"));
1288 }
1289#endif
1290}
1291
1292void tst_Compiler::cxx11_static_assert()
1293{
1294#ifndef Q_COMPILER_STATIC_ASSERT
1295 QSKIP("Compiler does not support C++11 feature");
1296#else
1297 static_assert(true, "Message");
1298#endif
1299}
1300
1301#ifdef Q_COMPILER_TEMPLATE_ALIAS
1302template <typename T> using Map = QMap<QString, T>;
1303#endif
1304
1305void tst_Compiler::cxx11_template_alias()
1306{
1307#ifndef Q_COMPILER_TEMPLATE_ALIAS
1308 QSKIP("Compiler does not support C++11 feature");
1309#else
1310 Map<QVariant> m;
1311 m.insert(akey: "Hello", avalue: "World");
1312 QCOMPARE(m.value("Hello").toString(), QString("World"));
1313
1314 using X = int;
1315 X i = 0;
1316 Q_UNUSED(i);
1317#endif
1318}
1319
1320#ifdef Q_COMPILER_THREAD_LOCAL
1321static thread_local int stl = 42;
1322thread_local int gtl = 42;
1323#endif
1324
1325void tst_Compiler::cxx11_thread_local()
1326{
1327#ifndef Q_COMPILER_THREAD_LOCAL
1328 QSKIP("Compiler does not support C++11 feature");
1329#else
1330 thread_local int v = 1;
1331 QVERIFY(v);
1332 QVERIFY(stl);
1333 QVERIFY(gtl);
1334
1335 thread_local QString s = "Hello";
1336 QVERIFY(!s.isEmpty());
1337#endif
1338}
1339
1340#ifdef Q_COMPILER_UDL
1341QString operator"" _tstqstring(const char *str, size_t len)
1342{
1343 return QString::fromUtf8(str, size: len) + " UDL";
1344}
1345#endif
1346
1347void tst_Compiler::cxx11_udl()
1348{
1349#ifndef Q_COMPILER_UDL
1350 QSKIP("Compiler does not support C++11 feature");
1351#else
1352 QString s = "Hello World"_tstqstring;
1353 QCOMPARE(s, QString("Hello World UDL"));
1354#endif
1355}
1356
1357void tst_Compiler::cxx11_unicode_strings()
1358{
1359#ifndef Q_COMPILER_UNICODE_STRINGS
1360 QSKIP("Compiler does not support C++11 feature");
1361#else
1362 static const char16_t u[] = u"\u200BHello\u00A0World";
1363 QCOMPARE(u[0], char16_t(0x200B));
1364
1365 static const char32_t U[] = U"\ufffe";
1366 QCOMPARE(U[0], char32_t(0xfffe));
1367
1368 QCOMPARE(u"\U00010000"[0], char16_t(0xD800));
1369 QCOMPARE(u"\U00010000"[1], char16_t(0xDC00));
1370#endif
1371}
1372
1373static void noop(QPair<int, int>) {}
1374void tst_Compiler::cxx11_uniform_init()
1375{
1376#ifndef Q_COMPILER_UNIFORM_INIT
1377 QSKIP("Compiler does not support C++11 feature");
1378 noop(QPair<int,int>());
1379#else
1380 QString s{"Hello"};
1381 int i{};
1382 noop(QPair<int,int>{1,1});
1383 noop({i,1});
1384#endif
1385}
1386
1387void tst_Compiler::cxx11_unrestricted_unions()
1388{
1389#ifndef Q_COMPILER_UNRESTRICTED_UNIONS
1390 QSKIP("Compiler does not support C++11 feature");
1391#else
1392 union U {
1393 QString s;
1394 U() {}
1395 U(const QString &s) : s(s) {}
1396 ~U() {}
1397 };
1398 U u;
1399 std::aligned_storage<sizeof(QString), Q_ALIGNOF(QString)> as;
1400 Q_UNUSED(u);
1401 Q_UNUSED(as);
1402
1403 U u2("hello");
1404 u2.s.~QString();
1405#endif
1406}
1407
1408void tst_Compiler::cxx11_variadic_macros()
1409{
1410#ifndef Q_COMPILER_VARIADIC_MACROS
1411 QSKIP("Compiler does not support C++11 feature");
1412#else
1413# define TEST_VARARG(x, ...) __VA_ARGS__
1414 QCOMPARE(TEST_VARARG(0, 1), 1);
1415#endif
1416}
1417
1418#ifdef Q_COMPILER_VARIADIC_TEMPLATES
1419template <typename... Args> struct VariadicTemplate {};
1420#endif
1421
1422void tst_Compiler::cxx11_variadic_templates()
1423{
1424#ifndef Q_COMPILER_VARIADIC_TEMPLATES
1425 QSKIP("Compiler does not support C++11 feature");
1426#else
1427 VariadicTemplate<> v0;
1428 VariadicTemplate<int> v1;
1429 VariadicTemplate<int, int, int, int,
1430 int, int, int, int> v8;
1431 Q_UNUSED(v0);
1432 Q_UNUSED(v1);
1433 Q_UNUSED(v8);
1434#endif
1435}
1436
1437void tst_Compiler::cxx14_binary_literals()
1438{
1439#if __cpp_binary_literals-0 < 201304
1440 QSKIP("Compiler does not support this C++14 feature");
1441#else
1442 int i = 0b11001001;
1443 QCOMPARE(i, 0xC9);
1444#endif
1445}
1446
1447void tst_Compiler::cxx14_init_captures()
1448{
1449#if __cpp_init_captures-0 < 201304
1450 QSKIP("Compiler does not support this C++14 feature");
1451#else
1452 QCOMPARE([x = 42]() { return x; }(), 42);
1453#endif
1454}
1455
1456void tst_Compiler::cxx14_generic_lambdas()
1457{
1458#if __cpp_generic_lambdas-0 < 201304
1459 QSKIP("Compiler does not support this C++14 feature");
1460#else
1461 auto identity = [](auto x) { return x; };
1462 QCOMPARE(identity(42), 42);
1463 QCOMPARE(identity(42U), 42U);
1464 QCOMPARE(identity(42L), 42L);
1465#endif
1466}
1467
1468#if __cpp_constexpr-0 >= 201304
1469constexpr int relaxedConstexpr(int i)
1470{
1471 i *= 2;
1472 i += 2;
1473 return i;
1474}
1475#endif
1476
1477void tst_Compiler::cxx14_constexpr()
1478{
1479#if __cpp_constexpr-0 < 201304
1480 QSKIP("Compiler does not support this C++14 feature");
1481#else
1482 QCOMPARE(relaxedConstexpr(0), 2);
1483 QCOMPARE(relaxedConstexpr(2), 6);
1484#endif
1485}
1486
1487void tst_Compiler::cxx14_decltype_auto()
1488{
1489#if __cpp_decltype_auto-0 < 201304
1490 QSKIP("Compiler does not support this C++14 feature");
1491#else
1492 QList<int> l;
1493 l << 1;
1494 decltype(auto) value = l[0];
1495 value = 2;
1496 QCOMPARE(l.at(0), 2);
1497#endif
1498}
1499
1500#if __cpp_return_type_deduction >= 201304
1501auto returnTypeDeduction(bool choice)
1502{
1503 if (choice)
1504 return 1U;
1505 return returnTypeDeduction(choice: !choice);
1506}
1507#endif
1508
1509void tst_Compiler::cxx14_return_type_deduction()
1510{
1511#if __cpp_return_type_deduction-0 < 201304
1512 QSKIP("Compiler does not support this C++14 feature");
1513#else
1514 QCOMPARE(returnTypeDeduction(false), 1U);
1515#endif
1516}
1517
1518void tst_Compiler::cxx14_aggregate_nsdmi()
1519{
1520#if __cpp_aggregate_nsdmi-0 < 201304
1521 QSKIP("Compiler does not support this C++14 feature");
1522#else
1523 struct S { int i, j = i; };
1524 S s = { .i: 1 };
1525 QCOMPARE(s.j, 1);
1526#endif
1527}
1528
1529#if __cpp_variable_templates >= 201304
1530template <typename T> constexpr T variableTemplate = T(42);
1531#endif
1532void tst_Compiler::cxx14_variable_templates()
1533{
1534#if __cpp_variable_templates-0 < 201304
1535 QSKIP("Compiler does not support this C++14 feature");
1536#else
1537 QCOMPARE(variableTemplate<int>, 42);
1538 QCOMPARE(variableTemplate<long>, 42L);
1539 QCOMPARE(variableTemplate<unsigned>, 42U);
1540 QCOMPARE(variableTemplate<unsigned long long>, 42ULL);
1541#endif
1542}
1543
1544void tst_Compiler::runtimeArrays()
1545{
1546#if __cpp_runtime_arrays-0 < 201304
1547 QSKIP("Compiler does not support this C++14 feature");
1548#else
1549 int i[QRandomGenerator::global()->generate() & 0x1f];
1550 Q_UNUSED(i);
1551#endif
1552}
1553
1554QTEST_MAIN(tst_Compiler)
1555#include "tst_compiler.moc"
1556

source code of qtbase/tests/auto/other/compiler/tst_compiler.cpp