xref: /llvm-project/clang/test/SemaCXX/warn-comma-operator.cpp (revision ccbc22cd8976c285d76e9f66dd5cac2fe908d084)
1 // RUN: %clang_cc1 -fsyntax-only -Wcomma -std=c++11 -verify %s
2 // RUN: %clang_cc1 -fsyntax-only -Wcomma -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
3 
4 // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c89 -verify %s
5 // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c99 -verify %s
6 // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c11 -verify %s
7 // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c17 -verify %s
8 
9 // int returning function
return_four(void)10 int return_four(void) { return 5; }
11 
12 // Test builtin operators
test_builtin(void)13 void test_builtin(void) {
14   int x = 0, y = 0;
15   for (; y < 10; x++, y++) {}
16   for (; y < 10; ++x, y++) {}
17   for (; y < 10; x++, ++y) {}
18   for (; y < 10; ++x, ++y) {}
19   for (; y < 10; x--, ++y) {}
20   for (; y < 10; --x, ++y) {}
21   for (; y < 10; x = 5, ++y) {}
22   for (; y < 10; x *= 5, ++y) {}
23   for (; y < 10; x /= 5, ++y) {}
24   for (; y < 10; x %= 5, ++y) {}
25   for (; y < 10; x += 5, ++y) {}
26   for (; y < 10; x -= 5, ++y) {}
27   for (; y < 10; x <<= 5, ++y) {}
28   for (; y < 10; x >>= 5, ++y) {}
29   for (; y < 10; x &= 5, ++y) {}
30   for (; y < 10; x |= 5, ++y) {}
31   for (; y < 10; x ^= 5, ++y) {}
32 }
33 
34 // Test nested comma operators
test_nested(void)35 void test_nested(void) {
36   int x1, x2, x3;
37   int y1, *y2 = 0, y3 = 5;
38 
39 #if __STDC_VERSION >= 199901L
40   for (int z1 = 5, z2 = 4, z3 = 3; x1 <4; ++x1) {}
41 #endif
42 }
43 
44 // Confusing "," for "=="
test_compare(void)45 void test_compare(void) {
46   if (return_four(), 5) {}
47   // expected-warning@-1{{comma operator}}
48   // expected-note@-2{{cast expression to void}}
49   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:7-[[@LINE-3]]:7}:"static_cast<void>("
50   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:20-[[@LINE-4]]:20}:")"
51 
52   if (return_four() == 5) {}
53 }
54 
55 // Confusing "," for "+"
test_plus(void)56 int test_plus(void) {
57   return return_four(), return_four();
58   // expected-warning@-1{{comma operator}}
59   // expected-note@-2{{cast expression to void}}
60   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<void>("
61   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")"
62 
63   return return_four() + return_four();
64 }
65 
66 // Be sure to look through parentheses
test_parentheses(void)67 void test_parentheses(void) {
68   int x, y;
69   for (x = 0; return_four(), x;) {}
70   // expected-warning@-1{{comma operator}}
71   // expected-note@-2{{cast expression to void}}
72   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:15-[[@LINE-3]]:15}:"static_cast<void>("
73   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:28-[[@LINE-4]]:28}:")"
74 
75   for (x = 0; (return_four()), (x) ;) {}
76   // expected-warning@-1{{comma operator}}
77   // expected-note@-2{{cast expression to void}}
78   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:15-[[@LINE-3]]:15}:"static_cast<void>("
79   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:30-[[@LINE-4]]:30}:")"
80 }
81 
test_increment(void)82 void test_increment(void) {
83   int x, y;
84   ++x, ++y;
85   // expected-warning@-1{{comma operator}}
86   // expected-note@-2{{cast expression to void}}
87   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast<void>("
88   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:6-[[@LINE-4]]:6}:")"
89 }
90 
91 // Check for comma operator in conditions.
test_conditions(int x)92 void test_conditions(int x) {
93   x = (return_four(), x);
94   // expected-warning@-1{{comma operator}}
95   // expected-note@-2{{cast expression to void}}
96   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:8-[[@LINE-3]]:8}:"static_cast<void>("
97   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:21-[[@LINE-4]]:21}:")"
98 
99   int y = (return_four(), x);
100   // expected-warning@-1{{comma operator}}
101   // expected-note@-2{{cast expression to void}}
102   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:"static_cast<void>("
103   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:25-[[@LINE-4]]:25}:")"
104 
105   for (; return_four(), x;) {}
106   // expected-warning@-1{{comma operator}}
107   // expected-note@-2{{cast expression to void}}
108   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<void>("
109   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")"
110 
111   while (return_four(), x) {}
112   // expected-warning@-1{{comma operator}}
113   // expected-note@-2{{cast expression to void}}
114   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<void>("
115   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")"
116 
117   if (return_four(), x) {}
118   // expected-warning@-1{{comma operator}}
119   // expected-note@-2{{cast expression to void}}
120   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:7-[[@LINE-3]]:7}:"static_cast<void>("
121   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:20-[[@LINE-4]]:20}:")"
122 
123   do { } while (return_four(), x);
124   // expected-warning@-1{{comma operator}}
125   // expected-note@-2{{cast expression to void}}
126   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:"static_cast<void>("
127   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:30-[[@LINE-4]]:30}:")"
128 }
129 
130 // Nested comma operator with fix-its.
test_nested_fixits(void)131 void test_nested_fixits(void) {
132   return_four(), return_four(), return_four(), return_four();
133   // expected-warning@-1 3{{comma operator}}
134   // expected-note@-2 3{{cast expression to void}}
135   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast<void>("
136   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:16-[[@LINE-4]]:16}:")"
137   // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:18-[[@LINE-5]]:18}:"static_cast<void>("
138   // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:31-[[@LINE-6]]:31}:")"
139   // CHECK: fix-it:{{.*}}:{[[@LINE-7]]:33-[[@LINE-7]]:33}:"static_cast<void>("
140   // CHECK: fix-it:{{.*}}:{[[@LINE-8]]:46-[[@LINE-8]]:46}:")"
141 }
142 
143 
144 void void_func();
int_func()145 int int_func() { return 0; }
146 
void_function_comma()147 void void_function_comma(){
148   void_func(), int_func(); // expected no -Wcomma because of the returning type `void`
149   // Reported by https://github.com/llvm/llvm-project/issues/57151
150   // Descriptions about -Wcomma: https://reviews.llvm.org/D3976
151 }
152 
153 typedef void Void;
154 Void typedef_func();
155 
whatever()156 void whatever() {
157   // We don't get confused about type aliases.
158   typedef_func(), int_func();
159   // Even function pointers don't confuse us.
160   void (*fp)() = void_func;
161   fp(), int_func();
162 }
163 
164 #ifdef __cplusplus
165 class S2 {
166 public:
167   void advance();
168 
169   S2 operator++();
170   S2 operator++(int);
171   S2 operator--();
172   S2 operator--(int);
173   S2 operator=(int);
174   S2 operator*=(int);
175   S2 operator/=(int);
176   S2 operator%=(int);
177   S2 operator+=(int);
178   S2 operator-=(int);
179   S2 operator<<=(int);
180   S2 operator>>=(int);
181   S2 operator&=(int);
182   S2 operator|=(int);
183   S2 operator^=(int);
184 };
185 
186 // Test overloaded operators
test_overloaded_operator()187 void test_overloaded_operator() {
188   S2 x;
189   int y;
190   for (; y < 10; x++, y++) {}
191   for (; y < 10; ++x, y++) {}
192   for (; y < 10; x++, ++y) {}
193   for (; y < 10; ++x, ++y) {}
194   for (; y < 10; x--, ++y) {}
195   for (; y < 10; --x, ++y) {}
196   for (; y < 10; x = 5, ++y) {}
197   for (; y < 10; x *= 5, ++y) {}
198   for (; y < 10; x /= 5, ++y) {}
199   for (; y < 10; x %= 5, ++y) {}
200   for (; y < 10; x += 5, ++y) {}
201   for (; y < 10; x -= 5, ++y) {}
202   for (; y < 10; x <<= 5, ++y) {}
203   for (; y < 10; x >>= 5, ++y) {}
204   for (; y < 10; x &= 5, ++y) {}
205   for (; y < 10; x |= 5, ++y) {}
206   for (; y < 10; x ^= 5, ++y) {}
207 }
208 
209 class Stream {
210  public:
211   Stream& operator<<(int);
212 } cout;
213 
214 // Confusing "," for "<<"
test_stream()215 void test_stream() {
216   cout << 5 << return_four();
217   cout << 5, return_four();
218   // expected-warning@-1{{comma operator}}
219   // expected-note@-2{{cast expression to void}}
220   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast<void>("
221   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:12-[[@LINE-4]]:12}:")"
222 }
223 
224 void Concat(int);
225 void Concat(int, int);
226 
227 // Testing extra parentheses in function call
test_overloaded_function()228 void test_overloaded_function() {
229   Concat((return_four() , 5));
230   // expected-warning@-1{{comma operator}}
231   // expected-note@-2{{cast expression to void}}
232   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast<void>("
233   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:24-[[@LINE-4]]:24}:")"
234 
235   Concat(return_four() , 5);
236 }
237 
238 bool DoStuff();
239 class S9 {
240 public:
241  bool Advance();
242  bool More();
243 };
244 
245 // Ignore comma operator in for-loop initializations and increments.
test_for_loop()246 void test_for_loop() {
247   int x, y;
248   for (x = 0, y = 5; x < y; ++x) {}
249   for (x = 0; x < 10; DoStuff(), ++x) {}
250   for (S9 s; s.More(); s.Advance(), ++x) {}
251 }
252 
253 // Ignore comma operator in templates.
254 namespace test_template {
255 template <bool T>
256 struct B { static const bool value = T; };
257 
258 typedef B<true> true_type;
259 typedef B<false> false_type;
260 
261 template <bool...>
262 struct bool_seq;
263 
264 template <typename... xs>
265 class Foo {
266   typedef bool_seq<((void)xs::value, true)...> all_true;
267   typedef bool_seq<((void)xs::value, false)...> all_false;
268   typedef bool_seq<xs::value...> seq;
269 };
270 
271 const auto X = Foo<true_type>();
272 }
273 
274 namespace test_mutex {
275 class Mutex {
276  public:
277   Mutex();
278   ~Mutex();
279 };
280 class MutexLock {
281 public:
282   MutexLock(Mutex &);
283   MutexLock();
284   ~MutexLock();
285 };
286 class BuiltinMutex {
287   Mutex M;
288 };
289 Mutex StatusMutex;
290 bool Status;
291 
get_status()292 bool get_status() {
293   return (MutexLock(StatusMutex), Status);
294   // expected-warning@-1{{comma operator}}
295   // expected-note@-2{{cast expression to void}}
296   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast<void>("
297   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:33-[[@LINE-4]]:33}:")"
298   return (MutexLock(), Status);
299   // expected-warning@-1{{comma operator}}
300   // expected-note@-2{{cast expression to void}}
301   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast<void>("
302   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:22-[[@LINE-4]]:22}:")"
303   return (BuiltinMutex(), Status);
304   // expected-warning@-1{{comma operator}}
305   // expected-note@-2{{cast expression to void}}
306   // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast<void>("
307   // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:25-[[@LINE-4]]:25}:")"
308 }
309 }
310 
311 // PR39375 - test cast to void to silence warnings
312 template <typename T>
test_dependent_cast()313 void test_dependent_cast() {
314   (void)42, 0;
315   static_cast<void>(42), 0;
316 
317   (void)T{}, 0;
318   static_cast<void>(T{}), 0;
319 }
320 
321 namespace {
322 
323 // issue #57151
324 
325 struct S {
mem__anon5eb83f490111::S326   void mem() {}
327 };
328 
whatever()329 void whatever() {
330   struct S s;
331   // Member function calls also work as expected.
332   s.mem(), int_func();
333   // As do lambda calls.
334   []() { return; }(), int_func();
335 }
336 
337 } // namespace
338 
339 #endif  // ifdef __cplusplus
340