summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/DeclCXX.cpp9
-rw-r--r--clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp15
2 files changed, 21 insertions, 3 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 59710a55498..4939c37edc7 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2067,10 +2067,15 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
if (DevirtualizedMethod->hasAttr<FinalAttr>())
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<FinalAttr>())
return DevirtualizedMethod;
+ if (const auto *dtor = BestDynamicDecl->getDestructor()) {
+ if (dtor->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+ }
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
index 2ab2f759cfe..130103de97a 100644
--- a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -24,11 +24,24 @@ namespace Test2 {
}
}
-namespace Test3 {
+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(); };
+
struct B final : A { };
// CHECK-LABEL: define i32 @_ZN5Test31fEPNS_1BE
OpenPOWER on IntegriCloud