15c553e37SReid Kleckner // RUN: %clang_cc1 -verify -std=c++11 %s
2*b3a9978dSNico Weber // expected-no-diagnostics
35c553e37SReid Kleckner template <typename T> struct OwnPtr {
45c553e37SReid Kleckner   T *p;
~OwnPtrOwnPtr55c553e37SReid Kleckner   ~OwnPtr() {
65c553e37SReid Kleckner     static_assert(sizeof(T) > 0, "incomplete T");
75c553e37SReid Kleckner     delete p;
85c553e37SReid Kleckner   }
95c553e37SReid Kleckner };
105c553e37SReid Kleckner 
115c553e37SReid Kleckner namespace use_vtable_for_vcall {
12*b3a9978dSNico Weber struct Incomplete;
135c553e37SReid Kleckner struct A {
~Ause_vtable_for_vcall::A145c553e37SReid Kleckner   virtual ~A() {}
muse_vtable_for_vcall::A155c553e37SReid Kleckner   virtual void m() {}
165c553e37SReid Kleckner };
17*b3a9978dSNico Weber struct B : A {
185c553e37SReid Kleckner   B();
muse_vtable_for_vcall::B195c553e37SReid Kleckner   virtual void m() { }
m2use_vtable_for_vcall::B205c553e37SReid Kleckner   virtual void m2() { static_cast<A *>(this)->m(); }
215c553e37SReid Kleckner   OwnPtr<Incomplete> m_sqlError;
225c553e37SReid Kleckner };
235c553e37SReid Kleckner 
f()24*b3a9978dSNico Weber void f() {
25*b3a9978dSNico Weber   // Since B's constructor is declared out of line, nothing in this file
26*b3a9978dSNico Weber   // references a vtable, so the destructor doesn't get built.
27*b3a9978dSNico Weber   A *b = new B();
28*b3a9978dSNico Weber   b->m();
29*b3a9978dSNico Weber   delete b;
305c553e37SReid Kleckner }
315c553e37SReid Kleckner }
325c553e37SReid Kleckner 
335c553e37SReid Kleckner namespace dont_mark_qualified_vcall {
345c553e37SReid Kleckner struct Incomplete;
355c553e37SReid Kleckner struct A {
~Adont_mark_qualified_vcall::A365c553e37SReid Kleckner   virtual ~A() {}
mdont_mark_qualified_vcall::A375c553e37SReid Kleckner   virtual void m() {}
385c553e37SReid Kleckner };
395c553e37SReid Kleckner struct B : A {
405c553e37SReid Kleckner   B();
415c553e37SReid Kleckner   // Previously we would mark B's vtable referenced to devirtualize this call to
425c553e37SReid Kleckner   // A::m, even though it's not a virtual call.
mdont_mark_qualified_vcall::B435c553e37SReid Kleckner   virtual void m() { A::m(); }
445c553e37SReid Kleckner   OwnPtr<Incomplete> m_sqlError;
455c553e37SReid Kleckner };
465c553e37SReid Kleckner 
f()475c553e37SReid Kleckner B *f() {
485c553e37SReid Kleckner   return new B();
495c553e37SReid Kleckner }
505c553e37SReid Kleckner }
51