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