Short live Q_NODISCARD_CTOR

[ChangeLog][QtCore] Introduced Q_NODISCARD_CTOR which resolves to
[[nodiscard]] attribute for constructors on compilers that support
it, and does nothing on other compilers.

Using [[nodiscard]] attribute on a constructor is a C++20 feature,
however in practice it is supported on most of the compilers that
we use in Qt 6. Clang generates a [-Wunused-value] warning, GCC
and MinGW generate a [-Wunused-result] warnings, and MSVC
generates a C4834 warning.
However, there are some exceptions.

The Integrity compiler provides the following warning:
 "tst_qglobal.cpp", line 699: warning #3435-D:
           the "nodiscard" attribute doesn't apply to constructors,
           destructors, or routines with void return type
           [[nodiscard]] explicit Test(int val) : m_val(val) {}

The QNX compiler (QCC 8.3.0) and GCC 9.3.1 on OpenSUSE generate
the [-Wattributes] warning:
 tst_qglobal.cpp: In member function
   'void tst_QGlobal::nodiscardConstructor()':
 tst_qglobal.cpp:699:44: warning: 'nodiscard' attribute applied to
   'tst_QGlobal::nodiscardConstructor()::Test::Test(int)' with void
    return type [-Wattributes]
          [[nodiscard]] explicit Test(int val) : m_val(val) {}

These warnings will lead to build failures when compiled with
-warnings-are-errors flag, so for these compilers the macro
does not do anything.

An attempt to use __attribute__((__warn_unused_result__)) was
also unsuccessful on these compilers, so this patch goes for
an easy solution, and simply checks
 __has_cpp_attribute(nodiscard) >= 201907L
to decide if the attribute is supported or not.

This commit also introduces a syntax-only test, and also applies
the new macro to QMutexLocker, because not all platforms in the
CI build and run unit tests.

Fixes: QTBUG-104161
Change-Id: Ib4230661a5ad5e8af0d67b21b034486ebcd67562
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2023-04-06 13:00:25 +02:00
parent d3b3fc538b
commit 959800f6de
3 changed files with 33 additions and 0 deletions

View File

@ -970,6 +970,15 @@
#define Q_DECL_ENUMERATOR_DEPRECATED Q_DECL_DEPRECATED #define Q_DECL_ENUMERATOR_DEPRECATED Q_DECL_DEPRECATED
#define Q_DECL_ENUMERATOR_DEPRECATED_X(x) Q_DECL_DEPRECATED_X(x) #define Q_DECL_ENUMERATOR_DEPRECATED_X(x) Q_DECL_DEPRECATED_X(x)
// [[nodiscard]] constructor
#ifndef Q_NODISCARD_CTOR
# if __has_cpp_attribute(nodiscard) >= 201907L
# define Q_NODISCARD_CTOR [[nodiscard]]
# else
# define Q_NODISCARD_CTOR
# endif
#endif
/* /*
* Fallback macros to certain compiler features * Fallback macros to certain compiler features
*/ */

View File

@ -231,6 +231,7 @@ template <typename Mutex>
class [[nodiscard]] QMutexLocker class [[nodiscard]] QMutexLocker
{ {
public: public:
Q_NODISCARD_CTOR
inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT
{ {
m_mutex = mutex; m_mutex = mutex;
@ -240,6 +241,7 @@ public:
} }
} }
Q_NODISCARD_CTOR
inline QMutexLocker(QMutexLocker &&other) noexcept inline QMutexLocker(QMutexLocker &&other) noexcept
: m_mutex(std::exchange(other.m_mutex, nullptr)), : m_mutex(std::exchange(other.m_mutex, nullptr)),
m_isLocked(std::exchange(other.m_isLocked, false)) m_isLocked(std::exchange(other.m_isLocked, false))
@ -326,6 +328,7 @@ template <typename Mutex>
class [[nodiscard]] QMutexLocker class [[nodiscard]] QMutexLocker
{ {
public: public:
Q_NODISCARD_CTOR
inline explicit QMutexLocker(Mutex *) noexcept {} inline explicit QMutexLocker(Mutex *) noexcept {}
inline ~QMutexLocker() noexcept {} inline ~QMutexLocker() noexcept {}

View File

@ -37,6 +37,7 @@ private slots:
void qRoundDoubles(); void qRoundDoubles();
void PRImacros(); void PRImacros();
void testqToUnderlying(); void testqToUnderlying();
void nodiscardConstructor();
}; };
extern "C" { // functions in qglobal.c extern "C" { // functions in qglobal.c
@ -691,5 +692,25 @@ void tst_QGlobal::testqToUnderlying()
QCOMPARE(qToUnderlying(EE2), 456UL); QCOMPARE(qToUnderlying(EE2), 456UL);
} }
void tst_QGlobal::nodiscardConstructor()
{
// Syntax-only test, just to make sure that Q_NODISCARD_CTOR compiles
// on all platforms.
// Other code is just to silence all various compiler warnings about
// unused private members or methods.
class Test {
public:
Q_NODISCARD_CTOR explicit Test(int val) : m_val(val) {}
int get() const { return m_val; }
private:
int m_val;
};
Test t{42};
QCOMPARE(t.get(), 42);
}
QTEST_APPLESS_MAIN(tst_QGlobal) QTEST_APPLESS_MAIN(tst_QGlobal)
#include "tst_qglobal.moc" #include "tst_qglobal.moc"