From patchwork Wed May 1 06:33:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1930063 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=H/tpaE4m; 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 4VTnNH0hKgz1ymc for ; Wed, 1 May 2024 16:34:21 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 131F63858428 for ; Wed, 1 May 2024 06:34:19 +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.129.124]) by sourceware.org (Postfix) with ESMTPS id 23C7B3858D34 for ; Wed, 1 May 2024 06:33:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 23C7B3858D34 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 23C7B3858D34 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714545239; cv=none; b=DtAt0tcY/F2aK4+Ep8+s/hmH8AiRowf/UIOmrDfr8FfzVDBRH/lcEr+FpDOX64WCAO5VASOEpjEox4eukCyABcXlUSDiHU9tXcFP6VFD3791rWIkA176BR6ZwoGHbRe+5D9satuwn8rayRZb3P/8U1r7efqXvDz1/fncmJpK9jU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714545239; c=relaxed/simple; bh=UqPNbqnqKEWqz9x0m6LEkGvtVp5RDxI1pRDzgm1ZpSI=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=L1RxTiZ+Naebsm+OTe/9QshJU8mXKPzilgida8qNVXLt+L6DKWBTWouS0nhwb6sj/tn+8HBLB1EPVhsTLj/YMj3qsBAgG0Jql7cikR2OZGzbC3ooxA3z5hdXzXY1CUjlCdKUBBCTVqrmFTjHdea02A1UK5hLS37Y3xHrszPK7Z4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1714545236; 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=x/gmC2TghkIdBRDloC7YJknMtRLm++LU8f5SiYDbsog=; b=H/tpaE4mrfYkSmERsia9QtzIroZAEG/rKJLZX4unC3AcEvw/a0rw5OuEdnWwJyG6m5iUYB xbHSVA5Huwr87LQ88hnJ0iy7X5tKdo9PNgh4WheGNSyzO0qIhN/NFr6puEobPYToytY2RI GnDAiug7yuDuChVF16HAIXFxsAI4Ipg= 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-671-Iq8faHjNO72EwjZIQM_U6g-1; Wed, 01 May 2024 02:33:55 -0400 X-MC-Unique: Iq8faHjNO72EwjZIQM_U6g-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (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 07C9B3C025D7 for ; Wed, 1 May 2024 06:33:55 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.5]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8C22751BF; Wed, 1 May 2024 06:33:54 +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 4416XqdQ1723521 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 1 May 2024 08:33:52 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 4416XqeU1723520; Wed, 1 May 2024 08:33:52 +0200 Date: Wed, 1 May 2024 08:33:52 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Implement C++26 P2573R2 - = delete("should have a reason"); [PR114458] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.5 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 C++26 P2573R2 = delete("should have a reason"); paper. I've tried to avoid increasing compile time memory for it when it isn't used (e.g. by adding a new lang_decl tree member), so the reason is represented as STRING_CST in DECL_INITIAL (which normally is for DECL_DELETED_FN error_mark_node) and to differentiate this delete("reason") initializer from some bogus attempt to initialize a function with "reason" using the RID_DELETE identifier as TREE_TYPE of the STRING_CST, as nothing needs to care about the type of the reason. If preferred it could be say TREE_LIST with the reason STRING_CST and RID_DELETE identifier or something similar instead, but that would need more compile time memory when it is used. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-05-01 Jakub Jelinek PR c++/114458 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Predefine __cpp_deleted_function=202403L for C++26. gcc/cp/ChangeLog * parser.cc (cp_parser_pure_specifier): Implement C++26 P2573R2 - = delete("should have a reason");. Parse deleted-function-body. * decl.cc (duplicate_decls): Copy DECL_INITIAL from DECL_DELETED_FN olddecl to newdecl if it is a STRING_CST. (cp_finish_decl): Handle deleted init with a reason. * decl2.cc: Include "escaped_string.h". (grokfield): Handle deleted init with a reason. (mark_used): Emit DECL_DELETED_FN reason in the message if any. gcc/testsuite/ * g++.dg/cpp26/feat-cxx26.C (__cpp_deleted_function): Add test. * g++.dg/cpp26/delete-reason1.C: New test. * g++.dg/cpp26/delete-reason2.C: New test. * g++.dg/parse/error65.C (f1): Adjust expected diagnostics. Jakub --- gcc/c-family/c-cppbuiltin.cc.jj 2024-04-30 08:57:07.359039013 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2024-04-30 19:16:45.069542205 +0200 @@ -1092,6 +1092,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_static_assert=202306L"); cpp_define (pfile, "__cpp_placeholder_variables=202306L"); cpp_define (pfile, "__cpp_structured_bindings=202403L"); + cpp_define (pfile, "__cpp_deleted_function=202403L"); } if (flag_concepts) { --- gcc/cp/parser.cc.jj 2024-04-30 08:57:07.349039147 +0200 +++ gcc/cp/parser.cc 2024-04-30 16:47:01.427952875 +0200 @@ -28573,6 +28573,27 @@ cp_parser_pure_specifier (cp_parser* par || token->keyword == RID_DELETE) { maybe_warn_cpp0x (CPP0X_DEFAULTED_DELETED); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + if (cxx_dialect >= cxx11 && cxx_dialect < cxx26) + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__26_extensions, + "% reason only available with " + "%<-std=c++2c%> or %<-std=gnu++2c%>"); + + /* Consume the `('. */ + matching_parens parens; + parens.consume_open (parser); + tree reason = cp_parser_unevaluated_string_literal (parser); + /* Consume the `)'. */ + parens.require_close (parser); + if (TREE_CODE (reason) == STRING_CST) + { + TREE_TYPE (reason) = token->u.value; + return reason; + } + } + return token->u.value; } --- gcc/cp/decl.cc.jj 2024-04-30 08:55:26.172389593 +0200 +++ gcc/cp/decl.cc 2024-04-30 19:01:32.316543498 +0200 @@ -2410,6 +2410,10 @@ duplicate_decls (tree newdecl, tree oldd "previous declaration of %qD", olddecl); } DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (olddecl); + if (DECL_DELETED_FN (olddecl) + && DECL_INITIAL (olddecl) + && TREE_CODE (DECL_INITIAL (olddecl)) == STRING_CST) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); } } @@ -8587,17 +8591,20 @@ cp_finish_decl (tree decl, tree init, bo if (init && TREE_CODE (decl) == FUNCTION_DECL) { tree clone; - if (init == ridpointers[(int)RID_DELETE]) + if (init == ridpointers[(int)RID_DELETE] + || (TREE_CODE (init) == STRING_CST + && TREE_TYPE (init) == ridpointers[(int)RID_DELETE])) { /* FIXME check this is 1st decl. */ DECL_DELETED_FN (decl) = 1; DECL_DECLARED_INLINE_P (decl) = 1; - DECL_INITIAL (decl) = error_mark_node; + DECL_INITIAL (decl) + = TREE_CODE (init) == STRING_CST ? init : error_mark_node; FOR_EACH_CLONE (clone, decl) { DECL_DELETED_FN (clone) = 1; DECL_DECLARED_INLINE_P (clone) = 1; - DECL_INITIAL (clone) = error_mark_node; + DECL_INITIAL (clone) = DECL_INITIAL (decl); } init = NULL_TREE; } --- gcc/cp/decl2.cc.jj 2024-04-25 20:33:30.770858926 +0200 +++ gcc/cp/decl2.cc 2024-04-30 18:49:37.555956481 +0200 @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. #include "asan.h" #include "optabs-query.h" #include "omp-general.h" +#include "escaped_string.h" /* Id for dumping the raw trees. */ int raw_dump_id; @@ -1042,7 +1043,10 @@ grokfield (const cp_declarator *declarat init = NULL_TREE; int initialized; - if (init == ridpointers[(int)RID_DELETE]) + if (init == ridpointers[(int)RID_DELETE] + || (init + && TREE_CODE (init) == STRING_CST + && TREE_TYPE (init) == ridpointers[(int)RID_DELETE])) initialized = SD_DELETED; else if (init == ridpointers[(int)RID_DEFAULT]) initialized = SD_DEFAULTED; @@ -1127,10 +1131,14 @@ grokfield (const cp_declarator *declarat { if (TREE_CODE (value) == FUNCTION_DECL) { - if (init == ridpointers[(int)RID_DELETE]) + if (init == ridpointers[(int)RID_DELETE] + || (TREE_CODE (init) == STRING_CST + && TREE_TYPE (init) == ridpointers[(int)RID_DELETE])) { DECL_DELETED_FN (value) = 1; DECL_DECLARED_INLINE_P (value) = 1; + if (TREE_CODE (init) == STRING_CST) + DECL_INITIAL (value) = init; } else if (init == ridpointers[(int)RID_DEFAULT]) { @@ -5884,7 +5892,16 @@ mark_used (tree decl, tsubst_flags_t com sorry ("converting lambda that uses %<...%> to function pointer"); else if (complain & tf_error) { - error ("use of deleted function %qD", decl); + if (DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST) + { + escaped_string msg; + msg.escape (TREE_STRING_POINTER (DECL_INITIAL (decl))); + error ("use of deleted function %qD: %s", + decl, (const char *) msg); + } + else + error ("use of deleted function %qD", decl); if (!maybe_explain_implicit_delete (decl)) inform (DECL_SOURCE_LOCATION (decl), "declared here"); } --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2024-04-30 08:57:07.401038450 +0200 +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-04-30 19:17:46.105740201 +0200 @@ -609,3 +609,9 @@ #elif __cpp_placeholder_variables != 202306 # error "__cpp_placeholder_variables != 202306" #endif + +#ifndef __cpp_deleted_function +# error "__cpp_deleted_function" +#elif __cpp_deleted_function != 202403 +# error "__cpp_deleted_function != 202403" +#endif --- gcc/testsuite/g++.dg/cpp26/delete-reason1.C.jj 2024-04-30 19:18:05.223488994 +0200 +++ gcc/testsuite/g++.dg/cpp26/delete-reason1.C 2024-04-30 19:33:30.813363904 +0200 @@ -0,0 +1,41 @@ +// P2573R2 = delete("should have a reason"); +// { dg-do compile { target c++11 } } +// { dg-options "" } + +void foo () = delete ("reason"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-message "declared here" "" { target *-*-* } .-1 } +struct S { + void bar () = delete ("another reason"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } +}; // { dg-message "declared here" "" { target *-*-* } .-1 } +int baz (int) = delete ("yet another reason"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } +int baz (int); // { dg-message "declared here" } +template +void qux (T) = delete ("some other reason"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-message "declared here" "" { target *-*-* } .-1 } +template +struct U { + U () = delete ("my reasons"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + U (int); // { dg-message "declared here" "" { target *-*-* } .-1 } + ~U () = delete ("your reasons"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } +}; // { dg-message "declared here" "" { target *-*-* } .-1 } +template <> +void qux (long long) = delete; // { dg-message "declared here" } +template +void corge (T) = delete; // { dg-message "declared here" } +template <> +void corge (double) = delete ("their reasons"); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-message "declared here" "" { target *-*-* } .-1 } + +void +test (U &x) +{ + foo (); // { dg-error "use of deleted function 'void foo\\\(\\\)': reason" } + S{}.bar (); // { dg-error "use of deleted function 'void S::bar\\\(\\\)': another reason" } + baz (0); // { dg-error "use of deleted function 'int baz\\\(int\\\)': yet another reason" } + qux (0L); // { dg-error "use of deleted function 'void qux\\\(T\\\) \\\[with T = long int\\\]': some other reason" } + qux (0LL); // { dg-error "use of deleted function 'void qux\\\(T\\\) \\\[with T = long long int\\\]'" } + U u; // { dg-error "use of deleted function 'U::U\\\(\\\) \\\[with T = long int\\\]': my reasons" } + // { dg-error "use of deleted function 'U::~U\\\(\\\) \\\[with T = long int\\\]': your reasons" "" { target *-*-* } .-1 } + corge (0); // { dg-error "use of deleted function 'void corge\\\(T\\\) \\\[with T = int\\\]'" } + corge (0.0); // { dg-error "use of deleted function 'void corge\\\(T\\\) \\\[with T = double\\\]': their reasons" } +} --- gcc/testsuite/g++.dg/cpp26/delete-reason2.C.jj 2024-04-30 19:34:02.853944821 +0200 +++ gcc/testsuite/g++.dg/cpp26/delete-reason2.C 2024-04-30 19:40:31.070867037 +0200 @@ -0,0 +1,20 @@ +// P2573R2 = delete("should have a reason"); +// { dg-do compile { target c++11 } } +// { dg-options "" } + +void foo () = delete (; // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "expected string-literal before ';' token" "" { target *-*-* } .-1 } + // { dg-error "expected '\\\)' before ';' token" "" { target *-*-* } .-2 } +void bar () = delete (); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "expected string-literal before '\\\)' token" "" { target *-*-* } .-1 } +void baz () = delete (0); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "expected string-literal before numeric constant" "" { target *-*-* } .-1 } + // { dg-error "expected '\\\)' before numeric constant" "" { target *-*-* } .-2 } + // { dg-error "expected ',' or ';' before numeric constant" "" { target *-*-* } .-3 } +void qux () = delete (L""); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "a wide string is invalid in this context before '\\\)' token" "" { target *-*-* } .-1 } +void corge () = delete (u8""); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "a wide string is invalid in this context before '\\\)' token" "" { target *-*-* } .-1 } +void garply () = delete ("something" + 0); // { dg-warning "'delete' reason only available with" "" { target c++23_down } } + // { dg-error "expected '\\\)' before '\\\+' token" "" { target *-*-* } .-1 } + // { dg-error "expected ',' or ';' before '\\\+' token" "" { target *-*-* } .-2 } --- gcc/testsuite/g++.dg/parse/error65.C.jj 2023-10-18 12:37:14.462340550 +0200 +++ gcc/testsuite/g++.dg/parse/error65.C 2024-05-01 08:25:10.215013182 +0200 @@ -1,8 +1,7 @@ // PR c++/111840 // { dg-do compile { target c++11 } } -// NB: =delete("reason") may be allowed via P2573. -int f1() = delete("should have a reason"); // { dg-error "expected" } +int f1() = delete("should have a reason"); // { dg-error "'delete' reason only available with" "" { target c++23_down } } int f2() = delete[""]; // { dg-error "expected" } int f3() = delete{""}; // { dg-error "expected" } int f4() = delete""; // { dg-error "expected" }