PR c++/89144 - link error with constexpr initializer_list.
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
This commit is contained in:
parent
705c92a2ab
commit
d950b005f9
5 changed files with 69 additions and 26 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
11
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11.C
Normal file
11
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11.C
Normal file
|
@ -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>(); }
|
10
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11a.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/constexpr-initlist11a.C
Normal file
|
@ -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>(); }
|
Loading…
Add table
Reference in a new issue