]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: wrong error due to std::initializer_list opt [PR116476]
authorMarek Polacek <polacek@redhat.com>
Wed, 28 Aug 2024 19:45:49 +0000 (15:45 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 28 Aug 2024 22:45:54 +0000 (18:45 -0400)
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>
gcc/cp/call.cc
gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C [new file with mode: 0644]

index 623e4c66c117cc1bad2eba1a25bfa78785289b51..fa7f05d76f6868051f8ed597e66c29cbe5bfce71 100644 (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
      we call the same function for direct-init as copy-list-init.  */
   conversion_obstack_sentinel cos;
+  init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST);
   tree arg = build_stub_object (init_elttype);
   conversion *c = implicit_conversion (elttype, init_elttype, arg, false,
                                       LOOKUP_NORMAL, tf_none);
@@ -4326,6 +4327,10 @@ maybe_init_list_as_array (tree elttype, tree init)
     c = next_conversion (c);
   if (!c || c->kind != ck_user)
     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;
   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))
     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));
   arr = finish_compound_literal (arr, init, tf_none);
   DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-opt2.C
new file mode 100644 (file)
index 0000000..6c71857
--- /dev/null
@@ -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};