https://gcc.gnu.org/g:bd35a92f8d44e91c96e8b6f01805fe4a68acf9eb

commit r15-61-gbd35a92f8d44e91c96e8b6f01805fe4a68acf9eb
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Apr 30 08:57:15 2024 +0200

    c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456]
    
    The following patch implements the P0609R3 paper; we build the
    VAR_DECLs for the structured binding identifiers early, so all we need
    IMHO is just to parse the attributed identifier list and pass the attributes
    to the VAR_DECL creation.
    
    The paper mentions maybe_unused and gnu::nonstring attributes as examples
    where they can be useful.  Not sure about either of them.
    For maybe_unused, the thing is that both GCC and clang already don't
    diagnose maybe unused for the structured binding identifiers, because it
    would be a false positive too often; and there is no easy way to find out
    if a structured binding has been written with the P0609R3 paper in mind or
    not (maybe we could turn it on if in the structured binding is any
    attribute, even if just [[]] and record that as a flag on the whole
    underlying decl, so that we'd diagnose
      auto [a, b, c[[]]] = d;
      // use a, c but not b
    but not
      auto [e, f, g] = d;
      // use a, c but not b
    ).  For gnu::nonstring, the issue is that we currently don't allow the
    attribute on references to char * or references to char[], just on
    char */char[].  I've filed a PR for that.
    
    The first testcase in the patch tests it on [[]] and [[maybe_unused]],
    just whether it is parsed properly, second on gnu::deprecated, which
    works.  Haven't used deprecated attribute because the paper said that
    attribute is for further investigation.
    
    2024-04-30  Jakub Jelinek  <ja...@redhat.com>
    
            PR c++/114456
    gcc/c-family/
            * c-cppbuiltin.cc (c_cpp_builtins): Predefine
            __cpp_structured_bindings for C++26 to 202403L rather than
            201606L.
    gcc/cp/
            * parser.cc (cp_parser_decomposition_declaration): Implement C++26
            P0609R3 - Attributes for Structured Bindings.  Parse attributed
            identifier lists for structured binding declarations, pass the
            attributes to start_decl.
    gcc/testsuite/
            * g++.dg/cpp26/decomp1.C: New test.
            * g++.dg/cpp26/decomp2.C: New test.
            * g++.dg/cpp26/feat-cxx26.C (__cpp_structured_bindings): Expect
            202403 rather than 201606.

Diff:
---
 gcc/c-family/c-cppbuiltin.cc            |  4 ++-
 gcc/cp/parser.cc                        | 33 ++++++++++++++++++++---
 gcc/testsuite/g++.dg/cpp26/decomp1.C    | 33 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/decomp2.C    | 46 +++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp26/feat-cxx26.C |  4 +--
 5 files changed, 114 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 38f32032982..0a927b28836 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1044,7 +1044,8 @@ c_cpp_builtins (cpp_reader *pfile)
          /* Old macro, superseded by
             __cpp_nontype_template_parameter_auto.  */
          cpp_define (pfile, "__cpp_template_auto=201606L");
-         cpp_define (pfile, "__cpp_structured_bindings=201606L");
+         if (cxx_dialect <= cxx23)
+           cpp_define (pfile, "__cpp_structured_bindings=201606L");
          cpp_define (pfile, "__cpp_variadic_using=201611L");
          cpp_define (pfile, "__cpp_guaranteed_copy_elision=201606L");
          cpp_define (pfile, "__cpp_nontype_template_parameter_auto=201606L");
@@ -1090,6 +1091,7 @@ c_cpp_builtins (cpp_reader *pfile)
          cpp_define (pfile, "__cpp_constexpr=202306L");
          cpp_define (pfile, "__cpp_static_assert=202306L");
          cpp_define (pfile, "__cpp_placeholder_variables=202306L");
