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

Reply via email to