c++, v2: Fix up handling of for-range-decls of expansion stmt [PR124488]

Message ID adNPtKeCGfTsY0wD@tucnak
State New
Headers
Series c++, v2: Fix up handling of for-range-decls of expansion stmt [PR124488] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Jakub Jelinek April 6, 2026, 6:16 a.m. UTC
  On Fri, Apr 03, 2026 at 06:03:22PM -0400, Jason Merrill wrote:
> > +  if (VAR_P (range_decl))
> > +    {
> > +      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (range_decl) = 1;
> > +      if (decl_maybe_constant_var_p (range_decl)
> > +	  /* FIXME setting TREE_CONSTANT on refs breaks the back end.  */
> > +	  && !TYPE_REF_P (TREE_TYPE (range_decl)))
> > +	TREE_CONSTANT (range_decl) = true;
> > +      /* Make it value dependent.  */
> > +      retrofit_lang_decl (range_decl);
> > +      SET_DECL_DEPENDENT_INIT_P (range_decl, 1);
> > +      DECL_INITIAL (range_decl) = for_range_identifier;
> 
> Why is the dummy DECL_INITIAL needed as well as DECL_DEPENDENT_INIT_P?

I was just afraid something might have called value_dependent_expression_p
also on the DECL_INITIAL and for NULL_TREE it returns false.

But I have nothing in the testsuite that would need it, so here is an
updated patch without that.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-04-06  Jakub Jelinek  <jakub@redhat.com>

	PR c++/124488
	* parser.cc (cp_parser_expansion_statement): Set
	DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P, DECL_DEPENDENT_INIT_P and
	if maybe constant non-reference TREE_CONSTANT on range_decl.
	* pt.cc (tsubst_stmt) <case TEMPLATE_FOR_STMT>: Set
	DECL_DEPENDENT_INIT_P on decl.

	* g++.dg/cpp26/expansion-stmt33.C: New test.



	Jakub
  

Comments

Jason Merrill April 6, 2026, 4:37 p.m. UTC | #1
On 4/6/26 2:16 AM, Jakub Jelinek wrote:
> On Fri, Apr 03, 2026 at 06:03:22PM -0400, Jason Merrill wrote:
>>> +  if (VAR_P (range_decl))
>>> +    {
>>> +      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (range_decl) = 1;
>>> +      if (decl_maybe_constant_var_p (range_decl)
>>> +	  /* FIXME setting TREE_CONSTANT on refs breaks the back end.  */
>>> +	  && !TYPE_REF_P (TREE_TYPE (range_decl)))
>>> +	TREE_CONSTANT (range_decl) = true;
>>> +      /* Make it value dependent.  */
>>> +      retrofit_lang_decl (range_decl);
>>> +      SET_DECL_DEPENDENT_INIT_P (range_decl, 1);
>>> +      DECL_INITIAL (range_decl) = for_range_identifier;
>>
>> Why is the dummy DECL_INITIAL needed as well as DECL_DEPENDENT_INIT_P?
> 
> I was just afraid something might have called value_dependent_expression_p
> also on the DECL_INITIAL and for NULL_TREE it returns false.
> 
> But I have nothing in the testsuite that would need it, so here is an
> updated patch without that.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

> 2026-04-06  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/124488
> 	* parser.cc (cp_parser_expansion_statement): Set
> 	DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P, DECL_DEPENDENT_INIT_P and
> 	if maybe constant non-reference TREE_CONSTANT on range_decl.
> 	* pt.cc (tsubst_stmt) <case TEMPLATE_FOR_STMT>: Set
> 	DECL_DEPENDENT_INIT_P on decl.
> 
> 	* g++.dg/cpp26/expansion-stmt33.C: New test.
> 
> --- gcc/cp/parser.cc.jj	2026-03-18 06:35:08.369968785 +0100
> +++ gcc/cp/parser.cc	2026-03-20 10:24:40.519275212 +0100
> @@ -16677,6 +16677,20 @@ cp_parser_expansion_statement (cp_parser
>     TEMPLATE_FOR_EXPR (r) = expansion_init;
>     TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block);
>   
> +  /* We don't know yet if range_decl will be initialized by constant
> +     expression or not.  */
> +  if (VAR_P (range_decl))
> +    {
> +      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (range_decl) = 1;
> +      if (decl_maybe_constant_var_p (range_decl)
> +	  /* FIXME setting TREE_CONSTANT on refs breaks the back end.  */
> +	  && !TYPE_REF_P (TREE_TYPE (range_decl)))
> +	TREE_CONSTANT (range_decl) = true;
> +      /* Make it value dependent.  */
> +      retrofit_lang_decl (range_decl);
> +      SET_DECL_DEPENDENT_INIT_P (range_decl, 1);
> +    }
> +
>     /* Parse the body of the expansion-statement.  */
>     parser->in_statement = IN_EXPANSION_STMT;
>     bool prev = note_iteration_stmt_body_start ();
> --- gcc/cp/pt.cc.jj	2026-03-18 06:35:08.372968734 +0100
> +++ gcc/cp/pt.cc	2026-03-20 10:24:49.890114568 +0100
> @@ -19776,6 +19776,11 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	      orig_decl = TREE_VEC_ELT (orig_decl, 0);
>   	    tree decl = tsubst (orig_decl, args, complain, in_decl);
>   	    maybe_push_decl (decl);
> +	    if (VAR_P (decl))
> +	      {
> +		retrofit_lang_decl (decl);
> +		SET_DECL_DEPENDENT_INIT_P (decl, 1);
> +	      }
>   
>   	    cp_decomp decomp_d, *decomp = NULL;
>   	    if (DECL_DECOMPOSITION_P (decl))
> --- gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C.jj	2026-03-20 10:02:54.569810934 +0100
> +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C	2026-03-20 10:27:18.603565158 +0100
> @@ -0,0 +1,17 @@
> +// PR c++/124488
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +void
> +foo ()
> +{
> +  template for (constexpr int a : { 42 })	// { dg-warning "'template for' only available with" "" { target c++23_down } }
> +    auto b = [] () { return a; };
> +}
> +
> +void
> +bar (int x)
> +{
> +  template for (const int a : { 42, ++x, 5 })	// { dg-warning "'template for' only available with" "" { target c++23_down } }
> +    const int b = a;
> +}
> 
> 
> 	Jakub
>
  

Patch

--- gcc/cp/parser.cc.jj	2026-03-18 06:35:08.369968785 +0100
+++ gcc/cp/parser.cc	2026-03-20 10:24:40.519275212 +0100
@@ -16677,6 +16677,20 @@  cp_parser_expansion_statement (cp_parser
   TEMPLATE_FOR_EXPR (r) = expansion_init;
   TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block);
 
+  /* We don't know yet if range_decl will be initialized by constant
+     expression or not.  */
+  if (VAR_P (range_decl))
+    {
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (range_decl) = 1;
+      if (decl_maybe_constant_var_p (range_decl)
+	  /* FIXME setting TREE_CONSTANT on refs breaks the back end.  */
+	  && !TYPE_REF_P (TREE_TYPE (range_decl)))
+	TREE_CONSTANT (range_decl) = true;
+      /* Make it value dependent.  */
+      retrofit_lang_decl (range_decl);
+      SET_DECL_DEPENDENT_INIT_P (range_decl, 1);
+    }
+
   /* Parse the body of the expansion-statement.  */
   parser->in_statement = IN_EXPANSION_STMT;
   bool prev = note_iteration_stmt_body_start ();
--- gcc/cp/pt.cc.jj	2026-03-18 06:35:08.372968734 +0100
+++ gcc/cp/pt.cc	2026-03-20 10:24:49.890114568 +0100
@@ -19776,6 +19776,11 @@  tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	      orig_decl = TREE_VEC_ELT (orig_decl, 0);
 	    tree decl = tsubst (orig_decl, args, complain, in_decl);
 	    maybe_push_decl (decl);
+	    if (VAR_P (decl))
+	      {
+		retrofit_lang_decl (decl);
+		SET_DECL_DEPENDENT_INIT_P (decl, 1);
+	      }
 
 	    cp_decomp decomp_d, *decomp = NULL;
 	    if (DECL_DECOMPOSITION_P (decl))
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C.jj	2026-03-20 10:02:54.569810934 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C	2026-03-20 10:27:18.603565158 +0100
@@ -0,0 +1,17 @@ 
+// PR c++/124488
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+  template for (constexpr int a : { 42 })	// { dg-warning "'template for' only available with" "" { target c++23_down } }
+    auto b = [] () { return a; };
+}
+
+void
+bar (int x)
+{
+  template for (const int a : { 42, ++x, 5 })	// { dg-warning "'template for' only available with" "" { target c++23_down } }
+    const int b = a;
+}