]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Implement C++ CWG3048 - Empty destructuring expansion statements
authorJakub Jelinek <jakub@redhat.com>
Mon, 25 Aug 2025 14:29:17 +0000 (16:29 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 25 Aug 2025 14:29:17 +0000 (16:29 +0200)
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  <jakub@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
gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C [new file with mode: 0644]

index dfabc5437d8b04b03342529aef658158d07171a9..d628744dbfd1bbec9d7169e7dc9616ad124fc9a0 100644 (file)
@@ -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;
     }
 
index 0c69afafa49fb454cf0e042215a6f69aff64213c..87d14e4d5663b2cab9116304b36f1b3f430eb19c 100644 (file)
@@ -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 (file)
index 0000000..59e1ca5
--- /dev/null
@@ -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 (file)
index 0000000..b0558d0
--- /dev/null
@@ -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 }
+}