From 632fbaa22fbed7c090eb83775731bfff786c2198 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 28 Jun 2012 01:56:38 +0000 Subject: [PATCH] Fix another issue with devirtualizing calls to final methods by passing them the correct this pointer. There is some potential for sharing a bit more code with canDevirtualizeMemberFunctionCalls, but that can be done in an independent patch. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159326 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 7 ++++ lib/AST/Expr.cpp | 38 +++++++++++-------- lib/CodeGen/CGExprCXX.cpp | 25 +++++++----- ...irtualize-virtual-function-calls-final.cpp | 26 +++++++++++++ 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 7a9cfaeebe..aedbefc5e1 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -634,6 +634,13 @@ public: /// ParenExpr or CastExprs, returning their operand. Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY; + /// Ignore parentheses and derived-to-base casts. + Expr *ignoreParenBaseCasts() LLVM_READONLY; + + const Expr *ignoreParenBaseCasts() const LLVM_READONLY { + return const_cast(this)->ignoreParenBaseCasts(); + } + /// \brief Determine whether this expression is a default function argument. /// /// Default arguments are implicitly generated in the abstract syntax tree diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 15cf6602b7..b68f864711 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -34,21 +34,7 @@ using namespace clang; const CXXRecordDecl *Expr::getBestDynamicClassType() const { - const Expr *E = this; - - while (true) { - E = E->IgnoreParens(); - if (const CastExpr *CE = dyn_cast(E)) { - if (CE->getCastKind() == CK_DerivedToBase || - CE->getCastKind() == CK_UncheckedDerivedToBase || - CE->getCastKind() == CK_NoOp) { - E = CE->getSubExpr(); - continue; - } - } - - break; - } + const Expr *E = ignoreParenBaseCasts(); QualType DerivedType = E->getType(); if (const PointerType *PTy = DerivedType->getAs()) @@ -2231,7 +2217,27 @@ Expr *Expr::IgnoreParenLValueCasts() { } return E; } - + +Expr *Expr::ignoreParenBaseCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast(E)) { + E = P->getSubExpr(); + continue; + } + if (CastExpr *CE = dyn_cast(E)) { + if (CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + + return E; + } +} + Expr *Expr::IgnoreParenImpCasts() { Expr *E = this; while (true) { diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 30324b97ef..a39e82408d 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -172,11 +172,21 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } // Compute the object pointer. + const Expr *Base = ME->getBase(); + bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier(); + bool Devirtualize = CanUseVirtualCall && + canDevirtualizeMemberFunctionCalls(getContext(), Base, MD); + + const Expr *Inner = Base; + if (Devirtualize) + Inner = Base->ignoreParenBaseCasts(); + llvm::Value *This; if (ME->isArrow()) - This = EmitScalarExpr(ME->getBase()); + This = EmitScalarExpr(Inner); else - This = EmitLValue(ME->getBase()).getAddress(); + This = EmitLValue(Inner).getAddress(); + if (MD->isTrivial()) { if (isa(MD)) return RValue::get(0); @@ -223,11 +233,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, // // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. - const Expr *Base = ME->getBase(); - bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier() - && !canDevirtualizeMemberFunctionCalls(getContext(), - Base, MD); - const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); + bool UseVirtualCall = CanUseVirtualCall && !Devirtualize; + const CXXRecordDecl *MostDerivedClassDecl = Inner->getBestDynamicClassType(); llvm::Value *Callee; if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) { @@ -238,7 +245,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, MD->isVirtual() && ME->hasQualifier()) Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty); - else if (ME->hasQualifier()) + else if (!Devirtualize) Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty); else { const CXXMethodDecl *DM = @@ -258,7 +265,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, MD->isVirtual() && ME->hasQualifier()) Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty); - else if (ME->hasQualifier()) + else if (!Devirtualize) Callee = CGM.GetAddrOfFunction(MD, Ty); else { const CXXMethodDecl *DerivedMethod = diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp index f7b10f647b..ba92012bce 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -107,3 +107,29 @@ namespace Test6 { static_cast(d)->~A(); } } + +namespace Test7 { + struct foo { + virtual void g() {} + }; + + struct bar { + virtual int f() { return 0; } + }; + + struct zed final : public foo, public bar { + int z; + virtual int f() {return z;} + }; + + // CHECK: define i32 @_ZN5Test71fEPNS_3zedE + int f(zed *z) { + // CHECK: alloca + // CHECK-NEXT: store + // CHECK-NEXT: load + // CHECK-NEXT: bitcast + // CHECK-NEXT: call {{.*}} @_ZN5Test73zed1fEv + // CHECK-NEXT: ret + return static_cast(z)->f(); + } +}