Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

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.

--- gcc/cp/pt.cc.jj     2025-08-23 15:51:08.726081054 +0200
+++ gcc/cp/pt.cc        2025-08-23 16:56:58.997154023 +0200
@@ -32834,11 +32834,6 @@ finish_expansion_stmt (tree expansion_st
                                         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);
@@ -32850,7 +32845,8 @@ finish_expansion_stmt (tree expansion_st
        = 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;
@@ -32871,7 +32867,7 @@ finish_expansion_stmt (tree expansion_st
       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;
     }
 
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C.jj    2025-08-15 
22:38:29.076869994 +0200
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C       2025-08-23 
17:05:32.182449214 +0200
@@ -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 } }
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C.jj    2025-08-23 
17:08:16.771305746 +0200
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C       2025-08-23 
17:08:48.477892823 +0200
@@ -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 ();
+}
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C.jj    2025-08-23 
17:08:25.082197512 +0200
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C       2025-08-23 
17:12:29.452987817 +0200
@@ -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 }
+}

        Jakub

Reply via email to