c++: designators in single-element init lists

While looking at PR100489, it occurred to me that places that currently
use an initializer-list with a single element to initialize an object of the
same type shouldn't do that if the element has a designator.

gcc/cp/ChangeLog:

	* call.c (reference_binding): Check for designator.
	(implicit_conversion_1, build_special_member_call): Likewise.
	* decl.c (reshape_init_r): Likewise.
	* pt.c (do_class_deduction): Likewise.
	* typeck2.c (digest_init_r): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/desig19.C: New test.
This commit is contained in:
Jason Merrill 2021-05-19 21:13:43 -04:00
parent 84fd1b5dff
commit 885035eacb
5 changed files with 42 additions and 2 deletions

View file

@ -1731,7 +1731,8 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
because A[] and A[2] are reference-related. But we don't do it
because grok_reference_init has deduced the array size (to 1), and
A[1] and A[2] aren't reference-related. */
if (CONSTRUCTOR_NELTS (expr) == 1)
if (CONSTRUCTOR_NELTS (expr) == 1
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
{
tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
if (error_operand_p (elt))
@ -2095,6 +2096,7 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p,
{
if (BRACE_ENCLOSED_INITIALIZER_P (expr)
&& CONSTRUCTOR_NELTS (expr) == 1
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (expr)
&& !is_list_ctor (cand->fn))
{
/* "If C is not an initializer-list constructor and the
@ -10199,6 +10201,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
if (BRACE_ENCLOSED_INITIALIZER_P (arg)
&& !TYPE_HAS_LIST_CTOR (class_type)
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (arg)
&& CONSTRUCTOR_NELTS (arg) == 1)
arg = CONSTRUCTOR_ELT (arg, 0)->value;

View file

@ -6650,6 +6650,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
initialized from that element." Even if T is an aggregate. */
if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type))
&& first_initializer_p
/* But not if it's a designated init. */
&& !d->cur->index
&& d->end - d->cur == 1
&& reference_related_p (type, TREE_TYPE (init)))
{

View file

@ -29326,7 +29326,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
{
list_init_p = true;
try_list_ctor = TYPE_HAS_LIST_CTOR (type);
if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1)
if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (init))
{
/* As an exception, the first phase in 16.3.1.7 (considering the
initializer list as a single argument) is omitted if the

View file

@ -1183,6 +1183,7 @@ digest_init_r (tree type, tree init, int nested, int flags,
the object is initialized from that element." */
if (cxx_dialect >= cxx11
&& BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (stripped_init)
&& CONSTRUCTOR_NELTS (stripped_init) == 1
&& ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
|| VECTOR_TYPE_P (type)))

View file

@ -0,0 +1,33 @@
// { dg-do compile { target c++11 } }
// { dg-options "" }
struct A
{
int i;
constexpr operator int() { return 42; }
};
#define SA(X) static_assert ((X),#X)
constexpr A a1 { A() };
SA(a1.i == 0);
constexpr A a2 { i: A() };
SA(a2.i == 42);
#if __cpp_constexpr >= 201304L
constexpr int f3 () { A const &r { A() }; return r.i; }
SA(f3() == 0);
constexpr int f4 () { A const &r { i: A() }; return r.i; }
SA(f4() == 42);
constexpr int f5 () { A ar[1]{{ A() }}; return ar[0].i; }
SA(f5() == 0);
constexpr int f5a () { A ar[1]{{ i: A() }}; return ar[0].i; }
SA(f5a() == 42);
#if __cpp_constexpr >= 201907L
constexpr int f6 () { A* p = new A{A()}; int i = p->i; delete p; return i; }
SA(f6() == 0);
constexpr int f6a () { A* p = new A{i:A()}; int i = p->i; delete p; return i; }
SA(f6a() == 42);
#endif
#endif
constexpr int f7 (A a) { return a.i; }
SA(f7({A()}) == 0);
SA(f7({i:A()}) == 42);