xref: /llvm-project/clang/test/SemaCXX/warn-unused-value.cpp (revision 3ad31e12ccfc7db25f3cbedc4ee966e7099ac78f)
1 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
2 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++98 %s
3 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++11 %s
4 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++17 %s
5 
6 // PR4806
7 namespace test0 {
8   class Box {
9   public:
10     int i;
11     volatile int j;
12   };
13 
doit()14   void doit() {
15     // pointer to volatile has side effect (thus no warning)
16     Box* box = new Box;
17     box->i; // expected-warning {{expression result unused}}
18     box->j;
19 #if __cplusplus <= 199711L
20     // expected-warning@-2 {{expression result unused}}
21 #endif
22   }
23 }
24 
25 namespace test1 {
26 struct Foo {
27   int i;
operator ==test1::Foo28   bool operator==(const Foo& rhs) {
29     return i == rhs.i;
30   }
31 };
32 
33 #define NOP(x) (x)
b(Foo f1,Foo f2)34 void b(Foo f1, Foo f2) {
35   NOP(f1 == f2);  // expected-warning {{expression result unused}}
36 }
37 #undef NOP
38 }
39 
40 namespace test2 {
41   extern "C++" {
42     namespace std {
43       template<typename T> struct basic_string {
44         struct X {};
methodtest2::std::basic_string45         void method() const {
46          X* x;
47          &x[0];  // expected-warning {{expression result unused}}
48         }
49       };
50       typedef basic_string<char> string;
func(const std::string & str)51       void func(const std::string& str) {
52         str.method();  // expected-note {{in instantiation of member function}}
53       }
54     }
55   }
56 }
57 
58 namespace test3 {
59 struct Used {
60   Used();
61   Used(int);
62   Used(int, int);
~Usedtest3::Used63   ~Used() {}
64 };
65 struct __attribute__((warn_unused)) Unused {
66   Unused();
67   Unused(int);
68   Unused(int, int);
~Unusedtest3::Unused69   ~Unused() {}
70 };
f()71 void f() {
72   Used();
73   Used(1);
74   Used(1, 1);
75   Unused();     // expected-warning {{expression result unused}}
76   Unused(1);    // expected-warning {{expression result unused}}
77   Unused(1, 1); // expected-warning {{expression result unused}}
78 #if __cplusplus >= 201103L // C++11 or later
79   Used({});
80   Unused({}); // expected-warning {{expression result unused}}
81 #endif
82 }
83 }
84 
85 namespace std {
86   struct type_info {};
87 }
88 
89 namespace test4 {
90 struct Good { Good &f(); };
91 struct Bad { virtual Bad& f(); };
92 
f()93 void f() {
94   int i = 0;
95   (void)typeid(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
96 
97   Good g;
98   (void)typeid(g.f()); // Ok; not a polymorphic use of a glvalue.
99 
100   // This is a polymorphic use of a glvalue, which results in the typeid being
101   // evaluated instead of unevaluated.
102   Bad b;
103   (void)typeid(b.f()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
104 
105   extern Bad * pb;
106   // This typeid can throw but that is not a side-effect that we care about
107   // warning for since this is idiomatic code
108   (void)typeid(*pb);
109   (void)sizeof(typeid(*pb));
110   (void)typeid(*++pb); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
111   (void)sizeof(typeid(*++pb)); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
112   // FIXME: we should not warn about this in an unevaluated context
113   // expected-warning@-2 {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
114 
115   // A dereference of a volatile pointer is a side effecting operation, however
116   // since it is idiomatic code, and the alternatives induce higher maintenance
117   // costs, it is allowed.
118   int * volatile x;
119   (void)sizeof(*x); // Ok
120 }
121 }
122 
123 static volatile char var1 = 'a';
124 volatile char var2 = 'a';
125 static volatile char arr1[] = "hello";
126 volatile char arr2[] = "hello";
volatile_array()127 void volatile_array() {
128   static volatile char var3 = 'a';
129   volatile char var4 = 'a';
130   static volatile char arr3[] = "hello";
131   volatile char arr4[] = "hello";
132 
133   // These all result in volatile loads in C and C++11. In C++98, they don't,
134   // but we suppress the warning in the case where '(void)var;' might be
135   // idiomatically suppressing an 'unused variable' warning.
136   (void)var1;
137   (void)var2;
138 #if __cplusplus < 201103L
139   // expected-warning@-2 {{expression result unused; assign into a variable to force a volatile load}}
140 #endif
141   (void)var3;
142   (void)var4;
143 
144   // None of these result in volatile loads in any language mode, and it's not
145   // really reasonable to assume that they would, since volatile array loads
146   // don't really exist anywhere.
147   (void)arr1;
148   (void)arr2;
149   (void)arr3;
150   (void)arr4;
151 }
152 
153 #if __cplusplus >= 201103L // C++11 or later
154 namespace test5 {
155 int v[(5, 6)]; // expected-warning {{left operand of comma operator has no effect}}
foo()156 void foo() {
157   new double[false ? (1, 2) : 3]
158             // FIXME: We shouldn't diagnose the unreachable constant expression
159             // here.
160             [false ? (1, 2) : 3]; // expected-warning {{left operand of comma operator has no effect}}
161 }
162 } // namespace test5
163 
164 // comma operator diagnostics should be suppressed in a SFINAE context.
c(int)165 template <typename T, int = (T{},0)> int c(int) { return 0; }
c(double)166 template <typename T, int> int c(double) { return 1; }
foo()167 int foo() { return c<int>(0); }
168 
169 #endif
170 
171 #if __cplusplus >= 201703L // C++17 or later
172 namespace test6 {
b()173 auto b() {
174   if constexpr (false)
175     return (1,0);
176   else
177     return (1.0,0.0); // expected-warning {{left operand of comma operator has no effect}}
178 }
179 } // namespace test6
180 #endif
181