https://gcc.gnu.org/g:05baaa6feb9a8093646113c95f4cb8590ddd6de8

commit r16-3369-g05baaa6feb9a8093646113c95f4cb8590ddd6de8
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Mon Aug 25 16:29:17 2025 +0200

    c++: Implement C++ CWG3048 - Empty destructuring expansion statements
    
    The following patch implements the proposed resolution of
    https://cplusplus.github.io/CWG/issues/3048.html
    Instead of rejecting structured binding size it just builds a normal
    decl rather than structured binding declaration.
    
    2025-08-25  Jakub Jelinek  <ja...@redhat.com>
    
            * pt.cc (finish_expansion_stmt): Implement C++ CWG3048
            - Empty destructuring expansion statements.  Don't error for
            destructuring expansion stmts if sz is 0, don't call
            fit_decomposition_lang_decl if n is 0 and pass NULL rather than
            this_decomp to cp_finish_decl.
    
            * g++.dg/cpp26/expansion-stmt15.C: Don't expect error on
            destructuring expansion stmts with structured binding size 0.
            * g++.dg/cpp26/expansion-stmt21.C: New test.
            * g++.dg/cpp26/expansion-stmt22.C: New test.

Diff:
---
 gcc/cp/pt.cc                                  | 10 +++-------
 gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C |  4 ++--
 gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C | 24 ++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C | 16 ++++++++++++++++
 4 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dfabc5437d8b..d628744dbfd1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -32827,11 +32827,6 @@ finish_expansion_stmt (tree expansion_stmt, tree args,
                                         tf_warning_or_error);
       if (sz < 0)
        return;
-      if (sz == 0)
-       {
-         error_at (loc, "empty structured binding");
-         return;
-       }
       n = sz;
       tree auto_node = make_auto ();
       tree decomp_type = cp_build_reference_type (auto_node, true);
@@ -32843,7 +32838,8 @@ finish_expansion_stmt (tree expansion_stmt, tree args,
        = DECL_DECLARED_CONSTEXPR_P (range_decl);
       if (DECL_DECLARED_CONSTEXPR_P (decl))
        TREE_READONLY (decl) = 1;
-      fit_decomposition_lang_decl (decl, NULL_TREE);
+      if (n)
+       fit_decomposition_lang_decl (decl, NULL_TREE);
       pushdecl (decl);
       cp_decomp this_decomp;
       this_decomp.count = n;
@@ -32864,7 +32860,7 @@ finish_expansion_stmt (tree expansion_stmt, tree args,
       DECL_NAME (decl) = for_range__identifier;
       cp_finish_decl (decl, expansion_init,
                      /*is_constant_init*/false, NULL_TREE,
-                     LOOKUP_ONLYCONVERTING, &this_decomp);
+                     LOOKUP_ONLYCONVERTING, n ? &this_decomp : NULL);
       DECL_NAME (decl) = NULL_TREE;
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C 
b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
index 0c69afafa49f..87d14e4d5663 100644
--- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
@@ -27,11 +27,11 @@ foo (int n)
   int e = 42;
   d[0] = 42;
   template for (auto a : A {})         // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
-    ;                                  // { dg-error "empty structured 
binding" "" { target *-*-* } .-1 }
+    ;
   template for (int b : B {})          // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
     ;
   template for (int i : c)             // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
-    ;                                  // { dg-error "empty structured 
binding" "" { target *-*-* } .-1 }
+    ;
   template for (int i : d)             // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
     ;                                  // { dg-error "cannot decompose 
variable length array" "" { target *-*-* } .-1 }
   template for (auto a : C {})         // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C 
b/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C
new file mode 100644
index 000000000000..59e1ca5ec389
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C
@@ -0,0 +1,24 @@
+// DR3048 - Empty destructuring expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A {};
+
+int
+foo ()
+{
+  int c[0] = {};
+  int r = 0;
+  template for (auto a : A {})         // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
+    ++r;
+  template for (int i : c)             // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
+    ++r;
+  return r;
+}
+
+int
+main ()
+{
+  if (foo () != 0)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C 
b/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C
new file mode 100644
index 000000000000..b0558d0d96dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C
@@ -0,0 +1,16 @@
+// DR3048 - Empty destructuring expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {};
+
+void
+foo ()
+{
+  static constexpr A b {};
+  template for (constexpr auto a : b)  // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
+    ;
+  A c {};
+  template for (constexpr auto a : c)  // { dg-warning "'template for' only 
available with" "" { target c++23_down } }
+    ;                                  // { dg-error "'c' is not a constant 
expression" "" { target *-*-* } .-1 }
+}

Reply via email to