Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp +++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp @@ -192,8 +192,27 @@ Results.merge(Uncaught); } else if (const auto *Call = dyn_cast(St)) { if (const FunctionDecl *Func = Call->getDirectCallee()) { - ExceptionInfo Excs = throwsException(Func, CallStack); - Results.merge(Excs); + bool MightThrow; + + switch (Func->getExceptionSpecType()) { + case EST_DynamicNone: + case EST_NoThrow: + case EST_BasicNoexcept: + case EST_DependentNoexcept: // Let's be optimistic here (necessary e.g. + // for variant assignment; see PR#52254) + case EST_NoexceptTrue: + MightThrow = false; + break; + + default: + MightThrow = true; + break; + } + + if (MightThrow) { + ExceptionInfo Excs = throwsException(Func, CallStack); + Results.merge(Excs); + } } } else { for (const Stmt *Child : St->children()) { Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-exception-escape.cpp @@ -288,6 +288,29 @@ return recursion_helper(n); } +// The following functions all incorrectly throw exceptions, *but* calling them +// should not yield a warning because they are marked as noexcept (or similar). +void est_dynamic_none() throw() { throw 42; } +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_dynamic_none' which should not throw exceptions +void est_basic_noexcept() noexcept { throw 42; } +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_basic_noexcept' which should not throw exceptions +void est_noexcept_true() noexcept(true) { throw 42; } +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_noexcept_true' which should not throw exceptions +template +void est_dependent_noexcept() noexcept(T::should_throw) { throw 42; } +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'est_dependent_noexcept>' which should not throw exceptions +template +struct ShouldThrow { + static const bool should_throw = B; +}; + +void only_calls_non_throwing() noexcept { + est_dynamic_none(); + est_basic_noexcept(); + est_noexcept_true(); + est_dependent_noexcept>(); +} + int main() { // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'main' which should not throw exceptions throw 1;