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:
parent
ef7c0594bf
commit
0ac2dca977
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
111
tests/auto/corelib/global/qglobal/qglobal.c
Normal file
111
tests/auto/corelib/global/qglobal/qglobal.c
Normal 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
CONFIG += testcase
|
||||
TARGET = tst_qglobal
|
||||
QT = core testlib
|
||||
SOURCES = tst_qglobal.cpp
|
||||
SOURCES = tst_qglobal.cpp qglobal.c
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user