c++: constexpr non-trivial aggregate init [PR105191]
My patch for PR92385 made us use VEC_INIT_EXPR for aggregate initialization of an array where some elements are not explicitly initialized. Constexpr handling of that was treating initialization from {} as equivalent to value-initialization, which is problematic for classes with default member initializers that make the default constructor non-trivial; in older standard modes, not initializing all members makes a constructor non-constexpr, but aggregate initialization is fine. PR c++/105191 PR c++/92385 gcc/cp/ChangeLog: * tree.cc (build_vec_init_elt): Do {}-init for aggregates. * constexpr.cc (cxx_eval_vec_init): Only treat {} as value-init for non-aggregate types. (build_vec_init_expr): Also check constancy of explicit initializer elements. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-array28.C: New test.
This commit is contained in:
parent
58586721c7
commit
4822108e61
|
@ -5008,7 +5008,8 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
|
|||
bool value_init = VEC_INIT_EXPR_VALUE_INIT (t);
|
||||
if (!init || !BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
;
|
||||
else if (CONSTRUCTOR_NELTS (init) == 0)
|
||||
else if (CONSTRUCTOR_NELTS (init) == 0
|
||||
&& !CP_AGGREGATE_TYPE_P (strip_array_types (atype)))
|
||||
{
|
||||
/* Handle {} as value-init. */
|
||||
init = NULL_TREE;
|
||||
|
|
|
@ -740,7 +740,7 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain)
|
|||
constructor calls until gimplification time; now we only do it to set
|
||||
VEC_INIT_EXPR_IS_CONSTEXPR.
|
||||
|
||||
We assume that init is either NULL_TREE, void_type_node (indicating
|
||||
We assume that init is either NULL_TREE, {}, void_type_node (indicating
|
||||
value-initialization), or another array to copy. */
|
||||
|
||||
static tree
|
||||
|
@ -752,7 +752,20 @@ build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
|
|||
|| !CLASS_TYPE_P (inner_type))
|
||||
/* No interesting initialization to do. */
|
||||
return integer_zero_node;
|
||||
else if (init == void_type_node)
|
||||
if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
{
|
||||
/* Even if init has initializers for some array elements,
|
||||
we're interested in the {}-init of trailing elements. */
|
||||
if (CP_AGGREGATE_TYPE_P (inner_type))
|
||||
{
|
||||
tree empty = build_constructor (init_list_type_node, nullptr);
|
||||
return digest_init (inner_type, empty, complain);
|
||||
}
|
||||
else
|
||||
/* It's equivalent to value-init. */
|
||||
init = void_type_node;
|
||||
}
|
||||
if (init == void_type_node)
|
||||
return build_value_init (inner_type, complain);
|
||||
|
||||
releasing_vec argvec;
|
||||
|
@ -808,9 +821,13 @@ build_vec_init_expr (tree type, tree init, tsubst_flags_t complain)
|
|||
TREE_SIDE_EFFECTS (init) = true;
|
||||
SET_EXPR_LOCATION (init, input_location);
|
||||
|
||||
if (cxx_dialect >= cxx11
|
||||
&& potential_constant_expression (elt_init))
|
||||
VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
|
||||
if (cxx_dialect >= cxx11)
|
||||
{
|
||||
bool cx = potential_constant_expression (elt_init);
|
||||
if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
cx &= potential_constant_expression (init);
|
||||
VEC_INIT_EXPR_IS_CONSTEXPR (init) = cx;
|
||||
}
|
||||
VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
|
||||
|
||||
return init;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// PR c++/105191
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct A {
|
||||
const char* message = "";
|
||||
};
|
||||
|
||||
enum class B { };
|
||||
|
||||
struct C {
|
||||
A a;
|
||||
B b;
|
||||
};
|
||||
|
||||
struct D {
|
||||
C cs[1];
|
||||
};
|
||||
|
||||
constexpr D ds[4] = {
|
||||
D{},
|
||||
};
|
Loading…
Reference in New Issue