summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2022-10-06 12:36:27 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2022-10-10 20:19:45 +0200
commitfcd294a9ec2a17b3512d03e84ae3560d7fcd3f74 (patch)
tree0af75d4c92f44194f14e3107d2b3cfcf5a34940d
parent2ef130a41d26b1b75fe402c398900a05ae381a6a (diff)
QPrivateSignal: disable implicit conversions from initializer_list
The whole point of QPrivateSignal is to forbid anyone but the class itself from emitting a certain signal. This is a "workaround" introduced in Qt 5.0, due to the fact that the PMF syntax for connections requires users to take the address of a signal, and that is only possible if the signal itself is public. (In fact, signals were protected in Qt 4.) The Q_OBJECT macro defines the private QPrivateSignal class. A QObject subclass that wants to "protect" its signal emissions can declare a signal carrying an argument of type QPrivateSignal: signals: void aSignal(int, QPrivateSignal); If the class itself wants to emit the signal, it can do so: emit aSignal(42, QPrivateSignal()); But if "someone else" wants to, they can't use the QPrivateSignal type because it's private. emit obj.aSignal(42, SomeClass::QPrivateSignal()); // ERROR Here's a hair in this soup: list initialization. If a braced-init-list is used, [over.ics.list] simply *ignores* access control. This allows an "untyped" initializer-list to match QPrivateSignal and perform aggregate initialization: emit obj.aSignal(42, {}); // works! This kind of defeats the whole purpose. Therefore: make QPrivateSignal not an aggregate and give it an explicit default constructor, disabling copy-list-initialization for it. This means that using `{}` will fail to compile (class is no longer an aggregate, a constructor must be selected, and copy-list-initialization will not select an explicit constructor). This isn't a complete fix by any means. There's always the possibility of using enough template magic to extract QPrivateSignal's type (e.g. as a local alias) and then create an object of that type; but that sounds extremely unlikely to be happening "by accident" (whilst it's super-easy to just type {} as the argument and not realize that you were not supposed to do so). [ChangeLog][QtCore][Potentially Source-Incompatible Changes] It is no longer possible to use `{}` to construct a QPrivateSignal object (specifically, QPrivateSignal's default constructor is now explicit). This means that emitting a signal that carries a QPrivateSignal argument (i.e. a "private signal") cannot any longer be done by using something like `emit aSignal({})`; instead, such usages must be ported to `emit aSignal(QPrivateSignal());` or equivalent. Change-Id: Iac379aee3a8adca5a91d5db906a61bfcd0abc89f Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/kernel/qtmetamacros.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/src/corelib/kernel/qtmetamacros.h b/src/corelib/kernel/qtmetamacros.h
index 8a880f34a5..79e3375ed5 100644
--- a/src/corelib/kernel/qtmetamacros.h
+++ b/src/corelib/kernel/qtmetamacros.h
@@ -127,7 +127,7 @@ private: \
Q_OBJECT_NO_ATTRIBUTES_WARNING \
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
QT_WARNING_POP \
- struct QPrivateSignal {}; \
+ struct QPrivateSignal { explicit QPrivateSignal() = default; }; \
QT_ANNOTATE_CLASS(qt_qobject, "")
/* qmake ignore Q_OBJECT */