https://gcc.gnu.org/g:6c3aaf09c4db2dc97d2347e94e4c0c364047136e

commit r16-8464-g6c3aaf09c4db2dc97d2347e94e4c0c364047136e
Author: Jakub Jelinek <[email protected]>
Date:   Sat Apr 4 11:32:33 2026 +0200

    c++: Implement CWG3119 - for-range-declaration of an expansion-statement as 
a templated entity
    
    The following patch implements the proposed resolution of
    https://wg21.link/cwg3119
    Temporarily setting processing_template_decl around the
    cp_parser_simple_declaration causes all kinds of ICEs and miscompilations,
    this patch just sets in_expansion_stmt around it and allows the sb
    pack in that case.
    
    2026-04-04  Jakub Jelinek  <[email protected]>
    
            * parser.cc (cp_parser_expansion_statement): Temporarily set
            in_expansion_stmt to true around cp_parser_simple_declaration
            for range_decl.
            (cp_parser_decomposition_declaration): Don't reject structured 
binding
            packs if in_expansion_stmt is set.
    
            * g++.dg/cpp26/expansion-stmt34.C: New test.

Diff:
---
 gcc/cp/parser.cc                              |  5 +++-
 gcc/testsuite/g++.dg/cpp26/expansion-stmt34.C | 40 +++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 84eef39941c9..518858fc7760 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -16606,6 +16606,8 @@ cp_parser_expansion_statement (cp_parser* parser, bool 
*if_p)
   /* A colon is used in expansion-statement.  */
   parser->colon_corrects_to_scope_p = false;
 
+  in_expansion_stmt = true;
+
   /* Parse the declaration.  */
   tree range_decl;
   cp_parser_simple_declaration (parser,
@@ -16614,6 +16616,7 @@ cp_parser_expansion_statement (cp_parser* parser, bool 
*if_p)
   if (range_decl == NULL_TREE)
     range_decl = error_mark_node;
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+  in_expansion_stmt = save_in_expansion_stmt;
 
   cp_parser_require (parser, CPP_COLON, RT_COLON);
 
@@ -18254,7 +18257,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
        if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
          {
            location_t elloc = cp_lexer_peek_token (parser->lexer)->location;
-           if (!processing_template_decl)
+           if (!processing_template_decl && !in_expansion_stmt)
              error_at (elloc, "structured binding pack outside of template");
            else if (pack != -1)
              error_at (elloc,
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt34.C 
b/gcc/testsuite/g++.dg/cpp26/expansion-stmt34.C
new file mode 100644
index 000000000000..b35f022b427c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt34.C
@@ -0,0 +1,40 @@
+// CWG3119 - for-range-declaration of an expansion-statement as a templated
+// entity.
+// { dg-do run { target c++26 } }
+
+namespace std {
+  using size_t = decltype (sizeof 0);
+  template<typename T> struct tuple_size;
+  template<size_t, typename> struct tuple_element;
+}
+struct B { int a; long b; };
+struct C { char a; short b; int c; long d; long long e; float f; };
+struct E { char a; template <int I> char &get () { return a; } };
+
+template <> struct std::tuple_size <E> { static const int value = 7; };
+template <std::size_t I> struct std::tuple_element <I, E> { using type = char; 
};
+
+struct A
+{
+  B b;
+  C c;
+  int d[3];
+  E e;
+};
+
+template <typename ...T>
+int
+foo (T... x)
+{
+  return sizeof... (x);
+}
+
+int
+main ()
+{
+  int ret = 0;
+  template for (auto [...e] : A ())
+    ret += foo (e...);
+  if (ret != 18)
+    __builtin_abort ();
+}

Reply via email to