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