public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Martin Liska <marxin@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc(refs/users/marxin/heads/PR94314-fix-new-delete-pair-deletion-part-3)] c++: Fix wrong paren-init of aggregates interference [PR93790]
Date: Tue, 14 Apr 2020 06:35:56 +0000 (GMT)	[thread overview]
Message-ID: <20200414063556.38678385DC10@sourceware.org> (raw)

https://gcc.gnu.org/g:830c572428758f134bd001e699a08e622e2452c3

commit 830c572428758f134bd001e699a08e622e2452c3
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Apr 8 17:03:53 2020 -0400

    c++: Fix wrong paren-init of aggregates interference [PR93790]
    
    This PR points out that we are rejecting valid code in C++20.  The
    problem is that we were surreptitiously transforming
    
      T& t(e)
    
    into
    
      T& t{e}
    
    which is wrong, because the type of e had a conversion function to T,
    while aggregate initialization of t from e doesn't work.  Therefore, I
    was violating a design principle of P0960, which says that any existing
    meaning of A(b) should not change.  So I think we should only attempt to
    aggregate-initialize if the original expression was ill-formed.
    
    Another design principle is that () should work where {} works, so this:
    
      struct S { int i; };
      const S& s(1);
    
    has to keep working.  Thus the special handling for paren-lists with one
    element.  (A paren-list with more than one element would give you "error:
    expression list treated as compound expression in initializer" C++17.)
    
            PR c++/93790
            * call.c (initialize_reference): If the reference binding failed, maybe
            try initializing from { }.
            * decl.c (grok_reference_init): For T& t(e), set
            LOOKUP_AGGREGATE_PAREN_INIT but don't build up a constructor yet.
    
            * g++.dg/cpp2a/paren-init23.C: New test.
            * g++.dg/init/aggr14.C: New test.

Diff:
---
 gcc/cp/ChangeLog                          |  8 ++++++++
 gcc/cp/call.c                             | 14 ++++++++++++++
 gcc/cp/decl.c                             | 19 ++++++++++++++++---
 gcc/testsuite/ChangeLog                   |  6 ++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init23.C | 19 +++++++++++++++++++
 gcc/testsuite/g++.dg/init/aggr14.C        | 14 ++++++++++++++
 6 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e63f30bf3c1..cdd9b52915a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2020-04-09  Marek Polacek  <polacek@redhat.com>
+
+	PR c++/93790
+	* call.c (initialize_reference): If the reference binding failed, maybe
+	try initializing from { }.
+	* decl.c (grok_reference_init): For T& t(e), set
+	LOOKUP_AGGREGATE_PAREN_INIT but don't build up a constructor yet.
+
 2020-04-08  Iain Sandoe  <iain@sandoe.co.uk>
 	    Jun Ma <JunMa@linux.alibaba.com>
 
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 02220ffb3a1..1f3d9d23b5b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -12196,6 +12196,20 @@ initialize_reference (tree type, tree expr,
 
   conv = reference_binding (type, TREE_TYPE (expr), expr, /*c_cast_p=*/false,
 			    flags, complain);
+  /* If this conversion failed, we're in C++20, and we have something like
+     A& a(b) where A is an aggregate, try again, this time as A& a{b}.  */
+  if ((!conv || conv->bad_p)
+      && (flags & LOOKUP_AGGREGATE_PAREN_INIT))
+    {
+      tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr);
+      CONSTRUCTOR_IS_DIRECT_INIT (e) = true;
+      CONSTRUCTOR_IS_PAREN_INIT (e) = true;
+      conversion *c = reference_binding (type, TREE_TYPE (e), e,
+					 /*c_cast_p=*/false, flags, complain);
+      /* If this worked, use it.  */
+      if (c && !c->bad_p)
+	expr = e, conv = c;
+    }
   if (!conv || conv->bad_p)
     {
       if (complain & tf_error)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index a6a1340e631..1447b89e692 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5568,9 +5568,22 @@ grok_reference_init (tree decl, tree type, tree init, int flags)
 	  && !DECL_DECOMPOSITION_P (decl)
 	  && (cxx_dialect >= cxx2a))
 	{
-	  init = build_constructor_from_list (init_list_type_node, init);
-	  CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
-	  CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+	  /* We don't know yet if we should treat const A& r(1) as
+	     const A& r{1}.  */
+	  if (list_length (init) == 1)
+	    {
+	      flags |= LOOKUP_AGGREGATE_PAREN_INIT;
+	      init = build_x_compound_expr_from_list (init, ELK_INIT,
+						      tf_warning_or_error);
+	    }
+	  /* If the list had more than one element, the code is ill-formed
+	     pre-C++20, so we can build a constructor right away.  */
+	  else
+	    {
+	      init = build_constructor_from_list (init_list_type_node, init);
+	      CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+	      CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+	    }
 	}
       else
 	init = build_x_compound_expr_from_list (init, ELK_INIT,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6a972217610..a5bd5614e5a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2020-04-09  Marek Polacek  <polacek@redhat.com>
+
+	PR c++/93790
+	* g++.dg/cpp2a/paren-init23.C: New test.
+	* g++.dg/init/aggr14.C: New test.
+
 2020-04-09  Jan Hubicka  <hubicka@ucw.cz>
 
 	PR tree-optimization/91322
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init23.C b/gcc/testsuite/g++.dg/cpp2a/paren-init23.C
new file mode 100644
index 00000000000..6038f63be5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init23.C
@@ -0,0 +1,19 @@
+// PR c++/93790 - wrong paren-init of aggregates interference.
+// { dg-do compile { target c++2a } }
+
+struct S {
+  int i;
+};
+const S& s(1);
+
+struct A {
+  int i;
+  A(int);
+};
+const A& a(1);
+
+struct B {
+  int i;
+  B(int) = delete;
+};
+const B& b(1); // { dg-error "use of deleted function" }
diff --git a/gcc/testsuite/g++.dg/init/aggr14.C b/gcc/testsuite/g++.dg/init/aggr14.C
new file mode 100644
index 00000000000..538b467d467
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/aggr14.C
@@ -0,0 +1,14 @@
+// PR c++/93790 - wrong paren-init of aggregates interference.
+// { dg-do compile }
+
+struct S {};
+class S_refwrap {
+    S& Sref_;
+public:
+    S_refwrap(S& Sref) : Sref_(Sref) {}
+    operator S&() { return Sref_; }
+};
+
+S s;
+S_refwrap r(s);
+S& s2(r);


                 reply	other threads:[~2020-04-14  6:35 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20200414063556.38678385DC10@sourceware.org \
    --to=marxin@gcc.gnu.org \
    --cc=gcc-cvs@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).