]> granicus.if.org Git - clang/commitdiff
Don't try to devirtualize non-virtual calls
authorReid Kleckner <reid@kleckner.net>
Tue, 16 Sep 2014 22:23:33 +0000 (22:23 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 16 Sep 2014 22:23:33 +0000 (22:23 +0000)
We would end up marking the vtable of the derived class as used for no
reason. Because the call itself is qualified, it is never virtual, and
the vtable of the derived class isn't helpful. We would end up rejecting
code that MSVC accepts for no benefit.

See http://crbug.com/413478

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217910 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
test/SemaCXX/devirtualize-vtable-marking.cpp [new file with mode: 0644]

index 57c4f33ca030128d97b0f087032e1912b49e8d8b..6b01b1f4b0ca41ab9c2a1aab8b8befb819cc2104 100644 (file)
@@ -12581,6 +12581,10 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
   CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
   if (!MD)
     return;
+  // Only attempt to devirtualize if this is truly a virtual call.
+  bool IsVirtualCall = MD->isVirtual() && !ME->hasQualifier();
+  if (!IsVirtualCall)
+    return;
   const Expr *Base = ME->getBase();
   const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
   if (!MostDerivedClassDecl)
diff --git a/test/SemaCXX/devirtualize-vtable-marking.cpp b/test/SemaCXX/devirtualize-vtable-marking.cpp
new file mode 100644 (file)
index 0000000..fc3e8ce
--- /dev/null
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+template <typename T> struct OwnPtr {
+  T *p;
+  ~OwnPtr() {
+    // expected-error@+1 {{invalid application of 'sizeof'}}
+    static_assert(sizeof(T) > 0, "incomplete T");
+    delete p;
+  }
+};
+
+namespace use_vtable_for_vcall {
+struct Incomplete; // expected-note {{forward declaration}}
+struct A {
+  virtual ~A() {}
+  virtual void m() {}
+};
+struct B : A { // expected-note {{in instantiation}}
+  B();
+  virtual void m() { }
+  virtual void m2() { static_cast<A *>(this)->m(); }
+  OwnPtr<Incomplete> m_sqlError;
+};
+
+B *f() {
+  return new B();
+}
+}
+
+namespace dont_mark_qualified_vcall {
+struct Incomplete;
+struct A {
+  virtual ~A() {}
+  virtual void m() {}
+};
+struct B : A {
+  B();
+  // Previously we would mark B's vtable referenced to devirtualize this call to
+  // A::m, even though it's not a virtual call.
+  virtual void m() { A::m(); }
+  OwnPtr<Incomplete> m_sqlError;
+};
+
+B *f() {
+  return new B();
+}
+}