Re: [PATCH] c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456]

2024-04-29 Thread Jason Merrill

On 4/29/24 00:11, Jakub Jelinek wrote:

Hi!

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.

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


OK.


2024-04-29  Jakub Jelinek  

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.

--- gcc/cp/parser.cc.jj 2024-04-26 11:42:24.653016208 +0200
+++ gcc/cp/parser.cc2024-04-26 13:59:17.791482874 +0200
@@ -16075,13 +16075,37 @@ cp_parser_decomposition_declaration (cp_
  
/* Parse the identifier-list.  */

auto_vec 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_
  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, _specs, SD_DECOMPOSITION,
-  NULL_TREE, NULL_TREE, _pushed_scope);
+  NULL_TREE, attr, _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_
  
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),
  );
@@ -16193,7 +16220,7 @@ cp_parser_decomposition_declaration (cp_
else if (decl != error_mark_node)
  {
*maybe_range_for_decl = prev;
-  cp_decomp decomp = { prev, v.length () };
+  cp_decomp decomp = { prev, cnt };
/* 

[PATCH] c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456]

2024-04-29 Thread Jakub Jelinek
Hi!

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.

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

2024-04-29  Jakub Jelinek  

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.

--- gcc/cp/parser.cc.jj 2024-04-26 11:42:24.653016208 +0200
+++ gcc/cp/parser.cc2024-04-26 13:59:17.791482874 +0200
@@ -16075,13 +16075,37 @@ cp_parser_decomposition_declaration (cp_
 
   /* Parse the identifier-list.  */
   auto_vec 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_
  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, _specs, SD_DECOMPOSITION,
-  NULL_TREE, NULL_TREE, _pushed_scope);
+  NULL_TREE, attr, _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_
 
   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),
  );
@@ -16193,7 +16220,7 @@ cp_parser_decomposition_declaration (cp_
   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