]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Fix up handling of for-range-decls of expansion stmt [PR124488]
authorJakub Jelinek <jakub@redhat.com>
Mon, 6 Apr 2026 21:10:46 +0000 (23:10 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 6 Apr 2026 21:10:46 +0000 (23:10 +0200)
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  <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.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp26/expansion-stmt33.C [new file with mode: 0644]

index 518858fc776005b03b09e88f0f16049dec3b7cb4..3a8d56dc14650ce819709a7acee524ab9d0762d8 100644 (file)
@@ -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 ();
index d83ff031d77bd33e89c41a95c82422f4d484941b..673da9a19b40692d77e1c49d866b073dc942573d 100644 (file)
@@ -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 (file)
index 0000000..c7f79ef
--- /dev/null
@@ -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;
+}