зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
d558b5238d
Коммит
632fbaa22f
|
@ -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<Expr*>(this)->ignoreParenBaseCasts();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this expression is a default function argument.
|
||||
///
|
||||
/// Default arguments are implicitly generated in the abstract syntax tree
|
||||
|
|
|
@ -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<CastExpr>(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<PointerType>())
|
||||
|
@ -2232,6 +2218,26 @@ Expr *Expr::IgnoreParenLValueCasts() {
|
|||
return E;
|
||||
}
|
||||
|
||||
Expr *Expr::ignoreParenBaseCasts() {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
if (CastExpr *CE = dyn_cast<CastExpr>(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) {
|
||||
|
|
|
@ -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<CXXDestructorDecl>(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<CXXDestructorDecl>(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 =
|
||||
|
|
|
@ -107,3 +107,29 @@ namespace Test6 {
|
|||
static_cast<A*>(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<bar*>(z)->f();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче