aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2011-04-10 18:20:53 +0000
committerAnders Carlsson <andersca@mac.com>2011-04-10 18:20:53 +0000
commitcd0b32e73a66a20a8dab7a7f0ce963dc669f7c0a (patch)
tree0460db11e326216c85839a35be0c294452865a5e
parentb8bced0b75fa4188c91753d5a1de6d164af45450 (diff)
Strip off parens and no-op casts when deciding if an expr can be devirtualized. Fixes the second half of PR9660.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129253 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGExprCXX.cpp26
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls.cpp10
2 files changed, 35 insertions, 1 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 777036bc3b..075fdc30a8 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/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/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index 74795b5dfb..5eede66cd7 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/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();
}
+