From fcb57391f73d36914e10ba964dbd9b01fe6f3af2 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Tue, 4 Feb 2025 15:19:31 +0100 Subject: [PATCH] QtGlobal: introduce a helper macro for declaring the RO5 SMFs as defaulted If a class honors the RO0 we usually just leave a comment in the class' body, and don't explicitly redeclare any of the RO5 special member functions. In some cases we may need to redeclare (some of) them. The main use-case so far is to declare a protected destructor for a base class that is not polymorphic, in order to prevent slicing; the compiler-provided destructor is always public. We can easily declare and default such a protected destructor, but that comes with the problem that now we're violating the RO5 (as far as C++ is concerned, declaring a SMF counts towards the RO5, even if it's immediately defaulted). Specifically: by declaring the destructor, the class loses the compiler-generated move operations, and the copy operations are generated but deprecated. Clang >= 18 warns about this. In such a scenario we *must* redeclare all five SMFs... and default them all. This is boilerplate, therefore I'm adding a macro to streamline it. Apply the new macro to a couple of cases were manual refactoring has already been done. Pick-to: 6.9 6.8 6.5 Change-Id: I5dc0ff9770621fbec0b1057c164d0623f901e3e9 Reviewed-by: Marc Mutz Reviewed-by: Thiago Macieira --- src/corelib/global/qtclasshelpermacros.h | 25 ++++++++++++++++++++++++ src/corelib/global/qxpfunctional.h | 6 +----- src/corelib/tools/qlist.h | 12 ++---------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h index a608b11fb99..5b0a67b4eae 100644 --- a/src/corelib/global/qtclasshelpermacros.h +++ b/src/corelib/global/qtclasshelpermacros.h @@ -83,6 +83,31 @@ QT_BEGIN_NAMESPACE return *this; \ } +/* + This macro defines the RO5 special member functions (destructor, + copy+move constructors and assignment operators) as defaulted. + + Normally we don't use this macro if we're fine with these functions + to be public; we instead leave a comment in the class declaration, + something like: + + // compiler-generated special member functions are fine! + + In some cases a class may need to redeclare these functions, for + instance if it wants to change their accessibility. Since + defaulting all five is boilerplate, use this macro instead. + + Note that the default constructor is not covered, and this macro + will prevented its automatic generation. +*/ + +#define QT_DECLARE_RO5_SMF_AS_DEFAULTED(Class) \ + ~Class() = default; \ + Class(const Class &) = default; \ + Class(Class &&) = default; \ + Class &operator=(const Class &) = default; \ + Class &operator=(Class &&) = default; + /* These macros can be used to define tag structs in the preferred way (ie. with explicit default ctor). diff --git a/src/corelib/global/qxpfunctional.h b/src/corelib/global/qxpfunctional.h index 320ca5417c8..2dd7de669d0 100644 --- a/src/corelib/global/qxpfunctional.h +++ b/src/corelib/global/qxpfunctional.h @@ -72,11 +72,7 @@ template class function_ref_base { protected: - ~function_ref_base() = default; - function_ref_base(const function_ref_base &) = default; - function_ref_base(function_ref_base &&) = default; - function_ref_base &operator=(const function_ref_base &) = default; - function_ref_base &operator=(function_ref_base &&) = default; + QT_DECLARE_RO5_SMF_AS_DEFAULTED(function_ref_base) using BoundEntityType = detail::BoundEntityType; diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index c9b931e420a..eac3fce608a 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -32,11 +32,7 @@ template struct QListSpecialMethodsBase { protected: QListSpecialMethodsBase() = default; - ~QListSpecialMethodsBase() = default; - QListSpecialMethodsBase(const QListSpecialMethodsBase &) = default; - QListSpecialMethodsBase(QListSpecialMethodsBase &&) = default; - QListSpecialMethodsBase &operator=(const QListSpecialMethodsBase &) = default; - QListSpecialMethodsBase &operator=(QListSpecialMethodsBase &&) = default; + QT_DECLARE_RO5_SMF_AS_DEFAULTED(QListSpecialMethodsBase) using Self = QList; Self *self() { return static_cast(this); } @@ -58,11 +54,7 @@ template struct QListSpecialMethods : QListSpecialMethodsBase { protected: QListSpecialMethods() = default; - ~QListSpecialMethods() = default; - QListSpecialMethods(const QListSpecialMethods &) = default; - QListSpecialMethods(QListSpecialMethods &&) = default; - QListSpecialMethods &operator=(const QListSpecialMethods &) = default; - QListSpecialMethods &operator=(QListSpecialMethods &&) = default; + QT_DECLARE_RO5_SMF_AS_DEFAULTED(QListSpecialMethods) public: using QListSpecialMethodsBase::indexOf;