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
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
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
>
@@ -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 ();
@@ -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))
@@ -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;
+}