@@ -3516,14 +3516,21 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
{
gcc_checking_assert (orig && TREE_CODE (orig) == FUNCTION_DECL);
+ *resumer = error_mark_node;
+ *destroyer = error_mark_node;
if (!coro_function_valid_p (orig))
- return false;
+ {
+ /* For early errors, we do not want a diagnostic about the missing
+ ramp return value, since the user cannot fix this - a 'return' is
+ not allowed in a coroutine. */
+ TREE_NO_WARNING (orig) = true;
+ return false;
+ }
/* We can't validly get here with an empty statement list, since there's no
way for the FE to decide it's a coroutine in the absence of any code. */
tree fnbody = pop_stmt_list (DECL_SAVED_TREE (orig));
- if (fnbody == NULL_TREE)
- return false;
+ gcc_checking_assert (fnbody != NULL_TREE);
/* We don't have the locus of the opening brace - it's filled in later (and
there doesn't really seem to be any easy way to get at it).
@@ -3537,7 +3544,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
if (body_start == NULL_TREE || body_start == error_mark_node)
{
DECL_SAVED_TREE (orig) = push_stmt_list ();
- append_to_statement_list (DECL_SAVED_TREE (orig), &fnbody);
+ append_to_statement_list (fnbody, &DECL_SAVED_TREE (orig));
+ /* Suppress warnings about the missing return value. */
+ TREE_NO_WARNING (orig) = true;
return false;
}
@@ -3606,13 +3615,21 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
the coroutine promise. */
tree initial_await = build_init_or_final_await (fn_start, false);
if (initial_await == error_mark_node)
- return false;
+ {
+ /* Suppress warnings about the missing return value. */
+ TREE_NO_WARNING (orig) = true;
+ return false;
+ }
/* The type of the frame var for this is the type of its temp proxy. */
tree initial_suspend_type = TREE_TYPE (TREE_OPERAND (initial_await, 1));
tree final_await = build_init_or_final_await (fn_start, true);
if (final_await == error_mark_node)
- return false;
+ {
+ /* Suppress warnings about the missing return value. */
+ TREE_NO_WARNING (orig) = true;
+ return false;
+ }
/* The type of the frame var for this is the type of its temp proxy. */
tree final_suspend_type = TREE_TYPE (TREE_OPERAND (final_await, 1));
@@ -4196,6 +4213,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
{
BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body);
DECL_SAVED_TREE (orig) = newbody;
+ /* Suppress warnings about the missing return value. */
+ TREE_NO_WARNING (orig) = true;
return false;
}
@@ -16880,6 +16880,7 @@ finish_function (bool inline_p)
bool coro_p = flag_coroutines
&& !processing_template_decl
&& DECL_COROUTINE_P (fndecl);
+ bool coro_emit_helpers = false;
/* When we get some parse errors, we can end up without a
current_function_decl, so cope. */
@@ -16908,18 +16909,16 @@ finish_function (bool inline_p)
if (coro_p)
{
- if (!morph_fn_to_coro (fndecl, &resumer, &destroyer))
- {
- DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
- poplevel (1, 0, 1);
- DECL_SAVED_TREE (fndecl) = error_mark_node;
- return fndecl;
- }
+ /* Only try to emit the coroutine outlined helper functions if the
+ transforms succeeded. Otherwise, treat errors in the same way as
+ a regular function. */
+ coro_emit_helpers = morph_fn_to_coro (fndecl, &resumer, &destroyer);
/* We should handle coroutine IFNs in middle end lowering. */
cfun->coroutine_component = true;
- if (use_eh_spec_block (fndecl))
+ /* Do not try to process the ramp's EH unless outlining succeeded. */
+ if (coro_emit_helpers && use_eh_spec_block (fndecl))
finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
(TREE_TYPE (fndecl)),
current_eh_spec_block);
@@ -17168,8 +17167,9 @@ finish_function (bool inline_p)
&& !DECL_OMP_DECLARE_REDUCTION_P (fndecl))
cp_genericize (fndecl);
- /* Emit the resumer and destroyer functions now. */
- if (coro_p)
+ /* Emit the resumer and destroyer functions now, providing that we have
+ not encountered some fatal error. */
+ if (coro_emit_helpers)
{
emit_coro_helper (resumer);
emit_coro_helper (destroyer);
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+// Check diagnostic return from missing promise initial suspend entry.
+
+#define MISSING_FINAL_SUSPEND
+#include "coro1-ret-int-yield-int.h"
+
+coro1
+my_coro () // { dg-error {no member named 'final_suspend' in} }
+{
+ co_return 0;
+}
+
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+// Check diagnostic return from missing promise initial suspend entry.
+
+#define MISSING_INITIAL_SUSPEND
+#include "coro1-ret-int-yield-int.h"
+
+coro1
+my_coro () // { dg-error {no member named 'initial_suspend' in} }
+{
+ co_return 0;
+}
+
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
@@ -27,6 +27,12 @@ bar ()
co_return 0;
}
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
+
int main (int ac, char *av[]) {
MissingPromiseYield x = bar ();
return 0;
@@ -16,3 +16,9 @@ bar ()
co_yield 22; // { dg-error {unable to find the promise type for this coroutine} }
co_return 0;
}
+
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
@@ -28,6 +28,12 @@ bar ()
co_return 6174; // { dg-error {no member named 'return_value' in} }
}
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
+
int main (int ac, char *av[]) {
MissingRetValue x = bar ();
return 0;
@@ -28,6 +28,12 @@ bar ()
co_return; // { dg-error "no member named .return_void. in" }
}
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
+
int main (int ac, char *av[]) {
MissingRetVoid x = bar ();
return 0;
@@ -12,6 +12,12 @@ bar ()
co_return;
}
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
+
int main (int ac, char *av[]) {
MissingUEH x = bar ();
return 0;
@@ -99,14 +99,20 @@ struct coro1 {
return handle_type::from_promise (*this);
}
+#ifdef MISSING_INITIAL_SUSPEND
+#else
auto initial_suspend () {
PRINT ("get initial_suspend (always)");
return suspend_always_prt{};
}
+#endif
+#ifdef MISSING_FINAL_SUSPEND
+#else
auto final_suspend () {
PRINT ("get final_suspend (always)");
return suspend_always_prt{};
}
+#endif
#ifdef USE_AWAIT_TRANSFORM
new file mode 100644
@@ -0,0 +1,10 @@
+
+void no_coroutine_traits() {
+ co_await 4; // { dg-error {coroutines require a traits template\; cannot find 'std::coroutine_traits'} }
+}
+
+// check we have not messed up continuation of the compilation.
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
new file mode 100644
@@ -0,0 +1,49 @@
+
+namespace std::experimental {
+template <typename R, typename... T> struct coroutine_traits {
+ using promise_type = typename R::promise_type;
+};
+
+template <class Promise = void> struct coroutine_handle;
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+template <class Promise> struct coroutine_handle : coroutine_handle<void> {
+ coroutine_handle() = default;
+ static coroutine_handle from_address(void *) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+struct Task {
+ struct promise_type {
+ Task get_return_object();
+ void return_void() {}
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+template <typename _AwrT> auto SyncAwait(_AwrT &&A) {
+ if (!A.await_ready()) {
+ auto AwaitAsync = [&]() -> Task {
+ try { (void)(co_await A); } catch (...) {} // { dg-error {coroutines require a traits template; cannot find 'std::coroutine_traits'} }
+ };
+ Task t = AwaitAsync();
+ }
+ return A.await_resume();
+}
+
+void f() {
+ suspend_always test;
+ SyncAwait(test);
+}