1 // RUN: %clang_cc1 -verify -std=c++11 %s
2 // expected-no-diagnostics
3 template <typename T> struct OwnPtr {
4   T *p;
~OwnPtrOwnPtr5   ~OwnPtr() {
6     static_assert(sizeof(T) > 0, "incomplete T");
7     delete p;
8   }
9 };
10 
11 namespace use_vtable_for_vcall {
12 struct Incomplete;
13 struct A {
~Ause_vtable_for_vcall::A14   virtual ~A() {}
muse_vtable_for_vcall::A15   virtual void m() {}
16 };
17 struct B : A {
18   B();
muse_vtable_for_vcall::B19   virtual void m() { }
m2use_vtable_for_vcall::B20   virtual void m2() { static_cast<A *>(this)->m(); }
21   OwnPtr<Incomplete> m_sqlError;
22 };
23 
f()24 void f() {
25   // Since B's constructor is declared out of line, nothing in this file
26   // references a vtable, so the destructor doesn't get built.
27   A *b = new B();
28   b->m();
29   delete b;
30 }
31 }
32 
33 namespace dont_mark_qualified_vcall {
34 struct Incomplete;
35 struct A {
~Adont_mark_qualified_vcall::A36   virtual ~A() {}
mdont_mark_qualified_vcall::A37   virtual void m() {}
38 };
39 struct B : A {
40   B();
41   // Previously we would mark B's vtable referenced to devirtualize this call to
42   // A::m, even though it's not a virtual call.
mdont_mark_qualified_vcall::B43   virtual void m() { A::m(); }
44   OwnPtr<Incomplete> m_sqlError;
45 };
46 
f()47 B *f() {
48   return new B();
49 }
50 }
51