diff options
-rw-r--r-- | src/corelib/tools/qtaggedpointer.h | 22 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp | 28 |
2 files changed, 38 insertions, 12 deletions
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h index 7d631a5e0c..6fa1e67acb 100644 --- a/src/corelib/tools/qtaggedpointer.h +++ b/src/corelib/tools/qtaggedpointer.h @@ -73,10 +73,8 @@ namespace QtPrivate { template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType> class QTaggedPointer { - static constexpr quintptr tagMask = QtPrivate::TagInfo<T>::alignment - 1; - static constexpr quintptr pointerMask = ~tagMask; - - using TagInternalType = typename QtPrivate::TagInfo<T>::TagType; + static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; } + static constexpr quintptr pointerMask() { return ~tagMask(); } public: using Type = T; @@ -87,7 +85,7 @@ public: { Q_STATIC_ASSERT(sizeof(Type*) == sizeof(QTaggedPointer<Type>)); - Q_ASSERT_X((quintptr(pointer) & tagMask) == 0, + Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0, "QTaggedPointer<T, Tag>", "Pointer is not aligned"); setTag(tag); @@ -111,37 +109,37 @@ public: QTaggedPointer<T, Tag> &operator=(T *other) noexcept { - d = reinterpret_cast<quintptr>(other) | (d & tagMask); + d = reinterpret_cast<quintptr>(other) | (d & tagMask()); return *this; } QTaggedPointer<T, Tag> &operator=(std::nullptr_t) noexcept { - d &= tagMask; + d &= tagMask(); return *this; } static constexpr TagType maximumTag() noexcept { - return TagType(TagInternalType(tagMask)); + return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask())); } void setTag(TagType tag) { - Q_ASSERT_X((static_cast<TagInternalType>(tag) & pointerMask) == 0, + Q_ASSERT_X((static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & pointerMask()) == 0, "QTaggedPointer<T, Tag>::setTag", "Tag is larger than allowed by number of available tag bits"); - d = (d & pointerMask) | (static_cast<TagInternalType>(tag) & tagMask); + d = (d & pointerMask()) | (static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & tagMask()); } TagType tag() const noexcept { - return TagType(TagInternalType(d & tagMask)); + return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask())); } Type* pointer() const noexcept { - return reinterpret_cast<T*>(d & pointerMask); + return reinterpret_cast<T*>(d & pointerMask()); } bool isNull() const noexcept diff --git a/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp b/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp index 36308d61bc..d98a53098f 100644 --- a/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp +++ b/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp @@ -43,6 +43,7 @@ private Q_SLOTS: void tag(); void objectMember(); void customTagType(); + void taggedLinkedList(); }; void tst_QTaggedPointer::construction() @@ -396,5 +397,32 @@ void tst_QTaggedPointer::customTagType() QCOMPARE(p.tag(), Bar::FirstTag | Bar::SecondTag); } +// Compile-only test to ensure it's possible to use tagged pointers +// with incomplete types. +struct LinkedListItem +{ + enum Tag { + NoTag = 0, + FirstTag = 1 + }; + Q_DECLARE_FLAGS(Tags, Tag) + + QTaggedPointer<LinkedListItem, Tag> next; + + ~LinkedListItem() + { + delete next.pointer(); + } +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(LinkedListItem::Tags) + +void tst_QTaggedPointer::taggedLinkedList() +{ + QScopedPointer<LinkedListItem> lli(new LinkedListItem); + lli->next = QTaggedPointer<LinkedListItem, LinkedListItem::Tag>(new LinkedListItem); + lli->next.setTag(LinkedListItem::FirstTag); +} + QTEST_MAIN(tst_QTaggedPointer) #include "tst_qtaggedpointer.moc" |