|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \ | 
|  | // RUN:                    -analyzer-checker=debug.ExprInspection \ | 
|  | // RUN:                    -std=c++11 -verify=impure %s | 
|  |  | 
|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \ | 
|  | // RUN:                    -analyzer-checker=debug.ExprInspection \ | 
|  | // RUN:                    -std=c++11 -verify=pure -std=c++11 %s | 
|  |  | 
|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \ | 
|  | // RUN:                    -analyzer-checker=optin.cplusplus.VirtualCall \ | 
|  | // RUN:                    -analyzer-checker=debug.ExprInspection \ | 
|  | // RUN:                    -std=c++11 -verify=pure,impure -std=c++11 %s | 
|  |  | 
|  | #include "virtualcall.h" | 
|  |  | 
|  | void clang_analyzer_warnIfReached(); | 
|  |  | 
|  | class A { | 
|  | public: | 
|  | A(); | 
|  |  | 
|  | ~A(){}; | 
|  |  | 
|  | virtual int foo() = 0; | 
|  | virtual void bar() = 0; | 
|  | void f() { | 
|  | foo(); // pure-warning{{Call to pure virtual method 'A::foo' during construction has undefined behavior}} | 
|  | clang_analyzer_warnIfReached(); // no-warning | 
|  | } | 
|  | }; | 
|  |  | 
|  | A::A() { | 
|  | f(); | 
|  | } | 
|  |  | 
|  | class B { | 
|  | public: | 
|  | B() { | 
|  | foo(); // impure-warning {{Call to virtual method 'B::foo' during construction bypasses virtual dispatch}} | 
|  | } | 
|  | ~B(); | 
|  |  | 
|  | virtual int foo(); | 
|  | virtual void bar() { | 
|  | foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}} | 
|  | } | 
|  | }; | 
|  |  | 
|  | B::~B() { | 
|  | this->B::foo(); // no-warning | 
|  | this->B::bar(); | 
|  | this->foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}} | 
|  | } | 
|  |  | 
|  | class C : public B { | 
|  | public: | 
|  | C(); | 
|  | ~C(); | 
|  |  | 
|  | virtual int foo(); | 
|  | void f(int i); | 
|  | }; | 
|  |  | 
|  | C::C() { | 
|  | f(foo()); // impure-warning {{Call to virtual method 'C::foo' during construction bypasses virtual dispatch}} | 
|  | } | 
|  |  | 
|  | class D : public B { | 
|  | public: | 
|  | D() { | 
|  | foo(); // no-warning | 
|  | } | 
|  | ~D() { bar(); } | 
|  | int foo() final; | 
|  | void bar() final { foo(); } // no-warning | 
|  | }; | 
|  |  | 
|  | class E final : public B { | 
|  | public: | 
|  | E() { | 
|  | foo(); // no-warning | 
|  | } | 
|  | ~E() { bar(); } | 
|  | int foo() override; | 
|  | }; | 
|  |  | 
|  | class F { | 
|  | public: | 
|  | F() { | 
|  | void (F::*ptr)() = &F::foo; | 
|  | (this->*ptr)(); | 
|  | } | 
|  | void foo(); | 
|  | }; | 
|  |  | 
|  | class G { | 
|  | public: | 
|  | G() {} | 
|  | virtual void bar(); | 
|  | void foo() { | 
|  | bar(); // no warning | 
|  | } | 
|  | }; | 
|  |  | 
|  | class H { | 
|  | public: | 
|  | H() : initState(0) { init(); } | 
|  | int initState; | 
|  | virtual void f() const; | 
|  | void init() { | 
|  | if (initState) | 
|  | f(); // no warning | 
|  | } | 
|  |  | 
|  | H(int i) { | 
|  | G g; | 
|  | g.foo(); | 
|  | g.bar(); // no warning | 
|  | f(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}} | 
|  | H &h = *this; | 
|  | h.f(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}} | 
|  | } | 
|  | }; | 
|  |  | 
|  | class X { | 
|  | public: | 
|  | X() { | 
|  | g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}} | 
|  | } | 
|  | X(int i) { | 
|  | if (i > 0) { | 
|  | X x(i - 1); | 
|  | x.g(); // no warning | 
|  | } | 
|  | g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}} | 
|  | } | 
|  | virtual void g(); | 
|  | }; | 
|  |  | 
|  | class M; | 
|  | class N { | 
|  | public: | 
|  | virtual void virtualMethod(); | 
|  | void callFooOfM(M *); | 
|  | }; | 
|  | class M { | 
|  | public: | 
|  | M() { | 
|  | N n; | 
|  | n.virtualMethod(); // no warning | 
|  | n.callFooOfM(this); | 
|  | } | 
|  | virtual void foo(); | 
|  | }; | 
|  | void N::callFooOfM(M *m) { | 
|  | m->foo(); // impure-warning {{Call to virtual method 'M::foo' during construction bypasses virtual dispatch}} | 
|  | } | 
|  |  | 
|  | class Y { | 
|  | public: | 
|  | virtual void foobar(); | 
|  | void fooY() { | 
|  | F f1; | 
|  | foobar(); // impure-warning {{Call to virtual method 'Y::foobar' during construction bypasses virtual dispatch}} | 
|  | } | 
|  | Y() { fooY(); } | 
|  | }; | 
|  |  | 
|  | int main() { | 
|  | B b; | 
|  | C c; | 
|  | D d; | 
|  | E e; | 
|  | F f; | 
|  | G g; | 
|  | H h; | 
|  | H h1(1); | 
|  | X x; | 
|  | X x1(1); | 
|  | M m; | 
|  | Y *y = new Y; | 
|  | delete y; | 
|  | header::Z z; | 
|  | } | 
|  |  | 
|  | namespace PR34451 { | 
|  | struct a { | 
|  | void b() { | 
|  | a c[1]; | 
|  | c->b(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | class e { | 
|  | public: | 
|  | void b() const; | 
|  | }; | 
|  |  | 
|  | class c { | 
|  | void m_fn2() const; | 
|  | e d[]; | 
|  | }; | 
|  |  | 
|  | void c::m_fn2() const { d->b(); } | 
|  | } |