r286534 - PR30937: don't devirtualize if we find that the callee is a pure virtual
Mehdi Amini via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 10 18:11:40 PST 2016
Could we emit llvm.unreachable in this case?
—
Mehdi
> On Nov 10, 2016, at 5:01 PM, Richard Smith via cfe-commits <cfe-commits at lists.llvm.org> wrote:
>
> Author: rsmith
> Date: Thu Nov 10 19:01:31 2016
> New Revision: 286534
>
> URL: http://llvm.org/viewvc/llvm-project?rev=286534&view=rev
> Log:
> PR30937: don't devirtualize if we find that the callee is a pure virtual
> function. In that case, there is no requirement that the callee is actually
> defined, and the code may in fact be valid and have defined behavior if the
> virtual call is unreachable.
>
> Modified:
> cfe/trunk/lib/CodeGen/CGClass.cpp
> cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=286534&r1=286533&r2=286534&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGClass.cpp Thu Nov 10 19:01:31 2016
> @@ -2851,9 +2851,9 @@ CodeGenFunction::CanDevirtualizeMemberFu
> return false;
>
> // If the member function is marked 'final', we know that it can't be
> - // overridden and can therefore devirtualize it.
> + // overridden and can therefore devirtualize it unless it's pure virtual.
> if (MD->hasAttr<FinalAttr>())
> - return true;
> + return !MD->isPure();
>
> // If the base expression (after skipping derived-to-base conversions) is a
> // class prvalue, then we can devirtualize.
> @@ -2861,31 +2861,28 @@ CodeGenFunction::CanDevirtualizeMemberFu
> if (Base->isRValue() && Base->getType()->isRecordType())
> return true;
>
> - // If the most derived class is marked final, we know that no subclass can
> - // override this member function and so we can devirtualize it. For example:
> - //
> - // struct A { virtual void f(); }
> - // struct B final : A { };
> - //
> - // void f(B *b) {
> - // b->f();
> - // }
> - //
> - if (const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType()) {
> - if (BestDynamicDecl->hasAttr<FinalAttr>())
> - return true;
> -
> - // There may be a method corresponding to MD in a derived class. If that
> - // method is marked final, we can devirtualize it.
> - const CXXMethodDecl *DevirtualizedMethod =
> - MD->getCorrespondingMethodInClass(BestDynamicDecl);
> - if (DevirtualizedMethod->hasAttr<FinalAttr>())
> - return true;
> - }
> + // If we don't even know what we would call, we can't devirtualize.
> + const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
> + if (!BestDynamicDecl)
> + return false;
> +
> + // There may be a method corresponding to MD in a derived class.
> + const CXXMethodDecl *DevirtualizedMethod =
> + MD->getCorrespondingMethodInClass(BestDynamicDecl);
> +
> + // If that method is pure virtual, we can't devirtualize. If this code is
> + // reached, the result would be UB, not a direct call to the derived class
> + // function, and we can't assume the derived class function is defined.
> + if (DevirtualizedMethod->isPure())
> + return false;
> +
> + // If that method is marked final, we can devirtualize it.
> + if (DevirtualizedMethod->hasAttr<FinalAttr>())
> + return true;
>
> // Similarly, if the class itself is marked 'final' it can't be overridden
> // and we can therefore devirtualize the member function call.
> - if (MD->getParent()->hasAttr<FinalAttr>())
> + if (BestDynamicDecl->hasAttr<FinalAttr>())
> return true;
>
> if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
>
> Modified: cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp?rev=286534&r1=286533&r2=286534&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp Thu Nov 10 19:01:31 2016
> @@ -161,3 +161,37 @@ namespace test4 {
> p->fish.eat();
> }
> }
> +
> +// Do not devirtualize to pure virtual function calls.
> +namespace test5 {
> + struct X {
> + virtual void f() = 0;
> + };
> + struct Y {};
> + // CHECK-LABEL: define {{.*}} @_ZN5test51f
> + void f(Y &y, X Y::*p) {
> + // CHECK-NOT: call {{.*}} @_ZN5test51X1fEv
> + // CHECK: call void %
> + (y.*p).f();
> + };
> +
> + struct Z final {
> + virtual void f() = 0;
> + };
> + // CHECK-LABEL: define {{.*}} @_ZN5test51g
> + void g(Z &z) {
> + // CHECK-NOT: call {{.*}} @_ZN5test51Z1fEv
> + // CHECK: call void %
> + z.f();
> + }
> +
> + struct Q {
> + virtual void f() final = 0;
> + };
> + // CHECK-LABEL: define {{.*}} @_ZN5test51h
> + void h(Q &q) {
> + // CHECK-NOT: call {{.*}} @_ZN5test51Q1fEv
> + // CHECK: call void %
> + q.f();
> + }
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list