diff mbox series

coroutines: Ensure co_await_exprs have TREE_SIDE_EFFECTS set [PR 101133].

Message ID 20211003194817.67417-1-iain@sandoe.co.uk
State New
Headers show
Series coroutines: Ensure co_await_exprs have TREE_SIDE_EFFECTS set [PR 101133]. | expand

Commit Message

Iain Sandoe Oct. 3, 2021, 7:48 p.m. UTC
Hi,

Although it is not immediately evident from the symptoms, the PR is
caused by a variable having a DECL_INITIAL() containing a co_await.
This is not correct, since such expressions have side-effects.

We were marking the overall co_await expression correctly, but if a
consumer of that expression stripped out the underlying co_await_expr
then the latter would not be properly marked.

Fixed by marking both the underlying and any containing await expr
with TREE_SIDE_EFFECTS.  Also mark type-dependent co_await expressions.

tested on x86_64, powerpc64le linux and x86_64 darwin,
pushed to master as obvious, thanks,
Iain

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

	PR c++/101133

gcc/cp/ChangeLog:

	* coroutines.cc (build_co_await): Mark co_await_expr trees
	with TREE_SIDE_EFFECTS, also mark any containing expression.
	(finish_co_await_expr): Mark type-dependent co_await_expr
	trees with TREE_SIDE_EFFECTS.

gcc/testsuite/ChangeLog:

	* g++.dg/coroutines/pr101133.C: New test.
---
 gcc/cp/coroutines.cc                       | 24 ++++++++---------
 gcc/testsuite/g++.dg/coroutines/pr101133.C | 31 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/coroutines/pr101133.C
diff mbox series

Patch

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 876a14606f8..bff5b6343e5 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1117,13 +1117,15 @@  build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind)
 				a, e_proxy, o, awaiter_calls,
 				build_int_cst (integer_type_node,
 					       (int) suspend_kind));
+  TREE_SIDE_EFFECTS (await_expr) = true;
   if (te)
     {
       TREE_OPERAND (te, 1) = await_expr;
+      TREE_SIDE_EFFECTS (te) = true;
       await_expr = te;
     }
-  tree t = convert_from_reference (await_expr);
-  return t;
+  SET_EXPR_LOCATION (await_expr, loc);
+  return convert_from_reference (await_expr);
 }
 
 tree
@@ -1149,8 +1151,13 @@  finish_co_await_expr (location_t kw, tree expr)
      co_await with the expression unchanged.  */
   tree functype = TREE_TYPE (current_function_decl);
   if (dependent_type_p (functype) || type_dependent_expression_p (expr))
-    return build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr,
-		       NULL_TREE, NULL_TREE, NULL_TREE, integer_zero_node);
+    {
+      tree aw_expr = build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr,
+				 NULL_TREE, NULL_TREE, NULL_TREE,
+				 integer_zero_node);
+      TREE_SIDE_EFFECTS (aw_expr) = true;
+      return aw_expr;
+    }
 
   /* We must be able to look up the "await_transform" method in the scope of
      the promise type, and obtain its return type.  */
@@ -1187,14 +1194,7 @@  finish_co_await_expr (location_t kw, tree expr)
     }
 
   /* Now we want to build co_await a.  */
-  tree op = build_co_await (kw, a, CO_AWAIT_SUSPEND_POINT);
-  if (op != error_mark_node)
-    {
-      TREE_SIDE_EFFECTS (op) = 1;
-      SET_EXPR_LOCATION (op, kw);
-    }
-
-  return op;
+  return build_co_await (kw, a, CO_AWAIT_SUSPEND_POINT);
 }
 
 /* Take the EXPR given and attempt to build:
diff --git a/gcc/testsuite/g++.dg/coroutines/pr101133.C b/gcc/testsuite/g++.dg/coroutines/pr101133.C
new file mode 100644
index 00000000000..6c6bc163251
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr101133.C
@@ -0,0 +1,31 @@ 
+#include <coroutine>
+#include <string>
+
+template<typename T>
+struct Awaiter
+{
+    bool await_ready()                          const { return false; }    
+    void await_suspend(std::coroutine_handle<>) const {}    
+    T    await_resume()                         const { return T{}; }
+};
+
+struct ReturnObject
+{
+    struct promise_type
+    {
+        ReturnObject       get_return_object()        { return {}; }
+        std::suspend_never initial_suspend() noexcept { return {}; }
+        std::suspend_never final_suspend()   noexcept { return {}; }
+        void               return_void()              {}
+        void               unhandled_exception()      {}
+    };
+};
+
+ReturnObject f()
+{
+    auto a1 = Awaiter<int>{};
+    auto a2 = Awaiter<std::string>{};
+
+    [[maybe_unused]] auto v1 = co_await a1; // ok
+    [[maybe_unused]] std::string v2 = co_await a2; // error
+}