njames93 updated this revision to Diff 309512. njames93 added a comment. Made ManagedStatic code transparent to users for RefCounted objects.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D92480/new/ https://reviews.llvm.org/D92480 Files: clang/lib/ASTMatchers/ASTMatchersInternal.cpp llvm/include/llvm/ADT/IntrusiveRefCntPtr.h llvm/include/llvm/Support/ManagedStatic.h
Index: llvm/include/llvm/Support/ManagedStatic.h =================================================================== --- llvm/include/llvm/Support/ManagedStatic.h +++ llvm/include/llvm/Support/ManagedStatic.h @@ -15,21 +15,79 @@ #include <atomic> #include <cstddef> +#include <type_traits> namespace llvm { +namespace detail { +// Helper struct to detect classes that has Retain and Release member functions +// that are const with no params. +template <typename T> struct HasRetainRelease { +private: + template <typename U> + static constexpr decltype(std::declval<U const>().Retain(), + std::declval<U const>().Release(), bool()) + test(int) { + return true; + } + + template <typename U> static constexpr bool test(...) { return false; } + +public: + static constexpr bool Value = test<T>(int()); +}; + +template <typename T> +std::enable_if_t<!HasRetainRelease<T>::Value, void *> createObject() { + return new T(); +} + +template <typename T> +std::enable_if_t<HasRetainRelease<T>::Value, void *> createObject() { + T *Ptr = new T(); + Ptr->Retain(); + return Ptr; +} + +template <typename T> +std::enable_if_t<!HasRetainRelease<T>::Value> deleteObject(T *Ptr) { + delete Ptr; +} + +template <typename T> +std::enable_if_t<HasRetainRelease<T>::Value> deleteObject(T *Ptr) { + Ptr->Release(); +} + +template <typename T, size_t N> +std::enable_if_t<!HasRetainRelease<T>::Value> deleteObject(T *Ptr) { + delete[] Ptr; +} + +template <typename T, size_t N> +std::enable_if_t<HasRetainRelease<T>::Value> deleteObject(T *Ptr) { + for (auto I = Ptr, E = I + N; I != E; ++I) + I->Release(); +} +} // namespace detail + /// object_creator - Helper method for ManagedStatic. -template <class C> struct object_creator { - static void *call() { return new C(); } + +template <typename T> struct object_creator { + static void *call() { return detail::createObject<T>(); } }; /// object_deleter - Helper method for ManagedStatic. -/// template <typename T> struct object_deleter { - static void call(void *Ptr) { delete (T *)Ptr; } + static void call(void *Ptr) { + return detail::deleteObject(static_cast<T *>(Ptr)); + } }; + template <typename T, size_t N> struct object_deleter<T[N]> { - static void call(void *Ptr) { delete[](T *)Ptr; } + static void call(void *Ptr) { + return detail::deleteObject<T, N>(static_cast<T *>(Ptr)); + } }; // ManagedStatic must be initialized to zero, and it must *not* have a dynamic Index: llvm/include/llvm/ADT/IntrusiveRefCntPtr.h =================================================================== --- llvm/include/llvm/ADT/IntrusiveRefCntPtr.h +++ llvm/include/llvm/ADT/IntrusiveRefCntPtr.h @@ -70,11 +70,23 @@ template <class Derived> class RefCountedBase { mutable unsigned RefCount = 0; -public: +protected: RefCountedBase() = default; RefCountedBase(const RefCountedBase &) {} RefCountedBase &operator=(const RefCountedBase &) = delete; +#ifndef NDEBUG + ~RefCountedBase() { + assert(RefCount == 0 && + "Destruction occured when there are still references to this."); + } +#else + // Default the destructor in release builds, A trivial destructor may enable + // better codegen. + ~RefCountedBase() = default; +#endif + +public: void Retain() const { ++RefCount; } void Release() const { @@ -94,6 +106,17 @@ ThreadSafeRefCountedBase & operator=(const ThreadSafeRefCountedBase &) = delete; +#ifndef NDEBUG + ~ThreadSafeRefCountedBase() { + assert(RefCount == 0 && + "Destruction occured when there are still references to this."); + } +#else + // Default the destructor in release builds, A trivial destructor may enable + // better codegen. + ~ThreadSafeRefCountedBase() = default; +#endif + public: void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -156,9 +156,7 @@ /// of cache hits. class TrueMatcherImpl : public DynMatcherInterface { public: - TrueMatcherImpl() { - Retain(); // Reference count will never become zero. - } + TrueMatcherImpl() = default; bool dynMatches(const DynTypedNode &, ASTMatchFinder *, BoundNodesTreeBuilder *) const override { @@ -191,6 +189,9 @@ IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; }; +// Use a custom deleter for the TrueMatcherInstance ManagedStatic. This prevents +// an assert firing when the refcount is nonzero while running its destructor. + } // namespace static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits