Commit 830c5724 by Marek Polacek

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.
parent 14828900
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>
......
......@@ -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)
......
......@@ -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,
......
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
......
// 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" }
// 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment