|  | // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s | 
|  | // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++98 %s | 
|  | // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++11 %s | 
|  | // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++17 %s | 
|  |  | 
|  | // PR4806 | 
|  | namespace test0 { | 
|  | class Box { | 
|  | public: | 
|  | int i; | 
|  | volatile int j; | 
|  | }; | 
|  |  | 
|  | void doit() { | 
|  | // pointer to volatile has side effect (thus no warning) | 
|  | Box* box = new Box; | 
|  | box->i; // expected-warning {{expression result unused}} | 
|  | box->j; | 
|  | #if __cplusplus <= 199711L | 
|  | // expected-warning@-2 {{expression result unused}} | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace test1 { | 
|  | struct Foo { | 
|  | int i; | 
|  | bool operator==(const Foo& rhs) { | 
|  | return i == rhs.i; | 
|  | } | 
|  | }; | 
|  |  | 
|  | #define NOP(x) (x) | 
|  | void b(Foo f1, Foo f2) { | 
|  | NOP(f1 == f2);  // expected-warning {{expression result unused}} | 
|  | } | 
|  | #undef NOP | 
|  | } | 
|  |  | 
|  | namespace test2 { | 
|  | extern "C++" { | 
|  | namespace std { | 
|  | template<typename T> struct basic_string { | 
|  | struct X {}; | 
|  | void method() const { | 
|  | X* x; | 
|  | &x[0];  // expected-warning {{expression result unused}} | 
|  | } | 
|  | }; | 
|  | typedef basic_string<char> string; | 
|  | void func(const std::string& str) { | 
|  | str.method();  // expected-note {{in instantiation of member function}} | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace test3 { | 
|  | struct Used { | 
|  | Used(); | 
|  | Used(int); | 
|  | Used(int, int); | 
|  | ~Used() {} | 
|  | }; | 
|  | struct __attribute__((warn_unused)) Unused { | 
|  | Unused(); | 
|  | Unused(int); | 
|  | Unused(int, int); | 
|  | ~Unused() {} | 
|  | }; | 
|  | void f() { | 
|  | Used(); | 
|  | Used(1); | 
|  | Used(1, 1); | 
|  | Unused();     // expected-warning {{expression result unused}} | 
|  | Unused(1);    // expected-warning {{expression result unused}} | 
|  | Unused(1, 1); // expected-warning {{expression result unused}} | 
|  | #if __cplusplus >= 201103L // C++11 or later | 
|  | Used({}); | 
|  | Unused({}); // expected-warning {{expression result unused}} | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace std { | 
|  | struct type_info {}; | 
|  | } | 
|  |  | 
|  | namespace test4 { | 
|  | struct Good { Good &f(); }; | 
|  | struct Bad { virtual Bad& f(); }; | 
|  |  | 
|  | void f() { | 
|  | int i = 0; | 
|  | (void)typeid(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}} | 
|  |  | 
|  | Good g; | 
|  | (void)typeid(g.f()); // Ok; not a polymorphic use of a glvalue. | 
|  |  | 
|  | // This is a polymorphic use of a glvalue, which results in the typeid being | 
|  | // evaluated instead of unevaluated. | 
|  | Bad b; | 
|  | (void)typeid(b.f()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} | 
|  |  | 
|  | // A dereference of a volatile pointer is a side effecting operation, however | 
|  | // since it is idiomatic code, and the alternatives induce higher maintenance | 
|  | // costs, it is allowed. | 
|  | int * volatile x; | 
|  | (void)sizeof(*x); // Ok | 
|  | } | 
|  | } | 
|  |  | 
|  | static volatile char var1 = 'a'; | 
|  | volatile char var2 = 'a'; | 
|  | static volatile char arr1[] = "hello"; | 
|  | volatile char arr2[] = "hello"; | 
|  | void volatile_array() { | 
|  | static volatile char var3 = 'a'; | 
|  | volatile char var4 = 'a'; | 
|  | static volatile char arr3[] = "hello"; | 
|  | volatile char arr4[] = "hello"; | 
|  |  | 
|  | // These all result in volatile loads in C and C++11. In C++98, they don't, | 
|  | // but we suppress the warning in the case where '(void)var;' might be | 
|  | // idiomatically suppressing an 'unused variable' warning. | 
|  | (void)var1; | 
|  | (void)var2; | 
|  | #if __cplusplus < 201103L | 
|  | // expected-warning@-2 {{expression result unused; assign into a variable to force a volatile load}} | 
|  | #endif | 
|  | (void)var3; | 
|  | (void)var4; | 
|  |  | 
|  | // None of these result in volatile loads in any language mode, and it's not | 
|  | // really reasonable to assume that they would, since volatile array loads | 
|  | // don't really exist anywhere. | 
|  | (void)arr1; | 
|  | (void)arr2; | 
|  | (void)arr3; | 
|  | (void)arr4; | 
|  | } | 
|  |  | 
|  | #if __cplusplus >= 201103L // C++11 or later | 
|  | namespace test5 { | 
|  | int v[(5, 6)]; // expected-warning {{left operand of comma operator has no effect}} | 
|  | void foo() { | 
|  | new double[false ? (1, 2) : 3] | 
|  | // FIXME: We shouldn't diagnose the unreachable constant expression | 
|  | // here. | 
|  | [false ? (1, 2) : 3]; // expected-warning {{left operand of comma operator has no effect}} | 
|  | } | 
|  | } // namespace test5 | 
|  |  | 
|  | // comma operator diagnostics should be suppressed in a SFINAE context. | 
|  | template <typename T, int = (T{},0)> int c(int) { return 0; } | 
|  | template <typename T, int> int c(double) { return 1; } | 
|  | int foo() { return c<int>(0); } | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #if __cplusplus >= 201703L // C++17 or later | 
|  | namespace test6 { | 
|  | auto b() { | 
|  | if constexpr (false) | 
|  | return (1,0); | 
|  | else | 
|  | return (1.0,0.0); // expected-warning {{left operand of comma operator has no effect}} | 
|  | } | 
|  | } // namespace test6 | 
|  | #endif |