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()24void 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()47B *f() { 48 return new B(); 49 } 50 } 51