diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp --- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ExceptionAnalyzer.h" +#include namespace clang::tidy::utils { @@ -149,37 +150,27 @@ } bool isFunctionPointerConvertible(QualType From, QualType To) { - if (!From->isFunctionPointerType() && !From->isFunctionType() && - !From->isMemberFunctionPointerType()) - return false; - - if (!To->isFunctionPointerType() && !To->isMemberFunctionPointerType()) + ODRHash FromHash, ToHash; + + if (From->isFunctionPointerType()) + FromHash.AddType(From->getPointeeType().getTypePtr()); + else if (From->isFunctionType()) + FromHash.AddType(From->castAs()); + else if (From->isMemberFunctionPointerType()) + FromHash.AddType(From->castAs()); + else return false; - if (To->isFunctionPointerType()) { - if (From->isFunctionPointerType()) - return To->getPointeeType() == From->getPointeeType(); - - if (From->isFunctionType()) - return To->getPointeeType() == From; - + if (To->isFunctionPointerType()) + ToHash.AddType(To->getPointeeType().getTypePtr()); + else if (From->isFunctionType()) + ToHash.AddType(To->castAs()); + else if (From->isMemberFunctionPointerType()) + ToHash.AddType(To->castAs()); + else return false; - } - - if (To->isMemberFunctionPointerType()) { - if (!From->isMemberFunctionPointerType()) - return false; - - const auto *FromMember = cast(From); - const auto *ToMember = cast(To); - // Note: converting Derived::* to Base::* is a different kind of conversion, - // called Pointer-to-member conversion. - return FromMember->getClass() == ToMember->getClass() && - FromMember->getPointeeType() == ToMember->getPointeeType(); - } - - return false; + return FromHash.CalculateHash() == ToHash.CalculateHash(); } // Checks if From is qualification convertible to To based on the current @@ -278,16 +269,17 @@ return false; if (!isSameP_i(From, To)) { - if (LangOpts.CPlusPlus20) { - if (From->isConstantArrayType() && !To->isIncompleteArrayType()) - return false; + if (!LangOpts.CPlusPlus20) + return false; - if (From->isIncompleteArrayType() && !To->isIncompleteArrayType()) - return false; + if (From->isConstantArrayType() && !To->isIncompleteArrayType()) + return false; - } else { + if (From->isIncompleteArrayType() && !To->isIncompleteArrayType()) + return false; + + if (From->isMemberPointerType() || To->isMemberPointerType()) return false; - } } ++I; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp @@ -1,10 +1,9 @@ -// RUN: %check_clang_tidy -std=c++11,c++14 %s bugprone-exception-escape %t -- \ +// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-exception-escape %t -- \ // RUN: -config="{CheckOptions: [ \ // RUN: {key: bugprone-exception-escape.IgnoredExceptions, value: 'ignored1,ignored2'}, \ // RUN: {key: bugprone-exception-escape.FunctionsThatShouldNotThrow, value: 'enabled1,enabled2,enabled3'} \ // RUN: ]}" \ // RUN: -- -fexceptions -// FIXME: Fix the checker to work in C++17 or later mode. struct throwing_destructor { ~throwing_destructor() { @@ -152,7 +151,7 @@ } // FIXME: In this case 'a' is convertible to the handler and should be caught -// but in reality it's thrown. Note that clang doesn't report a warning for +// but in reality it's thrown. Note that clang doesn't report a warning for // this either. void throw_catch_multi_ptr_5() noexcept { try { @@ -249,7 +248,7 @@ void throw_derived_catch_base_ptr_c() noexcept { try { derived d; - throw &d; + throw &d; } catch(const base *) { } } @@ -259,7 +258,7 @@ try { derived d; const derived *p = &d; - throw p; + throw p; } catch(base *) { } } @@ -282,7 +281,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_private' which should not throw exceptions try { B b; - throw b; + throw b; } catch(A) { } } @@ -291,7 +290,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_private_ptr' which should not throw exceptions try { B b; - throw &b; + throw &b; } catch(A *) { } } @@ -300,7 +299,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_protected' which should not throw exceptions try { C c; - throw c; + throw c; } catch(A) { } } @@ -309,7 +308,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_protected_ptr' which should not throw exceptions try { C c; - throw &c; + throw &c; } catch(A *) { } } @@ -318,7 +317,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_ambiguous' which should not throw exceptions try { E e; - throw e; + throw e; } catch(A) { } } @@ -327,7 +326,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_ambiguous_ptr' which should not throw exceptions try { E e; - throw e; + throw e; } catch(A) { } } @@ -420,6 +419,7 @@ struct baseMember { int *iptr; virtual void foo(){}; + void cfoo() {}; }; struct derivedMember : baseMember { @@ -441,6 +441,14 @@ } } +void throw_derivedfn_catch_basefn() noexcept { + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derivedfn_catch_basefn' which should not throw exceptions + try { + throw &derivedMember::foo; + } catch(void(baseMember::*)()) { + } +} + void throw_basem_catch_basem_throw() noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_basem_catch_basem_throw' which should not throw exceptions try {