Index: tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp |
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp |
index 5c277a4aaf296da8e859781d0189b7ea3e16c12e..21ef6e3e73f46ee718ad6e16ab96ca2dbb640b18 100644 |
--- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp |
+++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp |
@@ -665,10 +665,36 @@ void BlinkGCPluginConsumer::CheckUnneededFinalization(RecordInfo* info) { |
bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) { |
CXXDestructorDecl* dtor = info->record()->getDestructor(); |
+ |
+ // If the destructor is virtual (or one of the bases are by way of the |
+ // recursive call below), consider this class as having a non-empty |
+ // finalizer. Not doing so runs counter to standard C++ reflexes like |
+ // |
+ // class A : public GarbageCollectedMixin { |
+ // public: |
+ // virtual ~A() { }; |
+ // virtual void f() = 0; |
+ // }; |
+ // class B : public GarbageCollectedFinalized<B>, public A { |
+ // USING_GARBAGE_COLLECTED_MIXIN(B); |
+ // public: |
+ // ~B() override { } |
+ // void f() override { } |
+ // }; |
+ // |
+ // and it is considered a step too far to report a warning for such |
+ // explicit usage of empty destructors. |
+ if (dtor && dtor->isVirtual()) |
+ return true; |
+ |
if (dtor && dtor->isUserProvided()) { |
if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody())) |
return true; |
} |
+ |
+ if (info->GetFinalizeDispatchMethod()) |
+ return true; |
+ |
for (auto& base : info->GetBases()) |
if (HasNonEmptyFinalizer(base.second.info())) |
return true; |