summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qtaggedpointer.h
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2022-08-30 16:02:22 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2022-09-29 16:18:55 +0200
commit42b66bd809f0cadf232cd8527746b55cd00d9f10 (patch)
tree622136468df0b8dcf8e6912d9f0e988a7a147c5c /src/corelib/tools/qtaggedpointer.h
parent11a9af6484fc34b6b8fd166292b16229ed808c6b (diff)
QTaggedPointer: disable operator= with an empty initializer list
Given a QTaggedPointer, users may write taggedPtr = {}; to mean "reset it". This is error-prone: due to overload resolution, this actually ends up calling QTaggedPointer<T>::operator=(T *), which changes the pointer but *not* the tag, and not the implicitly declared QTaggedPointer<T>:operator=(const QTaggedPointer<T> &) which would reset both pointer and tag. Given the idiomatic usage of {} is indeed to perform a full reset (cf. std::exchange(obj, {}), std::take, etc.), work around this by disabling the operator= overload for pointers in case an initializer list is passed. In other words, make `={}` fall back to the implicitly declared overload. Note, this breaks some usages, such as taggedPtr = {rawPtr}; but at least we get a compile error for these, and they don't look common at all. [ChangeLog][QtCore][QTaggedPointer] The operator assignment taking a raw pointer has been reimplemented in order to avoid subtle issues when assigning `{}` to a QTaggedPointer. This will cause code that assigns a braced-init-list to a QTaggedPointer object to stop compiling (for instance, `tagPtr = {ptr}` is now ill-formed). Change-Id: I5e572a9b0f119ddb2df17f1797934933dff2ba7b Task-number: QTBUG-106070 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/tools/qtaggedpointer.h')
-rw-r--r--src/corelib/tools/qtaggedpointer.h23
1 files changed, 21 insertions, 2 deletions
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
index 504645993a..a08912c4a5 100644
--- a/src/corelib/tools/qtaggedpointer.h
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -72,11 +72,30 @@ public:
return !isNull();
}
- QTaggedPointer &operator=(T *other) noexcept
+#ifdef Q_QDOC
+ QTaggedPointer &operator=(T *other) noexcept;
+#else
+ // Disables the usage of `ptr = {}`, which would go through this operator
+ // (rather than using the implicitly-generated assignment operator).
+ // The operators have different semantics: the ones here leave the tag intact,
+ // the implicitly-generated one overwrites it.
+ template <typename U,
+ std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
+ QTaggedPointer &operator=(U *other) noexcept
+ {
+ T *otherT = other;
+ d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
+ return *this;
+ }
+
+ template <typename U,
+ std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
+ QTaggedPointer &operator=(U) noexcept
{
- d = reinterpret_cast<quintptr>(other) | (d & tagMask());
+ d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
return *this;
}
+#endif
static constexpr Tag maximumTag() noexcept
{