forked from OSchip/llvm-project
285 lines
11 KiB
C++
285 lines
11 KiB
C++
// 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 <typename T>
|
|
void ThrowException() { throw T(); }
|
|
// CHECK-NOTES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-2]]:31: note: type 'bad_generic_exception<int>' 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<std::exception>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-6]]:31: note: type 'bad_generic_exception<std::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<non_derived_exception>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-10]]:31: note: type 'exotic_exception<non_derived_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<CLASS>()
|
|
#define THROW_BAD_EXCEPTION throw int(42);
|
|
#define THROW_GOOD_EXCEPTION throw std::exception();
|
|
#define THROW_DERIVED_EXCEPTION throw deep_hierarchy();
|
|
|
|
template <typename T>
|
|
class generic_exception : std::exception {};
|
|
|
|
template <typename T>
|
|
class bad_generic_exception {};
|
|
|
|
template <typename T>
|
|
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<int>(); // Ok,
|
|
THROW_EXCEPTION(generic_exception<float>); // Ok
|
|
|
|
throw bad_generic_exception<int>();
|
|
// CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-24]]:1: note: type defined here
|
|
throw bad_generic_exception<std::exception>();
|
|
// CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-27]]:1: note: type defined here
|
|
THROW_EXCEPTION(bad_generic_exception<int>);
|
|
THROW_EXCEPTION(bad_generic_exception<std::exception>);
|
|
|
|
throw exotic_exception<non_derived_exception>();
|
|
// CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
|
|
// CHECK-NOTES: [[@LINE-30]]:1: note: type defined here
|
|
THROW_EXCEPTION(exotic_exception<non_derived_exception>);
|
|
|
|
throw exotic_exception<derived_exception>(); // Ok
|
|
THROW_EXCEPTION(exotic_exception<derived_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 <typename T>
|
|
void templated_thrower() {
|
|
throw T{}();
|
|
// CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
|
|
}
|
|
template <typename T>
|
|
void templated_thrower2() {
|
|
T ExceptionFactory; // This test found a <dependant-type> 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<invalid_argument_maker>();
|
|
templated_thrower<int_maker>();
|
|
|
|
templated_thrower2<invalid_argument_maker>();
|
|
templated_thrower2<int_maker>();
|
|
|
|
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 <typename T>
|
|
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 <typename T>
|
|
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<invalid_argument_factory>();
|
|
templated_factory<int_factory>();
|
|
|
|
templated_factory2<invalid_argument_factory>();
|
|
templated_factory2<int_factory>();
|
|
|
|
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 <typename T>
|
|
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 <int V>
|
|
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<int> IntThrow;
|
|
ThrowClassTemplateParam<std::invalid_argument> ArgThrow;
|
|
|
|
ThrowValueTemplate<42> ValueThrow;
|
|
}
|