c++: wrong error due to std::initializer_list opt [PR116476]

Here maybe_init_list_as_array gets elttype=field, init={NON_LVALUE_EXPR <2>}
and it tries to convert the init's element type (int) to field
using implicit_conversion, which works, so overall maybe_init_list_as_array
is successful.

But it constifies init_elttype so we end up with "const int".  Later,
when we actually perform the conversion and invoke field::field(T&&),
we end up with this error:

  error: binding reference of type 'int&&' to 'const int' discards qualifiers

So I think maybe_init_list_as_array should try to perform the conversion,
like it does below with fc.

	PR c++/116476

gcc/cp/ChangeLog:

	* call.cc (maybe_init_list_as_array): Try convert_like and see if it
	worked.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/initlist-opt2.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
Marek Polacek 2024-08-28 15:45:49 -04:00
parent b8ef805e4d
commit 9f79c7ddff
2 changed files with 26 additions and 1 deletions

View File

@ -4319,6 +4319,7 @@ maybe_init_list_as_array (tree elttype, tree init)
/* Check with a stub expression to weed out special cases, and check whether /* Check with a stub expression to weed out special cases, and check whether
we call the same function for direct-init as copy-list-init. */ we call the same function for direct-init as copy-list-init. */
conversion_obstack_sentinel cos; conversion_obstack_sentinel cos;
init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
tree arg = build_stub_object (init_elttype); tree arg = build_stub_object (init_elttype);
conversion *c = implicit_conversion (elttype, init_elttype, arg, false, conversion *c = implicit_conversion (elttype, init_elttype, arg, false,
LOOKUP_NORMAL, tf_none); LOOKUP_NORMAL, tf_none);
@ -4326,6 +4327,10 @@ maybe_init_list_as_array (tree elttype, tree init)
c = next_conversion (c); c = next_conversion (c);
if (!c || c->kind != ck_user) if (!c || c->kind != ck_user)
return NULL_TREE; return NULL_TREE;
/* Check that we actually can perform the conversion. */
if (convert_like (c, arg, tf_none) == error_mark_node)
/* Let the normal code give the error. */
return NULL_TREE;
tree first = CONSTRUCTOR_ELT (init, 0)->value; tree first = CONSTRUCTOR_ELT (init, 0)->value;
conversion *fc = implicit_conversion (elttype, init_elttype, first, false, conversion *fc = implicit_conversion (elttype, init_elttype, first, false,
@ -4358,7 +4363,6 @@ maybe_init_list_as_array (tree elttype, tree init)
if (!is_xible (INIT_EXPR, elttype, copy_argtypes)) if (!is_xible (INIT_EXPR, elttype, copy_argtypes))
return NULL_TREE; return NULL_TREE;
init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init)); tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init));
arr = finish_compound_literal (arr, init, tf_none); arr = finish_compound_literal (arr, init, tf_none);
DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true; DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true;

View File

@ -0,0 +1,21 @@
// PR c++/116476
// { dg-do compile { target c++11 } }
namespace std {
template <typename T>
class initializer_list {
T *_M_len;
__SIZE_TYPE__ size;
};
} // namespace std
template <class T>
struct field {
field(T &&) {}
};
struct vector {
vector(std::initializer_list<field<int>>) { }
};
vector fields_normal{2};