From c201c5aedfcb131d2ac829346812560509904c7d Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Fri, 12 Aug 2022 16:36:54 +0200 Subject: [PATCH] Extract header qtclasshelpermacros.h Move the class helper macros from qglobal.h and Q_DECLARE_SHARED from qtypeinfo.h there. Task-number: QTBUG-99313 Change-Id: I8c8b6241a76916176a48c09fbaf4effc87683770 Reviewed-by: Edward Welbourne Reviewed-by: Oswald Buddenhagen --- src/corelib/CMakeLists.txt | 1 + src/corelib/global/qglobal.cpp | 57 -------- src/corelib/global/qglobal.h | 105 +------------- src/corelib/global/qtclasshelpermacros.h | 144 ++++++++++++++++++++ src/corelib/global/qtclasshelpermacros.qdoc | 59 ++++++++ src/corelib/global/qtypeinfo.h | 17 --- 6 files changed, 205 insertions(+), 178 deletions(-) create mode 100644 src/corelib/global/qtclasshelpermacros.h create mode 100644 src/corelib/global/qtclasshelpermacros.qdoc diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index b0af8067100..faaa0ff0210 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -74,6 +74,7 @@ qt_internal_add_module(Core global/qrandom.cpp global/qrandom.h global/qrandom_p.h global/qsysinfo.h global/qsystemdetection.h + global/qtclasshelpermacros.h global/qtconfigmacros.h global/qtdeprecationmarkers.h global/qtrace_p.h diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index de28cd87af5..5d9660830ef 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -511,63 +511,6 @@ using namespace Qt::StringLiterals; (bitmask). */ -/*! - \macro Q_DISABLE_COPY(Class) - \relates QObject - - Disables the use of copy constructors and assignment operators - for the given \a Class. - - Instances of subclasses of QObject should not be thought of as - values that can be copied or assigned, but as unique identities. - This means that when you create your own subclass of QObject - (director or indirect), you should \e not give it a copy constructor - or an assignment operator. However, it may not enough to simply - omit them from your class, because, if you mistakenly write some code - that requires a copy constructor or an assignment operator (it's easy - to do), your compiler will thoughtfully create it for you. You must - do more. - - The curious user will have seen that the Qt classes derived - from QObject typically include this macro in a private section: - - \snippet code/src_corelib_global_qglobal.cpp 43 - - It declares a copy constructor and an assignment operator in the - private section, so that if you use them by mistake, the compiler - will report an error. - - \snippet code/src_corelib_global_qglobal.cpp 44 - - But even this might not catch absolutely every case. You might be - tempted to do something like this: - - \snippet code/src_corelib_global_qglobal.cpp 45 - - First of all, don't do that. Most compilers will generate code that - uses the copy constructor, so the privacy violation error will be - reported, but your C++ compiler is not required to generate code for - this statement in a specific way. It could generate code using - \e{neither} the copy constructor \e{nor} the assignment operator we - made private. In that case, no error would be reported, but your - application would probably crash when you called a member function - of \c{w}. - - \sa Q_DISABLE_COPY_MOVE -*/ - -/*! - \macro Q_DISABLE_COPY_MOVE(Class) - \relates QObject - - A convenience macro that disables the use of copy constructors, assignment - operators, move constructors and move assignment operators for the given - \a Class. - - \sa Q_DISABLE_COPY - \since 5.13 -*/ - /*! \macro Q_DECLARE_FLAGS(Flags, Enum) \relates QFlags diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 13452bf22ab..4329f9f0934 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -46,6 +46,7 @@ inline void qt_noop(void) {} #include #include +#include /* Avoid "unused parameter" warnings @@ -55,65 +56,6 @@ inline void qt_noop(void) {} #ifndef __ASSEMBLER__ QT_BEGIN_NAMESPACE -/* - Some classes do not permit copies to be made of an object. These - classes contains a private copy constructor and assignment - operator to disable copying (the compiler gives an error message). -*/ -#define Q_DISABLE_COPY(Class) \ - Class(const Class &) = delete;\ - Class &operator=(const Class &) = delete; - -#define Q_DISABLE_COPY_MOVE(Class) \ - Q_DISABLE_COPY(Class) \ - Class(Class &&) = delete; \ - Class &operator=(Class &&) = delete; - -/* - Implementing a move assignment operator using an established - technique (move-and-swap, pure swap) is just boilerplate. - Here's a couple of *private* macros for convenience. - - To know which one to use: - - * if you don't have a move constructor (*) => use pure swap; - * if you have a move constructor, then - * if your class holds just memory (no file handles, no user-defined - datatypes, etc.) => use pure swap; - * use move and swap. - - The preference should always go for the move-and-swap one, as it - will deterministically destroy the data previously held in *this, - and not "dump" it in the moved-from object (which may then be alive - for longer). - - The requirement for either macro is the presence of a member swap(), - which any value class that defines its own special member functions - should have anyhow. - - (*) Many value classes in Qt do not have move constructors; mostly, - the implicitly shared classes using QSharedDataPointer and friends. - The reason is mostly historical: those classes require either an - out-of-line move constructor, which we could not provide before we - made C++11 mandatory (and that we don't like anyhow), or - an out-of-line dtor for the Q(E)DSP member (cf. QPixmap). - - If you can however add a move constructor to a class lacking it, - consider doing so, then reevaluate which macro to choose. -*/ -#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Class) \ - Class &operator=(Class &&other) noexcept { \ - Class moved(std::move(other)); \ - swap(moved); \ - return *this; \ - } - -#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class) \ - Class &operator=(Class &&other) noexcept { \ - swap(other); \ - return *this; \ - } - /* No, this is not an evil backdoor. QT_BUILD_INTERNAL just exports more symbols for Qt's internal unit tests. If you want slower loading times and more @@ -244,26 +186,6 @@ typedef void (*QFunctionPointer)(); # define Q_UNIMPLEMENTED() qWarning("Unimplemented code.") #endif -/* - Compilers which follow outdated template instantiation rules - require a class to have a comparison operator to exist when - a QList of this type is instantiated. It's not actually - used in the list, though. Hence the dummy implementation. - Just in case other code relies on it we better trigger a warning - mandating a real implementation. -*/ - -#ifdef Q_FULL_TEMPLATE_INSTANTIATION -# define Q_DUMMY_COMPARISON_OPERATOR(C) \ - bool operator==(const C&) const { \ - qWarning(#C"::operator==(const "#C"&) was called"); \ - return false; \ - } -#else - -# define Q_DUMMY_COMPARISON_OPERATOR(C) -#endif - QT_WARNING_PUSH // warning: noexcept-expression evaluates to 'false' because of a call to 'void swap(..., ...)' QT_WARNING_DISABLE_GCC("-Wnoexcept") @@ -328,33 +250,8 @@ constexpr std::underlying_type_t qToUnderlying(Enum e) noexcept return static_cast>(e); } -template inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; } -template inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get()) -{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); } - // The body must be a statement: #define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP -#define Q_DECLARE_PRIVATE(Class) \ - inline Class##Private* d_func() noexcept \ - { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ - inline const Class##Private* d_func() const noexcept \ - { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ - friend class Class##Private; - -#define Q_DECLARE_PRIVATE_D(Dptr, Class) \ - inline Class##Private* d_func() noexcept \ - { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(Dptr));) } \ - inline const Class##Private* d_func() const noexcept \ - { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(Dptr));) } \ - friend class Class##Private; - -#define Q_DECLARE_PUBLIC(Class) \ - inline Class* q_func() noexcept { return static_cast(q_ptr); } \ - inline const Class* q_func() const noexcept { return static_cast(q_ptr); } \ - friend class Class; - -#define Q_D(Class) Class##Private * const d = d_func() -#define Q_Q(Class) Class * const q = q_func() #define QT_MODULE(x) diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h new file mode 100644 index 00000000000..3c594049108 --- /dev/null +++ b/src/corelib/global/qtclasshelpermacros.h @@ -0,0 +1,144 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTCLASSHELPERMACROS_H +#define QTCLASSHELPERMACROS_H + +#include + +#if 0 +#pragma qt_class(QtClassHelperMacros) +#pragma qt_sync_stop_processing +#endif + +QT_BEGIN_NAMESPACE + +#if defined(__cplusplus) + +/* + Some classes do not permit copies to be made of an object. These + classes contains a private copy constructor and assignment + operator to disable copying (the compiler gives an error message). +*/ +#define Q_DISABLE_COPY(Class) \ + Class(const Class &) = delete;\ + Class &operator=(const Class &) = delete; + +#define Q_DISABLE_COPY_MOVE(Class) \ + Q_DISABLE_COPY(Class) \ + Class(Class &&) = delete; \ + Class &operator=(Class &&) = delete; + +/* + Implementing a move assignment operator using an established + technique (move-and-swap, pure swap) is just boilerplate. + Here's a couple of *private* macros for convenience. + + To know which one to use: + + * if you don't have a move constructor (*) => use pure swap; + * if you have a move constructor, then + * if your class holds just memory (no file handles, no user-defined + datatypes, etc.) => use pure swap; + * use move and swap. + + The preference should always go for the move-and-swap one, as it + will deterministically destroy the data previously held in *this, + and not "dump" it in the moved-from object (which may then be alive + for longer). + + The requirement for either macro is the presence of a member swap(), + which any value class that defines its own special member functions + should have anyhow. + + (*) Many value classes in Qt do not have move constructors; mostly, + the implicitly shared classes using QSharedDataPointer and friends. + The reason is mostly historical: those classes require either an + out-of-line move constructor, which we could not provide before we + made C++11 mandatory (and that we don't like anyhow), or + an out-of-line dtor for the Q(E)DSP member (cf. QPixmap). + + If you can however add a move constructor to a class lacking it, + consider doing so, then reevaluate which macro to choose. +*/ +#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Class) \ + Class &operator=(Class &&other) noexcept { \ + Class moved(std::move(other)); \ + swap(moved); \ + return *this; \ + } + +#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class) \ + Class &operator=(Class &&other) noexcept { \ + swap(other); \ + return *this; \ + } + +template inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; } +template inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get()) +{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); } + +#define Q_DECLARE_PRIVATE(Class) \ + inline Class##Private* d_func() noexcept \ + { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ + inline const Class##Private* d_func() const noexcept \ + { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ + friend class Class##Private; + +#define Q_DECLARE_PRIVATE_D(Dptr, Class) \ + inline Class##Private* d_func() noexcept \ + { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(Dptr));) } \ + inline const Class##Private* d_func() const noexcept \ + { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(Dptr));) } \ + friend class Class##Private; + +#define Q_DECLARE_PUBLIC(Class) \ + inline Class* q_func() noexcept { return static_cast(q_ptr); } \ + inline const Class* q_func() const noexcept { return static_cast(q_ptr); } \ + friend class Class; + +#define Q_D(Class) Class##Private * const d = d_func() +#define Q_Q(Class) Class * const q = q_func() + +/* + Compilers which follow outdated template instantiation rules + require a class to have a comparison operator to exist when + a QList of this type is instantiated. It's not actually + used in the list, though. Hence the dummy implementation. + Just in case other code relies on it we better trigger a warning + mandating a real implementation. +*/ + +#ifdef Q_FULL_TEMPLATE_INSTANTIATION +# define Q_DUMMY_COMPARISON_OPERATOR(C) \ + bool operator==(const C&) const { \ + qWarning(#C"::operator==(const "#C"&) was called"); \ + return false; \ + } +#else + +# define Q_DUMMY_COMPARISON_OPERATOR(C) +#endif + +/* + Specialize a shared type with: + + Q_DECLARE_SHARED(type) + + where 'type' is the name of the type to specialize. NOTE: shared + types must define a member-swap, and be defined in the same + namespace as Qt for this to work. +*/ + +#define Q_DECLARE_SHARED_IMPL(TYPE, FLAGS) \ +Q_DECLARE_TYPEINFO(TYPE, FLAGS); \ +inline void swap(TYPE &value1, TYPE &value2) \ + noexcept(noexcept(value1.swap(value2))) \ +{ value1.swap(value2); } +#define Q_DECLARE_SHARED(TYPE) Q_DECLARE_SHARED_IMPL(TYPE, Q_RELOCATABLE_TYPE) + +#endif // __cplusplus + +QT_END_NAMESPACE + +#endif // QTCLASSHELPERMACROS_H diff --git a/src/corelib/global/qtclasshelpermacros.qdoc b/src/corelib/global/qtclasshelpermacros.qdoc new file mode 100644 index 00000000000..50c8f6e8d93 --- /dev/null +++ b/src/corelib/global/qtclasshelpermacros.qdoc @@ -0,0 +1,59 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \macro Q_DISABLE_COPY(Class) + \relates QtClassHelperMacros + + Disables the use of copy constructors and assignment operators + for the given \a Class. + + Instances of subclasses of QObject should not be thought of as + values that can be copied or assigned, but as unique identities. + This means that when you create your own subclass of QObject + (director or indirect), you should \e not give it a copy constructor + or an assignment operator. However, it may not enough to simply + omit them from your class, because, if you mistakenly write some code + that requires a copy constructor or an assignment operator (it's easy + to do), your compiler will thoughtfully create it for you. You must + do more. + + The curious user will have seen that the Qt classes derived + from QObject typically include this macro in a private section: + + \snippet code/src_corelib_global_qglobal.cpp 43 + + It declares a copy constructor and an assignment operator in the + private section, so that if you use them by mistake, the compiler + will report an error. + + \snippet code/src_corelib_global_qglobal.cpp 44 + + But even this might not catch absolutely every case. You might be + tempted to do something like this: + + \snippet code/src_corelib_global_qglobal.cpp 45 + + First of all, don't do that. Most compilers will generate code that + uses the copy constructor, so the privacy violation error will be + reported, but your C++ compiler is not required to generate code for + this statement in a specific way. It could generate code using + \e{neither} the copy constructor \e{nor} the assignment operator we + made private. In that case, no error would be reported, but your + application would probably crash when you called a member function + of \c{w}. + + \sa Q_DISABLE_COPY_MOVE +*/ + +/*! + \macro Q_DISABLE_COPY_MOVE(Class) + \relates QtClassHelperMacros + + A convenience macro that disables the use of copy constructors, assignment + operators, move constructors and move assignment operators for the given + \a Class. + + \sa Q_DISABLE_COPY + \since 5.13 +*/ diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index 1938967a91a..73bf6140c7a 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -143,23 +143,6 @@ template class QFlags; template Q_DECLARE_TYPEINFO_BODY(QFlags, Q_PRIMITIVE_TYPE); -/* - Specialize a shared type with: - - Q_DECLARE_SHARED(type) - - where 'type' is the name of the type to specialize. NOTE: shared - types must define a member-swap, and be defined in the same - namespace as Qt for this to work. -*/ - -#define Q_DECLARE_SHARED_IMPL(TYPE, FLAGS) \ -Q_DECLARE_TYPEINFO(TYPE, FLAGS); \ -inline void swap(TYPE &value1, TYPE &value2) \ - noexcept(noexcept(value1.swap(value2))) \ -{ value1.swap(value2); } -#define Q_DECLARE_SHARED(TYPE) Q_DECLARE_SHARED_IMPL(TYPE, Q_RELOCATABLE_TYPE) - namespace QTypeTraits {