c++: Fix wrong paren-init of aggregates interference [PR93790]
authorMarek Polacek <polacek@redhat.com>
Wed, 8 Apr 2020 21:03:53 +0000 (17:03 -0400)
committerMarek Polacek <polacek@redhat.com>
Thu, 9 Apr 2020 12:28:46 +0000 (08:28 -0400)
commit830c572428758f134bd001e699a08e622e2452c3
treeeb650334e618b8cfd52b357a2f8e84b87eda04fd
parent148289004696940ea5828d19e63a1e3791a2fb70
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.
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/paren-init23.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/aggr14.C [new file with mode: 0644]