// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions namespace std { class exception {}; class invalid_argument : public exception {}; } // namespace std class derived_exception : public std::exception {}; class deep_hierarchy : public derived_exception {}; class non_derived_exception {}; class terrible_idea : public non_derived_exception, public derived_exception {}; // FIXME: More complicated kinds of inheritance should be checked later, but there is // currently no way use ASTMatchers for this kind of task. #if 0 class bad_inheritance : private std::exception {}; class no_good_inheritance : protected std::exception {}; class really_creative : public non_derived_exception, private std::exception {}; #endif void problematic() { try { throw int(42); // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } catch (int e) { } throw int(42); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' try { throw 12; // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } catch (...) { throw; // Ok, even if the type is not known, conforming code can never rethrow a non-std::exception object. } try { throw non_derived_exception(); // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' // CHECK-NOTES: 10:1: note: type defined here } catch (non_derived_exception &e) { } throw non_derived_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' // CHECK-NOTES: 10:1: note: type defined here // FIXME: More complicated kinds of inheritance should be checked later, but there is // currently no way use ASTMatchers for this kind of task. #if 0 // Handle private inheritance cases correctly. try { throw bad_inheritance(); // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception' // CHECK NOTES: 11:1: note: type defined here throw no_good_inheritance(); // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception' // CHECK NOTES: 12:1: note: type defined here throw really_creative(); // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception' // CHECK NOTES: 13:1: note: type defined here } catch (...) { } throw bad_inheritance(); // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception' // CHECK NOTES: 11:1: note: type defined here throw no_good_inheritance(); // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception' // CHECK NOTES: 12:1: note: type defined here throw really_creative(); // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception' // CHECK NOTES: 13:1: note: type defined here #endif } void allowed_throws() { try { throw std::exception(); // Ok } catch (std::exception &e) { // Ok } throw std::exception(); try { throw derived_exception(); // Ok } catch (derived_exception &e) { // Ok } throw derived_exception(); // Ok try { throw deep_hierarchy(); // Ok, multiple levels of inheritance } catch (deep_hierarchy &e) { // Ok } throw deep_hierarchy(); // Ok try { throw terrible_idea(); // Ok, but multiple inheritance isn't clean } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance } throw terrible_idea(); // Ok, but multiple inheritance } void test_lambdas() { auto BadLambda = []() { throw int(42); }; // CHECK-NOTES: [[@LINE-1]]:33: warning: throwing an exception whose type 'int' is not derived from 'std::exception' auto GoodLambda = []() { throw derived_exception(); }; } // Templated function that throws exception based on template type template void ThrowException() { throw T(); } // CHECK-NOTES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-2]]:31: note: type 'bad_generic_exception' is a template instantiation of 'T' // CHECK-NOTES: [[@LINE+25]]:1: note: type defined here // CHECK-NOTES: [[@LINE-5]]:31: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-6]]:31: note: type 'bad_generic_exception' is a template instantiation of 'T' // CHECK-NOTES: [[@LINE+21]]:1: note: type defined here // CHECK-NOTES: [[@LINE-9]]:31: warning: throwing an exception whose type 'exotic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-10]]:31: note: type 'exotic_exception' is a template instantiation of 'T' // CHECK-NOTES: [[@LINE+20]]:1: note: type defined here // CHECK-NOTES: [[@LINE-13]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-14]]:31: note: type 'int' is a template instantiation of 'T' // CHECK-NOTES: [[@LINE-16]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-17]]:31: note: type 'non_derived_exception' is a template instantiation of 'T' // CHECK-NOTES: 10:1: note: type defined here #define THROW_EXCEPTION(CLASS) ThrowException() #define THROW_BAD_EXCEPTION throw int(42); #define THROW_GOOD_EXCEPTION throw std::exception(); #define THROW_DERIVED_EXCEPTION throw deep_hierarchy(); template class generic_exception : std::exception {}; template class bad_generic_exception {}; template class exotic_exception : public T {}; void generic_exceptions() { THROW_EXCEPTION(int); THROW_EXCEPTION(non_derived_exception); THROW_EXCEPTION(std::exception); // Ok THROW_EXCEPTION(derived_exception); // Ok THROW_EXCEPTION(deep_hierarchy); // Ok THROW_BAD_EXCEPTION; // CHECK-NOTES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-22]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION' THROW_GOOD_EXCEPTION; THROW_DERIVED_EXCEPTION; throw generic_exception(); // Ok, THROW_EXCEPTION(generic_exception); // Ok throw bad_generic_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-24]]:1: note: type defined here throw bad_generic_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-27]]:1: note: type defined here THROW_EXCEPTION(bad_generic_exception); THROW_EXCEPTION(bad_generic_exception); throw exotic_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-30]]:1: note: type defined here THROW_EXCEPTION(exotic_exception); throw exotic_exception(); // Ok THROW_EXCEPTION(exotic_exception); // Ok } // Test for typedefed exception types typedef int TypedefedBad; typedef derived_exception TypedefedGood; using UsingBad = int; using UsingGood = deep_hierarchy; void typedefed() { throw TypedefedBad(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-8]]:1: note: type defined here throw TypedefedGood(); // Ok throw UsingBad(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-11]]:1: note: type defined here throw UsingGood(); // Ok } // Fix PR37913 struct invalid_argument_maker { ::std::invalid_argument operator()() const; }; struct int_maker { int operator()() const; }; template void templated_thrower() { throw T{}(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } template void templated_thrower2() { T ExceptionFactory; // This test found a which did not happend with 'throw T{}()' throw ExceptionFactory(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } void exception_created_with_function() { templated_thrower(); templated_thrower(); templated_thrower2(); templated_thrower2(); throw invalid_argument_maker{}(); throw int_maker{}(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } struct invalid_argument_factory { ::std::invalid_argument make_exception() const; }; struct int_factory { int make_exception() const; }; template void templated_factory() { T f; throw f.make_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } template void templated_factory2() { throw T().make_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } void exception_from_factory() { templated_factory(); templated_factory(); templated_factory2(); templated_factory2(); throw invalid_argument_factory().make_exception(); throw int_factory().make_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' invalid_argument_factory inv_f; throw inv_f.make_exception(); int_factory int_f; throw int_f.make_exception(); // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } template struct ThrowClassTemplateParam { ThrowClassTemplateParam() { throw T(); } // CHECK-NOTES: [[@LINE-1]]:37: warning: throwing an exception whose type 'int' is not derived from 'std::exception' // CHECK-NOTES: [[@LINE-2]]:37: note: type 'int' is a template instantiation of 'T' }; template struct ThrowValueTemplate { ThrowValueTemplate() { throw V; } // CHECK-NOTES: [[@LINE-1]]:32: warning: throwing an exception whose type 'int' is not derived from 'std::exception' }; void class_templates() { ThrowClassTemplateParam IntThrow; ThrowClassTemplateParam ArgThrow; ThrowValueTemplate<42> ValueThrow; }