diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-11-11 19:54:32 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2024-11-11 20:04:33 +0100 |
commit | 417b4cc9bf218083838aeab458bbb7510e36375a (patch) | |
tree | 0250e834233b8fdbf772d8cce01a1ff1ff32e24c /gcc/cp | |
parent | dfc9062eca47c237953c88a5614ae792792d058d (diff) | |
download | gcc-417b4cc9bf218083838aeab458bbb7510e36375a.zip gcc-417b4cc9bf218083838aeab458bbb7510e36375a.tar.gz gcc-417b4cc9bf218083838aeab458bbb7510e36375a.tar.bz2 |
c++: Add __builtin_operator_{new,delete} support
clang++ adds __builtin_operator_{new,delete} builtins which as documented
work similarly to ::operator {new,delete}, except that it is an error
if the called ::operator {new,delete} is not a replaceable global operator
and allow optimizations which C++ normally allows just when those are used
from new/delete expressions https://eel.is/c++draft/expr.new#14
When using these builtins, the same optimizations can be done even when
using those builtins.
For GCC we note that in the CALL_FROM_NEW_OR_DELETE_P flag on CALL_EXPRs.
The following patch implements it as a C++ FE keyword (because passing
references through ... changes the argument and so BUILT_IN_FRONTEND
builtin can't be used), just attempts to call the ::operator {new,delete}
and if it isn't replaceable, diagnoses it.
libstdc++ already uses the builtin in some cases.
2024-11-11 Jakub Jelinek <jakub@redhat.com>
gcc/c-family/
* c-common.h (enum rid): Add RID_BUILTIN_OPERATOR_NEW
and RID_BUILTIN_OPERATOR_DELETE.
(names_builtin_p): Change return type from bool to int.
* c-common.cc (c_common_reswords): Add __builtin_operator_new
and __builtin_operator_delete.
gcc/c/
* c-decl.cc (names_builtin_p): Change return type from
bool to int, adjust return statments.
gcc/cp/
* parser.cc (cp_parser_postfix_expression): Handle
RID_BUILTIN_OPERATOR_NEW and RID_BUILTIN_OPERATOR_DELETE.
* cp-objcp-common.cc (names_builtin_p): Change return type from
bool to int, adjust return statments. Handle
RID_BUILTIN_OPERATOR_NEW and RID_BUILTIN_OPERATOR_DELETE.
* pt.cc (tsubst_expr) <case CALL_EXPR>: Handle
CALL_FROM_NEW_OR_DELETE_P.
gcc/
* doc/extend.texi (New/Delete Builtins): Document
__builtin_operator_new and __builtin_operator_delete.
gcc/testsuite/
* g++.dg/ext/builtin-operator-new-1.C: New test.
* g++.dg/ext/builtin-operator-new-2.C: New test.
* g++.dg/ext/builtin-operator-new-3.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/cp-objcp-common.cc | 21 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 35 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 24 |
3 files changed, 71 insertions, 9 deletions
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 1e43db3..921931b 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -545,10 +545,10 @@ identifier_global_tag (tree name) return ret; } -/* Returns true if NAME refers to a built-in function or function-like - operator. */ +/* Returns non-zero (result of __has_builtin) if NAME refers to a built-in + function or function-like operator. */ -bool +int names_builtin_p (const char *name) { tree id = get_identifier (name); @@ -556,23 +556,23 @@ names_builtin_p (const char *name) { if (TREE_CODE (binding) == FUNCTION_DECL && DECL_IS_UNDECLARED_BUILTIN (binding)) - return true; + return 1; /* Handle the case when an overload for a built-in name exists. */ if (TREE_CODE (binding) != OVERLOAD) - return false; + return 0; for (ovl_iterator it (binding); it; ++it) { tree decl = *it; if (DECL_IS_UNDECLARED_BUILTIN (decl)) - return true; + return 1; } } /* Check for built-in traits. */ if (IDENTIFIER_TRAIT_P (id)) - return true; + return 1; /* Also detect common reserved C++ words that aren't strictly built-in functions. */ @@ -587,12 +587,15 @@ names_builtin_p (const char *name) case RID_BUILTIN_ASSOC_BARRIER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: - return true; + return 1; + case RID_BUILTIN_OPERATOR_NEW: + case RID_BUILTIN_OPERATOR_DELETE: + return 201802L; default: break; } - return false; + return 0; } /* Register c++-specific dumps. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index c1375ec..07b1222 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -7733,6 +7733,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: case RID_BUILTIN_ASSOC_BARRIER: + case RID_BUILTIN_OPERATOR_NEW: + case RID_BUILTIN_OPERATOR_DELETE: { vec<tree, va_gc> *vec; @@ -7819,6 +7821,39 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_OPERATOR_NEW: + case RID_BUILTIN_OPERATOR_DELETE: + tree fn; + fn = ovl_op_identifier (keyword == RID_BUILTIN_OPERATOR_NEW + ? NEW_EXPR : DELETE_EXPR); + fn = lookup_qualified_name (global_namespace, fn); + postfix_expression = finish_call_expr (fn, &vec, true, false, + tf_warning_or_error); + if (postfix_expression != error_mark_node) + { + tree call = extract_call_expr (postfix_expression); + fn = cp_get_callee_fndecl_nofold (call); + if (fn ? !DECL_IS_REPLACEABLE_OPERATOR (fn) + : !processing_template_decl) + { + auto_diagnostic_group d; + if (keyword == RID_BUILTIN_OPERATOR_NEW) + error_at (loc, "call to %<__builtin_operator_new%> " + "does not select replaceable global " + "allocation function"); + else + error_at (loc, "call to %<__builtin_operator_delete%> " + "does not select replaceable global " + "deallocation function"); + if (fn) + inform (DECL_SOURCE_LOCATION (fn), + "selected function declared here"); + } + else if (call && TREE_CODE (call) == CALL_EXPR) + CALL_FROM_NEW_OR_DELETE_P (call) = 1; + } + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f4213f8..35ec7eb 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21242,6 +21242,30 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) else if (TREE_CODE (call) == AGGR_INIT_EXPR) AGGR_INIT_EXPR_MUST_TAIL (call) = mtc; } + if (CALL_FROM_NEW_OR_DELETE_P (t)) + { + tree call = extract_call_expr (ret); + tree fn = cp_get_callee_fndecl_nofold (call); + if (fn ? !DECL_IS_REPLACEABLE_OPERATOR (fn) + : !processing_template_decl) + { + auto_diagnostic_group d; + location_t loc = cp_expr_loc_or_input_loc (t); + if (!fn || IDENTIFIER_NEW_OP_P (DECL_NAME (fn))) + error_at (loc, "call to %<__builtin_operator_new%> " + "does not select replaceable global " + "allocation function"); + else + error_at (loc, "call to %<__builtin_operator_delete%> " + "does not select replaceable global " + "deallocation function"); + if (fn) + inform (DECL_SOURCE_LOCATION (fn), + "selected function declared here"); + } + else if (call && TREE_CODE (call) == CALL_EXPR) + CALL_FROM_NEW_OR_DELETE_P (call) = 1; + } if (warning_suppressed_p (t, OPT_Wpessimizing_move)) /* This also suppresses -Wredundant-move. */ suppress_warning (ret, OPT_Wpessimizing_move); |