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

Add tests for co_yield and co_await


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D147417

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

Index: clang/include/clang/AST/StmtCXX.h
===================================================================
--- clang/include/clang/AST/StmtCXX.h
+++ clang/include/clang/AST/StmtCXX.h
@@ -443,6 +443,17 @@
                                                    NumParams);
   }
 
+  child_range childrenExclBody() {
+    return child_range(getStoredStmts() + SubStmt::Body + 1,
+                       getStoredStmts() + SubStmt::FirstParamMove + NumParams);
+  }
+
+  const_child_range childrenExclBody() const {
+    return const_child_range(getStoredStmts() + SubStmt::Body + 1,
+                             getStoredStmts() + SubStmt::FirstParamMove +
+                                 NumParams);
+  }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == CoroutineBodyStmtClass;
   }
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
@@ -0,0 +1,779 @@
+// RUN: %check_clang_tidy -std=c++20 %s bugprone-exception-escape %t -- \
+// RUN:     -- -fexceptions
+
+namespace std {
+
+template <bool B, class T = void> struct enable_if {};
+
+template <class T> struct enable_if<true, T> {
+  typedef T type;
+};
+
+template <bool B, class T = void>
+using enable_if_t = typename enable_if<B, T>::type;
+
+template <class T, class U> struct is_same {
+  static constexpr bool value = false;
+};
+
+template <class T> struct is_same<T, T> {
+  static constexpr bool value = false;
+};
+
+template <class T, class U>
+inline constexpr bool is_same_v = is_same<T, U>::value;
+
+template <class Ret, typename... T> struct coroutine_traits {
+  using promise_type = typename Ret::promise_type;
+};
+
+template <class Promise = void> struct coroutine_handle {
+  static coroutine_handle from_address(void *) noexcept;
+  static coroutine_handle from_promise(Promise &promise);
+  constexpr void *address() const noexcept;
+};
+
+template <> struct coroutine_handle<void> {
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+  static coroutine_handle from_address(void *);
+  constexpr void *address() const noexcept;
+};
+
+struct suspend_always {
+  bool await_ready() noexcept { return false; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
+};
+
+struct suspend_never {
+  bool await_ready() noexcept { return true; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
+};
+
+} // namespace std
+
+template <typename Task, typename T, bool ThrowInPromiseConstructor,
+          bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
+          bool ThrowInUnhandledException>
+struct Promise;
+
+template <
+    typename T, bool ThrowInTaskConstructor = false,
+    bool ThrowInPromiseConstructor = false, bool ThrowInInitialSuspend = false,
+    bool ThrowInGetReturnObject = false, bool ThrowInUnhandledException = false>
+struct Task {
+  using promise_type =
+      Promise<Task, T, ThrowInPromiseConstructor, ThrowInInitialSuspend,
+              ThrowInGetReturnObject, ThrowInUnhandledException>;
+
+  explicit Task(promise_type &p) {
+    if constexpr (ThrowInTaskConstructor) {
+      throw 1;
+    }
+
+    p.return_val = this;
+  }
+
+  bool await_ready() { return true; }
+
+  void await_suspend(std::coroutine_handle<> h) {}
+
+  void await_resume() {}
+
+  T value;
+};
+
+template <bool ThrowInTaskConstructor, bool ThrowInPromiseConstructor,
+          bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
+          bool ThrowInUnhandledException>
+struct Task<void, ThrowInTaskConstructor, ThrowInPromiseConstructor,
+            ThrowInInitialSuspend, ThrowInGetReturnObject,
+            ThrowInUnhandledException> {
+  using promise_type =
+      Promise<Task, void, ThrowInPromiseConstructor, ThrowInInitialSuspend,
+              ThrowInGetReturnObject, ThrowInUnhandledException>;
+
+  explicit Task(promise_type &p) {
+    if constexpr (ThrowInTaskConstructor) {
+      throw 1;
+    }
+
+    p.return_val = this;
+  }
+
+  bool await_ready() { return true; }
+
+  void await_suspend(std::coroutine_handle<> h) {}
+
+  void await_resume() {}
+};
+
+template <typename Task, typename T, bool ThrowInPromiseConstructor,
+          bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
+          bool ThrowInUnhandledException>
+struct Promise {
+  Promise() {
+    if constexpr (ThrowInPromiseConstructor) {
+      throw 1;
+    }
+  }
+
+  Task get_return_object() {
+    if constexpr (ThrowInGetReturnObject) {
+      throw 1;
+    }
+
+    return Task{*this};
+  }
+
+  std::suspend_never initial_suspend() const {
+    if constexpr (ThrowInInitialSuspend) {
+      throw 1;
+    }
+
+    return {};
+  }
+
+  std::suspend_never final_suspend() const noexcept { return {}; }
+
+  template <typename U> void return_value(U &&val) {
+    return_val->value = static_cast<U &&>(val);
+  }
+
+  template <typename U> std::suspend_never yield_value(U &&val) {
+    return_val->value = static_cast<U &&>(val);
+    return {};
+  }
+
+  void unhandled_exception() {
+    if constexpr (ThrowInUnhandledException) {
+      throw 1;
+    }
+  }
+
+  Task *return_val;
+};
+
+template <typename Task, bool ThrowInPromiseConstructor,
+          bool ThrowInInitialSuspend, bool ThrowInGetReturnObject,
+          bool ThrowInUnhandledException>
+struct Promise<Task, void, ThrowInPromiseConstructor, ThrowInInitialSuspend,
+               ThrowInGetReturnObject, ThrowInUnhandledException> {
+  Promise() {
+    if constexpr (ThrowInPromiseConstructor) {
+      throw 1;
+    }
+  }
+
+  Task get_return_object() {
+    if constexpr (ThrowInGetReturnObject) {
+      throw 1;
+    }
+
+    return Task{*this};
+  }
+
+  std::suspend_never initial_suspend() const {
+    if constexpr (ThrowInInitialSuspend) {
+      throw 1;
+    }
+
+    return {};
+  }
+
+  std::suspend_never final_suspend() const noexcept { return {}; }
+
+  void return_void() {}
+
+  void unhandled_exception() {
+    if constexpr (ThrowInUnhandledException) {
+      throw 1;
+    }
+  }
+
+  Task *return_val;
+};
+
+struct Evil {
+  ~Evil() noexcept(false) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function '~Evil' which should not throw exceptions
+    throw 42;
+  }
+};
+
+Task<int> returnOne() { co_return 1; }
+
+namespace function {
+
+namespace coreturn {
+
+Task<int> a_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'a_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+}
+
+Task<int> b_ShouldNotDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'b_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+}
+
+Task<int> c_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_return a / b;
+}
+
+Task<int> c_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_return a / b;
+}
+
+Task<int, true> d_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldNotDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, true> d_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, true> e_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldNotDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, true> e_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, true> f_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldNotDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, false, true> g_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:38: warning: an exception may be thrown in function 'g_ShouldNotDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, false, true> g_ShouldDiag(const int a,
+                                                  const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, false, false, true> h_ShouldNotDiag(const int a,
+                                                            const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldNotDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+Task<int, false, false, false, false, true> h_ShouldDiag(const int a,
+                                                         const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
+  co_return a / b;
+}
+
+} // namespace coreturn
+
+namespace coyield {
+
+Task<int> a_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'a_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+}
+
+Task<int> b_ShouldNotDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'b_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+}
+
+Task<int> c_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_yield a / b;
+}
+
+Task<int> c_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_yield a / b;
+}
+
+Task<int, true> d_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldNotDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, true> d_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, true> e_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldNotDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, true> e_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, true> f_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldNotDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, false, true> g_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:38: warning: an exception may be thrown in function 'g_ShouldNotDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, false, true> g_ShouldDiag(const int a,
+                                                  const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, false, false, true> h_ShouldNotDiag(const int a,
+                                                            const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldNotDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+Task<int, false, false, false, false, true> h_ShouldDiag(const int a,
+                                                         const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
+  co_yield a / b;
+}
+
+} // namespace coyield
+
+namespace coawait {
+
+Task<void> a_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: an exception may be thrown in function 'a_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_await returnOne();
+}
+
+Task<void> b_ShouldNotDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: an exception may be thrown in function 'b_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_await returnOne();
+}
+
+Task<void> c_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: an exception may be thrown in function 'c_ShouldNotDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_await returnOne();
+}
+
+Task<void> c_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_await returnOne();
+}
+
+Task<void, true> d_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:18: warning: an exception may be thrown in function 'd_ShouldNotDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, true> d_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, true> e_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:25: warning: an exception may be thrown in function 'e_ShouldNotDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, true> e_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, true> f_ShouldNotDiag(const int a, const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:32: warning: an exception may be thrown in function 'f_ShouldNotDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, false, true> g_ShouldNotDiag(const int a,
+                                                      const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:39: warning: an exception may be thrown in function 'g_ShouldNotDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, false, true> g_ShouldDiag(const int a,
+                                                   const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, false, false, true> h_ShouldNotDiag(const int a,
+                                                             const int b) {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:46: warning: an exception may be thrown in function 'h_ShouldNotDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+Task<void, false, false, false, false, true>
+h_ShouldDiag(const int a, const int b) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
+  co_await returnOne();
+}
+
+} // namespace coawait
+
+} // namespace function
+
+namespace lambda {
+
+namespace coreturn {
+
+const auto a_ShouldNotDiag = [](const int a, const int b) -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+};
+
+const auto b_ShouldNotDiag = [](const int a,
+                                const int b) noexcept -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_return a / b;
+};
+
+const auto c_ShouldNotDiag = [](const int a, const int b) -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_return a / b;
+};
+
+const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<int> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_return a / b;
+};
+
+const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<int, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto d_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<int, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto e_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<int, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto e_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<int, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto f_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<int, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto f_ShouldDiag =
+    [](const int a, const int b) noexcept -> Task<int, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto g_ShouldNotDiag =
+    [](const int a, const int b) -> Task<int, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto g_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto h_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_return a / b;
+};
+
+const auto h_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, 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_return a / b;
+};
+
+} // namespace coreturn
+
+namespace coyield {
+
+const auto a_ShouldNotDiag = [](const int a, const int b) -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+};
+
+const auto b_ShouldNotDiag = [](const int a,
+                                const int b) noexcept -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_yield a / b;
+};
+
+const auto c_ShouldNotDiag = [](const int a, const int b) -> Task<int> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_yield a / b;
+};
+
+const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<int> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_yield a / b;
+};
+
+const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<int, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto d_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<int, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto e_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<int, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto e_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<int, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto f_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<int, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto f_ShouldDiag =
+    [](const int a, const int b) noexcept -> Task<int, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto g_ShouldNotDiag =
+    [](const int a, const int b) -> Task<int, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto g_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, false, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto h_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<int, false, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_yield a / b;
+};
+
+const auto h_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<int, 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_yield a / b;
+};
+
+} // namespace coyield
+
+namespace coawait {
+
+const auto a_ShouldNotDiag = [](const int a, const int b) -> Task<void> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_await returnOne();
+};
+
+const auto b_ShouldNotDiag = [](const int a,
+                                const int b) noexcept -> Task<void> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw b;
+
+  co_await returnOne();
+};
+
+const auto c_ShouldNotDiag = [](const int a, const int b) -> Task<void> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_await returnOne();
+};
+
+const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<void> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  if (b == 0)
+    throw Evil{};
+
+  co_await returnOne();
+};
+
+const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<void, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto d_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<void, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto e_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<void, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto e_ShouldDiag = [](const int a,
+                             const int b) noexcept -> Task<void, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto f_ShouldNotDiag = [](const int a,
+                                const int b) -> Task<void, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:30: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto f_ShouldDiag =
+    [](const int a, const int b) noexcept -> Task<void, false, false, true> {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto g_ShouldNotDiag =
+    [](const int a, const int b) -> Task<void, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto g_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<void, 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();
+};
+
+const auto h_ShouldNotDiag =
+    [](const int a,
+       const int b) -> Task<void, false, false, false, false, true> {
+  // CHECK-MESSAGES-NOT: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
+  co_await returnOne();
+};
+
+const auto h_ShouldDiag =
+    [](const int a,
+       const int b) noexcept -> Task<void, 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();
+};
+
+} // namespace coawait
+
+} // namespace lambda
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
@@ -523,6 +523,19 @@
     ExceptionInfo Excs =
         throwsException(DefaultInit->getExpr(), Caught, CallStack);
     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);
+    }
+    ExceptionInfo Excs = throwsException(Coro->getBody(), Caught, CallStack);
+    for (const Type *Throwable : Excs.getExceptionTypes()) {
+      if (const auto ThrowableRec = Throwable->getAsCXXRecordDecl()) {
+        ExceptionInfo DestructorExcs =
+            throwsException(ThrowableRec->getDestructor(), CallStack);
+        Results.merge(DestructorExcs);
+      }
+    }
   } else {
     for (const Stmt *Child : St->children()) {
       ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to