Strip off parens and no-op casts when deciding if an expr can be devirtualized. Fixes the second half of PR9660.

llvm-svn: 129253
This commit is contained in:
Anders Carlsson 2011-04-10 18:20:53 +00:00
parent e5ec21c977
commit c53d9e8350
2 changed files with 35 additions and 1 deletions

View File

@ -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.

View File

@ -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();
}