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>
This commit is contained in:
Thiago Macieira 2017-11-05 17:54:35 -08:00
parent ef7c0594bf
commit 0ac2dca977
5 changed files with 185 additions and 27 deletions

View File

@ -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)

View File

@ -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>
@ -687,11 +714,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() Q_DECL_NOTHROW;
# define Q_INLINE_TEMPLATE inline
#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();

View File

@ -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

View File

@ -1,4 +1,4 @@
CONFIG += testcase
TARGET = tst_qglobal
QT = core testlib
SOURCES = tst_qglobal.cpp
SOURCES = tst_qglobal.cpp qglobal.c

View File

@ -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;