diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp index 4dd4a95f880ac..1dde049051785 100644 --- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp @@ -142,13 +142,22 @@ ExceptionSpecAnalyzer::analyzeFunctionEST(const FunctionDecl *FuncDecl, return State::NotThrowing; case CT_Dependent: { const Expr *NoexceptExpr = FuncProto->getNoexceptExpr(); + if (!NoexceptExpr) + return State::NotThrowing; + + // We can't resolve value dependence so just return unknown + if (NoexceptExpr->isValueDependent()) + return State::Unknown; + + // Try to evaluate the expression to a boolean value bool Result = false; - return (NoexceptExpr && !NoexceptExpr->isValueDependent() && - NoexceptExpr->EvaluateAsBooleanCondition( - Result, FuncDecl->getASTContext(), true) && - Result) - ? State::NotThrowing - : State::Throwing; + if (NoexceptExpr->EvaluateAsBooleanCondition( + Result, FuncDecl->getASTContext(), true)) + return Result ? State::NotThrowing : State::Throwing; + + // The noexcept expression is not value dependent but we can't evaluate it + // as a boolean condition so we have no idea if its throwing or not + return State::Unknown; } default: return State::Throwing; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 60d92ccf97149..60b82f4c50dd7 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -294,9 +294,14 @@ Changes in existing checks ` check to properly escape single quotes. +- Improved :doc:`performance-noexcept-move-constructor + ` to better handle + conditional noexcept expressions, eliminating false-positives. + - Improved :doc:`performance-noexcept-swap ` check to enforce a stricter - match with the swap function signature, eliminating false-positives. + match with the swap function signature and better handling of condition + noexcept expressions, eliminating false-positives. - Improved :doc:`readability-braces-around-statements ` check to diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp index 60596c2876c0a..347a1e3220061 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp @@ -1,5 +1,14 @@ // RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions +namespace std +{ + template + struct is_nothrow_move_constructible + { + static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T)); + }; +} // namespace std + struct Empty {}; @@ -379,3 +388,12 @@ struct OK31 { OK31(OK31 &&) noexcept(TrueT::value) = default; OK31& operator=(OK31 &&) noexcept(TrueT::value) = default; }; + +namespace gh68101 +{ + template + class Container { + public: + Container(Container&&) noexcept(std::is_nothrow_move_constructible::value); + }; +} // namespace gh68101 diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp index 392b5d17d456e..dfc71a2bb9ab3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp @@ -1,5 +1,14 @@ // RUN: %check_clang_tidy %s performance-noexcept-swap %t -- -- -fexceptions +namespace std +{ + template + struct is_nothrow_move_constructible + { + static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T)); + }; +} // namespace std + void throwing_function() noexcept(false); void noexcept_function() noexcept; @@ -54,9 +63,6 @@ struct D { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] }; -template -void swap(D &, D &) noexcept(D::kFalse); -// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] void swap(D &, D &) noexcept(D::kFalse); // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap] @@ -151,9 +157,8 @@ struct OK16 { void swap(OK16 &) noexcept(kTrue); }; -// FIXME: This gives a warning, but it should be OK. -//template -//void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); +template +void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); template void swap(OK16 &, OK16 &) noexcept(OK16::kTrue); @@ -217,4 +222,13 @@ namespace PR64303 { friend void swap(Test&, Test&); // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: swap functions should be marked noexcept [performance-noexcept-swap] }; -} +} // namespace PR64303 + +namespace gh68101 +{ + template + class Container { + public: + void swap(Container&) noexcept(std::is_nothrow_move_constructible::value); + }; +} // namespace gh68101