PR c++/89144 - link error with constexpr initializer_list.
authorJason Merrill <jason@redhat.com>
Tue, 12 Feb 2019 21:18:51 +0000 (16:18 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 12 Feb 2019 21:18:51 +0000 (16:18 -0500)
In this PR, we were unnecessarily rejecting a constexpr initializer_list
with no elements.  This seems like a fairly useless degenerate case, but it
makes sense to avoid allocating an underlying array at all if there are no
elements and instead use a null pointer, like the initializer_list default
constructor.

If the (automatic storage duration) list does have initializer elements, we
continue to reject the declaration, because the initializer_list ends up
referring to an automatic storage duration temporary array, which is not a
suitable constant initializer.  If we make it static, it should be OK
because we refer to a static array.  The second hunk fixes that case.  It
also means we won't diagnose some real errors in templates, but those
diagnostics aren't required, and we'll get them when the template is
instantiated.

* call.c (convert_like_real) [ck_list]: Don't allocate a temporary
array for an empty list.
* typeck2.c (store_init_value): Don't use cxx_constant_init in a
template.

From-SVN: r268827

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11a.C [new file with mode: 0644]

index 5fe18ccdab63f48313003db86407b3c944d8b279..cb74761571682fb0c21da27e652e072307b2cfbb 100644 (file)
@@ -1,3 +1,11 @@
+2019-02-12  Jason Merrill  <jason@redhat.com>
+
+       PR c++/89144 - link error with constexpr initializer_list.
+       * call.c (convert_like_real) [ck_list]: Don't allocate a temporary
+       array for an empty list.
+       * typeck2.c (store_init_value): Don't use cxx_constant_init in a
+       template.
+
 2019-02-11  Jason Merrill  <jason@redhat.com>
 
        PR c++/89241 - ICE with __func__ in lambda in template.
index e9c131dd66b4f6f2da3d58a036bb9e2d34652143..c53eb582aac9a3509f1f4296d82e3dc35e5e8899 100644 (file)
@@ -7085,34 +7085,42 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
       {
        /* Conversion to std::initializer_list<T>.  */
        tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0);
-       tree new_ctor = build_constructor (init_list_type_node, NULL);
        unsigned len = CONSTRUCTOR_NELTS (expr);
-       tree array, val, field;
-       vec<constructor_elt, va_gc> *vec = NULL;
-       unsigned ix;
+       tree array;
 
-       /* Convert all the elements.  */
-       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
+       if (len)
          {
-           tree sub = convert_like_real (convs->u.list[ix], val, fn, argnum,
-                                         false, false, complain);
-           if (sub == error_mark_node)
-             return sub;
-           if (!BRACE_ENCLOSED_INITIALIZER_P (val)
-               && !check_narrowing (TREE_TYPE (sub), val, complain))
-             return error_mark_node;
-           CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor), NULL_TREE, sub);
-           if (!TREE_CONSTANT (sub))
-             TREE_CONSTANT (new_ctor) = false;
+           tree val; unsigned ix;
+
+           tree new_ctor = build_constructor (init_list_type_node, NULL);
+
+           /* Convert all the elements.  */
+           FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
+             {
+               tree sub = convert_like_real (convs->u.list[ix], val, fn,
+                                             argnum, false, false, complain);
+               if (sub == error_mark_node)
+                 return sub;
+               if (!BRACE_ENCLOSED_INITIALIZER_P (val)
+                   && !check_narrowing (TREE_TYPE (sub), val, complain))
+                 return error_mark_node;
+               CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor),
+                                       NULL_TREE, sub);
+               if (!TREE_CONSTANT (sub))
+                 TREE_CONSTANT (new_ctor) = false;
+             }
+           /* Build up the array.  */
+           elttype = cp_build_qualified_type
+             (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
+           array = build_array_of_n_type (elttype, len);
+           array = finish_compound_literal (array, new_ctor, complain);
+           /* Take the address explicitly rather than via decay_conversion
+              to avoid the error about taking the address of a temporary.  */
+           array = cp_build_addr_expr (array, complain);
          }
-       /* Build up the array.  */
-       elttype = cp_build_qualified_type
-         (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
-       array = build_array_of_n_type (elttype, len);
-       array = finish_compound_literal (array, new_ctor, complain);
-       /* Take the address explicitly rather than via decay_conversion
-          to avoid the error about taking the address of a temporary.  */
-       array = cp_build_addr_expr (array, complain);
+       else
+         array = nullptr_node;
+
        array = cp_convert (build_pointer_type (elttype), array, complain);
        if (array == error_mark_node)
          return error_mark_node;
@@ -7123,11 +7131,12 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
        totype = complete_type_or_maybe_complain (totype, NULL_TREE, complain);
        if (!totype)
          return error_mark_node;
-       field = next_initializable_field (TYPE_FIELDS (totype));
+       tree field = next_initializable_field (TYPE_FIELDS (totype));
+       vec<constructor_elt, va_gc> *vec = NULL;
        CONSTRUCTOR_APPEND_ELT (vec, field, array);
        field = next_initializable_field (DECL_CHAIN (field));
        CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
-       new_ctor = build_constructor (totype, vec);
+       tree new_ctor = build_constructor (totype, vec);
        return get_target_expr_sfinae (new_ctor, complain);
       }
 
index 05998a3dc17aa2982ce462a79dd6f4c0c2e9293d..ac2c253196b3bb2e559550b7bcbf760867e3ea81 100644 (file)
@@ -850,6 +850,11 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
             non-inline in-class-initialized static data member.  */
          if (!require_constant_expression (value))
            value = error_mark_node;
+         else if (processing_template_decl)
+           /* In a template we might not have done the necessary
+              transformations to make value actually constant,
+              e.g. extend_ref_init_temps.  */
+           value = maybe_constant_init (value, decl, true);
          else
            value = cxx_constant_init (value, decl);
        }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11.C
new file mode 100644 (file)
index 0000000..da5eab2
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/89144
+// { dg-do link { target c++11 } }
+
+#include <initializer_list>
+
+template <class> void b() {
+  static constexpr std::initializer_list<int> c{ 42 };
+  constexpr std::initializer_list<int> l { };
+}
+
+int main() { b<int>(); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11a.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11a.C
new file mode 100644 (file)
index 0000000..2597c38
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/89144
+// { dg-do link { target c++11 } }
+
+#include <initializer_list>
+
+template <class> void b() {
+  constexpr std::initializer_list<int> l { 42 }; // { dg-error "" }
+}
+
+int main() { b<int>(); }