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 @@ -148,28 +148,44 @@ return false; } +bool isFunctionTypeEqual(const FunctionType *From, const FunctionType *To) { + if (From == To) + return true; + + const auto *FromProto = dyn_cast(From); + const auto *ToProto = dyn_cast(To); + if (!FromProto || !ToProto) + return false; + + if (!FromProto->hasExceptionSpec() && !ToProto->hasExceptionSpec()) + return false; + + return FromProto->getNumParams() == ToProto->getNumParams() && + FromProto->isVariadic() == ToProto->isVariadic() && + FromProto->getParamTypes() == ToProto->getParamTypes() && + FromProto->getReturnType() == ToProto->getReturnType() && + FromProto->getMethodQuals() == ToProto->getMethodQuals() && + FromProto->getRefQualifier() == ToProto->getRefQualifier(); +} + bool isFunctionPointerConvertible(QualType From, QualType To) { if (!From->isFunctionPointerType() && !From->isFunctionType() && !From->isMemberFunctionPointerType()) return false; - if (!To->isFunctionPointerType() && !To->isMemberFunctionPointerType()) - return false; - if (To->isFunctionPointerType()) { + const auto *ToFunctionTypePtr = + To->getPointeeType()->castAs(); + if (From->isFunctionPointerType()) - return To->getPointeeType() == From->getPointeeType(); + return isFunctionTypeEqual( + ToFunctionTypePtr, From->getPointeeType()->castAs()); if (From->isFunctionType()) - return To->getPointeeType() == From; - - return false; - } - - if (To->isMemberFunctionPointerType()) { - if (!From->isMemberFunctionPointerType()) - return false; - + return isFunctionTypeEqual(ToFunctionTypePtr, + From->castAs()); + } else if (To->isMemberFunctionPointerType() && + From->isMemberFunctionPointerType()) { const auto *FromMember = cast(From); const auto *ToMember = cast(To); @@ -278,16 +294,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() {