xref: /llvm-project/clang/test/SemaCXX/warn-unused-result.cpp (revision 3edbe36c3eb01d1c35ac1761da108e3a493258ee)
1 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
2 
3 int f() __attribute__((warn_unused_result));
4 
5 struct S {
6   void t() const;
7 };
8 S g1() __attribute__((warn_unused_result));
9 S *g2() __attribute__((warn_unused_result));
10 S &g3() __attribute__((warn_unused_result));
11 
12 void test() {
13   f(); // expected-warning {{ignoring return value}}
14   g1(); // expected-warning {{ignoring return value}}
15   g2(); // expected-warning {{ignoring return value}}
16   g3(); // expected-warning {{ignoring return value}}
17 
18   (void)f();
19   (void)g1();
20   (void)g2();
21   (void)g3();
22 
23   if (f() == 0) return;
24 
25   g1().t();
26   g2()->t();
27   g3().t();
28 
29   int i = f();
30   S s1 = g1();
31   S *s2 = g2();
32   S &s3 = g3();
33   const S &s4 = g1();
34 }
35 
36 void testSubstmts(int i) {
37   switch (i) {
38   case 0:
39     f(); // expected-warning {{ignoring return value}}
40   default:
41     f(); // expected-warning {{ignoring return value}}
42   }
43 
44   if (i)
45     f(); // expected-warning {{ignoring return value}}
46   else
47     f(); // expected-warning {{ignoring return value}}
48 
49   while (i)
50     f(); // expected-warning {{ignoring return value}}
51 
52   do
53     f(); // expected-warning {{ignoring return value}}
54   while (i);
55 
56   for (f(); // expected-warning {{ignoring return value}}
57        ;
58        f() // expected-warning {{ignoring return value}}
59       )
60     f(); // expected-warning {{ignoring return value}}
61 
62   f(),  // expected-warning {{ignoring return value}}
63   (void)f();
64 }
65 
66 struct X {
67  int foo() __attribute__((warn_unused_result));
68 };
69 
70 void bah() {
71   X x, *x2;
72   x.foo(); // expected-warning {{ignoring return value}}
73   x2->foo(); // expected-warning {{ignoring return value}}
74 }
75 
76 namespace warn_unused_CXX11 {
77 class Status;
78 class Foo {
79  public:
80   Status doStuff();
81 };
82 
83 struct [[clang::warn_unused_result]] Status {
84   bool ok() const;
85   Status& operator=(const Status& x);
86   inline void Update(const Status& new_status) {
87     if (ok()) {
88       *this = new_status; //no-warning
89     }
90   }
91 };
92 Status DoSomething();
93 Status& DoSomethingElse();
94 Status* DoAnotherThing();
95 Status** DoYetAnotherThing();
96 void lazy() {
97   Status s = DoSomething();
98   if (!s.ok()) return;
99   Status &rs = DoSomethingElse();
100   if (!rs.ok()) return;
101   Status *ps = DoAnotherThing();
102   if (!ps->ok()) return;
103   Status **pps = DoYetAnotherThing();
104   if (!(*pps)->ok()) return;
105 
106   (void)DoSomething();
107   (void)DoSomethingElse();
108   (void)DoAnotherThing();
109   (void)DoYetAnotherThing();
110 
111   DoSomething(); // expected-warning {{ignoring return value of type 'Status' declared with 'warn_unused_result'}}
112   DoSomethingElse();
113   DoAnotherThing();
114   DoYetAnotherThing();
115 }
116 
117 template <typename T>
118 class [[clang::warn_unused_result]] StatusOr {
119 };
120 StatusOr<int> doit();
121 void test() {
122   Foo f;
123   f.doStuff(); // expected-warning {{ignoring return value of type 'Status' declared with 'warn_unused_result'}}
124   doit(); // expected-warning {{ignoring return value of type 'StatusOr<int>' declared with 'warn_unused_result'}}
125 
126   auto func = []() { return Status(); };
127   func(); // expected-warning {{ignoring return value of type 'Status' declared with 'warn_unused_result'}}
128 }
129 }
130 
131 namespace PR17587 {
132 struct [[clang::warn_unused_result]] Status;
133 
134 struct Foo {
135   Status Bar();
136 };
137 
138 struct Status {};
139 
140 void Bar() {
141   Foo f;
142   f.Bar(); // expected-warning {{ignoring return value of type 'Status' declared with 'warn_unused_result'}}
143 };
144 
145 }
146 
147 namespace PR18571 {
148 // Unevaluated contexts should not trigger unused result warnings.
149 template <typename T>
150 auto foo(T) -> decltype(f(), bool()) { // Should not warn.
151   return true;
152 }
153 
154 void g() {
155   foo(1);
156 }
157 }
158 
159 namespace std {
160 class type_info { };
161 }
162 
163 namespace {
164 // The typeid expression operand is evaluated only when the expression type is
165 // a glvalue of polymorphic class type.
166 
167 struct B {
168   virtual void f() {}
169 };
170 
171 struct D : B {
172   void f() override {}
173 };
174 
175 struct C {};
176 
177 void g() {
178   // The typeid expression operand is evaluated only when the expression type is
179   // a glvalue of polymorphic class type; otherwise the expression operand is not
180   // evaluated and should not trigger a diagnostic.
181   D d;
182   C c;
183   (void)typeid(f(), c); // Should not warn.
184   (void)typeid(f(), d); // expected-warning {{ignoring return value}} expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
185 
186   // The sizeof expression operand is never evaluated.
187   (void)sizeof(f(), c); // Should not warn.
188 
189    // The noexcept expression operand is never evaluated.
190   (void)noexcept(f(), false); // Should not warn.
191 }
192 }
193 
194 namespace {
195 // C++ Methods should warn even in their own class.
196 struct [[clang::warn_unused_result]] S {
197   S DoThing() { return {}; };
198   S operator++(int) { return {}; };
199   S operator--(int) { return {}; };
200   // Improperly written prefix.
201   S operator++() { return {}; };
202   S operator--() { return {}; };
203 };
204 
205 struct [[clang::warn_unused_result]] P {
206   P DoThing() { return {}; };
207 };
208 
209 P operator++(const P &, int) { return {}; };
210 P operator--(const P &, int) { return {}; };
211 // Improperly written prefix.
212 P operator++(const P &) { return {}; };
213 P operator--(const P &) { return {}; };
214 
215 void f() {
216   S s;
217   P p;
218   s.DoThing(); // expected-warning {{ignoring return value of type 'S' declared with 'warn_unused_result'}}
219   p.DoThing(); // expected-warning {{ignoring return value of type 'P' declared with 'warn_unused_result'}}
220   // Only postfix is expected to warn when written correctly.
221   s++; // expected-warning {{ignoring return value of type 'S' declared with 'warn_unused_result'}}
222   s--; // expected-warning {{ignoring return value of type 'S' declared with 'warn_unused_result'}}
223   p++; // expected-warning {{ignoring return value of type 'P' declared with 'warn_unused_result'}}
224   p--; // expected-warning {{ignoring return value of type 'P' declared with 'warn_unused_result'}}
225   // Improperly written prefix operators should still warn.
226   ++s; // expected-warning {{ignoring return value of type 'S' declared with 'warn_unused_result'}}
227   --s; // expected-warning {{ignoring return value of type 'S' declared with 'warn_unused_result'}}
228   ++p; // expected-warning {{ignoring return value of type 'P' declared with 'warn_unused_result'}}
229   --p; // expected-warning {{ignoring return value of type 'P' declared with 'warn_unused_result'}}
230 
231   // Silencing the warning by cast to void still works.
232   (void)s.DoThing();
233   (void)s++;
234   (void)p++;
235   (void)++s;
236   (void)++p;
237 }
238 } // namespace
239 
240 namespace PR39837 {
241 [[clang::warn_unused_result]] int f(int);
242 
243 void g() {
244   int a[2];
245   for (int b : a)
246     f(b); // expected-warning {{ignoring return value of function declared with 'warn_unused_result'}}
247 }
248 } // namespace PR39837
249 
250 namespace PR45520 {
251 [[nodiscard]] bool (*f)(); // expected-warning {{'nodiscard' attribute only applies to functions, classes, or enumerations}}
252 [[clang::warn_unused_result]] bool (*g)();
253 __attribute__((warn_unused_result)) bool (*h)();
254 
255 void i([[nodiscard]] bool (*fp)()); // expected-warning {{'nodiscard' attribute only applies to functions, classes, or enumerations}}
256 }
257 
258 namespace unused_typedef_result {
259 [[clang::warn_unused_result]] typedef void *a;
260 typedef a indirect;
261 a af1();
262 indirect indirectf1();
263 void af2() {
264   af1(); // expected-warning {{ignoring return value of type 'a' declared with 'warn_unused_result'}}
265   void *(*a1)();
266   a1(); // no warning
267   a (*a2)();
268   a2(); // expected-warning {{ignoring return value of type 'a' declared with 'warn_unused_result'}}
269   indirectf1(); // expected-warning {{ignoring return value of type 'a' declared with 'warn_unused_result'}}
270 }
271 [[nodiscard]] typedef void *b1; // expected-warning {{'[[nodiscard]]' attribute ignored when applied to a typedef; consider using '__attribute__((warn_unused_result))' or '[[clang::warn_unused_result]]' instead}}
272 [[gnu::warn_unused_result]] typedef void *b2; // expected-warning {{'[[gnu::warn_unused_result]]' attribute ignored when applied to a typedef; consider using '__attribute__((warn_unused_result))' or '[[clang::warn_unused_result]]' instead}}
273 b1 b1f1();
274 b2 b2f1();
275 void bf2() {
276   b1f1(); // no warning
277   b2f1(); // no warning
278 }
279 __attribute__((warn_unused_result)) typedef void *c;
280 c cf1();
281 void cf2() {
282   cf1(); // expected-warning {{ignoring return value of type 'c' declared with 'warn_unused_result'}}
283   void *(*c1)();
284   c1();
285   c (*c2)();
286   c2(); // expected-warning {{ignoring return value of type 'c' declared with 'warn_unused_result'}}
287 }
288 }
289 
290 namespace nodiscard_specialization {
291 // Test to only mark a specialization of class template as nodiscard
292 template<typename T> struct S { S(int) {} };
293 template<> struct [[nodiscard]] S<int> { S(int) {} };
294 template<typename T> struct [[clang::warn_unused_result]] S<const T> { S(int) {} };
295 
296 template<typename T>
297 S<T> obtain(const T&) { return {2}; }
298 
299 template<typename T>
300 [[nodiscard]] S<T> obtain2(const T&) { return {2}; }
301 
302 template<typename T>
303 __attribute__((warn_unused_result)) S<T> obtain3(const T&) { return {2}; }
304 
305 void use() {
306   obtain(1.0);             // no warning
307   obtain(1);               // expected-warning {{ignoring return value of type 'S<int>' declared with 'nodiscard'}}
308   obtain<const double>(1); // expected-warning {{ignoring return value of type 'S<const double>' declared with 'warn_unused_result'}}
309 
310   S<double>(2);     // no warning
311   S<int>(2);        // expected-warning {{ignoring temporary of type 'S<int>' declared with 'nodiscard'}}
312   S<const char>(2); // no warning (warn_unused_result does not diagnose constructor temporaries)
313 
314   // function should take precedence over type
315   obtain2(1.0);             // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
316   obtain2(1);               // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
317   obtain2<const double>(1); // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
318   obtain3(1.0);             // expected-warning {{ignoring return value of function declared with 'warn_unused_result'}}
319   obtain3(1);               // expected-warning {{ignoring return value of function declared with 'warn_unused_result'}}
320   obtain3<const double>(1); // expected-warning {{ignoring return value of function declared with 'warn_unused_result'}}
321 }
322 
323 // Test on constructor nodiscard
324 struct H {
325   explicit H(int) {}
326   [[nodiscard]] explicit H(double) {}
327   __attribute__((warn_unused_result)) H(const char*) {}
328 };
329 
330 struct [[nodiscard]] G {
331   explicit G(int) {}
332   [[nodiscard]] explicit G(double) {}
333   [[clang::warn_unused_result]] G(const char*) {}
334 };
335 
336 void use2() {
337   H{2};       // no warning
338   H(2.0);     // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard'}}
339   H("Hello"); // no warning (warn_unused_result does not diagnose constructor temporaries)
340 
341   // no warning for explicit cast to void
342   (void)H(2);
343   (void)H{2.0};
344   (void)H{"Hello"};
345 
346   // warns for all these invocations
347   // here, constructor/function should take precedence over type
348   G{2};       // expected-warning {{ignoring temporary of type 'G' declared with 'nodiscard'}}
349   G(2.0);     // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard'}}
350   G("Hello"); // expected-warning {{ignoring temporary created by a constructor declared with 'warn_unused_result'}}
351 
352   // no warning for explicit cast to void
353   (void)G(2);
354   (void)G{2.0};
355   (void)G{"Hello"};
356 }
357 } // namespace nodiscard_specialization
358 
359 namespace GH117975 {
360 // Test for a regression for ICE in CallExpr::getUnusedResultAttr
361 int f() { return 0; }
362 void id_print_name() {
363   (int) // expected-warning {{expression result unused}}
364     ((int(*)())f)();
365 }
366 } // namespace GH117975
367