+         cpp_define (pfile, "__cpp_structured_bindings=202403L");
        }
       if (flag_concepts)
         {
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 598380dda08..aefbffe8330 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -16075,13 +16075,37 @@ cp_parser_decomposition_declaration (cp_parser 
*parser,
 
   /* Parse the identifier-list.  */
   auto_vec<cp_expr, 10> v;
+  bool attr_diagnosed = false;
+  int first_attr = -1;
+  unsigned int cnt = 0;
   if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
     while (true)
       {
        cp_expr e = cp_parser_identifier (parser);
        if (e.get_value () == error_mark_node)
          break;
+       tree attr = NULL_TREE;
+       if (cp_next_tokens_can_be_std_attribute_p (parser))
+         {
+           if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed)
+             {
+               pedwarn (cp_lexer_peek_token (parser->lexer)->location,
+                        OPT_Wc__26_extensions,
+                        "structured bindings with attributed identifiers "
+                        "only available with %<-std=c++2c%> or "
+                        "%<-std=gnu++2c%>");
+               attr_diagnosed = true;
+             }
+           attr = cp_parser_std_attribute_spec_seq (parser);
+           if (attr == error_mark_node)
+             attr = NULL_TREE;
+           if (attr && first_attr == -1)
+             first_attr = v.length ();
+         }
        v.safe_push (e);
+       ++cnt;
+       if (first_attr != -1)
+         v.safe_push (attr);
        if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
          break;
        cp_lexer_consume_token (parser->lexer);
@@ -16139,8 +16163,11 @@ cp_parser_decomposition_declaration (cp_parser *parser,
          declarator->id_loc = e.get_location ();
        }
       tree elt_pushed_scope;
+      tree attr = NULL_TREE;
+      if (first_attr != -1 && i >= (unsigned) first_attr)
+       attr = v[++i].get_value ();
       tree decl2 = start_decl (declarator, &decl_specs, SD_DECOMPOSITION,
-                              NULL_TREE, NULL_TREE, &elt_pushed_scope);
+                              NULL_TREE, attr, &elt_pushed_scope);
       if (decl2 == error_mark_node)
        decl = error_mark_node;
       else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
@@ -16183,7 +16210,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
 
       if (decl != error_mark_node)
        {
-         cp_decomp decomp = { prev, v.length () };
+         cp_decomp decomp = { prev, cnt };
          cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
                          (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT),
                          &decomp);
@@ -16193,7 +16220,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
   else if (decl != error_mark_node)
     {
       *maybe_range_for_decl = prev;
-      cp_decomp decomp = { prev, v.length () };
+      cp_decomp decomp = { prev, cnt };
       /* Ensure DECL_VALUE_EXPR is created for all the decls but
         the underlying DECL.  */
       cp_finish_decomp (decl, &decomp);
diff --git a/gcc/testsuite/g++.dg/cpp26/decomp1.C 
b/gcc/testsuite/g++.dg/cpp26/decomp1.C
new file mode 100644
index 00000000000..b3c241f1d3a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/decomp1.C
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  template <int I> int& get() { return i; }
+};
+
+template<> struct std::tuple_size<A> { static const int value = 3; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+struct B {
+  int i, j;
+  long long k, l;
+} z[6];
+
+void
+foo (A &a, B &b)
+{
+  auto [ c [[]], d, e [[maybe_unused]] ] = a;          // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+                                                       // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+  auto [ f, h [[maybe_unused]] [[]], i [[]], j ] = b;  // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+                                                       // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+  for (auto [ k, l [[maybe_unused]], m, n [[]]] : z)   // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+    ;                                                  // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+  auto &[o[[]][[]][[]], p[[]], q[[]]] = a;             // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+    ;                                                  // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/decomp2.C 
b/gcc/testsuite/g++.dg/cpp26/decomp2.C
new file mode 100644
index 00000000000..582a0fb8a2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/decomp2.C
@@ -0,0 +1,46 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  template <int I> int& get() { return i; }
+};
+
+template<> struct std::tuple_size<A> { static const int value = 3; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+struct B {
+  int i, j;
+  long long k, l;
+} z[6];
+
+void
+foo (A &a, B &b)
+{
+  auto [ c [[]], d, e [[gnu::deprecated]] ] = a;       // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+                                                       // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+                                                       // { dg-message 
"declared here" "" { target *-*-* } .-2 }
+  ++c;
+  ++d;
+  ++e;                                                 // { dg-warning "'e' is 
deprecated" }
+  auto [ f, h [[gnu::deprecated]] [[]], i [[]], j ] = b;// { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+                                                       // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+                                                       // { dg-message 
"declared here" "" { target *-*-* } .-2 }
+  ++f;
+  ++h;                                                 // { dg-warning "'h' is 
deprecated" }
+  ++i;
+  ++j;
+  for (auto [ k, l [[gnu::deprecated]], m, n [[]]] : z)        // { dg-warning 
"structured bindings with attributed identifiers only available with" "" { 
target { c++17 && c++23_down } } }
+    {                                                  // { dg-warning 
"structured bindings only available with" "" { target c++14_down } .-1 }
+                                                       // { dg-message 
"declared here" "" { target *-*-* } .-2 }
+      ++k;
+      ++l;                                             // { dg-warning "'l' is 
deprecated" }
+      ++m;
+      ++n;
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 
b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
index d19fca49995..204f8bac47d 100644
--- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
+++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
@@ -394,8 +394,8 @@
 
 #ifndef __cpp_structured_bindings
 #  error "__cpp_structured_bindings"
-#elif __cpp_structured_bindings != 201606
-#  error "__cpp_structured_bindings != 201606"
+#elif __cpp_structured_bindings != 202403
+#  error "__cpp_structured_bindings != 202403"
 #endif
 
 #ifndef __cpp_template_template_args

Reply via email to