今天在項(xiàng)目中遇到了__has_feature(objc_arc)宏,通過查找文檔發(fā)現(xiàn)該宏語句是用來判斷clang(編譯前端)是否支持某個功能特性,這里是判斷是否支持objc_arc(自動引用計(jì)數(shù))内颗。
栗子:
#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
Clang文檔中的定義:
__has_feature
and __has_extension
These function-like macros take a single identifier argument that is the name of a feature. __has_feature
evaluates to 1 if the feature is both supported by Clang and standardized in the current language standard or 0 if not (but see below), while __has_extension
evaluates to 1 if the feature is supported by Clang in the current language (either as a language extension or a standard language feature) or 0 if not. They can be used like this:
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef __has_extension
#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
#endif
...
#if __has_feature(cxx_rvalue_references)
// This code will only be compiled with the -std=c++11 and -std=gnu++11
// options, because rvalue references are only standardized in C++11.
#endif
#if __has_extension(cxx_rvalue_references)
// This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
// and -std=gnu++98 options, because rvalue references are supported as a
// language extension in C++98.
#endif
For backward compatibility, __has_feature
can also be used to test for support for non-standardized features, i.e. features not prefixed c_
, cxx_
or objc_
.
Another use of __has_feature
is to check for compiler features not related to the language standard, such as e.g. AddressSanitizer.
If the -pedantic-errors
option is given, __has_extension
is equivalent to __has_feature
.
The feature tag is described along with the language feature below.
The feature name or extension name can also be specified with a preceding and following __
(double underscore) to avoid interference from a macro with the same name. For instance, __cxx_rvalue_references__
can be used instead of cxx_rvalue_references
.
clang API Documentation:
00855 /// HasFeature - Return true if we recognize and implement the feature
00856 /// specified by the identifier as a standard language feature.
00857 static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
00858 const LangOptions &LangOpts = PP.getLangOpts();
00859 StringRef Feature = II->getName();
00860
00861 // Normalize the feature name, __foo__ becomes foo.
00862 if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4)
00863 Feature = Feature.substr(2, Feature.size() - 4);
00864
00865 return llvm::StringSwitch<bool>(Feature)
00866 .Case("address_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Address))
00867 .Case("attribute_analyzer_noreturn", true)
00868 .Case("attribute_availability", true)
00869 .Case("attribute_availability_with_message", true)
00870 .Case("attribute_cf_returns_not_retained", true)
00871 .Case("attribute_cf_returns_retained", true)
00872 .Case("attribute_deprecated_with_message", true)
00873 .Case("attribute_ext_vector_type", true)
00874 .Case("attribute_ns_returns_not_retained", true)
00875 .Case("attribute_ns_returns_retained", true)
00876 .Case("attribute_ns_consumes_self", true)
00877 .Case("attribute_ns_consumed", true)
00878 .Case("attribute_cf_consumed", true)
00879 .Case("attribute_objc_ivar_unused", true)
00880 .Case("attribute_objc_method_family", true)
00881 .Case("attribute_overloadable", true)
00882 .Case("attribute_unavailable_with_message", true)
00883 .Case("attribute_unused_on_fields", true)
00884 .Case("blocks", LangOpts.Blocks)
00885 .Case("c_thread_safety_attributes", true)
00886 .Case("cxx_exceptions", LangOpts.CXXExceptions)
00887 .Case("cxx_rtti", LangOpts.RTTI)
00888 .Case("enumerator_attributes", true)
00889 .Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory))
00890 .Case("thread_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Thread))
00891 .Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow))
00892 // Objective-C features
00893 .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
00894 .Case("objc_arc", LangOpts.ObjCAutoRefCount)
00895 .Case("objc_arc_weak", LangOpts.ObjCARCWeak)
00896 .Case("objc_default_synthesize_properties", LangOpts.ObjC2)
00897 .Case("objc_fixed_enum", LangOpts.ObjC2)
00898 .Case("objc_instancetype", LangOpts.ObjC2)
00899 .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
00900 .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
00901 .Case("objc_property_explicit_atomic",
00902 true) // Does clang support explicit "atomic" keyword?
00903 .Case("objc_protocol_qualifier_mangling", true)
00904 .Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
00905 .Case("ownership_holds", true)
00906 .Case("ownership_returns", true)
00907 .Case("ownership_takes", true)
00908 .Case("objc_bool", true)
00909 .Case("objc_subscripting", LangOpts.ObjCRuntime.isNonFragile())
00910 .Case("objc_array_literals", LangOpts.ObjC2)
00911 .Case("objc_dictionary_literals", LangOpts.ObjC2)
00912 .Case("objc_boxed_expressions", LangOpts.ObjC2)
00913 .Case("arc_cf_code_audited", true)
00914 // C11 features
00915 .Case("c_alignas", LangOpts.C11)
00916 .Case("c_atomic", LangOpts.C11)
00917 .Case("c_generic_selections", LangOpts.C11)
00918 .Case("c_static_assert", LangOpts.C11)
00919 .Case("c_thread_local",
00920 LangOpts.C11 && PP.getTargetInfo().isTLSSupported())
00921 // C++11 features
00922 .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
00923 .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
00924 .Case("cxx_alignas", LangOpts.CPlusPlus11)
00925 .Case("cxx_atomic", LangOpts.CPlusPlus11)
00926 .Case("cxx_attributes", LangOpts.CPlusPlus11)
00927 .Case("cxx_auto_type", LangOpts.CPlusPlus11)
00928 .Case("cxx_constexpr", LangOpts.CPlusPlus11)
00929 .Case("cxx_decltype", LangOpts.CPlusPlus11)
00930 .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus11)
00931 .Case("cxx_default_function_template_args", LangOpts.CPlusPlus11)
00932 .Case("cxx_defaulted_functions", LangOpts.CPlusPlus11)
00933 .Case("cxx_delegating_constructors", LangOpts.CPlusPlus11)
00934 .Case("cxx_deleted_functions", LangOpts.CPlusPlus11)
00935 .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11)
00936 .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11)
00937 .Case("cxx_implicit_moves", LangOpts.CPlusPlus11)
00938 .Case("cxx_inheriting_constructors", LangOpts.CPlusPlus11)
00939 .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11)
00940 .Case("cxx_lambdas", LangOpts.CPlusPlus11)
00941 .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11)
00942 .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus11)
00943 .Case("cxx_noexcept", LangOpts.CPlusPlus11)
00944 .Case("cxx_nullptr", LangOpts.CPlusPlus11)
00945 .Case("cxx_override_control", LangOpts.CPlusPlus11)
00946 .Case("cxx_range_for", LangOpts.CPlusPlus11)
00947 .Case("cxx_raw_string_literals", LangOpts.CPlusPlus11)
00948 .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus11)
00949 .Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
00950 .Case("cxx_strong_enums", LangOpts.CPlusPlus11)
00951 .Case("cxx_static_assert", LangOpts.CPlusPlus11)
00952 .Case("cxx_thread_local",
00953 LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported())
00954 .Case("cxx_trailing_return", LangOpts.CPlusPlus11)
00955 .Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
00956 .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11)
00957 .Case("cxx_user_literals", LangOpts.CPlusPlus11)
00958 .Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
00959 // C++1y features
00960 .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus14)
00961 .Case("cxx_binary_literals", LangOpts.CPlusPlus14)
00962 .Case("cxx_contextual_conversions", LangOpts.CPlusPlus14)
00963 .Case("cxx_decltype_auto", LangOpts.CPlusPlus14)
00964 .Case("cxx_generic_lambdas", LangOpts.CPlusPlus14)
00965 .Case("cxx_init_captures", LangOpts.CPlusPlus14)
00966 .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus14)
00967 .Case("cxx_return_type_deduction", LangOpts.CPlusPlus14)
00968 .Case("cxx_variable_templates", LangOpts.CPlusPlus14)
00969 // C++ TSes
00970 //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
00971 //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
00972 // FIXME: Should this be __has_feature or __has_extension?
00973 //.Case("raw_invocation_type", LangOpts.CPlusPlus)
00974 // Type traits
00975 .Case("has_nothrow_assign", LangOpts.CPlusPlus)
00976 .Case("has_nothrow_copy", LangOpts.CPlusPlus)
00977 .Case("has_nothrow_constructor", LangOpts.CPlusPlus)
00978 .Case("has_trivial_assign", LangOpts.CPlusPlus)
00979 .Case("has_trivial_copy", LangOpts.CPlusPlus)
00980 .Case("has_trivial_constructor", LangOpts.CPlusPlus)
00981 .Case("has_trivial_destructor", LangOpts.CPlusPlus)
00982 .Case("has_virtual_destructor", LangOpts.CPlusPlus)
00983 .Case("is_abstract", LangOpts.CPlusPlus)
00984 .Case("is_base_of", LangOpts.CPlusPlus)
00985 .Case("is_class", LangOpts.CPlusPlus)
00986 .Case("is_constructible", LangOpts.CPlusPlus)
00987 .Case("is_convertible_to", LangOpts.CPlusPlus)
00988 .Case("is_empty", LangOpts.CPlusPlus)
00989 .Case("is_enum", LangOpts.CPlusPlus)
00990 .Case("is_final", LangOpts.CPlusPlus)
00991 .Case("is_literal", LangOpts.CPlusPlus)
00992 .Case("is_standard_layout", LangOpts.CPlusPlus)
00993 .Case("is_pod", LangOpts.CPlusPlus)
00994 .Case("is_polymorphic", LangOpts.CPlusPlus)
00995 .Case("is_sealed", LangOpts.MicrosoftExt)
00996 .Case("is_trivial", LangOpts.CPlusPlus)
00997 .Case("is_trivially_assignable", LangOpts.CPlusPlus)
00998 .Case("is_trivially_constructible", LangOpts.CPlusPlus)
00999 .Case("is_trivially_copyable", LangOpts.CPlusPlus)
01000 .Case("is_union", LangOpts.CPlusPlus)
01001 .Case("modules", LangOpts.Modules)
01002 .Case("tls", PP.getTargetInfo().isTLSSupported())
01003 .Case("underlying_type", LangOpts.CPlusPlus)
01004 .Default(false);
01005 }