From 82015992c853b50dac167da26b8b858ac4794c66 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 21 May 2025 13:14:20 +0200 Subject: [PATCH] tst_QScopedPointer: add a test for reset/delete ordering We have implementation divergence with libc++'s ~unique_ptr() behavior, so make sure QScopedPointer behaves the same way as unique_ptr is spec'ed, even though to check it, one has to rely on UB, at least according to LLVM devs (I don't think the test as written invokes UB). Code's a bit duplicated. I tried making the struct a template, but it's just too much of a fuss (needs a variable template, which we can't use in Qt 5), so I decided to use cut'n'paste. Task-number: QTBUG-137069 Pick-to: 6.9 6.8 6.5 5.15 Change-Id: I8b55718eaf3c6ad9a4d89d4fc9d64f0c41bb21fa Reviewed-by: Ahmad Samir --- .../qscopedpointer/tst_qscopedpointer.cpp | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp index 3468c97f429..97ce0271634 100644 --- a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp +++ b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp @@ -4,6 +4,8 @@ #include #include +#include + /*! \class tst_QScopedPointer \internal @@ -22,6 +24,7 @@ private Q_SLOTS: void dataOnValue(); void dataSignature(); void reset(); + void resetDeleteOrdering(); void dereferenceOperator(); void dereferenceOperatorSignature(); void pointerOperator(); @@ -127,6 +130,85 @@ void tst_QScopedPointer::reset() } } +void tst_QScopedPointer::resetDeleteOrdering() +{ + { + struct CheckingDeleter; + using SP = QScopedPointer; + static const SP *instance = nullptr; // QScopedPointer does not handle stateful deleters + static const int *expected = nullptr; + + struct CheckingDeleter { + static void cleanup(int *p) + { + const auto *value = instance->get(); + std::unique_ptr deleter(p); + QT_TRY { QCOMPARE(value, expected); } QT_CATCH(...) {} // eat QTest failure exception, if any + } + void operator()(int *p) { cleanup(p); } + }; + + // reset() + { + SP p(new int{42}); + instance = &p; + expected = nullptr; + p.reset(); + } + if (QTest::currentTestFailed()) + return; + // destructor + { + SP p(new int{48}); + instance = &p; + expected = p.get(); // inconsistent with reset(), but consistent with unique_ptr + } + if (QTest::currentTestFailed()) + return; + } + + // comparison with unique_ptr: + { + struct CheckingDeleter; + using UP = std::unique_ptr; + // unique_ptr handles stateful deleters, but be consistent with QScopedPointer test + static const UP *instance = nullptr; + static const int *expected = nullptr; + + struct CheckingDeleter { + void operator()(int *p) const + { + const auto *value = instance->get(); + std::unique_ptr deleter(p); + QT_TRY { QCOMPARE(value, expected); } QT_CATCH(...) {} // eat QTest failure exception, if any + } + }; + + // reset() + { + UP p(new int{42}); + instance = &p; + expected = nullptr; // https://eel.is/c++draft/unique.ptr#single.modifiers-3 ... 5 + p.reset(); + } + if (QTest::currentTestFailed()) + return; + // destructor +#ifdef Q_STL_LIBCPP + // This would fail on libc++ https://github.com/llvm/llvm-project/issues/108149 + if (false) +#endif + { + UP p(new int{48}); + instance = &p; + expected = p.get(); // https://eel.is/c++draft/unique.ptr#single.dtor + } + if (QTest::currentTestFailed()) + return; + + } +} + class AbstractClass { public: