[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-13 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL307883: [Sema] Mark a virtual CXXMethodDecl as used if a 
call to it can be (authored by ahatanak).

Changed prior to commit:
  https://reviews.llvm.org/D34301?vs=106347=106380#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D34301

Files:
  cfe/trunk/include/clang/AST/DeclCXX.h
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/AST/DeclCXX.cpp
  cfe/trunk/lib/CodeGen/CGClass.cpp
  cfe/trunk/lib/CodeGen/CGExprCXX.cpp
  cfe/trunk/lib/CodeGen/CodeGenFunction.h
  cfe/trunk/lib/Sema/SemaExpr.cpp
  cfe/trunk/lib/Sema/SemaOverload.cpp
  cfe/trunk/test/CodeGen/no-devirt.cpp
  cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
  cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp

Index: cfe/trunk/include/clang/AST/DeclCXX.h
===
--- cfe/trunk/include/clang/AST/DeclCXX.h
+++ cfe/trunk/include/clang/AST/DeclCXX.h
@@ -1886,6 +1886,19 @@
 return (CD->begin_overridden_methods() != CD->end_overridden_methods());
   }
 
+  /// If it's possible to devirtualize a call to this method, return the called
+  /// function. Otherwise, return null.
+
+  /// \param Base The object on which this virtual function is called.
+  /// \param IsAppleKext True if we are compiling for Apple kext.
+  CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext);
+
+  const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base,
+  bool IsAppleKext) const {
+return const_cast(this)->getDevirtualizedMethod(
+Base, IsAppleKext);
+  }
+
   /// \brief Determine whether this is a usual deallocation function
   /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
   /// delete or delete[] operator with a particular signature.
Index: cfe/trunk/include/clang/Sema/Sema.h
===
--- cfe/trunk/include/clang/Sema/Sema.h
+++ cfe/trunk/include/clang/Sema/Sema.h
@@ -3944,7 +3944,7 @@
   void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
   bool MightBeOdrUse = true);
   void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
-  void MarkDeclRefReferenced(DeclRefExpr *E);
+  void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
   void MarkMemberReferenced(MemberExpr *E);
 
   void UpdateMarkingForLValueToRValue(Expr *E);
Index: cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
===
--- cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,53 @@
 return static_cast(b)->f();
   }
 }
+
+namespace Test11 {
+  // Check that the definitions of Derived's operators are emitted.
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+  // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  class Base {
+  public:
+virtual void operator()() {}
+virtual bool operator==(const Base ) { return false; }
+virtual bool operator!() { return false; }
+virtual Base [](int i) { return *this; }
+  };
+
+  template
+  struct S {
+class Derived final : public Base {
+public:
+  void operator()() override {}
+  bool operator==(const Base ) override { return true; }
+  bool operator!() override { return true; }
+  Base [](int i) override { return *this; }
+};
+
+Derived *ptr = nullptr, *ptr2 = nullptr;
+
+void foo1() {
+  if (ptr && ptr2) {
+// These calls get devirtualized. Linkage fails if the definitions of
+// the called functions are not emitted.
+(*ptr)();
+(void)(*ptr == *ptr2);
+(void)(!(*ptr));
+(void)((*ptr)[1]);
+  }
+}
+  };
+
+  void foo2() {
+S *s = new S;
+s->foo1();
+  }
+}
Index: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
===
--- cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
+++ cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
@@ -275,9 +275,8 @@
   virtual D& operator=(const D&);
 };
 
-// Cannot emit D's vtable available_externally, because we cannot create
-// a reference to the inline virtual 

[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-12 Thread Vedant Kumar via Phabricator via cfe-commits
vsk accepted this revision.
vsk added a comment.
This revision is now accepted and ready to land.

Thanks, this looks great.


https://reviews.llvm.org/D34301



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 106347.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Define and use CXXMethodDecl::getDevirtualizedMethod, which returns the 
function that is called when a call is devirtualized.


https://reviews.llvm.org/D34301

Files:
  include/clang/AST/DeclCXX.h
  include/clang/Sema/Sema.h
  lib/AST/DeclCXX.cpp
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  test/CodeGen/no-devirt.cpp
  test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
  test/CodeGenCXX/vtable-available-externally.cpp

Index: test/CodeGenCXX/vtable-available-externally.cpp
===
--- test/CodeGenCXX/vtable-available-externally.cpp
+++ test/CodeGenCXX/vtable-available-externally.cpp
@@ -275,9 +275,8 @@
   virtual D& operator=(const D&);
 };
 
-// Cannot emit D's vtable available_externally, because we cannot create
-// a reference to the inline virtual D::operator= function.
-// CHECK-TEST11: @_ZTVN6Test111DE = external unnamed_addr constant
+// Can emit D's vtable available_externally.
+// CHECK-TEST11: @_ZTVN6Test111DE = available_externally unnamed_addr constant
 struct D : C {
   virtual void key();
 };
Index: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
===
--- test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,53 @@
 return static_cast(b)->f();
   }
 }
+
+namespace Test11 {
+  // Check that the definitions of Derived's operators are emitted.
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+  // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  class Base {
+  public:
+virtual void operator()() {}
+virtual bool operator==(const Base ) { return false; }
+virtual bool operator!() { return false; }
+virtual Base [](int i) { return *this; }
+  };
+
+  template
+  struct S {
+class Derived final : public Base {
+public:
+  void operator()() override {}
+  bool operator==(const Base ) override { return true; }
+  bool operator!() override { return true; }
+  Base [](int i) override { return *this; }
+};
+
+Derived *ptr = nullptr, *ptr2 = nullptr;
+
+void foo1() {
+  if (ptr && ptr2) {
+// These calls get devirtualized. Linkage fails if the definitions of
+// the called functions are not emitted.
+(*ptr)();
+(void)(*ptr == *ptr2);
+(void)(!(*ptr));
+(void)((*ptr)[1]);
+  }
+}
+  };
+
+  void foo2() {
+S *s = new S;
+s->foo1();
+  }
+}
Index: test/CodeGen/no-devirt.cpp
===
--- test/CodeGen/no-devirt.cpp
+++ test/CodeGen/no-devirt.cpp
@@ -21,7 +21,7 @@
 struct Wrapper {
   TmplWithArray data;
   bool indexIt(int a) {
-if (a > 6) return data[a] ;  // Should not devirtualize
+if (a > 6) return data[a] ;  // Should devirtualize
 if (a > 4) return data.func1(a); // Should devirtualize
 return data.func2(a);// Should devirtualize
   }
@@ -53,7 +53,7 @@
 }
 #endif
 
-// CHECK-NOT: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
 // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func1Ei
 // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func2Ei
 
Index: lib/Sema/SemaOverload.cpp
===
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -48,7 +48,7 @@
 /// A convenience routine for creating a decayed reference to a function.
 static ExprResult
 CreateFunctionRefExpr(Sema , FunctionDecl *Fn, NamedDecl *FoundDecl,
-  bool HadMultipleCandidates,
+  const Expr *Base, bool HadMultipleCandidates,
   SourceLocation Loc = SourceLocation(),
   const DeclarationNameLoc  = DeclarationNameLoc()){
   if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
@@ -68,7 +68,7 @@
   if (HadMultipleCandidates)
 DRE->setHadMultipleCandidates(true);
 
-  S.MarkDeclRefReferenced(DRE);
+  S.MarkDeclRefReferenced(DRE, Base);
   return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
  

[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-12 Thread Vedant Kumar via Phabricator via cfe-commits
vsk added a comment.

I suggest changing the API for 'canDevirtualizeCall' a bit but this is looking 
great overall. The code movement and test case changes look good.




Comment at: include/clang/AST/DeclCXX.h:1902
+  bool canDevirtualizeCall(const Expr *Base, bool IsAppleKext,
+   CXXMethodDecl *);
+

Something like `CXXMethodDecl *getDevirtualizedMethod(...)` would fit in better 
with the current API. E.g, getCorrespondingMethodInClass is done this way (and 
returns nullptr when a method is not found).



Comment at: lib/AST/DeclCXX.cpp:1693
+  const CXXMethodDecl *DM;
+  return ::canDevirtualizeCall(Base, this, IsAppleKext, DM);
+}

Instead of templating canDevirtualizeCall, you could do something like 
`const_cast(this)->getDevirtualizedMethod(...)`.


https://reviews.llvm.org/D34301



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 106149.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Address review comments.


https://reviews.llvm.org/D34301

Files:
  include/clang/AST/DeclCXX.h
  include/clang/Sema/Sema.h
  lib/AST/DeclCXX.cpp
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  test/CodeGen/no-devirt.cpp
  test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
  test/CodeGenCXX/vtable-available-externally.cpp

Index: test/CodeGenCXX/vtable-available-externally.cpp
===
--- test/CodeGenCXX/vtable-available-externally.cpp
+++ test/CodeGenCXX/vtable-available-externally.cpp
@@ -275,9 +275,8 @@
   virtual D& operator=(const D&);
 };
 
-// Cannot emit D's vtable available_externally, because we cannot create
-// a reference to the inline virtual D::operator= function.
-// CHECK-TEST11: @_ZTVN6Test111DE = external unnamed_addr constant
+// Can emit D's vtable available_externally.
+// CHECK-TEST11: @_ZTVN6Test111DE = available_externally unnamed_addr constant
 struct D : C {
   virtual void key();
 };
Index: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
===
--- test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,53 @@
 return static_cast(b)->f();
   }
 }
+
+namespace Test11 {
+  // Check that the definition of Derived::operator() is emitted.
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+  // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+  // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+  // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+  class Base {
+  public:
+virtual void operator()() {}
+virtual bool operator==(const Base ) { return false; }
+virtual bool operator!() { return false; }
+virtual Base [](int i) { return *this; }
+  };
+
+  template
+  struct S {
+class Derived final : public Base {
+public:
+  void operator()() override {}
+  bool operator==(const Base ) override { return true; }
+  bool operator!() override { return true; }
+  Base [](int i) override { return *this; }
+};
+
+Derived *ptr = nullptr, *ptr2 = nullptr;
+
+void foo1() {
+  if (ptr && ptr2) {
+// These calls get devirtualized. Linkage fails if the definitions of
+// the called functions are not emitted.
+(*ptr)();
+(void)(*ptr == *ptr2);
+(void)(!(*ptr));
+(void)((*ptr)[1]);
+  }
+}
+  };
+
+  void foo2() {
+S *s = new S;
+s->foo1();
+  }
+}
Index: test/CodeGen/no-devirt.cpp
===
--- test/CodeGen/no-devirt.cpp
+++ test/CodeGen/no-devirt.cpp
@@ -21,7 +21,7 @@
 struct Wrapper {
   TmplWithArray data;
   bool indexIt(int a) {
-if (a > 6) return data[a] ;  // Should not devirtualize
+if (a > 6) return data[a] ;  // Should devirtualize
 if (a > 4) return data.func1(a); // Should devirtualize
 return data.func2(a);// Should devirtualize
   }
@@ -53,7 +53,7 @@
 }
 #endif
 
-// CHECK-NOT: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
 // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func1Ei
 // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func2Ei
 
Index: lib/Sema/SemaOverload.cpp
===
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -48,7 +48,7 @@
 /// A convenience routine for creating a decayed reference to a function.
 static ExprResult
 CreateFunctionRefExpr(Sema , FunctionDecl *Fn, NamedDecl *FoundDecl,
-  bool HadMultipleCandidates,
+  const Expr *Base, bool HadMultipleCandidates,
   SourceLocation Loc = SourceLocation(),
   const DeclarationNameLoc  = DeclarationNameLoc()){
   if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
@@ -68,7 +68,7 @@
   if (HadMultipleCandidates)
 DRE->setHadMultipleCandidates(true);
 
-  S.MarkDeclRefReferenced(DRE);
+  S.MarkDeclRefReferenced(DRE, Base);
   return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
  CK_FunctionToPointerDecay);
 }
@@ -11946,6 +11946,7 @@
 FunctionDecl 

[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-07-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak marked 2 inline comments as done.
ahatanak added inline comments.



Comment at: lib/Sema/SemaExpr.cpp:14715
+if (Method->isVirtual() && !(Method->hasAttr() ||
+ Method->getParent()->hasAttr()))
   OdrUse = false;

vsk wrote:
> Do you think it makes sense to eliminate all candidate virtual methods which 
> can be devirtualized? If so, you could make 
> "CanDevirtualizeMemberFunctionCall" a shared utility between Sema and 
> CodeGen, and use it here. That function should give "the truth" about whether 
> or not a call can be devirtualized.
I moved CanDevirtualizeMemberFunctionCall to DeclCXX.cpp and added overloaded 
functions of canDevirtualizeCall and used one of them here. This caused changes 
in the generated IR in two test cases (no-devirt.cpp and 
vtable-available-externally.cpp). Both changes look correct to me.



Comment at: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp:271
+// Derived::operator() is not emitted, there will be a linker error.
+(*ptr)();
+  }

vsk wrote:
> Have you looked into why "ptr->operator()();" compiles? We are either missing 
> a devirtualization opportunity, or we have inconsistent logic for setting 
> MightBeOdrUse for member calls. Either way, I think this patch is the right 
> vehicle to address the issue.
"ptr->operator()();"  creates a MemberExpr, which MarkMemberReferenced handles. 
The difference between MarkMemberReferenced and MarkDeclRefReferenced is that 
the former sets OdrUse to false when the method is pure while the latter does 
so when the method is virtual.  Prior to r174341, MarkDeclRefReferenced was 
setting OdrUse to false for pure methods too (see r174242).


https://reviews.llvm.org/D34301



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-06-16 Thread Vedant Kumar via Phabricator via cfe-commits
vsk added a comment.

It looks




Comment at: lib/Sema/SemaExpr.cpp:14715
+if (Method->isVirtual() && !(Method->hasAttr() ||
+ Method->getParent()->hasAttr()))
   OdrUse = false;

Do you think it makes sense to eliminate all candidate virtual methods which 
can be devirtualized? If so, you could make "CanDevirtualizeMemberFunctionCall" 
a shared utility between Sema and CodeGen, and use it here. That function 
should give "the truth" about whether or not a call can be devirtualized.



Comment at: lib/Sema/SemaExpr.cpp:14717
   OdrUse = false;
   MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
 }

"MarkExprReferenced" has what looks like an incomplete version of 
"CanDevirtualizeMemberFunctionCall". Do you think there is an opportunity to 
share logic there as well?



Comment at: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp:271
+// Derived::operator() is not emitted, there will be a linker error.
+(*ptr)();
+  }

Have you looked into why "ptr->operator()();" compiles? We are either missing a 
devirtualization opportunity, or we have inconsistent logic for setting 
MightBeOdrUse for member calls. Either way, I think this patch is the right 
vehicle to address the issue.


https://reviews.llvm.org/D34301



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34301: [Sema] Make sure the definition of a referenced virtual function is emitted when it is final

2017-06-16 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
Herald added a subscriber: Prazek.

The test case I added used to fail because of a linker error.

Linkage failed because Sema::MarkDeclRefReferenced would prevent the virtual 
method definition from being emitted by setting OdrUse=false and then code-gen 
would devirtualized the virtual call because its class is marked final.

This patch fixes the bug.

rdar://problem/27455779


https://reviews.llvm.org/D34301

Files:
  lib/Sema/SemaExpr.cpp
  test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp


Index: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
===
--- test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,40 @@
 return static_cast(b)->f();
   }
 }
+
+namespace Test11 {
+  // Check that the definition of Derived::operator() is emitted.
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+  // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+  class Base {
+  public:
+virtual void operator()() {
+}
+  };
+
+  template
+  struct S {
+class Derived final : public Base {
+public:
+  void operator()() override {
+  }
+};
+
+Derived *ptr = nullptr;
+
+void foo1() {
+  if (ptr) {
+// This call gets devirtualized. If the definition of
+// Derived::operator() is not emitted, there will be a linker error.
+(*ptr)();
+  }
+}
+  };
+
+  void foo2() {
+S *s = new S;
+s->foo1();
+  }
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -14711,7 +14711,8 @@
   // if it's a qualified reference.
   bool OdrUse = true;
   if (CXXMethodDecl *Method = dyn_cast(E->getDecl()))
-if (Method->isVirtual())
+if (Method->isVirtual() && !(Method->hasAttr() ||
+ Method->getParent()->hasAttr()))
   OdrUse = false;
   MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
 }


Index: test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
===
--- test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,40 @@
 return static_cast(b)->f();
   }
 }
+
+namespace Test11 {
+  // Check that the definition of Derived::operator() is emitted.
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+  // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+  // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+  class Base {
+  public:
+virtual void operator()() {
+}
+  };
+
+  template
+  struct S {
+class Derived final : public Base {
+public:
+  void operator()() override {
+  }
+};
+
+Derived *ptr = nullptr;
+
+void foo1() {
+  if (ptr) {
+// This call gets devirtualized. If the definition of
+// Derived::operator() is not emitted, there will be a linker error.
+(*ptr)();
+  }
+}
+  };
+
+  void foo2() {
+S *s = new S;
+s->foo1();
+  }
+}
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -14711,7 +14711,8 @@
   // if it's a qualified reference.
   bool OdrUse = true;
   if (CXXMethodDecl *Method = dyn_cast(E->getDecl()))
-if (Method->isVirtual())
+if (Method->isVirtual() && !(Method->hasAttr() ||
+ Method->getParent()->hasAttr()))
   OdrUse = false;
   MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits