xref: /llvm-project/clang/test/CodeGenCXX/stmtexpr.cpp (revision 0f1c1be1968076d6f96f8a7bcc4a15cf195ecd97)
1 // RUN: %clang_cc1 -Wno-unused-value -triple i686-linux-gnu -emit-llvm -o - %s | FileCheck %s
2 extern "C" int printf(...);
3 extern "C" void abort();
4 
5 struct A
6 {
7   int i;
AA8   A (int j) : i(j) {printf("this = %p A(%d)\n", this, j);}
AA9   A (const A &j) : i(j.i) {printf("this = %p const A&(%d)\n", this, i);}
operator =A10   A& operator= (const A &j) { i = j.i; abort(); return *this; }
~AA11   ~A() { printf("this = %p ~A(%d)\n", this, i); }
12 };
13 
14 struct B
15 {
16   int i;
BB17   B (const A& a) { i = a.i; }
BB18   B() {printf("this = %p B()\n", this);}
BB19   B (const B &j) : i(j.i) {printf("this = %p const B&(%d)\n", this, i);}
~BB20   ~B() { printf("this = %p ~B(%d)\n", this, i); }
21 };
22 
foo(int j)23 A foo(int j)
24 {
25   return ({ j ? A(1) : A(0); });
26 }
27 
28 
foo2()29 void foo2()
30 {
31   A b = ({ A a(1); A a1(2); A a2(3); a1; a2; a; });
32   if (b.i != 1)
33     abort();
34   A c = ({ A a(1); A a1(2); A a2(3); a1; a2; a; A a3(4); a2; a3; });
35   if (c.i != 4)
36     abort();
37 }
38 
foo3()39 void foo3()
40 {
41   const A &b = ({ A a(1); a; });
42   if (b.i != 1)
43     abort();
44 }
45 
foo4()46 void foo4()
47 {
48 // CHECK: call {{.*}} @_ZN1AC1Ei
49 // CHECK: call {{.*}} @_ZN1AC1ERKS_
50 // CHECK: call {{.*}} @_ZN1AD1Ev
51 // CHECK: call {{.*}} @_ZN1BC1ERK1A
52 // CHECK: call {{.*}} @_ZN1AD1Ev
53   const B &b = ({ A a(1); a; });
54   if (b.i != 1)
55     abort();
56 }
57 
main()58 int main()
59 {
60   foo2();
61   foo3();
62   foo4();
63   return foo(1).i-1;
64 }
65 
66 int a[128];
foo5()67 int* foo5() {
68 // CHECK-NOT: memcpy
69   // Check that array-to-pointer conversion occurs in a
70   // statement-expression.
71   return (({ a; }));
72 }
73 
74 // Make sure this doesn't crash.
foo5(bool b)75 int foo5(bool b) {
76   int y = 0;
77   y = ({ A a(1); if (b) goto G; a.i; });
78   G: return y;
79 }
80 
81 // When we emit a full expression with cleanups that contains branches out of
82 // the full expression, the result of the inner expression (the call to
83 // call_with_cleanups in this case) may not dominate the fallthrough destination
84 // of the shared cleanup block.
85 //
86 // In this case the CFG will be a sequence of two diamonds, but the only
87 // dynamically possible execution paths are both left hand branches and both
88 // right hand branches. The first diamond LHS will call bar, and the second
89 // diamond LHS will assign the result to v, but the call to bar does not
90 // dominate the assignment.
91 int bar(A, int);
cleanup_exit_scalar(bool b)92 extern "C" int cleanup_exit_scalar(bool b) {
93   int v = bar(A(1), ({ if (b) return 42; 13; }));
94   return v;
95 }
96 
97 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar({{.*}})
98 // CHECK: call {{.*}} @_ZN1AC1Ei
99 //    Spill after bar.
100 // CHECK: %[[v:[^ ]*]] = call{{.*}} i32 @_Z3bar1Ai({{.*}})
101 // CHECK-NEXT: store i32 %[[v]], ptr %[[tmp:[^, ]*]]
102 //    Do cleanup.
103 // CHECK: call {{.*}} @_ZN1AD1Ev
104 // CHECK: switch
105 //    Reload before v assignment.
106 // CHECK: %[[v:[^ ]*]] = load i32, ptr %[[tmp]]
107 // CHECK-NEXT: store i32 %[[v]], ptr %v
108 
109 // No need to spill when the expression result is a constant, constants don't
110 // have dominance problems.
cleanup_exit_scalar_constant(bool b)111 extern "C" int cleanup_exit_scalar_constant(bool b) {
112   int v = (A(1), (void)({ if (b) return 42; 0; }), 13);
113   return v;
114 }
115 
116 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar_constant({{.*}})
117 // CHECK: store i32 13, ptr %v
118 
119 // Check for the same bug for lvalue expression evaluation kind.
120 // FIXME: What about non-reference lvalues, like bitfield lvalues and vector
121 // lvalues?
122 int &getref();
cleanup_exit_lvalue(bool cond)123 extern "C" int cleanup_exit_lvalue(bool cond) {
124   int &r = (A(1), ({ if (cond) return 0; (void)0; }), getref());
125   return r;
126 }
127 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue({{.*}})
128 // CHECK: call {{.*}} @_ZN1AC1Ei
129 //    Spill after bar.
130 // CHECK: %[[v:[^ ]*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_Z6getrefv({{.*}})
131 // CHECK-NEXT: store ptr %[[v]], ptr %[[tmp:[^, ]*]]
132 //    Do cleanup.
133 // CHECK: call {{.*}} @_ZN1AD1Ev
134 // CHECK: switch
135 //    Reload before v assignment.
136 // CHECK: %[[v:[^ ]*]] = load ptr, ptr %[[tmp]]
137 // CHECK-NEXT: store ptr %[[v]], ptr %r
138 
139 // Bind the reference to a byval argument. It is not an instruction or Constant,
140 // so it's a bit of a corner case.
141 struct ByVal { int x[3]; };
cleanup_exit_lvalue_byval(bool cond,ByVal arg)142 extern "C" int cleanup_exit_lvalue_byval(bool cond, ByVal arg) {
143   ByVal &r = (A(1), ({ if (cond) return 0; (void)ByVal(); }), arg);
144   return r.x[0];
145 }
146 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_byval({{.*}}, ptr noundef byval(%struct.ByVal) align 4 %arg)
147 // CHECK: call {{.*}} @_ZN1AC1Ei
148 // CHECK: call {{.*}} @_ZN1AD1Ev
149 // CHECK: switch
150 // CHECK: store ptr %arg, ptr %r
151 
152 // Bind the reference to a local variable. We don't need to spill it. Binding a
153 // reference to it doesn't generate any instructions.
cleanup_exit_lvalue_local(bool cond)154 extern "C" int cleanup_exit_lvalue_local(bool cond) {
155   int local = 42;
156   int &r = (A(1), ({ if (cond) return 0; (void)0; }), local);
157   return r;
158 }
159 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_local({{.*}})
160 // CHECK: %local = alloca i32
161 // CHECK: store i32 42, ptr %local
162 // CHECK: call {{.*}} @_ZN1AC1Ei
163 // CHECK-NOT: store ptr %local
164 // CHECK: call {{.*}} @_ZN1AD1Ev
165 // CHECK: switch
166 // CHECK: store ptr %local, ptr %r, align 4
167 
168 // We handle ExprWithCleanups for complex evaluation type separately, and it had
169 // the same bug.
170 _Complex float bar_complex(A, int);
cleanup_exit_complex(bool b)171 extern "C" int cleanup_exit_complex(bool b) {
172   _Complex float v = bar_complex(A(1), ({ if (b) return 42; 13; }));
173   return (float)v;
174 }
175 
176 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_complex({{.*}})
177 // CHECK: call {{.*}} @_ZN1AC1Ei
178 //    Spill after bar.
179 // CHECK: call {{.*}} @_Z11bar_complex1Ai({{.*}})
180 // CHECK: store float %{{.*}}, ptr %[[tmp1:[^, ]*]]
181 // CHECK: store float %{{.*}}, ptr %[[tmp2:[^, ]*]]
182 //    Do cleanup.
183 // CHECK: call {{.*}} @_ZN1AD1Ev
184 // CHECK: switch
185 //    Reload before v assignment.
186 // CHECK: %[[v1:[^ ]*]] = load float, ptr %[[tmp1]]
187 // CHECK: %[[v2:[^ ]*]] = load float, ptr %[[tmp2]]
188 // CHECK: store float %[[v1]], ptr %v.realp
189 // CHECK: store float %[[v2]], ptr %v.imagp
190 
191 extern "C" void then(int);
192 
193 // CHECK-LABEL: @{{.*}}volatile_load
volatile_load()194 void volatile_load() {
195   volatile int n;
196 
197   // CHECK-NOT: load volatile
198   // CHECK: load volatile
199   // CHECK-NOT: load volatile
200   ({n;});
201 
202   // CHECK-LABEL: @then(i32 noundef 1)
203   then(1);
204 
205   // CHECK-NOT: load volatile
206   // CHECK: load volatile
207   // CHECK-NOT: load volatile
208   ({goto lab; lab: n;});
209 
210   // CHECK-LABEL: @then(i32 noundef 2)
211   then(2);
212 
213   // CHECK-NOT: load volatile
214   // CHECK: load volatile
215   // CHECK-NOT: load volatile
216   ({[[gsl::suppress("foo")]] n;});
217 
218   // CHECK-LABEL: @then(i32 noundef 3)
219   then(3);
220 
221   // CHECK-NOT: load volatile
222   // CHECK: load volatile
223   // CHECK-NOT: load volatile
224   ({if (true) n;});
225 
226   // CHECK: }
227 }
228 
229 // CHECK-LABEL: @{{.*}}volatile_load_template
230 template<typename T>
volatile_load_template()231 void volatile_load_template() {
232   volatile T n;
233 
234   // CHECK-NOT: load volatile
235   // CHECK: load volatile
236   // CHECK-NOT: load volatile
237   ({n;});
238 
239   // CHECK-LABEL: @then(i32 noundef 1)
240   then(1);
241 
242   // CHECK-NOT: load volatile
243   // CHECK: load volatile
244   // CHECK-NOT: load volatile
245   ({goto lab; lab: n;});
246 
247   // CHECK-LABEL: @then(i32 noundef 2)
248   then(2);
249 
250   // CHECK-NOT: load volatile
251   // CHECK: load volatile
252   // CHECK-NOT: load volatile
253   ({[[gsl::suppress("foo")]] n;});
254 
255   // CHECK-LABEL: @then(i32 noundef 3)
256   then(3);
257 
258   // CHECK-NOT: load volatile
259   // CHECK: load volatile
260   // CHECK-NOT: load volatile
261   ({if (true) n;});
262 
263   // CHECK: }
264 }
265 template void volatile_load_template<int>();
266