// RUN: %clang_cc1 -fsyntax-only -Wcomma -std=c++11 -verify %s // RUN: %clang_cc1 -fsyntax-only -Wcomma -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c89 -verify %s // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c99 -verify %s // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c11 -verify %s // RUN: %clang_cc1 -fsyntax-only -Wcomma -x c -std=c17 -verify %s // int returning function int return_four(void) { return 5; } // Test builtin operators void test_builtin(void) { int x = 0, y = 0; for (; y < 10; x++, y++) {} for (; y < 10; ++x, y++) {} for (; y < 10; x++, ++y) {} for (; y < 10; ++x, ++y) {} for (; y < 10; x--, ++y) {} for (; y < 10; --x, ++y) {} for (; y < 10; x = 5, ++y) {} for (; y < 10; x *= 5, ++y) {} for (; y < 10; x /= 5, ++y) {} for (; y < 10; x %= 5, ++y) {} for (; y < 10; x += 5, ++y) {} for (; y < 10; x -= 5, ++y) {} for (; y < 10; x <<= 5, ++y) {} for (; y < 10; x >>= 5, ++y) {} for (; y < 10; x &= 5, ++y) {} for (; y < 10; x |= 5, ++y) {} for (; y < 10; x ^= 5, ++y) {} } // Test nested comma operators void test_nested(void) { int x1, x2, x3; int y1, *y2 = 0, y3 = 5; #if __STDC_VERSION >= 199901L for (int z1 = 5, z2 = 4, z3 = 3; x1 <4; ++x1) {} #endif } // Confusing "," for "==" void test_compare(void) { if (return_four(), 5) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:7-[[@LINE-3]]:7}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:20-[[@LINE-4]]:20}:")" if (return_four() == 5) {} } // Confusing "," for "+" int test_plus(void) { return return_four(), return_four(); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")" return return_four() + return_four(); } // Be sure to look through parentheses void test_parentheses(void) { int x, y; for (x = 0; return_four(), x;) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:15-[[@LINE-3]]:15}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:28-[[@LINE-4]]:28}:")" for (x = 0; (return_four()), (x) ;) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:15-[[@LINE-3]]:15}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:30-[[@LINE-4]]:30}:")" } void test_increment(void) { int x, y; ++x, ++y; // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:6-[[@LINE-4]]:6}:")" } // Check for comma operator in conditions. void test_conditions(int x) { x = (return_four(), x); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:8-[[@LINE-3]]:8}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:21-[[@LINE-4]]:21}:")" int y = (return_four(), x); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:25-[[@LINE-4]]:25}:")" for (; return_four(), x;) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")" while (return_four(), x) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:23-[[@LINE-4]]:23}:")" if (return_four(), x) {} // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:7-[[@LINE-3]]:7}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:20-[[@LINE-4]]:20}:")" do { } while (return_four(), x); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:30-[[@LINE-4]]:30}:")" } // Nested comma operator with fix-its. void test_nested_fixits(void) { return_four(), return_four(), return_four(), return_four(); // expected-warning@-1 3{{comma operator}} // expected-note@-2 3{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:16-[[@LINE-4]]:16}:")" // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:18-[[@LINE-5]]:18}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:31-[[@LINE-6]]:31}:")" // CHECK: fix-it:{{.*}}:{[[@LINE-7]]:33-[[@LINE-7]]:33}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-8]]:46-[[@LINE-8]]:46}:")" } void void_func(); int int_func() { return 0; } void void_function_comma(){ void_func(), int_func(); // expected no -Wcomma because of the returning type `void` // Reported by https://github.com/llvm/llvm-project/issues/57151 // Descriptions about -Wcomma: https://reviews.llvm.org/D3976 } typedef void Void; Void typedef_func(); void whatever() { // We don't get confused about type aliases. typedef_func(), int_func(); // Even function pointers don't confuse us. void (*fp)() = void_func; fp(), int_func(); } #ifdef __cplusplus class S2 { public: void advance(); S2 operator++(); S2 operator++(int); S2 operator--(); S2 operator--(int); S2 operator=(int); S2 operator*=(int); S2 operator/=(int); S2 operator%=(int); S2 operator+=(int); S2 operator-=(int); S2 operator<<=(int); S2 operator>>=(int); S2 operator&=(int); S2 operator|=(int); S2 operator^=(int); }; // Test overloaded operators void test_overloaded_operator() { S2 x; int y; for (; y < 10; x++, y++) {} for (; y < 10; ++x, y++) {} for (; y < 10; x++, ++y) {} for (; y < 10; ++x, ++y) {} for (; y < 10; x--, ++y) {} for (; y < 10; --x, ++y) {} for (; y < 10; x = 5, ++y) {} for (; y < 10; x *= 5, ++y) {} for (; y < 10; x /= 5, ++y) {} for (; y < 10; x %= 5, ++y) {} for (; y < 10; x += 5, ++y) {} for (; y < 10; x -= 5, ++y) {} for (; y < 10; x <<= 5, ++y) {} for (; y < 10; x >>= 5, ++y) {} for (; y < 10; x &= 5, ++y) {} for (; y < 10; x |= 5, ++y) {} for (; y < 10; x ^= 5, ++y) {} } class Stream { public: Stream& operator<<(int); } cout; // Confusing "," for "<<" void test_stream() { cout << 5 << return_four(); cout << 5, return_four(); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:3-[[@LINE-3]]:3}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:12-[[@LINE-4]]:12}:")" } void Concat(int); void Concat(int, int); // Testing extra parentheses in function call void test_overloaded_function() { Concat((return_four() , 5)); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:24-[[@LINE-4]]:24}:")" Concat(return_four() , 5); } bool DoStuff(); class S9 { public: bool Advance(); bool More(); }; // Ignore comma operator in for-loop initializations and increments. void test_for_loop() { int x, y; for (x = 0, y = 5; x < y; ++x) {} for (x = 0; x < 10; DoStuff(), ++x) {} for (S9 s; s.More(); s.Advance(), ++x) {} } // Ignore comma operator in templates. namespace test_template { template struct B { static const bool value = T; }; typedef B true_type; typedef B false_type; template struct bool_seq; template class Foo { typedef bool_seq<((void)xs::value, true)...> all_true; typedef bool_seq<((void)xs::value, false)...> all_false; typedef bool_seq seq; }; const auto X = Foo(); } namespace test_mutex { class Mutex { public: Mutex(); ~Mutex(); }; class MutexLock { public: MutexLock(Mutex &); MutexLock(); ~MutexLock(); }; class BuiltinMutex { Mutex M; }; Mutex StatusMutex; bool Status; bool get_status() { return (MutexLock(StatusMutex), Status); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:33-[[@LINE-4]]:33}:")" return (MutexLock(), Status); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:22-[[@LINE-4]]:22}:")" return (BuiltinMutex(), Status); // expected-warning@-1{{comma operator}} // expected-note@-2{{cast expression to void}} // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:11-[[@LINE-3]]:11}:"static_cast(" // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:25-[[@LINE-4]]:25}:")" } } // PR39375 - test cast to void to silence warnings template void test_dependent_cast() { (void)42, 0; static_cast(42), 0; (void)T{}, 0; static_cast(T{}), 0; } namespace { // issue #57151 struct S { void mem() {} }; void whatever() { struct S s; // Member function calls also work as expected. s.mem(), int_func(); // As do lambda calls. []() { return; }(), int_func(); } } // namespace #endif // ifdef __cplusplus