[cfe-commits] r159326 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/CodeGen/CGExprCXX.cpp test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
John McCall
rjmccall at apple.com
Wed Jun 27 19:41:59 PDT 2012
On Jun 27, 2012, at 6:56 PM, Rafael Espindola wrote:
> URL: http://llvm.org/viewvc/llvm-project?rev=159326&view=rev
> Log:
> 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.
>
> Modified:
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/lib/AST/Expr.cpp
> cfe/trunk/lib/CodeGen/CGExprCXX.cpp
> cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=159326&r1=159325&r2=159326&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Jun 27 20:56:38 2012
> @@ -172,11 +172,21 @@
> }
>
> // 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 @@
> //
> // 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();
Inner (and therefore "this") will indeed have type MostDerivedClassDecl
here, but that's not necessarily the type that declares the final override for
the method being called:
struct Primary { virtual ~Primary(); void *member; };
struct A { virtual void foo(); }; // its own final override
struct final B : Primary, A {}; // most derived
void test(B *b) {
b->foo();
}
My example happens to have us devirtualize to the original method,
but that's not necessarily the case; you can have arbitrary inheritance
and overriding between A and the most-derived class, like so:
struct A { virtual void foo(); };
struct B : A { virtual void foo(); }; // final override
struct final C : Primary, B {}; // most derived
void test(C *c) {
static_cast<A*>(c)->foo();
}
And of course the offset from A to B doesn't have to be zero, either:
struct A { virtual void foo(); };
struct B : Primary, A { virtual void foo(); }; // final override
struct final C : Primary, B {}; // most derived
void test(C *c) {
static_cast<A*>(d)->foo();
}
Really, you have to do a derived-to-base conversion from the most-derived
class to the base actually declaring the method. Fortunately, that can't
actually fail (they can in general, due to ambiguity) because of the
well-formedness constraints on final overriders.
John.
More information about the cfe-commits
mailing list