Re: [PATCH] c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456]
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]
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