1 // RUN: %clang_cc1 -std=c++98 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s
2 // RUN: %clang_cc1 -std=c++11 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s
3 // RUN: %clang_cc1 -std=c++1z %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s
4 
5 struct A {
6   virtual void f();
7   virtual void f_const() const;
8   virtual void g();
9 
10   A h();
11 };
12 
13 A g();
14 
f(A a,A * ap,A & ar)15 void f(A a, A *ap, A& ar) {
16   // This should not be a virtual function call.
17 
18   // CHECK: call void @_ZN1A1fEv(%struct.A* %a)
19   a.f();
20 
21   // CHECK: call void %
22   ap->f();
23 
24   // CHECK: call void %
25   ar.f();
26 
27   // CHECK: call void @_ZN1A1fEv
28   A().f();
29 
30   // CHECK: call void @_ZN1A1fEv
31   g().f();
32 
33   // CHECK: call void @_ZN1A1fEv
34   a.h().f();
35 
36   // CHECK: call void @_ZNK1A7f_constEv
37   a.f_const();
38 
39   // CHECK: call void @_ZN1A1fEv
40   (a).f();
41 }
42 
43 struct D : A { virtual void g(); };
44 struct XD { D d; };
45 
46 D gd();
47 
fd(D d,XD xd,D * p)48 void fd(D d, XD xd, D *p) {
49   // CHECK: call void @_ZN1A1fEv(%struct.A*
50   d.f();
51 
52   // CHECK: call void @_ZN1D1gEv(%struct.D*
53   d.g();
54 
55   // CHECK: call void @_ZN1A1fEv
56   D().f();
57 
58   // CHECK: call void @_ZN1D1gEv
59   D().g();
60 
61   // CHECK: call void @_ZN1A1fEv
62   gd().f();
63 
64   // CHECK: call void @_ZNK1A7f_constEv
65   d.f_const();
66 
67   // CHECK: call void @_ZN1A1fEv
68   (d).f();
69 
70   // CHECK: call void @_ZN1A1fEv
71   (true, d).f();
72 
73   // CHECK: call void @_ZN1D1gEv
74   (true, d).g();
75 
76   // CHECK: call void @_ZN1A1fEv
77   xd.d.f();
78 
79   // CHECK: call void @_ZN1A1fEv
80   XD().d.f();
81 
82   // CHECK: call void @_ZN1A1fEv
83   D XD::*mp;
84   (xd.*mp).f();
85 
86   // CHECK: call void @_ZN1D1gEv
87   (xd.*mp).g();
88 
89   // Can't devirtualize this; we have no guarantee that p points to a D here,
90   // due to the "single object is considered to be an array of one element"
91   // rule.
92   // CHECK: call void %
93   p[0].f();
94 
95   // FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array
96   // element type and the pointee type are not similar, behavior is undefined).
97   // CHECK: call void %
98   p[1].f();
99 }
100 
101 struct B {
102   virtual void f();
103   ~B();
104 
105   B h();
106 };
107 
108 
f()109 void f() {
110   // CHECK: call void @_ZN1B1fEv
111   B().f();
112 
113   // CHECK: call void @_ZN1B1fEv
114   B().h().f();
115 }
116 
117 namespace test2 {
118   struct foo {
119     virtual void f();
120     virtual ~foo();
121   };
122 
123   struct bar : public foo {
124     virtual void f();
125     virtual ~bar();
126   };
127 
f(bar * b)128   void f(bar *b) {
129     // CHECK: call void @_ZN5test23foo1fEv
130     // CHECK: call %"struct.test2::foo"* @_ZN5test23fooD1Ev
131     b->foo::f();
132     b->foo::~foo();
133   }
134 }
135 
136 namespace test3 {
137   // Test that we don't crash in this case.
138   struct B {
139   };
140   struct D : public B {
141   };
f(D d)142   void f(D d) {
143     // CHECK-LABEL: define void @_ZN5test31fENS_1DE
144     d.B::~B();
145   }
146 }
147 
148 namespace test4 {
149   struct Animal {
150     virtual void eat();
151   };
152   struct Fish : Animal {
153     virtual void eat();
154   };
155   struct Wrapper {
156     Fish fish;
157   };
158   extern Wrapper *p;
test()159   void test() {
160     // CHECK: call void @_ZN5test44Fish3eatEv
161     p->fish.eat();
162   }
163 }
164 
165 // Do not devirtualize to pure virtual function calls.
166 namespace test5 {
167   struct X {
168     virtual void f() = 0;
169   };
170   struct Y {};
171   // CHECK-LABEL: define {{.*}} @_ZN5test51f
f(Y & y,X Y::* p)172   void f(Y &y, X Y::*p) {
173     // CHECK-NOT: call {{.*}} @_ZN5test51X1fEv
174     // CHECK: call void %
175     (y.*p).f();
176   };
177 
178   struct Z final {
179     virtual void f() = 0;
180   };
181   // CHECK-LABEL: define {{.*}} @_ZN5test51g
g(Z & z)182   void g(Z &z) {
183     // CHECK-NOT: call {{.*}} @_ZN5test51Z1fEv
184     // CHECK: call void %
185     z.f();
186   }
187 
188   struct Q {
189     virtual void f() final = 0;
190   };
191   // CHECK-LABEL: define {{.*}} @_ZN5test51h
h(Q & q)192   void h(Q &q) {
193     // CHECK-NOT: call {{.*}} @_ZN5test51Q1fEv
194     // CHECK: call void %
195     q.f();
196   }
197 }
198