https://gcc.gnu.org/g:a96d7250389d05ab8f8a68c2c3cfad3c709a6cb4
commit r16-8483-ga96d7250389d05ab8f8a68c2c3cfad3c709a6cb4 Author: Jakub Jelinek <[email protected]> Date: Mon Apr 6 23:10:46 2026 +0200 c++: Fix up handling of for-range-decls of expansion stmt [PR124488] The following testcase is rejected, because we don't set all the needed flags on range_decl in cp_parser_expansion_statement. During parsing of the expansion stmt body, it should be treated as if there is a decl with value dependent initializer in a template, because the value it will have is yet to be determined (and possibly different in each instantiation of the body). For such decls, cp_finish_decl normally conservatively sets DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (because it might be initialized by constant expression) and for non-references also sets TREE_CONSTANT if decl_maybe_constant_var_p. Furthermore, those have a value dependent initializer and DECL_DEPENDENT_INIT_P is set on those too. The following patch arranges all of that for the range_decl. 2026-04-06 Jakub Jelinek <[email protected]> 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. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/parser.cc | 14 ++++++++++++++ gcc/cp/pt.cc | 5 +++++ gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 518858fc7760..3a8d56dc1465 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16685,6 +16685,20 @@ cp_parser_expansion_statement (cp_parser* parser, bool *if_p) 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 (); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d83ff031d77b..673da9a19b40 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -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)) diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C new file mode 100644 index 000000000000..c7f79efb3a56 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C @@ -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; +}
