summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIain Sandoe <iain@sandoe.co.uk>2022-04-17 20:58:28 +0100
committerIain Sandoe <iain@sandoe.co.uk>2022-04-28 13:51:44 +0100
commit15a176a833f23e64ad38690a678bf938227ce46f (patch)
tree837b6b0e44a19471835a43413837cb00fb0d98f3
parent9cb1f565a91e2dd57098c43593954b57c065a19b (diff)
downloadgcc-15a176a833f23e64ad38690a678bf938227ce46f.tar.gz
c++, coroutines: Make sure our temporaries are in a bind expr [PR105287]
There are a few cases where we can generate a temporary that does not need to be added to the coroutine frame (i.e. these are genuinely ephemeral). The intent was that unnamed temporaries should not be 'promoted' to coroutine frame entries. However there was a thinko and these were not actually ever added to the bind expressions being generated for the expanded awaits. This meant that they were showing in the global namspace, leading to an empty DECL_CONTEXT and the ICE reported. Signed-off-by: Iain Sandoe <iain@sandoe.co.uk> PR c++/105287 gcc/cp/ChangeLog: * coroutines.cc (maybe_promote_temps): Ensure generated temporaries are added to the bind expr. (add_var_to_bind): Fix local var naming to use portable punctuation. (register_local_var_uses): Do not add synthetic names to unnamed temporaries. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr105287.C: New test.
-rw-r--r--gcc/cp/coroutines.cc18
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr105287.C48
2 files changed, 57 insertions, 9 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 64f4b4412e5..9b651b845b7 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -3110,7 +3110,7 @@ maybe_promote_temps (tree *stmt, void *d)
If the initializer is a conditional expression, we need to collect
and declare any promoted variables nested within it. DTORs for such
variables must be run conditionally too. */
- if (t->var && DECL_NAME (t->var))
+ if (t->var)
{
tree var = t->var;
DECL_CHAIN (var) = vlist;
@@ -3311,7 +3311,7 @@ add_var_to_bind (tree& bind, tree var_type,
tree b_vars = BIND_EXPR_VARS (bind);
/* Build a variable to hold the condition, this will be included in the
frame as a local var. */
- char *nam = xasprintf ("%s.%d", nam_root, nam_vers);
+ char *nam = xasprintf ("__%s_%d", nam_root, nam_vers);
tree newvar = build_lang_decl (VAR_DECL, get_identifier (nam), var_type);
free (nam);
DECL_CHAIN (newvar) = b_vars;
@@ -3956,7 +3956,7 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
scopes with identically named locals and still be able to
identify them in the coroutine frame. */
tree lvname = DECL_NAME (lvar);
- char *buf;
+ char *buf = NULL;
/* The outermost bind scope contains the artificial variables that
we inject to implement the coro state machine. We want to be able
@@ -3966,14 +3966,14 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
else if (lvname != NULL_TREE)
buf = xasprintf ("%s_%u_%u", IDENTIFIER_POINTER (lvname),
lvd->nest_depth, lvd->bind_indx);
- else
- buf = xasprintf ("_D%u_%u_%u", DECL_UID (lvar), lvd->nest_depth,
- lvd->bind_indx);
/* TODO: Figure out if we should build a local type that has any
excess alignment or size from the original decl. */
- local_var.field_id
- = coro_make_frame_entry (lvd->field_list, buf, lvtype, lvd->loc);
- free (buf);
+ if (buf)
+ {
+ local_var.field_id = coro_make_frame_entry (lvd->field_list, buf,
+ lvtype, lvd->loc);
+ free (buf);
+ }
/* We don't walk any of the local var sub-trees, they won't contain
any bind exprs. */
}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr105287.C b/gcc/testsuite/g++.dg/coroutines/pr105287.C
new file mode 100644
index 00000000000..9790945287d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr105287.C
@@ -0,0 +1,48 @@
+// { dg-additional-options "-fanalyzer" }
+// { dg-excess-errors "lots of analyzer output, but no ICE" }
+namespace std {
+template <typename _Result> struct coroutine_traits : _Result {};
+template <typename = void> struct coroutine_handle {
+ operator coroutine_handle<>();
+};
+}
+struct coro1 {
+ using handle_type = std::coroutine_handle<>;
+ coro1(handle_type);
+ struct suspend_always_prt {
+ bool await_ready() noexcept;
+ void await_suspend(handle_type) noexcept;
+ void await_resume() noexcept;
+ };
+ struct promise_type {
+ std::coroutine_handle<> ch_;
+ auto get_return_object() { return ch_; }
+ auto initial_suspend() { return suspend_always_prt{}; }
+ auto final_suspend() noexcept { return suspend_always_prt{}; }
+ void unhandled_exception();
+ };
+};
+struct BoolAwaiter {
+ BoolAwaiter(bool);
+ bool await_ready();
+ void await_suspend(std::coroutine_handle<>);
+ bool await_resume();
+};
+struct IntAwaiter {
+ IntAwaiter(int);
+ bool await_ready();
+ void await_suspend(std::coroutine_handle<>);
+ int await_resume();
+};
+coro1 my_coro() {
+ int a = 1;
+ if (a == 0) {
+ int b = 5;
+
+ }
+ {
+ int c = 10;
+ }
+ co_await BoolAwaiter(true) && co_await IntAwaiter(a);
+
+ }