Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -2067,10 +2067,15 @@ if (DevirtualizedMethod->hasAttr()) return DevirtualizedMethod; - // Similarly, if the class itself is marked 'final' it can't be overridden - // and we can therefore devirtualize the member function call. + // Similarly, if the class itself or its destructor is marked 'final', + // the class can't be derived from and we can therefore devirtualize the + // member function call. if (BestDynamicDecl->hasAttr()) return DevirtualizedMethod; + if (const auto *dtor = BestDynamicDecl->getDestructor()) { + if (dtor->hasAttr()) + return DevirtualizedMethod; + } if (const auto *DRE = dyn_cast(Base)) { if (const auto *VD = dyn_cast(DRE->getDecl())) Index: clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp =================================================================== --- clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -24,6 +24,20 @@ } } +namespace Test2a { + struct A { + virtual ~A() final {} + virtual int f(); + }; + + // CHECK-LABEL: define i32 @_ZN6Test2a1fEPNS_1AE + int f(A *a) { + // CHECK: call i32 @_ZN6Test2a1A1fEv + return a->f(); + } +} + + namespace Test3 { struct A { virtual int f();