diff options
-rw-r--r-- | clang/lib/CodeGen/CGCXX.cpp | 16 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp | 18 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/virtual-function-calls.cpp | 7 |
3 files changed, 33 insertions, 8 deletions
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index af499427387..0744b79d45d 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -198,6 +198,20 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, Callee, Args, MD); } +/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given +/// expr can be devirtualized. +static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + // This is a record decl. We know the type and can devirtualize it. + return VD->getType()->isRecordType(); + } + } + + // We can't devirtualize the call. + return false; +} + RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { if (isa<BinaryOperator>(CE->getCallee())) return EmitCXXMemberPointerCallExpr(CE); @@ -235,7 +249,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { // because then we know what the type is. llvm::Value *Callee; if (MD->isVirtual() && !ME->hasQualifier() && - !ME->getBase()->getType()->isRecordType()) + !canDevirtualizeMemberFunctionCalls(ME->getBase())) Callee = BuildVirtualCall(MD, This, Ty); else if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD)) diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp new file mode 100644 index 00000000000..19206aebcef --- /dev/null +++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s + +struct A { + virtual void f(); +}; + +void f(A a, A *ap, A& ar) { + // This should not be a virtual function call. + + // CHECK: call void @_ZN1A1fEv(%struct.A* %a) + a.f(); + + // CHECK: call void % + ap->f(); + + // CHECK: call void % + ar.f(); +} diff --git a/clang/test/CodeGenCXX/virtual-function-calls.cpp b/clang/test/CodeGenCXX/virtual-function-calls.cpp index 34ab1df6896..d27a7c9bfc0 100644 --- a/clang/test/CodeGenCXX/virtual-function-calls.cpp +++ b/clang/test/CodeGenCXX/virtual-function-calls.cpp @@ -8,10 +8,3 @@ struct A { void f(A *a) { a->f('c'); } - -void f(A a) { - // This should not be a virtual function call. - - // CHECK: call void @_ZN1A1fEc - a.f('c'); -}
\ No newline at end of file |