aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorAlex Coplan <alex.coplan@arm.com>2023-03-17 16:30:51 +0000
committerAlex Coplan <alex.coplan@arm.com>2023-11-27 10:42:55 +0000
commit06280a906cb3dc80cf5e07cf3335b758848d488d (patch)
tree292a91ef3a9c33fd3761b3cff321303b5d03d656 /gcc/cp
parentd9abaa8d58f5729925b1db735d4723a9ea825eaa (diff)
downloadgcc-06280a906cb3dc80cf5e07cf3335b758848d488d.zip
gcc-06280a906cb3dc80cf5e07cf3335b758848d488d.tar.gz
gcc-06280a906cb3dc80cf5e07cf3335b758848d488d.tar.bz2
c-family: Implement __has_feature and __has_extension [PR60512]
This patch implements clang's __has_feature and __has_extension in GCC. Currently the patch aims to implement all documented features (and some undocumented ones) following the documentation at https://clang.llvm.org/docs/LanguageExtensions.html with the exception of the legacy features for C++ type traits. These are omitted, since as the clang documentation notes, __has_builtin is the correct "modern" way to query for these (which GCC already implements). gcc/c-family/ChangeLog: PR c++/60512 * c-common.cc (struct hf_feature_info): New. (c_common_register_feature): New. (init_has_feature): New. (has_feature_p): New. * c-common.h (c_common_has_feature): New. (c_family_register_lang_features): New. (c_common_register_feature): New. (has_feature_p): New. * c-lex.cc (init_c_lex): Plumb through has_feature callback. (c_common_has_builtin): Generalize and move common part ... (c_common_lex_availability_macro): ... here. (c_common_has_feature): New. * c-ppoutput.cc (init_pp_output): Plumb through has_feature. gcc/c/ChangeLog: PR c++/60512 * c-lang.cc (c_family_register_lang_features): New. * c-objc-common.cc (struct c_feature_info): New. (c_register_features): New. * c-objc-common.h (c_register_features): New. gcc/cp/ChangeLog: PR c++/60512 * cp-lang.cc (c_family_register_lang_features): New. * cp-objcp-common.cc (struct cp_feature_selector): New. (cp_feature_selector::has_feature): New. (struct cp_feature_info): New. (cp_register_features): New. * cp-objcp-common.h (cp_register_features): New. gcc/ChangeLog: PR c++/60512 * doc/cpp.texi: Document __has_{feature,extension}. gcc/objc/ChangeLog: PR c++/60512 * objc-act.cc (struct objc_feature_info): New. (objc_nonfragile_abi_p): New. (objc_common_register_features): New. * objc-act.h (objc_common_register_features): New. * objc-lang.cc (c_family_register_lang_features): New. gcc/objcp/ChangeLog: PR c++/60512 * objcp-lang.cc (c_family_register_lang_features): New. libcpp/ChangeLog: PR c++/60512 * include/cpplib.h (struct cpp_callbacks): Add has_feature. (enum cpp_builtin_type): Add BT_HAS_{FEATURE,EXTENSION}. * init.cc: Add __has_{feature,extension}. * macro.cc (_cpp_builtin_macro_text): Handle BT_HAS_{FEATURE,EXTENSION}. gcc/testsuite/ChangeLog: PR c++/60512 * c-c++-common/has-feature-common.c: New test. * c-c++-common/has-feature-pedantic.c: New test. * g++.dg/ext/has-feature.C: New test. * gcc.dg/asan/has-feature-asan.c: New test. * gcc.dg/has-feature.c: New test. * gcc.dg/ubsan/has-feature-ubsan.c: New test. * obj-c++.dg/has-feature.mm: New test. * objc.dg/has-feature.m: New test. Co-Authored-By: Iain Sandoe <iain@sandoe.co.uk>
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/cp-lang.cc9
-rw-r--r--gcc/cp/cp-objcp-common.cc144
-rw-r--r--gcc/cp/cp-objcp-common.h1
3 files changed, 154 insertions, 0 deletions
diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc
index f2ed83d..bdc25dd 100644
--- a/gcc/cp/cp-lang.cc
+++ b/gcc/cp/cp-lang.cc
@@ -119,6 +119,15 @@ objcp_tsubst_expr (tree /*t*/, tree /*args*/, tsubst_flags_t /*complain*/,
return NULL_TREE;
}
+/* Implement c-family hook to add language-specific features
+ for __has_{feature,extension}. */
+
+void
+c_family_register_lang_features ()
+{
+ cp_register_features ();
+}
+
static const char *
cxx_dwarf_name (tree t, int verbosity)
{
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 2093ae0..70f9e4a 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -23,10 +23,154 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "cp-tree.h"
#include "cp-objcp-common.h"
+#include "c-family/c-common.h"
#include "dwarf2.h"
#include "stringpool.h"
#include "contracts.h"
+/* Class to determine whether a given C++ language feature is available.
+ Used to implement __has_{feature,extension}. */
+
+struct cp_feature_selector
+{
+ enum
+ {
+ DIALECT,
+ FLAG
+ } kind;
+
+ enum class result
+ {
+ NONE,
+ EXT,
+ FEAT
+ };
+
+ union
+ {
+ const int *enable_flag;
+ struct {
+ enum cxx_dialect feat;
+ enum cxx_dialect ext;
+ } dialect;
+ };
+
+ constexpr cp_feature_selector (const int *flag)
+ : kind (FLAG), enable_flag (flag) {}
+ constexpr cp_feature_selector (enum cxx_dialect feat,
+ enum cxx_dialect ext)
+ : kind (DIALECT), dialect{feat, ext} {}
+ constexpr cp_feature_selector (enum cxx_dialect feat)
+ : cp_feature_selector (feat, feat) {}
+
+ inline result has_feature () const;
+};
+
+/* Check whether this language feature is available as a feature,
+ extension, or not at all. */
+
+cp_feature_selector::result
+cp_feature_selector::has_feature () const
+{
+ switch (kind)
+ {
+ case DIALECT:
+ if (cxx_dialect >= dialect.feat)
+ return result::FEAT;
+ else if (cxx_dialect >= dialect.ext)
+ return result::EXT;
+ else
+ return result::NONE;
+ case FLAG:
+ return *enable_flag ? result::FEAT : result::NONE;
+ }
+
+ gcc_unreachable ();
+}
+
+/* Information about a C++ language feature which can be queried
+ through __has_{feature,extension}. IDENT is the name of the feature,
+ and SELECTOR encodes how to compute whether the feature is available. */
+
+struct cp_feature_info
+{
+ const char *ident;
+ cp_feature_selector selector;
+};
+
+/* Table of features for __has_{feature,extension}. */
+
+static constexpr cp_feature_info cp_feature_table[] =
+{
+ { "cxx_exceptions", &flag_exceptions },
+ { "cxx_rtti", &flag_rtti },
+ { "cxx_access_control_sfinae", { cxx11, cxx98 } },
+ { "cxx_alias_templates", cxx11 },
+ { "cxx_alignas", cxx11 },
+ { "cxx_alignof", cxx11 },
+ { "cxx_attributes", cxx11 },
+ { "cxx_constexpr", cxx11 },
+ { "cxx_constexpr_string_builtins", cxx11 },
+ { "cxx_decltype", cxx11 },
+ { "cxx_decltype_incomplete_return_types", cxx11 },
+ { "cxx_default_function_template_args", cxx11 },
+ { "cxx_defaulted_functions", cxx11 },
+ { "cxx_delegating_constructors", cxx11 },
+ { "cxx_deleted_functions", cxx11 },
+ { "cxx_explicit_conversions", cxx11 },
+ { "cxx_generalized_initializers", cxx11 },
+ { "cxx_implicit_moves", cxx11 },
+ { "cxx_inheriting_constructors", cxx11 },
+ { "cxx_inline_namespaces", { cxx11, cxx98 } },
+ { "cxx_lambdas", cxx11 },
+ { "cxx_local_type_template_args", cxx11 },
+ { "cxx_noexcept", cxx11 },
+ { "cxx_nonstatic_member_init", cxx11 },
+ { "cxx_nullptr", cxx11 },
+ { "cxx_override_control", cxx11 },
+ { "cxx_reference_qualified_functions", cxx11 },
+ { "cxx_range_for", cxx11 },
+ { "cxx_raw_string_literals", cxx11 },
+ { "cxx_rvalue_references", cxx11 },
+ { "cxx_static_assert", cxx11 },
+ { "cxx_thread_local", cxx11 },
+ { "cxx_auto_type", cxx11 },
+ { "cxx_strong_enums", cxx11 },
+ { "cxx_trailing_return", cxx11 },
+ { "cxx_unicode_literals", cxx11 },
+ { "cxx_unrestricted_unions", cxx11 },
+ { "cxx_user_literals", cxx11 },
+ { "cxx_variadic_templates", { cxx11, cxx98 } },
+ { "cxx_binary_literals", { cxx14, cxx98 } },
+ { "cxx_contextual_conversions", { cxx14, cxx98 } },
+ { "cxx_decltype_auto", cxx14 },
+ { "cxx_aggregate_nsdmi", cxx14 },
+ { "cxx_init_captures", cxx14 },
+ { "cxx_generic_lambdas", cxx14 },
+ { "cxx_relaxed_constexpr", cxx14 },
+ { "cxx_return_type_deduction", cxx14 },
+ { "cxx_variable_templates", cxx14 },
+ { "modules", &flag_modules },
+};
+
+/* Register C++ language features for __has_{feature,extension}. */
+
+void
+cp_register_features ()
+{
+ using result = cp_feature_selector::result;
+
+ for (unsigned i = 0; i < ARRAY_SIZE (cp_feature_table); i++)
+ {
+ const cp_feature_info *info = cp_feature_table + i;
+ const auto res = info->selector.has_feature ();
+ if (res == result::NONE)
+ continue;
+
+ c_common_register_feature (info->ident, res == result::FEAT);
+ }
+}
+
/* Special routine to get the alias set for C++. */
alias_set_type
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 1408301..5b175b0 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -34,6 +34,7 @@ extern tree cp_classtype_as_base (const_tree);
extern tree cp_get_global_decls ();
extern tree cp_pushdecl (tree);
extern void cp_register_dumps (gcc::dump_manager *);
+extern void cp_register_features ();
extern bool cp_handle_option (size_t, const char *, HOST_WIDE_INT, int,
location_t, const struct cl_option_handlers *);
extern tree cxx_make_type_hook (tree_code);