From: Jason Merrill Date: Fri, 8 Apr 2022 19:33:41 +0000 (-0400) Subject: c++: constexpr non-trivial aggregate init [PR105191] X-Git-Tag: upstream/12.2.0~631 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4822108e61ab879067482704f2f7d1670813d61a;p=platform%2Fupstream%2Fgcc.git 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. --- diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 9c40b051574..db78b4a6545 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -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; diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 780a8d89165..63164bee638 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array28.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array28.C new file mode 100644 index 00000000000..d7706b9f0b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array28.C @@ -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{}, +};