| // RUN: %clang_cc1 -std=c++98 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | 
 | // RUN: %clang_cc1 -std=c++11 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | 
 | // RUN: %clang_cc1 -std=c++1z %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | 
 |  | 
 | struct A { | 
 |   virtual void f(); | 
 |   virtual void f_const() const; | 
 |   virtual void g(); | 
 |  | 
 |   A h(); | 
 | }; | 
 |  | 
 | A g(); | 
 |  | 
 | void f(A a, A *ap, A& ar) { | 
 |   // This should not be a virtual function call. | 
 |    | 
 |   // CHECK: call void @_ZN1A1fEv(%struct.A* %a) | 
 |   a.f(); | 
 |  | 
 |   // CHECK: call void %   | 
 |   ap->f(); | 
 |  | 
 |   // CHECK: call void %   | 
 |   ar.f(); | 
 |    | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   A().f(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   g().f(); | 
 |    | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   a.h().f(); | 
 |  | 
 |   // CHECK: call void @_ZNK1A7f_constEv | 
 |   a.f_const(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   (a).f(); | 
 | } | 
 |  | 
 | struct D : A { virtual void g(); }; | 
 | struct XD { D d; }; | 
 |  | 
 | D gd(); | 
 |  | 
 | void fd(D d, XD xd, D *p) { | 
 |   // CHECK: call void @_ZN1A1fEv(%struct.A* | 
 |   d.f(); | 
 |  | 
 |   // CHECK: call void @_ZN1D1gEv(%struct.D* | 
 |   d.g(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   D().f(); | 
 |  | 
 |   // CHECK: call void @_ZN1D1gEv | 
 |   D().g(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   gd().f(); | 
 |    | 
 |   // CHECK: call void @_ZNK1A7f_constEv | 
 |   d.f_const(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   (d).f(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   (true, d).f(); | 
 |  | 
 |   // CHECK: call void @_ZN1D1gEv | 
 |   (true, d).g(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   xd.d.f(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   XD().d.f(); | 
 |  | 
 |   // CHECK: call void @_ZN1A1fEv | 
 |   D XD::*mp; | 
 |   (xd.*mp).f(); | 
 |  | 
 |   // CHECK: call void @_ZN1D1gEv | 
 |   (xd.*mp).g(); | 
 |  | 
 |   // Can't devirtualize this; we have no guarantee that p points to a D here, | 
 |   // due to the "single object is considered to be an array of one element" | 
 |   // rule. | 
 |   // CHECK: call void % | 
 |   p[0].f(); | 
 |  | 
 |   // FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array | 
 |   // element type and the pointee type are not similar, behavior is undefined). | 
 |   // CHECK: call void % | 
 |   p[1].f(); | 
 | } | 
 |  | 
 | struct B { | 
 |   virtual void f(); | 
 |   ~B(); | 
 |    | 
 |   B h(); | 
 | }; | 
 |  | 
 |  | 
 | void f() { | 
 |   // CHECK: call void @_ZN1B1fEv | 
 |   B().f(); | 
 |    | 
 |   // CHECK: call void @_ZN1B1fEv | 
 |   B().h().f(); | 
 | } | 
 |  | 
 | namespace test2 { | 
 |   struct foo { | 
 |     virtual void f(); | 
 |     virtual ~foo(); | 
 |   }; | 
 |  | 
 |   struct bar : public foo { | 
 |     virtual void f(); | 
 |     virtual ~bar(); | 
 |   }; | 
 |  | 
 |   void f(bar *b) { | 
 |     // CHECK: call void @_ZN5test23foo1fEv | 
 |     // CHECK: call %"struct.test2::foo"* @_ZN5test23fooD1Ev | 
 |     b->foo::f(); | 
 |     b->foo::~foo(); | 
 |   } | 
 | } | 
 |  | 
 | namespace test3 { | 
 |   // Test that we don't crash in this case. | 
 |   struct B { | 
 |   }; | 
 |   struct D : public B { | 
 |   }; | 
 |   void f(D d) { | 
 |     // CHECK-LABEL: define void @_ZN5test31fENS_1DE | 
 |     d.B::~B(); | 
 |   } | 
 | } | 
 |  | 
 | namespace test4 { | 
 |   struct Animal { | 
 |     virtual void eat(); | 
 |   }; | 
 |   struct Fish : Animal { | 
 |     virtual void eat(); | 
 |   }; | 
 |   struct Wrapper { | 
 |     Fish fish; | 
 |   }; | 
 |   extern Wrapper *p; | 
 |   void test() { | 
 |     // CHECK: call void @_ZN5test44Fish3eatEv | 
 |     p->fish.eat(); | 
 |   } | 
 | } | 
 |  | 
 | // Do not devirtualize to pure virtual function calls. | 
 | namespace test5 { | 
 |   struct X { | 
 |     virtual void f() = 0; | 
 |   }; | 
 |   struct Y {}; | 
 |   // CHECK-LABEL: define {{.*}} @_ZN5test51f | 
 |   void f(Y &y, X Y::*p) { | 
 |     // CHECK-NOT: call {{.*}} @_ZN5test51X1fEv | 
 |     // CHECK: call void % | 
 |     (y.*p).f(); | 
 |   }; | 
 |  | 
 |   struct Z final { | 
 |     virtual void f() = 0; | 
 |   }; | 
 |   // CHECK-LABEL: define {{.*}} @_ZN5test51g | 
 |   void g(Z &z) { | 
 |     // CHECK-NOT: call {{.*}} @_ZN5test51Z1fEv | 
 |     // CHECK: call void % | 
 |     z.f(); | 
 |   } | 
 |  | 
 |   struct Q { | 
 |     virtual void f() final = 0; | 
 |   }; | 
 |   // CHECK-LABEL: define {{.*}} @_ZN5test51h | 
 |   void h(Q &q) { | 
 |     // CHECK-NOT: call {{.*}} @_ZN5test51Q1fEv | 
 |     // CHECK: call void % | 
 |     q.f(); | 
 |   } | 
 | } |