diff options
| author | Anders Carlsson <andersca@mac.com> | 2011-04-10 18:20:53 +0000 |
|---|---|---|
| committer | Anders Carlsson <andersca@mac.com> | 2011-04-10 18:20:53 +0000 |
| commit | c53d9e8350cb68d548161612f9ac494d3ed835bf (patch) | |
| tree | 15942564413e03e3784e11bc6f0edc00d9d64555 | |
| parent | e5ec21c977f3f0c797e3d9c903d78b176df713fb (diff) | |
| download | bcm5719-llvm-c53d9e8350cb68d548161612f9ac494d3ed835bf.tar.gz bcm5719-llvm-c53d9e8350cb68d548161612f9ac494d3ed835bf.zip | |
Strip off parens and no-op casts when deciding if an expr can be devirtualized. Fixes the second half of PR9660.
llvm-svn: 129253
| -rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 26 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp | 10 |
2 files changed, 35 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 777036bc3b3..075fdc30a8b 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -77,6 +77,31 @@ static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl()); } +// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do +// quite what we want. +static const Expr *skipNoOpCastsAndParens(const Expr *E) { + while (true) { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + continue; + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Extension) { + E = UO->getSubExpr(); + continue; + } + } + return E; + } +} + /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, @@ -112,6 +137,7 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, if (MD->getParent()->hasAttr<FinalAttr>()) return true; + Base = skipNoOpCastsAndParens(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. diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp index 74795b5dfb0..5eede66cd7b 100644 --- a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp +++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -2,7 +2,8 @@ struct A { virtual void f(); - + virtual void f_const() const; + A h(); }; @@ -28,6 +29,12 @@ void f(A a, A *ap, A& ar) { // CHECK: call void @_ZN1A1fEv a.h().f(); + + // CHECK: call void @_ZNK1A7f_constEv + a.f_const(); + + // CHECK: call void @_ZN1A1fEv + (a).f(); } struct B { @@ -45,3 +52,4 @@ void f() { // CHECK: call void @_ZN1B1fEv B().h().f(); } + |

