denizevrenci updated this revision to Diff 529140.
denizevrenci added a comment.

Sort tests out a bit more


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D152330/new/

https://reviews.llvm.org/D152330

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
  clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17,c++20 %s bugprone-exception-escape %t -- \
+// RUN:     -- -fexceptions
+
+void rethrower() {
+    throw;
+}
+
+void callsRethrower() {
+    rethrower();
+}
+
+void callsRethrowerNoexcept() noexcept {
+    rethrower();
+}
+
+int throwsAndCallsRethrower() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'throwsAndCallsRethrower' which should not throw exceptions
+    try {
+        throw 1;
+    } catch(...) {
+        rethrower();
+    }
+}
+
+int throwsAndCallsCallsRethrower() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'throwsAndCallsCallsRethrower' which should not throw exceptions
+    try {
+        throw 1;
+    } catch(...) {
+        callsRethrower();
+    }
+}
+
+void rethrowerNoexcept() noexcept {
+    throw;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
@@ -36,17 +36,18 @@
 
 template <typename Task, typename T, bool ThrowInPromiseConstructor,
           bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
-          bool ThrowInUnhandledException>
+          bool ThrowInUnhandledException, bool RethrowInUnhandledException>
 struct Promise;
 
 template <
     typename T, bool ThrowInTaskConstructor = false,
     bool ThrowInPromiseConstructor = false, bool ThrowInInitialSuspend = false,
-    bool ThrowInGetReturnObject = false, bool ThrowInUnhandledException = false>
+    bool ThrowInGetReturnObject = false, bool ThrowInUnhandledException = false,
+    bool RethrowInUnhandledException = false>
 struct Task {
   using promise_type =
       Promise<Task, T, ThrowInPromiseConstructor, ThrowInInitialSuspend,
-              ThrowInGetReturnObject, ThrowInUnhandledException>;
+              ThrowInGetReturnObject, ThrowInUnhandledException, RethrowInUnhandledException>;
 
   explicit Task(promise_type &p) {
     if constexpr (ThrowInTaskConstructor) {
@@ -67,13 +68,13 @@
 
 template <bool ThrowInTaskConstructor, bool ThrowInPromiseConstructor,
           bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
-          bool ThrowInUnhandledException>
+          bool ThrowInUnhandledException, bool RethrowInUnhandledException>
 struct Task<void, ThrowInTaskConstructor, ThrowInPromiseConstructor,
             ThrowInInitialSuspend, ThrowInGetReturnObject,
-            ThrowInUnhandledException> {
+            ThrowInUnhandledException, RethrowInUnhandledException> {
   using promise_type =
       Promise<Task, void, ThrowInPromiseConstructor, ThrowInInitialSuspend,
-              ThrowInGetReturnObject, ThrowInUnhandledException>;
+              ThrowInGetReturnObject, ThrowInUnhandledException, RethrowInUnhandledException>;
 
   explicit Task(promise_type &p) {
     if constexpr (ThrowInTaskConstructor) {
@@ -92,7 +93,7 @@
 
 template <typename Task, typename T, bool ThrowInPromiseConstructor,
           bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
-          bool ThrowInUnhandledException>
+          bool ThrowInUnhandledException, bool RethrowInUnhandledException>
 struct Promise {
   Promise() {
     if constexpr (ThrowInPromiseConstructor) {
@@ -130,6 +131,8 @@
   void unhandled_exception() {
     if constexpr (ThrowInUnhandledException) {
       throw 1;
+    } else if constexpr (RethrowInUnhandledException) {
+      throw;
     }
   }
 
@@ -138,9 +141,9 @@
 
 template <typename Task, bool ThrowInPromiseConstructor,
           bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
-          bool ThrowInUnhandledException>
+          bool ThrowInUnhandledException, bool RethrowInUnhandledException>
 struct Promise<Task, void, ThrowInPromiseConstructor, ThrowInInitialSuspend,
-               ThrowInGetReturnObject, ThrowInUnhandledException> {
+               ThrowInGetReturnObject, ThrowInUnhandledException, RethrowInUnhandledException> {
   Promise() {
     if constexpr (ThrowInPromiseConstructor) {
       throw 1;
@@ -170,6 +173,8 @@
   void unhandled_exception() {
     if constexpr (ThrowInUnhandledException) {
       throw 1;
+    } else if constexpr (RethrowInUnhandledException) {
+      throw;
     }
   }
 
@@ -266,6 +271,33 @@
   co_return a / b;
 }
 
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiag(const int a, const int b) {
+  co_return a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiagNoexcept(const int a, const int b) noexcept {
+  co_return a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldNotDiag(const int a, const int b) {
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+}
+
 } // namespace coreturn
 
 namespace coyield {
@@ -347,6 +379,33 @@
   co_yield a / b;
 }
 
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiag(const int a, const int b) {
+  co_yield a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiagNoexcept(const int a, const int b) noexcept {
+  co_yield a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldNotDiag(const int a, const int b) {
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+}
+
 } // namespace coyield
 
 namespace coawait {
@@ -429,6 +488,31 @@
   co_await returnOne();
 }
 
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiag(const int a, const int b) {
+  co_await returnOne();
+}
+
+Task<int, false, false, false, false, false, true>
+i_ShouldNotDiagNoexcept(const int a, const int b) noexcept {
+  co_await returnOne();
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldNotDiag(const int a, const int b) {
+  co_await returnOne();
+  if (b == 0)
+    throw b;
+}
+
+Task<int, false, false, false, false, false, true>
+j_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+  if (b == 0)
+    throw b;
+}
+
 } // namespace coawait
 
 } // namespace function
@@ -524,6 +608,37 @@
   co_return a / b;
 };
 
+const auto i_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  co_return a / b;
+};
+
+const auto i_ShouldNotDiagNoexcept =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  co_return a / b;
+};
+
+const auto j_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+};
+
+const auto j_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+};
+
 } // namespace coreturn
 
 namespace coyield {
@@ -615,6 +730,37 @@
   co_yield a / b;
 };
 
+const auto i_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  co_yield a / b;
+};
+
+const auto i_ShouldNotDiagNoexcept =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  co_yield a / b;
+};
+
+const auto j_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+};
+
+const auto j_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+};
+
 } // namespace coyield
 
 namespace coawait {
@@ -706,6 +852,35 @@
   co_await returnOne();
 };
 
+const auto i_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  co_await returnOne();
+};
+
+const auto i_ShouldNotDiagNoexcept =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  co_await returnOne();
+};
+
+const auto j_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, false, true> {
+  co_await returnOne();
+  if (b == 0)
+    throw b;
+};
+
+const auto j_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+  if (b == 0)
+    throw b;
+};
+
 } // namespace coawait
 
 } // namespace lambda
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
===================================================================
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
@@ -132,6 +132,7 @@
 private:
   ExceptionInfo
   throwsException(const FunctionDecl *Func,
+                  const ExceptionInfo::Throwables &Caught,
                   llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
   ExceptionInfo
   throwsException(const Stmt *St, const ExceptionInfo::Throwables &Caught,
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
@@ -419,21 +419,20 @@
 }
 
 ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
-    const FunctionDecl *Func,
+    const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
     llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
   if (CallStack.count(Func))
     return ExceptionInfo::createNonThrowing();
 
   if (const Stmt *Body = Func->getBody()) {
     CallStack.insert(Func);
-    ExceptionInfo Result =
-        throwsException(Body, ExceptionInfo::Throwables(), CallStack);
+    ExceptionInfo Result = throwsException(Body, Caught, CallStack);
 
     // For a constructor, we also have to check the initializers.
     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Func)) {
       for (const CXXCtorInitializer *Init : Ctor->inits()) {
-        ExceptionInfo Excs = throwsException(
-            Init->getInit(), ExceptionInfo::Throwables(), CallStack);
+        ExceptionInfo Excs =
+            throwsException(Init->getInit(), Caught, CallStack);
         Result.merge(Excs);
       }
     }
