[pushed,2/2] c++: be stricter about constinit [CWG2543]

Message ID 20230510150441.850396-2-jason@redhat.com
State Accepted
Headers
Series [pushed,1/2] c++: always check consteval address |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Jason Merrill May 10, 2023, 3:04 p.m. UTC
  Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

DR 2543 clarifies that constinit variables should follow the language, and
diagnose non-constant initializers (according to [expr.const]) even if they
can actually initialize the variables statically.

	DR 2543

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_outermost_constant_expr): Preserve
	TARGET_EXPR flags.
	(potential_constant_expression_1): Check TARGET_EXPR_ELIDING_P.
	* typeck2.cc (store_init_value): Diagnose constinit sooner.

gcc/testsuite/ChangeLog:

	* g++.dg/DRs/dr2543.C: New test.
---
 gcc/cp/constexpr.cc               | 12 +++++++
 gcc/cp/typeck2.cc                 | 55 +++++++++++++++++--------------
 gcc/testsuite/g++.dg/DRs/dr2543.C |  5 +++
 3 files changed, 48 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/DRs/dr2543.C
  

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 7b8090625e8..8f7f0b7d325 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8448,6 +8448,17 @@  cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 	}
     }
 
+  if (TREE_CODE (t) == TARGET_EXPR
+      && TREE_CODE (r) == TARGET_EXPR)
+    {
+      /* Preserve this flag for potential_constant_expression, and the others
+	 for good measure.  */
+      TARGET_EXPR_ELIDING_P (r) = TARGET_EXPR_ELIDING_P (t);
+      TARGET_EXPR_IMPLICIT_P (r) = TARGET_EXPR_IMPLICIT_P (t);
+      TARGET_EXPR_LIST_INIT_P (r) = TARGET_EXPR_LIST_INIT_P (t);
+      TARGET_EXPR_DIRECT_INIT_P (r) = TARGET_EXPR_DIRECT_INIT_P (t);
+    }
+
   /* Remember the original location if that wouldn't need a wrapper.  */
   if (location_t loc = EXPR_LOCATION (t))
     protected_set_expr_location (r, loc);
@@ -9774,6 +9785,7 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 
     case TARGET_EXPR:
       if (!TARGET_EXPR_DIRECT_INIT_P (t)
+	  && !TARGET_EXPR_ELIDING_P (t)
 	  && !literal_type_p (TREE_TYPE (t)))
 	{
 	  if (flags & tf_error)
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index bf03967a71f..f5cc7c8371c 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -843,23 +843,45 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       bool const_init;
       tree oldval = value;
       if (DECL_DECLARED_CONSTEXPR_P (decl)
+	  || DECL_DECLARED_CONSTINIT_P (decl)
 	  || (DECL_IN_AGGR_P (decl)
 	      && DECL_INITIALIZED_IN_CLASS_P (decl)))
 	{
 	  value = fold_non_dependent_expr (value, tf_warning_or_error,
 					   /*manifestly_const_eval=*/true,
 					   decl);
+	  if (value == error_mark_node)
+	    ;
 	  /* Diagnose a non-constant initializer for constexpr variable or
 	     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 if (!is_constant_expression (value))
+	    {
+	      /* Maybe we want to give this message for constexpr variables as
+		 well, but that will mean a lot of testsuite adjustment.  */
+	      if (DECL_DECLARED_CONSTINIT_P (decl))
+	      error_at (location_of (decl),
+			"%<constinit%> variable %qD does not have a "
+			"constant initializer", decl);
+	      require_constant_expression (value);
+	      value = error_mark_node;
+	    }
 	  else
-	    value = cxx_constant_init (value, decl);
+	    {
+	      value = maybe_constant_init (value, decl, true);
+
+	      /* In a template we might not have done the necessary
+		 transformations to make value actually constant,
+		 e.g. extend_ref_init_temps.  */
+	      if (!processing_template_decl
+		  && !TREE_CONSTANT (value))
+		{
+		  if (DECL_DECLARED_CONSTINIT_P (decl))
+		  error_at (location_of (decl),
+			    "%<constinit%> variable %qD does not have a "
+			    "constant initializer", decl);
+		  value = cxx_constant_init (value, decl);
+		}
+	    }
 	}
       else
 	value = fold_non_dependent_init (value, tf_warning_or_error,
@@ -875,22 +897,7 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       if (!TYPE_REF_P (type))
 	TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
       if (!const_init)
-	{
-	  /* [dcl.constinit]/2 "If a variable declared with the constinit
-	     specifier has dynamic initialization, the program is
-	     ill-formed."  */
-	  if (DECL_DECLARED_CONSTINIT_P (decl))
-	    {
-	      error_at (location_of (decl),
-			"%<constinit%> variable %qD does not have a constant "
-			"initializer", decl);
-	      if (require_constant_expression (value))
-		cxx_constant_init (value, decl);
-	      value = error_mark_node;
-	    }
-	  else
-	    value = oldval;
-	}
+	value = oldval;
     }
   /* Don't fold initializers of automatic variables in constexpr functions,
      that might fold away something that needs to be diagnosed at constexpr
diff --git a/gcc/testsuite/g++.dg/DRs/dr2543.C b/gcc/testsuite/g++.dg/DRs/dr2543.C
new file mode 100644
index 00000000000..87512d30455
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2543.C
@@ -0,0 +1,5 @@ 
+// CWG 2543
+// { dg-do compile { target c++20 } }
+
+float f;
+constinit int * pi = (int*) &f;	// { dg-error "constant" } reinterpret_cast, not constant-initialized