1 | // RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -std=c++17 -target x86_64-pc-linux-gnu \ |
2 | // RUN: | FileCheck %s -check-prefix=CHECK-EXCEPTIONS \ |
3 | // RUN: -implicit-check-not="{{warning|error}}:" |
4 | // RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -DNONEXCEPTIONS -fno-exceptions -std=c++17 -target x86_64-pc-linux-gnu \ |
5 | // RUN: | FileCheck %s -allow-empty -check-prefix=CHECK-NONEXCEPTIONS \ |
6 | // RUN: -implicit-check-not="{{warning|error}}:" |
7 | |
8 | struct S { |
9 | S() noexcept(false); |
10 | }; |
11 | |
12 | struct T { |
13 | T() noexcept; |
14 | }; |
15 | |
16 | struct U { |
17 | U() {} |
18 | }; |
19 | |
20 | struct V { |
21 | explicit V(const char *) {} // Can throw |
22 | }; |
23 | |
24 | struct Cleanup { |
25 | ~Cleanup() {} |
26 | }; |
27 | |
28 | struct W { |
29 | W(Cleanup c = {}) noexcept(false); |
30 | }; |
31 | |
32 | struct X { |
33 | X(S = {}) noexcept; |
34 | }; |
35 | |
36 | struct Y { |
37 | S s; |
38 | }; |
39 | |
40 | struct Z { |
41 | T t; |
42 | }; |
43 | |
44 | int f(); |
45 | int g() noexcept(false); |
46 | int h() noexcept(true); |
47 | |
48 | struct UserConv_Bad { |
49 | operator int() noexcept(false); |
50 | }; |
51 | |
52 | struct UserConv_Good { |
53 | operator int() noexcept; |
54 | }; |
55 | |
56 | UserConv_Bad some_bad_func() noexcept; |
57 | UserConv_Good some_good_func() noexcept; |
58 | |
59 | S s; |
60 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
61 | // CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here |
62 | // CHECK-NONEXCEPTIONS-NOT: warning: |
63 | T t; // ok |
64 | U u; |
65 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught |
66 | // CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here |
67 | // CHECK-NONEXCEPTIONS-NOT: warning: |
68 | V v("v" ); |
69 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught |
70 | // CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here |
71 | // CHECK-NONEXCEPTIONS-NOT: warning: |
72 | W w; |
73 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught |
74 | // CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here |
75 | // CHECK-NONEXCEPTIONS-NOT: warning: |
76 | X x1(S{}); |
77 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x1' with static storage duration may throw an exception that cannot be caught |
78 | // CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here |
79 | // CHECK-NONEXCEPTIONS-NOT: warning: |
80 | X x2; |
81 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x2' with static storage duration may throw an exception that cannot be caught |
82 | // CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here |
83 | // CHECK-NONEXCEPTIONS-NOT: warning: |
84 | Y y; |
85 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'y' with static storage duration may throw an exception that cannot be caught |
86 | // CHECK-EXCEPTIONS: 36:8: note: possibly throwing constructor declared here |
87 | // CHECK-NONEXCEPTIONS-NOT: warning: |
88 | Z z; |
89 | |
90 | int i = f(); |
91 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'i' with static storage duration may throw an exception that cannot be caught |
92 | // CHECK-EXCEPTIONS: 44:5: note: possibly throwing function declared here |
93 | // CHECK-NONEXCEPTIONS-NOT: warning: |
94 | int j = g(); |
95 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'j' with static storage duration may throw an exception that cannot be caught |
96 | // CHECK-EXCEPTIONS: 45:5: note: possibly throwing function declared here |
97 | // CHECK-NONEXCEPTIONS-NOT: warning: |
98 | int k = h(); |
99 | int l = some_bad_func(); |
100 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'l' with static storage duration may throw an exception that cannot be caught |
101 | // CHECK-EXCEPTIONS: 49:3: note: possibly throwing function declared here |
102 | // CHECK-NONEXCEPTIONS-NOT: warning: |
103 | int m = some_good_func(); |
104 | |
105 | typedef decltype(sizeof(int)) size_t; |
106 | inline void *operator new(size_t sz, void *here) noexcept { return here; } |
107 | char n[sizeof(int)]; |
108 | int *o = new (n) int(); |
109 | int *p = new int(); |
110 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'p' with static storage duration may throw an exception that cannot be caught |
111 | // CHECK-NONEXCEPTIONS-NOT: warning: |
112 | |
113 | thread_local S s3; |
114 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught |
115 | // CHECK-NONEXCEPTIONS-NOT: warning: |
116 | thread_local T t3; // ok |
117 | thread_local U u3; |
118 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught |
119 | // CHECK-NONEXCEPTIONS-NOT: warning: |
120 | thread_local V v3("v" ); |
121 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught |
122 | // CHECK-NONEXCEPTIONS-NOT: warning: |
123 | thread_local W w3; |
124 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught |
125 | // CHECK-NONEXCEPTIONS-NOT: warning: |
126 | |
127 | void f(S s1, T t1, U u1, V v1, W w1) { // ok, ok, ok, ok, ok |
128 | S s2; // ok |
129 | T t2; // ok |
130 | U u2; // ok |
131 | V v2("v" ); // ok |
132 | W w2; // ok |
133 | |
134 | thread_local S s3; // ok |
135 | thread_local T t3; // ok |
136 | thread_local U u3; // ok |
137 | thread_local V v3("v" ); // ok |
138 | thread_local W w3; // ok |
139 | |
140 | static S s4; // ok |
141 | static T t4; // ok |
142 | static U u4; // ok |
143 | static V v4("v" ); // ok |
144 | static W w4; // ok |
145 | } |
146 | |
147 | namespace { |
148 | S s; |
149 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
150 | // CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here |
151 | // CHECK-NONEXCEPTIONS-NOT: warning: |
152 | T t; // ok |
153 | U u; |
154 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught |
155 | // CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here |
156 | // CHECK-NONEXCEPTIONS-NOT: warning: |
157 | V v("v" ); |
158 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught |
159 | // CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here |
160 | // CHECK-NONEXCEPTIONS-NOT: warning: |
161 | W w; |
162 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught |
163 | // CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here |
164 | // CHECK-NONEXCEPTIONS-NOT: warning: |
165 | |
166 | thread_local S s3; |
167 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught |
168 | // CHECK-NONEXCEPTIONS-NOT: warning: |
169 | thread_local T t3; // ok |
170 | thread_local U u3; |
171 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught |
172 | // CHECK-NONEXCEPTIONS-NOT: warning: |
173 | thread_local V v3("v" ); |
174 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught |
175 | // CHECK-NONEXCEPTIONS-NOT: warning: |
176 | thread_local W w3; |
177 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught |
178 | // CHECK-NONEXCEPTIONS-NOT: warning: |
179 | }; // namespace |
180 | |
181 | class Statics { |
182 | static S s; // warn when initialized |
183 | static T t; // ok |
184 | static U u; // warn when initialized |
185 | static V v; // warn when initialized |
186 | static W w; // warn when initialized |
187 | |
188 | void f(S s, T t, U u, V v) { |
189 | S s2; // ok |
190 | T t2; // ok |
191 | U u2; // ok |
192 | V v2("v" ); // ok |
193 | W w2; // ok |
194 | |
195 | thread_local S s3; // ok |
196 | thread_local T t3; // ok |
197 | thread_local U u3; // ok |
198 | thread_local V v3("v" ); // ok |
199 | thread_local W w3; // ok |
200 | |
201 | static S s4; // ok |
202 | static T t4; // ok |
203 | static U u4; // ok |
204 | static V v4("v" ); // ok |
205 | static W w4; // ok |
206 | } |
207 | }; |
208 | |
209 | S Statics::s; |
210 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
211 | // CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here |
212 | // CHECK-NONEXCEPTIONS-NOT: warning: |
213 | T Statics::t; |
214 | U Statics::u; |
215 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught |
216 | // CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here |
217 | // CHECK-NONEXCEPTIONS-NOT: warning: |
218 | V Statics::v("v" ); |
219 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught |
220 | // CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here |
221 | // CHECK-NONEXCEPTIONS-NOT: warning: |
222 | W Statics::w; |
223 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught |
224 | // CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here |
225 | // CHECK-NONEXCEPTIONS-NOT: warning: |
226 | |
227 | #ifndef NONEXCEPTIONS |
228 | namespace pr35457 { |
229 | constexpr int foo(int x) { if (x <= 0) throw 12; return x; } |
230 | |
231 | constexpr int bar = foo(x: 1); // OK |
232 | // CHECK-EXCEPTIONS-NOT: warning: initialization of 'bar' with static storage |
233 | int baz = foo(x: 0); // Not OK; throws at runtime when exceptions are enabled. |
234 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'baz' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
235 | // CHECK-EXCEPTIONS: :[[@LINE-6]]:15: note: possibly throwing function declared here |
236 | } // namespace pr35457 |
237 | #endif // NONEXCEPTIONS |
238 | |
239 | namespace pr39777 { |
240 | struct S { S(); }; |
241 | struct T { T() noexcept; }; |
242 | |
243 | auto Okay1 = []{ S s; }; |
244 | auto Okay2 = []{ (void)new int; }; |
245 | auto NotOkay1 = []{ S s; return 12; }(); // Because the lambda call is not noexcept |
246 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay1' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
247 | // CHECK-EXCEPTIONS: :[[@LINE-7]]:12: note: possibly throwing constructor declared here |
248 | auto NotOkay2 = []() noexcept { S s; return 12; }(); // Because S::S() is not noexcept |
249 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay2' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
250 | // CHECK-EXCEPTIONS: :[[@LINE-10]]:12: note: possibly throwing constructor declared here |
251 | auto Okay3 = []() noexcept { T t; return t; }(); |
252 | |
253 | struct U { |
254 | U() noexcept; |
255 | auto getBadLambda() const noexcept { |
256 | return []{ S s; return s; }; |
257 | } |
258 | }; |
259 | auto Okay4 = []{ U u; return u.getBadLambda(); }(); |
260 | auto NotOkay3 = []() noexcept { U u; return u.getBadLambda(); }()(); // Because the lambda returned and called is not noexcept |
261 | // CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay3' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] |
262 | // CHECK-EXCEPTIONS: :[[@LINE-6]]:12: note: possibly throwing function declared here |
263 | |
264 | #ifndef NONEXCEPTIONS |
265 | struct Bad { |
266 | Bad() { |
267 | throw 12; |
268 | } |
269 | }; |
270 | |
271 | static auto NotOkay4 = [bad = Bad{}](){}; |
272 | // FIXME: the above should be diagnosed because the capture init can trigger |
273 | // an exception when constructing the Bad object. |
274 | #endif // NONEXCEPTIONS |
275 | } |
276 | |