diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -187,9 +187,20 @@ IntrusiveRefCntPtr InnerMatcher; }; +// Use a custom deleter for the TrueMatcherInstance ManagedStatic. This prevents +// an assert firing when the refcount is nonzero while running its destructor. +struct DynMatcherInterfaceDeleter { + static void call(void *Ptr) { + static_cast(Ptr)->Release(); + } +}; + } // namespace -static llvm::ManagedStatic TrueMatcherInstance; +static llvm::ManagedStatic, + DynMatcherInterfaceDeleter> + TrueMatcherInstance; bool ASTMatchFinder::isTraversalIgnoringImplicitNodes() const { return getASTContext().getParentMapContext().getTraversalKind() == diff --git a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h --- a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h +++ b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h @@ -70,10 +70,27 @@ template class RefCountedBase { mutable unsigned RefCount = 0; -public: +protected: RefCountedBase() = default; + // Copy and move constructors/assignments are no-ops as the RefCount isn't + // dictated by the class directly. RefCountedBase(const RefCountedBase &) {} + RefCountedBase(RefCountedBase &&) {} + RefCountedBase &operator=(const RefCountedBase &) { return *this; } + RefCountedBase &operator=(RefCountedBase &&) { return *this; } + +#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 { @@ -85,10 +102,29 @@ /// A thread-safe version of \c RefCountedBase. template class ThreadSafeRefCountedBase { - mutable std::atomic RefCount; + mutable std::atomic RefCount{0}; protected: - ThreadSafeRefCountedBase() : RefCount(0) {} + ThreadSafeRefCountedBase() = default; + ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {} + ThreadSafeRefCountedBase(ThreadSafeRefCountedBase &&) {} + ThreadSafeRefCountedBase &operator=(const ThreadSafeRefCountedBase &) { + return *this; + } + ThreadSafeRefCountedBase &operator=(ThreadSafeRefCountedBase &&) { + return *this; + } + +#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); }