bruno updated this revision to Diff 494740.
bruno added a comment.

Update checks that rely on `coroutine_traits` in `std-coroutine.h`


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

https://reviews.llvm.org/D142077

Files:
  clang/lib/Sema/SemaChecking.cpp
  clang/test/SemaCXX/Inputs/std-coroutine.h
  clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
  clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
  clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
  clang/test/SemaCXX/warn-unsequenced-coro.cpp

Index: clang/test/SemaCXX/warn-unsequenced-coro.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/warn-unsequenced-coro.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify -std=c++20 -I%S/Inputs -Wno-unused -Wno-uninitialized -Wunsequenced %s
+
+// expected-no-diagnostics
+
+#include "std-coroutine.h"
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+using namespace std;
+
+template<class T>
+struct Task {
+    struct promise_type {
+        Task<T> get_return_object() noexcept;
+        suspend_always initial_suspend() noexcept;
+        suspend_always final_suspend() noexcept;
+        void return_value(T);
+        void unhandled_exception();
+        auto yield_value(Task<T>) noexcept { return final_suspend(); }
+    };
+    bool await_ready() noexcept { return false; }
+    void await_suspend(coroutine_handle<>) noexcept {}
+    T await_resume();
+};
+
+template<>
+struct Task<void> {
+    struct promise_type {
+        Task<void> get_return_object() noexcept;
+        suspend_always initial_suspend() noexcept;
+        suspend_always final_suspend() noexcept;
+        void return_void() noexcept;
+        void unhandled_exception() noexcept;
+        auto yield_value(Task<void>) noexcept { return final_suspend(); }
+    };
+    bool await_ready() noexcept { return false; }
+    void await_suspend(coroutine_handle<>) noexcept {}
+    void await_resume() noexcept {}
+};
+
+template <typename T>
+class generator
+{
+  struct Promise
+  {
+    auto get_return_object() { return generator{*this}; }
+    auto initial_suspend() { return suspend_never{}; }
+    auto final_suspend() noexcept { return suspend_always{}; }
+    void unhandled_exception() {}
+    void return_void() {}
+
+    auto yield_value(T value)
+    {
+      value_ = std::move(value);
+      return suspend_always{};
+    }
+
+    T value_;
+  };
+
+  using Handle = coroutine_handle<Promise>;
+
+  struct sentinel{};
+  struct iterator
+  {
+    using iterator_category = input_iterator_tag;
+    using value_type = T;
+    using difference_type = ptrdiff_t;
+    using reference = T &;
+    using const_reference = const T &;
+    using pointer = T *;
+
+    iterator &operator++()
+    {
+      h_.resume();
+      return *this;
+    }
+    const_reference &operator*() const { return h_.promise().value_; }
+    bool operator!=(sentinel) { return !h_.done(); }
+
+    Handle h_;
+  };
+
+  explicit generator(Promise &p) : h_(Handle::from_promise(p)) {}
+  Handle h_;
+public:
+  using promise_type = Promise;
+  auto begin() { return iterator{h_}; }
+  auto end() { return sentinel{}; }
+};
+
+Task<void> c(int i) {
+  co_await (i = 0, std::suspend_always{});
+}
+
+generator<int> range(int start, int end)
+{
+  while (start < end)
+    co_yield start++;
+}
+
+Task<int> go(int const& val);
+Task<int> go1(int x) {
+  co_return co_await go(++x);
+}
\ No newline at end of file
Index: clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
+++ clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
@@ -28,5 +28,5 @@
 void test() {
   co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
   // expected-warning@-1{{support for 'std::experimental::coroutine_traits' will be removed}}
-  // expected-note@Inputs/std-coroutine.h:8 {{'coroutine_traits' declared here}}
+  // expected-note@Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
 }
Index: clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
+++ clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
@@ -27,5 +27,5 @@
   co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
   // expected-warning@-1{{support for 'std::experimental::coroutine_traits' will be removed}}
   // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
-  // expected-note@Inputs/std-coroutine.h:8 {{'coroutine_traits' declared here}}
+  // expected-note@Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
 }
Index: clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
+++ clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
@@ -26,5 +26,5 @@
   co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
   // expected-warning@-1{{support for 'std::experimental::coroutine_traits' will be removed}}
   // expected-note@Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
-  // expected-note@Inputs/std-coroutine.h:8 {{'coroutine_traits' declared here}}
+  // expected-note@Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
 }
Index: clang/test/SemaCXX/Inputs/std-coroutine.h
===================================================================
--- clang/test/SemaCXX/Inputs/std-coroutine.h
+++ clang/test/SemaCXX/Inputs/std-coroutine.h
@@ -4,12 +4,23 @@
 
 namespace std {
 
+template<typename T> struct remove_reference       { typedef T type; };
+template<typename T> struct remove_reference<T &>  { typedef T type; };
+template<typename T> struct remove_reference<T &&> { typedef T type; };
+
+template<typename T>
+typename remove_reference<T>::type &&move(T &&t) noexcept;
+
+struct input_iterator_tag {};
+struct forward_iterator_tag : public input_iterator_tag {};
+
 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 <>
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -15241,6 +15241,23 @@
     Base::VisitStmt(E);
   }
 
+  void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *CSE) {
+    for (auto *Sub : CSE->children()) {
+      const Expr *ChildExpr = dyn_cast_or_null<Expr>(Sub);
+      if (!ChildExpr)
+        continue;
+
+      if (ChildExpr == CSE->getOperand())
+        // Do not recurse over a CoroutineSuspendExpr's operand.
+        // The operand is also a subexpression of getCommonExpr(), and
+        // recursing into it directly could confuse object management
+        // for the sake of sequence tracking.
+        continue;
+
+      Visit(Sub);
+    }
+  }
+
   void VisitCastExpr(const CastExpr *E) {
     Object O = Object();
     if (E->getCastKind() == CK_LValueToRValue)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to