Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang-tidy] Improve ExceptionSpecAnalyzers handling of conditional noexcept expressions #68359

Merged
merged 1 commit into from
Oct 9, 2023

Conversation

AMS21
Copy link
Contributor

@AMS21 AMS21 commented Oct 5, 2023

The previous code was pretty messy and treated value dependant expressions which could not be evaluated the same as if they evaluted to false. Which was obviously not correct.

We now check if we can evaluate the dependant expressions and if not we truthfully return that we don't know if the function is declared as noexcept or not.

This fixes #68101

@llvmbot
Copy link
Member

llvmbot commented Oct 5, 2023

@llvm/pr-subscribers-clang-tidy

Changes

The previous code was pretty messy and treated value dependant expressions which could not be evaluated the same as if they evaluted to false. Which was obviously not correct.

We now check if we can evaluate the dependant expressions and if not we truthfully return that we don't know if the function is declared as noexcept or not.

This fixes #68101


Full diff: https://github.com/llvm/llvm-project/pull/68359.diff

4 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp (+15-6)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp (+18)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp (+21-7)
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
index 4dd4a95f880aca0..1dde0490517852d 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 0ecf786e73bc413..ee8576827696cec 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -284,6 +284,12 @@ Changes in existing checks
   <clang-tidy/checks/performance/faster-string-find>` check to properly escape
   single quotes.
 
+- Improved :doc:`performance-noexcept-move-constructor
+  <clang-tidy/checks/performance/noexcept-move-constructor>` and
+  :doc:`performance-noexcept-swap<clang-tidy/checks/performance/noexcept-swap>`
+  to better handle conditional noexcept expressions, eliminating
+  false-positives.
+
 - Improved :doc:`performance-noexcept-swap
   <clang-tidy/checks/performance/noexcept-swap>` check to enforce a stricter
   match with the swap function signature, eliminating false-positives.
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 60596c2876c0a34..347a1e3220061af 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 <typename T>
+  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<int>::value) = default;
   OK31& operator=(OK31 &&) noexcept(TrueT<int>::value) = default;
 };
+
+namespace gh68101
+{
+  template <typename T>
+  class Container {
+     public:
+      Container(Container&&) noexcept(std::is_nothrow_move_constructible<T>::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 392b5d17d456e71..dfc71a2bb9ab370 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 <typename T>
+  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 <typename T>
-void swap(D<T> &, D<T> &) noexcept(D<T>::kFalse);
-// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
 void swap(D<int> &, D<int> &) noexcept(D<int>::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 <typename T>
-//void swap(OK16<T> &, OK16<T> &) noexcept(OK16<T>::kTrue);
+template <typename T>
+void swap(OK16<T> &, OK16<T> &) noexcept(OK16<T>::kTrue);
 template <typename T>
 void swap(OK16<int> &, OK16<int> &) noexcept(OK16<int>::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 <typename T>
+  class Container {
+     public:
+      void swap(Container&) noexcept(std::is_nothrow_move_constructible<T>::value);
+  };
+} // namespace gh68101

Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+- LGTM, just split in release notes is needed.

… noexcept expressions

The previous code was pretty messy and treated value dependant
expressions which could not be evaluated the same as if they evaluted to
`false`. Which was obviously not correct.

We now check if we can evaluate the dependant expressions and if not we
truthfully return that we don't know if the function is declared as
`noexcept` or not.

This fixes llvm#68101
@AMS21
Copy link
Contributor Author

AMS21 commented Oct 9, 2023

If there are no more problems, I would kindly ask for this to be merged :)

@PiotrZSL PiotrZSL merged commit f9bd62f into llvm:main Oct 9, 2023
2 checks passed
@AMS21 AMS21 deleted the gh68101 branch October 9, 2023 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants