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 | |
43 | QT_USE_NAMESPACE |
44 | |
45 | class tst_Compiler : public QObject |
46 | { |
47 | Q_OBJECT |
48 | private 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 | |
130 | class TemplateMethodClass |
131 | { |
132 | public: |
133 | template <class T> |
134 | T foo() { return 42; } |
135 | }; |
136 | |
137 | void 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 |
147 | class TemplateConstructorClass |
148 | { |
149 | public: |
150 | template <class T> |
151 | TemplateConstructorClass(const T& t) { i = int(t); } |
152 | |
153 | int i; |
154 | }; |
155 | |
156 | void 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 |
167 | void tst_Compiler::template_constructors() |
168 | { QSKIP("Compiler doesn't do template constructors" ); } |
169 | #endif |
170 | |
171 | template <typename T> |
172 | struct OuterClass |
173 | { |
174 | template <typename U> |
175 | struct InnerClass |
176 | { |
177 | U convert(const T &t) { return static_cast<U>(t); } |
178 | }; |
179 | }; |
180 | |
181 | void 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 | |
190 | class TemplateMethodClass2 |
191 | { |
192 | public: |
193 | template <class T> |
194 | T foo() { return 42; } |
195 | }; |
196 | |
197 | template<> |
198 | int TemplateMethodClass2::foo<int>() |
199 | { return 43; } |
200 | |
201 | void 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 |
211 | class TemplateConstructorClass2 |
212 | { |
213 | public: |
214 | template <class T> |
215 | TemplateConstructorClass2(const T &t) { i = int(t); } |
216 | |
217 | int i; |
218 | }; |
219 | |
220 | template<> |
221 | TemplateConstructorClass2::TemplateConstructorClass2(const int &t) { i = t + 1; } |
222 | |
223 | void 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 |
234 | void tst_Compiler::constructorSpecialization() |
235 | { QSKIP("Compiler doesn't do constructor specialization" ); } |
236 | #endif |
237 | |
238 | class StaticTemplateClass |
239 | { |
240 | public: |
241 | template <class T> |
242 | static T foo() { return 42; } |
243 | }; |
244 | |
245 | void tst_Compiler::staticTemplateMethods() |
246 | { |
247 | QCOMPARE(StaticTemplateClass::foo<int>(), 42); |
248 | QCOMPARE(StaticTemplateClass::foo<uint>(), 42u); |
249 | } |
250 | |
251 | class StaticTemplateClass2 |
252 | { |
253 | public: |
254 | template <class T> |
255 | static T foo() { return 42; } |
256 | }; |
257 | |
258 | template<> |
259 | double StaticTemplateClass2::foo<double>() { return 18.5; } |
260 | |
261 | void 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 *********/ |
270 | namespace 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 | |
329 | struct MyString: public QString {}; |
330 | struct Qxxx {}; |
331 | |
332 | void 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 |
355 | void tst_Compiler::detectDataStream() |
356 | { QSKIP("Compiler doesn't evaluate templates correctly" ); } |
357 | #endif |
358 | |
359 | enum Enum1 { Foo = 0, Bar = 1 }; |
360 | enum Enum2 {}; |
361 | enum Enum3 { Something = 1 }; |
362 | |
363 | template <typename T> char QTypeInfoEnumHelper(T); |
364 | template <typename T> void *QTypeInfoEnumHelper(...); |
365 | |
366 | template <typename T> |
367 | struct QTestTypeInfo |
368 | { |
369 | enum { IsEnum = sizeof(QTypeInfoEnumHelper<T>(0)) == sizeof(void*) }; |
370 | }; |
371 | |
372 | void 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 | } |
390 | static int indicator = 0; |
391 | |
392 | // this is a silly C function |
393 | extern "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 |
398 | template <typename T> |
399 | void someCFunc(T *) { indicator = 10; } |
400 | |
401 | void tst_Compiler::overrideCFunction() |
402 | { |
403 | someCFunc((void*)0); |
404 | QCOMPARE(indicator, 42); |
405 | } |
406 | |
407 | #ifndef DONT_TEST_STL_SORTING |
408 | void 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 | |
423 | void 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 |
438 | void tst_Compiler::stdSortQList() |
439 | { QSKIP("Compiler's STL broken" ); } |
440 | void 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 |
445 | static int whatWasCalled = 0; |
446 | |
447 | void callOrderFunc(void *) |
448 | { |
449 | whatWasCalled = 1; |
450 | } |
451 | |
452 | template <typename T> |
453 | void callOrderFunc(T *) |
454 | { |
455 | whatWasCalled = 2; |
456 | } |
457 | |
458 | template <typename T> |
459 | void 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 | */ |
471 | void 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 |
499 | void 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 | |
515 | template<typename T> const char *resolveCharSignedness(); |
516 | |
517 | template<> |
518 | const char *resolveCharSignedness<char>() |
519 | { |
520 | return "char" ; |
521 | } |
522 | |
523 | template<> |
524 | const char *resolveCharSignedness<unsigned char>() |
525 | { |
526 | return "unsigned char" ; |
527 | } |
528 | |
529 | template<> |
530 | const char *resolveCharSignedness<signed char>() |
531 | { |
532 | return "signed char" ; |
533 | } |
534 | |
535 | void 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 | |
542 | class PrivateStaticTemplateMember |
543 | { |
544 | public: |
545 | long regularMember() |
546 | { |
547 | return helper<long, int>(b: 3); |
548 | } |
549 | |
550 | private: |
551 | template<typename A, typename B> |
552 | static A helper(const B b) |
553 | { |
554 | return A(b); |
555 | } |
556 | }; |
557 | |
558 | void 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 |
570 | static const union { unsigned char c[8]; double d; } qt_be_inf_bytes = { .c: { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } }; |
571 | static const union { unsigned char c[8]; double d; } qt_le_inf_bytes = { .c: { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } }; |
572 | static 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 | |
581 | static const unsigned char qt_be_inf_bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; |
582 | static const unsigned char qt_le_inf_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; |
583 | static 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 | |
597 | void tst_Compiler::staticConstUnionWithInitializerList() const |
598 | { |
599 | double d = qt_inf(); |
600 | QVERIFY(qIsInf(d)); |
601 | } |
602 | |
603 | #ifndef Q_NO_TEMPLATE_FRIENDS |
604 | template <typename T> class TemplateFriends |
605 | { |
606 | T value; |
607 | public: |
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 | |
616 | void tst_Compiler::templateFriends() |
617 | { |
618 | TemplateFriends<int> ti(42); |
619 | TemplateFriends<long> tl(0); |
620 | tl.copy(other: ti); |
621 | } |
622 | #else |
623 | void tst_Compiler::templateFriends() |
624 | { |
625 | QSKIP("Compiler does not support template friends" ); |
626 | } |
627 | #endif |
628 | |
629 | void 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 | |
641 | void 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 | |
653 | void 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 | |
663 | void 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 | |
683 | QT_WARNING_PUSH |
684 | QT_WARNING_DISABLE_CLANG("-Wignored-attributes" ) |
685 | QT_WARNING_DISABLE_CLANG("-Wunused-local-typedefs" ) |
686 | QT_WARNING_DISABLE_GCC("-Wattributes" ) |
687 | QT_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(); |
694 | void attribute_f2 [[noreturn]] (); |
695 | # if (defined(__cpp_namespace_attributes) && __cpp_namespace_attributes >= 201411) && __has_cpp_attribute(deprecated) |
696 | namespace [[deprecated]] NS { } |
697 | # endif |
698 | #endif |
699 | |
700 | void 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 | } |
781 | QT_WARNING_POP |
782 | |
783 | #ifdef Q_COMPILER_AUTO_FUNCTION |
784 | auto autoFunction() -> unsigned |
785 | { |
786 | return 1; |
787 | } |
788 | #endif |
789 | |
790 | void 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 | |
799 | void 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 | |
816 | void 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 |
831 | constexpr int constexprValue() |
832 | { |
833 | return 42; |
834 | } |
835 | #endif |
836 | |
837 | void 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 | |
849 | void 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 | |
859 | void 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 | |
884 | void 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 | |
900 | void 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 | |
916 | void 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 | |
935 | void 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 |
951 | template <typename T> T externTemplate() { return T(0); } |
952 | extern template int externTemplate<int>(); |
953 | #endif |
954 | |
955 | void 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 | |
964 | void 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 | |
983 | void 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 | |
995 | struct CallFunctor |
996 | { |
997 | template <typename Functor> static int f(Functor f) |
998 | { return f();} |
999 | }; |
1000 | |
1001 | void 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 | |
1010 | void 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 | |
1029 | void 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 | |
1042 | void 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 | |
1061 | namespace SomeNamespace { |
1062 | class AdlOnly { |
1063 | QVector<int> v; |
1064 | public: |
1065 | AdlOnly() : v(5) { std::fill_n(first: v.begin(), n: v.size(), value: 42); } |
1066 | |
1067 | private: |
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 | |
1075 | void 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 | |
1176 | void 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 | |
1189 | void 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 | |
1210 | class MoveDefinedQString { |
1211 | QString s; |
1212 | public: |
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 | |
1223 | private: |
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 | |
1232 | void 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 | |
1292 | void 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 |
1302 | template <typename T> using Map = QMap<QString, T>; |
1303 | #endif |
1304 | |
1305 | void 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 |
1321 | static thread_local int stl = 42; |
1322 | thread_local int gtl = 42; |
1323 | #endif |
1324 | |
1325 | void 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 |
1341 | QString operator"" _tstqstring(const char *str, size_t len) |
1342 | { |
1343 | return QString::fromUtf8(str, size: len) + " UDL" ; |
1344 | } |
1345 | #endif |
1346 | |
1347 | void 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 | |
1357 | void 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 | |
1373 | static void noop(QPair<int, int>) {} |
1374 | void 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 | |
1387 | void 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 | |
1408 | void 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 |
1419 | template <typename... Args> struct VariadicTemplate {}; |
1420 | #endif |
1421 | |
1422 | void 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 | |
1437 | void 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 | |
1447 | void 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 | |
1456 | void 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 |
1469 | constexpr int relaxedConstexpr(int i) |
1470 | { |
1471 | i *= 2; |
1472 | i += 2; |
1473 | return i; |
1474 | } |
1475 | #endif |
1476 | |
1477 | void 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 | |
1487 | void 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 |
1501 | auto returnTypeDeduction(bool choice) |
1502 | { |
1503 | if (choice) |
1504 | return 1U; |
1505 | return returnTypeDeduction(choice: !choice); |
1506 | } |
1507 | #endif |
1508 | |
1509 | void 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 | |
1518 | void 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 |
1530 | template <typename T> constexpr T variableTemplate = T(42); |
1531 | #endif |
1532 | void 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 | |
1544 | void 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 | |
1554 | QTEST_MAIN(tst_Compiler) |
1555 | #include "tst_compiler.moc" |
1556 | |