From patchwork Mon Apr 29 07:11:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1928846 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=LDXyJ2m+; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VSZK73jffz23hd for ; Mon, 29 Apr 2024 17:12:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B4D103858402 for ; Mon, 29 Apr 2024 07:12:25 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 13E873858D33 for ; Mon, 29 Apr 2024 07:12:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 13E873858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 13E873858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714374723; cv=none; b=XfRlxlQD+3IS8kSEk5gwCf0SqiS20bbiViHkdCFSONrxDNBvcdTgqb4ZurpKqrLW+HMQl3io3Qjbs4wb8UduMDviszRU2IQzTIncntJpTL9DthN9J+sq5Qvy17YCElO3PGAtapBqTtqPJgK+7HJYzdQwCe4mfNybn57F58hHV48= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714374723; c=relaxed/simple; bh=pLL4jL42pbanUNea/BJlnrU/8RXVa49Q9Z9nEeHFWZE=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=YfOssEvFcrcO1s3mWMOp+P5zly0Yjkid7oNyKPGMCT+hWm81b3Gi41xA96gcIQjy+AQchiB8Je13+XdFYQ6RXUxHx3Vf9Jw88yO/cAUnaxhZ9A6FiUr6lHZP3qYXyCbNC52f6jOsIc8afVLXvmheM+zqCrDuqFh3MyniaynjAyQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1714374720; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=VH+gMiV8QvMrP2R6UuGKwuZVxsa2m8ZZwrfvKXFR2/c=; b=LDXyJ2m+s/lqPmC61MeAastmqhBF67t7EnbdOvTapZgI+JsJosJ8e/pJOBw4xvwaAMNVE+ TTqYzk1roC6Jm87ZDQt7VdAkm5I21XazVABci8SYPYkULJ1vcrZVXmNGAQmW5Bk/ARHxEn 7thPMNhs9EJlo1ORLYTDaMf9gzEPmE0= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-564-5RrAtI13NxSvA5Nys5EYug-1; Mon, 29 Apr 2024 03:11:58 -0400 X-MC-Unique: 5RrAtI13NxSvA5Nys5EYug-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 917133C0F420 for ; Mon, 29 Apr 2024 07:11:58 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.5]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 53AA240BB4E; Mon, 29 Apr 2024 07:11:58 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 43T7Bu382872614 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 29 Apr 2024 09:11:57 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 43T7Bu312872613; Mon, 29 Apr 2024 09:11:56 +0200 Date: Mon, 29 Apr 2024 09:11:56 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Implement C++26 P0609R3 - Attributes for Structured Bindings [PR114456] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org 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. Jakub --- gcc/cp/parser.cc.jj 2024-04-26 11:42:24.653016208 +0200 +++ gcc/cp/parser.cc 2024-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, &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_ 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_ 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); --- gcc/c-family/c-cppbuiltin.cc.jj 2024-04-26 11:42:24.621016651 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2024-04-26 13:42:50.559184222 +0200 @@ -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) { --- gcc/testsuite/g++.dg/cpp26/decomp1.C.jj 2024-04-26 13:42:50.559184222 +0200 +++ gcc/testsuite/g++.dg/cpp26/decomp1.C 2024-04-26 14:24:59.276090634 +0200 @@ -0,0 +1,33 @@ +// { dg-do compile { target c++11 } } +// { dg-options "" } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + int i; + template int& get() { return i; } +}; + +template<> struct std::tuple_size { static const int value = 3; }; +template struct std::tuple_element { 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 } +} --- gcc/testsuite/g++.dg/cpp26/decomp2.C.jj 2024-04-26 14:21:31.454974172 +0200 +++ gcc/testsuite/g++.dg/cpp26/decomp2.C 2024-04-26 14:28:11.665421202 +0200 @@ -0,0 +1,46 @@ +// { dg-do compile { target c++11 } } +// { dg-options "" } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + int i; + template int& get() { return i; } +}; + +template<> struct std::tuple_size { static const int value = 3; }; +template struct std::tuple_element { 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; + } +} --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2024-04-26 11:42:24.675015903 +0200 +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-04-26 13:42:50.559184222 +0200 @@ -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