@@ -512,12 +511,12 @@
     Results.merge(Uncaught);
   } else if (const auto *Call = dyn_cast<CallExpr>(St)) {
     if (const FunctionDecl *Func = Call->getDirectCallee()) {
-      ExceptionInfo Excs = throwsException(Func, CallStack);
+      ExceptionInfo Excs = throwsException(Func, Caught, CallStack);
       Results.merge(Excs);
     }
   } else if (const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
     ExceptionInfo Excs =
-        throwsException(Construct->getConstructor(), CallStack);
+        throwsException(Construct->getConstructor(), Caught, CallStack);
     Results.merge(Excs);
   } else if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
     ExceptionInfo Excs =
@@ -525,14 +524,18 @@
     Results.merge(Excs);
   } else if (const auto *Coro = dyn_cast<CoroutineBodyStmt>(St)) {
     for (const Stmt *Child : Coro->childrenExclBody()) {
-      ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
-      Results.merge(Excs);
+      if (Child != Coro->getExceptionHandler()) {
+        ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
+        Results.merge(Excs);
+      }
     }
     ExceptionInfo Excs = throwsException(Coro->getBody(), Caught, CallStack);
+    Results.merge(throwsException(Coro->getExceptionHandler(),
+                                  Excs.getExceptionTypes(), CallStack));
     for (const Type *Throwable : Excs.getExceptionTypes()) {
       if (const auto ThrowableRec = Throwable->getAsCXXRecordDecl()) {
         ExceptionInfo DestructorExcs =
-            throwsException(ThrowableRec->getDestructor(), CallStack);
+            throwsException(ThrowableRec->getDestructor(), Caught, CallStack);
         Results.merge(DestructorExcs);
       }
     }
@@ -553,7 +556,8 @@
   const auto CacheEntry = FunctionCache.find(Func);
   if (CacheEntry == FunctionCache.end()) {
     llvm::SmallSet<const FunctionDecl *, 32> CallStack;
-    ExceptionList = throwsException(Func, CallStack);
+    ExceptionList =
+        throwsException(Func, ExceptionInfo::Throwables(), CallStack);
 
     // Cache the result of the analysis. This is done prior to filtering
     // because it is best to keep as much information as possible.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to