aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-05-02 09:34:31 +0200
committerJakub Jelinek <jakub@redhat.com>2024-05-02 09:34:31 +0200
commit2f15787f2e1a3afe2c2ad93d4eb0d3c1f73c8fbd (patch)
tree10da576af5ac3754ece3147a1ddb8224c7f205ad /gcc/cp
parentc59708fba3f98a4cc257741b88216b6caf6b4a87 (diff)
downloadgcc-2f15787f2e1a3afe2c2ad93d4eb0d3c1f73c8fbd.zip
gcc-2f15787f2e1a3afe2c2ad93d4eb0d3c1f73c8fbd.tar.gz
gcc-2f15787f2e1a3afe2c2ad93d4eb0d3c1f73c8fbd.tar.bz2
c++: Implement C++26 P2573R2 - = delete("should have a reason"); [PR114458]
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. 2024-05-02 Jakub Jelinek <jakub@redhat.com> 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. * cp-tree.h (DECL_DELETED_FN): Document representation of = delete("reason") on a DECL. 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.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/decl.cc13
-rw-r--r--gcc/cp/decl2.cc23
-rw-r--r--gcc/cp/parser.cc21
4 files changed, 55 insertions, 7 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5d1bd6b..933504b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4477,7 +4477,10 @@ get_vec_init_expr (tree t)
&& DECL_DECLARED_CONSTEXPR_P (NODE) \
&& DECL_CLASS_SCOPE_P (NODE)))
-/* Nonzero if DECL was declared with '= delete'. */
+/* Nonzero if DECL was declared with '= delete'.
+ = delete("reason") is represented in addition to this flag by DECL_INITIAL
+ being STRING_CST with the reason and TREE_TYPE of the STRING_CST the
+ RID_DELETE IDENTIFIER_NODE. */
#define DECL_DELETED_FN(DECL) \
(LANG_DECL_FN_CHECK (DECL)->min.base.threadprivate_or_deleted_p)
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index de0c02a..378311c 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2420,6 +2420,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
"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);
}
}
@@ -8597,17 +8601,20 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
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;
}
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 1f84878..6913efa 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#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;
@@ -1038,7 +1039,10 @@ grokfield (const cp_declarator *declarator,
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;
@@ -1123,10 +1127,14 @@ grokfield (const cp_declarator *declarator,
{
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])
{
@@ -5912,7 +5920,16 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
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");
}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a2bc6f6..7c3cfcf 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -28634,6 +28634,27 @@ cp_parser_pure_specifier (cp_parser* parser)
|| 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,
+ "%<delete%> 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;
}