summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-11-05 17:54:35 -0800
committerThiago Macieira <thiago.macieira@intel.com>2017-11-21 20:01:18 +0000
commit0ac2dca977ecc4020f51af57908a2640d00bcd9e (patch)
treebe399d18dc57bef0d1dad21affd6ec2c31e94132
parentef7c0594bf9e41813c9c841e00c3a52269d363f5 (diff)
Add support for C11 static_assert and thread_local
Tested with Clang, GCC 4.5 & up, ICC 17 and MSVC 2017. No current version of MSVC supports C11 and GCC implemented the features slightly later in C than in C++. Change-Id: I57a1bd6e0c194530b732fffd14f45c5074c9a052 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
-rw-r--r--src/corelib/global/qcompilerdetection.h29
-rw-r--r--src/corelib/global/qglobal.h53
-rw-r--r--tests/auto/corelib/global/qglobal/qglobal.c111
-rw-r--r--tests/auto/corelib/global/qglobal/qglobal.pro2
-rw-r--r--tests/auto/corelib/global/qglobal/tst_qglobal.cpp17
5 files changed, 185 insertions, 27 deletions
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 2c58ff87e9..e4b756f4b7 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -651,6 +651,12 @@
# undef Q_COMPILER_CONSTEXPR
# endif
# endif
+# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L s
+// C11 features supported. Only tested with ICC 17 and up.
+# define Q_COMPILER_STATIC_ASSERT
+# if __has_include(<threads.h>)
+# define Q_COMPILER_THREAD_LOCAL
+# endif
# endif
#endif
@@ -803,6 +809,17 @@
# endif
# endif
+# if defined(__STDC_VERSION__)
+# if __has_feature(c_static_assert)
+# define Q_COMPILER_STATIC_ASSERT
+# endif
+# if __has_feature(c_thread_local) && __has_include(<threads.h>)
+# if !defined(__FreeBSD__) /* FreeBSD clang fails on __cxa_thread_atexit */
+# define Q_COMPILER_THREAD_LOCAL
+# endif
+# endif
+# endif
+
# if defined(__has_warning)
# if __has_warning("-Wunused-private-field")
# define Q_DECL_UNUSED_MEMBER Q_DECL_UNUSED
@@ -898,6 +915,18 @@
# define Q_COMPILER_RETURN_TYPE_DEDUCTION
# endif
# endif
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L
+# if Q_CC_GNU >= 407
+ /* C11 features supported in GCC 4.7: */
+# define Q_COMPILER_STATIC_ASSERT
+# endif
+# if Q_CC_GNU >= 409
+ /* C11 features supported in GCC 4.9: */
+# if __has_include(<threads.h>)
+# define Q_COMPILER_THREAD_LOCAL
+# endif
+# endif
+# endif
#endif
#if defined(Q_CC_MSVC)
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index e49bace002..33b86a7321 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -47,6 +47,7 @@
# include <utility>
#endif
#ifndef __ASSEMBLER__
+# include <assert.h>
# include <stddef.h>
#endif
@@ -105,6 +106,32 @@
# define Q_OF_MACH_O
#endif
+/*
+ Avoid "unused parameter" warnings
+*/
+#define Q_UNUSED(x) (void)x;
+
+#if defined(__cplusplus) && defined(Q_COMPILER_STATIC_ASSERT)
+# define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition)
+# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
+#elif defined(Q_COMPILER_STATIC_ASSERT)
+// C11 mode - using the _S version in case <assert.h> doesn't do the right thing
+# define Q_STATIC_ASSERT(Condition) _Static_assert(!!(Condition), #Condition)
+# define Q_STATIC_ASSERT_X(Condition, Message) _Static_assert(!!(Condition), Message)
+#else
+// C89 & C99 version
+# define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
+# define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
+# ifdef __COUNTER__
+# define Q_STATIC_ASSERT(Condition) \
+ typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) [(Condition) ? 1 : -1];
+# else
+# define Q_STATIC_ASSERT(Condition) \
+ typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) [(Condition) ? 1 : -1];
+# endif /* __COUNTER__ */
+# define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
+#endif
+
#ifdef __cplusplus
#include <algorithm>
@@ -688,11 +715,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() Q_DECL_NOTHROW;
#endif
/*
- Avoid "unused parameter" warnings
-*/
-#define Q_UNUSED(x) (void)x;
-
-/*
Debugging and error handling
*/
@@ -750,27 +772,6 @@ Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *
# endif
#endif
-
-#ifdef Q_COMPILER_STATIC_ASSERT
-#define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition)
-#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
-#else
-// Intentionally undefined
-template <bool Test> class QStaticAssertFailure;
-template <> class QStaticAssertFailure<true> {};
-
-#define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
-#define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
-#ifdef __COUNTER__
-#define Q_STATIC_ASSERT(Condition) \
- enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
-#else
-#define Q_STATIC_ASSERT(Condition) \
- enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
-#endif /* __COUNTER__ */
-#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
-#endif
-
Q_NORETURN Q_CORE_EXPORT void qt_check_pointer(const char *, int) Q_DECL_NOTHROW;
Q_CORE_EXPORT void qBadAlloc();
diff --git a/tests/auto/corelib/global/qglobal/qglobal.c b/tests/auto/corelib/global/qglobal/qglobal.c
new file mode 100644
index 0000000000..6a6f53dfe0
--- /dev/null
+++ b/tests/auto/corelib/global/qglobal/qglobal.c
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#if QT_HAS_INCLUDE(<stdbool.h>) || __STDC_VERSION__ >= 199901L
+# include <stdbool.h>
+#else
+# undef true
+# define true 1
+# undef false
+# define false 0
+#endif
+
+#ifdef Q_COMPILER_THREAD_LOCAL
+# include <threads.h>
+#endif
+
+/*
+ * Certain features of qglobal.h must work in C mode too. We test that
+ * everything works.
+ */
+
+/* Types and Q_UNUSED */
+void tst_GlobalTypes()
+{
+ qint8 s8;
+ qint16 s16;
+ qint32 s32;
+ qint64 s64;
+ qlonglong sll;
+ Q_UNUSED(s8); Q_UNUSED(s16); Q_UNUSED(s32); Q_UNUSED(s64); Q_UNUSED(sll);
+
+ quint8 u8;
+ quint16 u16;
+ quint32 u32;
+ quint64 u64;
+ qulonglong ull;
+ Q_UNUSED(u8); Q_UNUSED(u16); Q_UNUSED(u32); Q_UNUSED(u64); Q_UNUSED(ull);
+
+ uchar uc;
+ ushort us;
+ uint ui;
+ ulong ul;
+ Q_UNUSED(uc); Q_UNUSED(us); Q_UNUSED(ui); Q_UNUSED(ul);
+
+ qreal qr;
+ Q_UNUSED(qr);
+}
+
+/* Qt version */
+int tst_QtVersion()
+{
+ return QT_VERSION;
+}
+
+const char *tst_qVersion() Q_DECL_NOTHROW
+{
+#if !defined(QT_NAMESPACE)
+ return qVersion();
+#else
+ return NULL;
+#endif
+}
+
+/* Static assertion */
+Q_STATIC_ASSERT(true);
+Q_STATIC_ASSERT(1);
+Q_STATIC_ASSERT_X(true, "Message");
+Q_STATIC_ASSERT_X(1, "Message");
+
+Q_STATIC_ASSERT(!false);
+Q_STATIC_ASSERT(!0);
+
+Q_STATIC_ASSERT(!!true);
+Q_STATIC_ASSERT(!!1);
+
+#ifdef Q_COMPILER_THREAD_LOCAL
+static thread_local int gt_var;
+void thread_local_test()
+{
+ thread_local int t_var;
+ t_var = gt_var;
+}
+#endif
+
diff --git a/tests/auto/corelib/global/qglobal/qglobal.pro b/tests/auto/corelib/global/qglobal/qglobal.pro
index b8ed7761f5..a40cb9a288 100644
--- a/tests/auto/corelib/global/qglobal/qglobal.pro
+++ b/tests/auto/corelib/global/qglobal/qglobal.pro
@@ -1,4 +1,4 @@
CONFIG += testcase
TARGET = tst_qglobal
QT = core testlib
-SOURCES = tst_qglobal.cpp
+SOURCES = tst_qglobal.cpp qglobal.c
diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
index 083526fdc4..78b954f373 100644
--- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
+++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
@@ -39,6 +39,7 @@ class tst_QGlobal: public QObject
Q_OBJECT
private slots:
+ void cMode();
void qIsNull();
void for_each();
void qassert();
@@ -56,6 +57,22 @@ private slots:
void testqOverload();
};
+extern "C" { // functions in qglobal.c
+void tst_GlobalTypes();
+int tst_QtVersion();
+const char *tst_qVersion();
+}
+
+void tst_QGlobal::cMode()
+{
+ tst_GlobalTypes();
+ QCOMPARE(tst_QtVersion(), QT_VERSION);
+
+#ifndef QT_NAMESPACE
+ QCOMPARE(tst_qVersion(), qVersion());
+#endif
+}
+
void tst_QGlobal::qIsNull()
{
double d = 0.0;