1 // RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions
2
3 namespace std {
4 class exception {};
5 class invalid_argument : public exception {};
6 } // namespace std
7
8 class derived_exception : public std::exception {};
9 class deep_hierarchy : public derived_exception {};
10 class non_derived_exception {};
11 class terrible_idea : public non_derived_exception, public derived_exception {};
12
13 // FIXME: More complicated kinds of inheritance should be checked later, but there is
14 // currently no way use ASTMatchers for this kind of task.
15 #if 0
16 class bad_inheritance : private std::exception {};
17 class no_good_inheritance : protected std::exception {};
18 class really_creative : public non_derived_exception, private std::exception {};
19 #endif
20
problematic()21 void problematic() {
22 try {
23 throw int(42);
24 // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
25 } catch (int e) {
26 }
27 throw int(42);
28 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
29
30 try {
31 throw 12;
32 // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
33 } catch (...) {
34 throw; // Ok, even if the type is not known, conforming code can never rethrow a non-std::exception object.
35 }
36
37 try {
38 throw non_derived_exception();
39 // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
40 // CHECK-NOTES: 10:1: note: type defined here
41 } catch (non_derived_exception &e) {
42 }
43 throw non_derived_exception();
44 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
45 // CHECK-NOTES: 10:1: note: type defined here
46
47 // FIXME: More complicated kinds of inheritance should be checked later, but there is
48 // currently no way use ASTMatchers for this kind of task.
49 #if 0
50 // Handle private inheritance cases correctly.
51 try {
52 throw bad_inheritance();
53 // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
54 // CHECK NOTES: 11:1: note: type defined here
55 throw no_good_inheritance();
56 // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
57 // CHECK NOTES: 12:1: note: type defined here
58 throw really_creative();
59 // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
60 // CHECK NOTES: 13:1: note: type defined here
61 } catch (...) {
62 }
63 throw bad_inheritance();
64 // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
65 // CHECK NOTES: 11:1: note: type defined here
66 throw no_good_inheritance();
67 // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
68 // CHECK NOTES: 12:1: note: type defined here
69 throw really_creative();
70 // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
71 // CHECK NOTES: 13:1: note: type defined here
72 #endif
73 }
74
allowed_throws()75 void allowed_throws() {
76 try {
77 throw std::exception(); // Ok
78 } catch (std::exception &e) { // Ok
79 }
80 throw std::exception();
81
82 try {
83 throw derived_exception(); // Ok
84 } catch (derived_exception &e) { // Ok
85 }
86 throw derived_exception(); // Ok
87
88 try {
89 throw deep_hierarchy(); // Ok, multiple levels of inheritance
90 } catch (deep_hierarchy &e) { // Ok
91 }
92 throw deep_hierarchy(); // Ok
93
94 try {
95 throw terrible_idea(); // Ok, but multiple inheritance isn't clean
96 } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance
97 }
98 throw terrible_idea(); // Ok, but multiple inheritance
99 }
100
test_lambdas()101 void test_lambdas() {
102 auto BadLambda = []() { throw int(42); };
103 // CHECK-NOTES: [[@LINE-1]]:33: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
104 auto GoodLambda = []() { throw derived_exception(); };
105 }
106
107 // Templated function that throws exception based on template type
108 template <typename T>
ThrowException()109 void ThrowException() { throw T(); }
110 // CHECK-NOTES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
111 // CHECK-NOTES: [[@LINE-2]]:31: note: type 'bad_generic_exception<int>' is a template instantiation of 'T'
112 // CHECK-NOTES: [[@LINE+25]]:1: note: type defined here
113
114 // CHECK-NOTES: [[@LINE-5]]:31: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
115 // CHECK-NOTES: [[@LINE-6]]:31: note: type 'bad_generic_exception<std::exception>' is a template instantiation of 'T'
116 // CHECK-NOTES: [[@LINE+21]]:1: note: type defined here
117
118 // CHECK-NOTES: [[@LINE-9]]:31: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
119 // CHECK-NOTES: [[@LINE-10]]:31: note: type 'exotic_exception<non_derived_exception>' is a template instantiation of 'T'
120 // CHECK-NOTES: [[@LINE+20]]:1: note: type defined here
121
122 // CHECK-NOTES: [[@LINE-13]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
123 // CHECK-NOTES: [[@LINE-14]]:31: note: type 'int' is a template instantiation of 'T'
124
125 // CHECK-NOTES: [[@LINE-16]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
126 // CHECK-NOTES: [[@LINE-17]]:31: note: type 'non_derived_exception' is a template instantiation of 'T'
127 // CHECK-NOTES: 10:1: note: type defined here
128
129 #define THROW_EXCEPTION(CLASS) ThrowException<CLASS>()
130 #define THROW_BAD_EXCEPTION throw int(42);
131 #define THROW_GOOD_EXCEPTION throw std::exception();
132 #define THROW_DERIVED_EXCEPTION throw deep_hierarchy();
133
134 template <typename T>
135 class generic_exception : std::exception {};
136
137 template <typename T>
138 class bad_generic_exception {};
139
140 template <typename T>
141 class exotic_exception : public T {};
142
generic_exceptions()143 void generic_exceptions() {
144 THROW_EXCEPTION(int);
145 THROW_EXCEPTION(non_derived_exception);
146 THROW_EXCEPTION(std::exception); // Ok
147 THROW_EXCEPTION(derived_exception); // Ok
148 THROW_EXCEPTION(deep_hierarchy); // Ok
149
150 THROW_BAD_EXCEPTION;
151 // CHECK-NOTES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
152 // CHECK-NOTES: [[@LINE-22]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION'
153 THROW_GOOD_EXCEPTION;
154 THROW_DERIVED_EXCEPTION;
155
156 throw generic_exception<int>(); // Ok,
157 THROW_EXCEPTION(generic_exception<float>); // Ok
158
159 throw bad_generic_exception<int>();
160 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
161 // CHECK-NOTES: [[@LINE-24]]:1: note: type defined here
162 throw bad_generic_exception<std::exception>();
163 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
164 // CHECK-NOTES: [[@LINE-27]]:1: note: type defined here
165 THROW_EXCEPTION(bad_generic_exception<int>);
166 THROW_EXCEPTION(bad_generic_exception<std::exception>);
167
168 throw exotic_exception<non_derived_exception>();
169 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
170 // CHECK-NOTES: [[@LINE-30]]:1: note: type defined here
171 THROW_EXCEPTION(exotic_exception<non_derived_exception>);
172
173 throw exotic_exception<derived_exception>(); // Ok
174 THROW_EXCEPTION(exotic_exception<derived_exception>); // Ok
175 }
176
177 // Test for typedefed exception types
178 typedef int TypedefedBad;
179 typedef derived_exception TypedefedGood;
180 using UsingBad = int;
181 using UsingGood = deep_hierarchy;
182
typedefed()183 void typedefed() {
184 throw TypedefedBad();
185 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception'
186 // CHECK-NOTES: [[@LINE-8]]:1: note: type defined here
187 throw TypedefedGood(); // Ok
188
189 throw UsingBad();
190 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception'
191 // CHECK-NOTES: [[@LINE-11]]:1: note: type defined here
192 throw UsingGood(); // Ok
193 }
194
195 // Fix PR37913
196 struct invalid_argument_maker {
197 ::std::invalid_argument operator()() const;
198 };
199 struct int_maker {
200 int operator()() const;
201 };
202
203 template <typename T>
templated_thrower()204 void templated_thrower() {
205 throw T{}();
206 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
207 }
208 template <typename T>
templated_thrower2()209 void templated_thrower2() {
210 T ExceptionFactory; // This test found a <dependant-type> which did not happend with 'throw T{}()'
211 throw ExceptionFactory();
212 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
213 }
214
exception_created_with_function()215 void exception_created_with_function() {
216 templated_thrower<invalid_argument_maker>();
217 templated_thrower<int_maker>();
218
219 templated_thrower2<invalid_argument_maker>();
220 templated_thrower2<int_maker>();
221
222 throw invalid_argument_maker{}();
223 throw int_maker{}();
224 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
225 }
226
227 struct invalid_argument_factory {
228 ::std::invalid_argument make_exception() const;
229 };
230
231 struct int_factory {
232 int make_exception() const;
233 };
234
235 template <typename T>
templated_factory()236 void templated_factory() {
237 T f;
238 throw f.make_exception();
239 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
240 }
241 template <typename T>
templated_factory2()242 void templated_factory2() {
243 throw T().make_exception();
244 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
245 }
246
exception_from_factory()247 void exception_from_factory() {
248 templated_factory<invalid_argument_factory>();
249 templated_factory<int_factory>();
250
251 templated_factory2<invalid_argument_factory>();
252 templated_factory2<int_factory>();
253
254 throw invalid_argument_factory().make_exception();
255 throw int_factory().make_exception();
256 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
257
258 invalid_argument_factory inv_f;
259 throw inv_f.make_exception();
260
261 int_factory int_f;
262 throw int_f.make_exception();
263 // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
264 }
265
266 template <typename T>
267 struct ThrowClassTemplateParam {
ThrowClassTemplateParamThrowClassTemplateParam268 ThrowClassTemplateParam() { throw T(); }
269 // CHECK-NOTES: [[@LINE-1]]:37: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
270 // CHECK-NOTES: [[@LINE-2]]:37: note: type 'int' is a template instantiation of 'T'
271 };
272
273 template <int V>
274 struct ThrowValueTemplate {
ThrowValueTemplateThrowValueTemplate275 ThrowValueTemplate() { throw V; }
276 // CHECK-NOTES: [[@LINE-1]]:32: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
277 };
278
class_templates()279 void class_templates() {
280 ThrowClassTemplateParam<int> IntThrow;
281 ThrowClassTemplateParam<std::invalid_argument> ArgThrow;
282
283 ThrowValueTemplate<42> ValueThrow;
284 }
285