public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "adrian.perl at web dot de" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug c++/99576] [coroutines] destructor of a temporary called too early within co_await expression
Date: Fri, 25 Nov 2022 11:50:54 +0000	[thread overview]
Message-ID: <bug-99576-4-Kpc7PLwH1M@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-99576-4@http.gcc.gnu.org/bugzilla/>

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99576

Adrian Perl <adrian.perl at web dot de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |adrian.perl at web dot de

--- Comment #5 from Adrian Perl <adrian.perl at web dot de> ---
Created attachment 53963
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53963&action=edit
Test applications

I also noticed this behaviour in gcc 11.2 and could reproduce it in all version
since 10.2 (even in the current trunk).

Since this issues has existed for some time now, I had a look at the code
myself and possibly found a fix. Please be aware that I am a complete novice in
regards to the gcc-sourcecode.

As the example posted by David Ledger (https://godbolt.org/z/8r8oGG4z5) was the
simplest one I could find, I used it to debug the issue.

Having a look at the generated tree using -fdump-tree-all-graph I found out
that the destructor of A gets indeed called twice, first by the destructor of
class Awaitable and then once more in a finally-clause.
...
                 resume.4:;
                  <<cleanup_point <<< Unknown tree: expr_stmt
                    Awaitable::await_resume (&Aw0) >>>>>;
                }
              finally
                {
                  Awaitable::~Awaitable (&Aw0);
                }
            }
          finally
            {
              A::~A (&D.58267);
            }
...
The finally clauses are generated by the maybe_promote_temps-function in
coroutines.cc, which modifies the lifetime-management of temporaries in
co_await statements in order to keep them alive across a suspension point. For
this purpose it recursivly searches all initializers to the right of the
co_await expression, using the helper functions flatten_await_stmt and
find_interesting_subtree.
In this recursion it finds the initialization of the Awaitable and also the
initialization of its member. So both the temporary Awaitable-instance and its
member get promoted, which leads to the generation of a (correct) destructor
call for the Awaitable and the (incorrect) call for its member.

So the error seems to be in the recursion, which also finds and promotes
initializations in sub-scopes like the constructor. 

Therefore I modified the check for relevant subexpressions to exclude trees
below constructor calls, as can be seen in this patch:

Patch:
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 01a3e831ee5..349b68ea239 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2684,6 +2684,10 @@ find_interesting_subtree (tree *expr_p, int *dosub, void
*d)
          return expr;
        }
     }
+  else if (TREE_CODE(expr) == CONSTRUCTOR)
+    {
+      *dosub = 0; /* We don't need to consider this any further.  */
+    }
   else if (tmp_target_expr_p (expr)
           && !p->temps_used->contains (expr))
     {
-- 
2.34.1

I checked the results of the patched compiler using most of the examples posted
in this and related bug reports (99576, 100611, 102217, 101244, 101976) and
always got the correct results, also matching the output of clang. I have
attached these test applications.

I also noticed that the incorrect behaviour is gone as soon as the Awaitable
has a user defined constructor. This likely moves the initalization of the
Awaitable to a seperate tree which does not get evaluated by
find_interesting_subtree. I checked the .dot-files and there was indeed an
additional tree for the constructor when it is defined by the user.

It would be great if someone could have a look at the patch, as I am unsure if
it could have any unforseen sideeffects.
Another (better?) fix for this issue could be to always generate the
constructor-tree.

  parent reply	other threads:[~2022-11-25 11:50 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-13 13:54 [Bug c++/99576] New: [coroutines] desctructor " lemourin at gmail dot com
2021-05-14 16:21 ` [Bug c++/99576] [coroutines] destructor " nilsgladitz at gmail dot com
2021-05-15 12:31 ` nilsgladitz at gmail dot com
2021-06-10 14:14 ` davidledger at live dot com.au
2021-06-23  8:54 ` victor.burckel at gmail dot com
2021-10-01 19:57 ` iains at gcc dot gnu.org
2022-11-25 11:50 ` adrian.perl at web dot de [this message]
2022-11-25 15:13 ` iains at gcc dot gnu.org
2022-11-26 16:28 ` adrian.perl at web dot de
2022-11-26 16:40 ` iains at gcc dot gnu.org
2022-11-27 14:24 ` adrian.perl at web dot de
2022-11-27 15:42 ` iains at gcc dot gnu.org
2022-11-27 16:08 ` adrian.perl at web dot de
2022-11-28 19:13 ` adrian.perl at web dot de
2022-11-30 11:47 ` iains at gcc dot gnu.org
2022-11-30 23:38 ` iains at gcc dot gnu.org
2022-12-02 20:54 ` iains at gcc dot gnu.org
2022-12-04 10:41 ` cvs-commit at gcc dot gnu.org
2023-07-07  9:32 ` rguenth at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-99576-4-Kpc7PLwH1M@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).