diff mbox series

[pushed] c++: constexpr non-trivial aggregate init [PR105191]

Message ID 20220409032729.2705255-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: constexpr non-trivial aggregate init [PR105191] | expand

Commit Message

Jason Merrill April 9, 2022, 3:27 a.m. UTC
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.

Tested x86_64-pc-linux-gnu, applying to trunk.

	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.
---
 gcc/cp/constexpr.cc                           |  3 ++-
 gcc/cp/tree.cc                                | 27 +++++++++++++++----
 .../g++.dg/cpp0x/constexpr-array28.C          | 21 +++++++++++++++
 3 files changed, 45 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array28.C


base-commit: 58586721c79f77224b8571a5dba732620d5546ab
diff mbox series

Patch

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{},
+};