From: Anders Carlsson Date: Sat, 29 Jan 2011 03:52:01 +0000 (+0000) Subject: When calling a virtual member function on a base class and the most derived class... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1679f5a84ae1e578b0de347c89eaf31e0465f33c;p=clang When calling a virtual member function on a base class and the most derived class is marked 'final', we can devirtualize the call. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124524 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 03b90e2587..fa6ac5469f 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -53,16 +53,39 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, Callee, ReturnValue, Args, MD); } +static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { + QualType DerivedType = Base->IgnoreParenCasts()->getType(); + if (const PointerType *PTy = DerivedType->getAs()) + DerivedType = PTy->getPointeeType(); + + return cast(DerivedType->castAs()->getDecl()); +} + /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, const Expr *Base, const CXXMethodDecl *MD) { - // Cannot divirtualize in kext mode. + // When building with -fapple-kext, all calls must go through the vtable since + // the kernel linker can do runtime patching of vtables. if (Context.getLangOptions().AppleKext) return false; + // If the most derived class is marked final, we know that no subclass can + // override this member function and so we can devirtualize it. For example: + // + // struct A { virtual void f(); } + // struct B final : A { }; + // + // void f(B *b) { + // b->f(); + // } + // + const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base); + if (MostDerivedClassDecl->hasAttr()) + return true; + // If the member function is marked 'final', we know that it can't be // overridden and can therefore devirtualize it. if (MD->hasAttr()) diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp index f6f2a49133..08a94903d5 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -23,3 +23,17 @@ namespace Test2 { return a->f(); } } + +namespace Test3 { + struct A { + virtual int f(); + }; + + struct B final : A { }; + + // CHECK: define i32 @_ZN5Test31fEPNS_1BE + int f(B *b) { + // CHECK: call i32 @_ZN5Test31A1fEv + return b->f(); + } +}