1 // RUN: %check_clang_tidy %s bugprone-unused-return-value %t -- -- -fexceptions
2
3 namespace std {
4
5 struct future {};
6
7 enum class launch {
8 async,
9 deferred
10 };
11
12 template <typename Function, typename... Args>
13 future async(Function &&, Args &&...);
14
15 template <typename Function, typename... Args>
16 future async(launch, Function &&, Args &&...);
17
18 template <typename ForwardIt, typename T>
19 ForwardIt remove(ForwardIt, ForwardIt, const T &);
20
21 template <typename ForwardIt, typename UnaryPredicate>
22 ForwardIt remove_if(ForwardIt, ForwardIt, UnaryPredicate);
23
24 template <typename ForwardIt>
25 ForwardIt unique(ForwardIt, ForwardIt);
26
27 template <typename T>
28 struct default_delete;
29
30 template <typename T, typename Deleter = std::default_delete<T>>
31 struct unique_ptr {
32 T *release() noexcept;
33 };
34
35 template <typename T>
36 struct char_traits;
37
38 template <typename T>
39 struct allocator;
40
41 template <typename CharT,
42 typename Traits = char_traits<CharT>,
43 typename Allocator = allocator<CharT>>
44 struct basic_string {
45 bool empty() const;
46 };
47
48 typedef basic_string<char> string;
49
50 template <typename T, typename Allocator = std::allocator<T>>
51 struct vector {
52 bool empty() const noexcept;
53 };
54
55 // the check should be able to match std lib calls even if the functions are
56 // declared inside inline namespaces
57 inline namespace v1 {
58
59 template <typename T>
60 T *launder(T *);
61
62 } // namespace v1
63 } // namespace std
64
65 struct Foo {
66 void f();
67 };
68
increment(int i)69 int increment(int i) {
70 return i + 1;
71 }
72
73 void useFuture(const std::future &fut);
74
warning()75 void warning() {
76 std::async(increment, 42);
77 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value returned by this function should be used
78 // CHECK-NOTES: [[@LINE-2]]:3: note: cast the expression to void to silence this warning
79
80 std::async(std::launch::async, increment, 42);
81 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
82 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
83
84 Foo F;
85 std::launder(&F);
86 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
87 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
88
89 std::remove(nullptr, nullptr, 1);
90 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
91 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
92
93 std::remove_if(nullptr, nullptr, nullptr);
94 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
95 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
96
97 std::unique(nullptr, nullptr);
98 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
99 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
100
101 std::unique_ptr<Foo> UPtr;
102 UPtr.release();
103 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
104 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
105
106 std::string Str;
107 Str.empty();
108 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
109 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
110
111 std::vector<Foo> Vec;
112 Vec.empty();
113 // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
114 // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
115
116 // test discarding return values inside different kinds of statements
117
118 auto Lambda = [] { std::remove(nullptr, nullptr, 1); };
119 // CHECK-NOTES: [[@LINE-1]]:22: warning: the value {{.*}} should be used
120 // CHECK-NOTES: [[@LINE-2]]:22: note: cast {{.*}} this warning
121
122 if (true)
123 std::remove(nullptr, nullptr, 1);
124 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
125 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
126 else if (true)
127 std::remove(nullptr, nullptr, 1);
128 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
129 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
130 else
131 std::remove(nullptr, nullptr, 1);
132 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
133 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
134
135 while (true)
136 std::remove(nullptr, nullptr, 1);
137 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
138 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
139
140 do
141 std::remove(nullptr, nullptr, 1);
142 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
143 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
144 while (true);
145
146 for (;;)
147 std::remove(nullptr, nullptr, 1);
148 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
149 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
150
151 for (std::remove(nullptr, nullptr, 1);;)
152 // CHECK-NOTES: [[@LINE-1]]:8: warning: the value {{.*}} should be used
153 // CHECK-NOTES: [[@LINE-2]]:8: note: cast {{.*}} this warning
154 ;
155
156 for (;; std::remove(nullptr, nullptr, 1))
157 // CHECK-NOTES: [[@LINE-1]]:11: warning: the value {{.*}} should be used
158 // CHECK-NOTES: [[@LINE-2]]:11: note: cast {{.*}} this warning
159 ;
160
161 for (auto C : "foo")
162 std::remove(nullptr, nullptr, 1);
163 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
164 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
165
166 switch (1) {
167 case 1:
168 std::remove(nullptr, nullptr, 1);
169 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
170 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
171 break;
172 default:
173 std::remove(nullptr, nullptr, 1);
174 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
175 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
176 break;
177 }
178
179 try {
180 std::remove(nullptr, nullptr, 1);
181 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
182 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
183 } catch (...) {
184 std::remove(nullptr, nullptr, 1);
185 // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
186 // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
187 }
188 }
189
noWarning()190 void noWarning() {
191 auto AsyncRetval1 = std::async(increment, 42);
192 auto AsyncRetval2 = std::async(std::launch::async, increment, 42);
193
194 Foo FNoWarning;
195 auto LaunderRetval = std::launder(&FNoWarning);
196
197 auto RemoveRetval = std::remove(nullptr, nullptr, 1);
198
199 auto RemoveIfRetval = std::remove_if(nullptr, nullptr, nullptr);
200
201 auto UniqueRetval = std::unique(nullptr, nullptr);
202
203 std::unique_ptr<Foo> UPtrNoWarning;
204 auto ReleaseRetval = UPtrNoWarning.release();
205
206 std::string StrNoWarning;
207 auto StrEmptyRetval = StrNoWarning.empty();
208
209 std::vector<Foo> VecNoWarning;
210 auto VecEmptyRetval = VecNoWarning.empty();
211
212 // test using the return value in different kinds of expressions
213 useFuture(std::async(increment, 42));
214 std::launder(&FNoWarning)->f();
215 delete std::launder(&FNoWarning);
216
217 if (std::launder(&FNoWarning))
218 ;
219 for (; std::launder(&FNoWarning);)
220 ;
221 while (std::launder(&FNoWarning))
222 ;
223 do
224 ;
225 while (std::launder(&FNoWarning));
226 switch (std::unique(1, 1))
227 ;
228
229 // cast to void should allow ignoring the return value
230 (void)std::async(increment, 42);
231
232 // test discarding return value of functions that are not configured to be checked
233 increment(1);
234
235 // test that the check is disabled inside GNU statement expressions
236 ({ std::async(increment, 42); });
237 auto StmtExprRetval = ({ std::async(increment, 42); });
238 }
239