From c1b5fa41f09512c74030b9a2a0d1564535e22a76 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne
-
+
+
This function-like macro takes a single identifier argument that is the name -of a feature. It evaluates to 1 if the feature is supported or 0 if not. It -can be used like this:
+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(attribute_overloadable) || \ - __has_feature(blocks) -... +#if __has_feature(cxx_rvalue_references) +// This code will only be compiled with the -std=c++0x and -std=gnu++0x +// options, because rvalue references are only standardized in C++0x. +#endif + +#if __has_extension(cxx_rvalue_references) +// This code will be compiled with the -std=c++0x, -std=gnu++0x, -std=c++98 +// and -std=gnu++98 options, because rvalue references are supported as a +// language extension in C++98. #endif -...
For backwards compatibility reasons,
+__has_feature
can also be used to test for support for
+non-standardized features, i.e. features not prefixed c_
,
+cxx_
or objc_
.
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.
@@ -295,7 +322,7 @@ float4 foo(float2 a, float2 b) { -Query for this feature with __has_feature(attribute_ext_vector_type).
+Query for this feature with __has_extension(attribute_ext_vector_type).
See also __builtin_shufflevector.
@@ -320,8 +347,8 @@ will be incorporated into the appropriate diagnostic:Query for this feature -with __has_feature(attribute_deprecated_with_message) -and __has_feature(attribute_unavailable_with_message).
+with __has_extension(attribute_deprecated_with_message) +and __has_extension(attribute_unavailable_with_message).Attributes on the enum declaration do not apply to individual enumerators.
-Query for this feature with __has_feature(enumerator_attributes).
+Query for this feature with __has_extension(enumerator_attributes).
The __has_feature macro can be used to query if certain upcoming -standard language features are enabled. Those features are listed here.
+The __has_feature or __has_extension macros can be used +to query if certain upcoming standard language features are enabled. Those +features are listed here. Features that are not yet implemented will be +noted.
+ +Currently, all features listed here are slated for inclusion in the upcoming -C++0x standard. As a result, all the features that clang supports are enabled -with the -std=c++0x option when compiling C++ code. Features that are -not yet implemented will be noted.
+The features listed below are slated for inclusion in the upcoming +C++0x standard. As a result, all these features are enabled +with the -std=c++0x option when compiling C++ code.
-Use __has_feature(cxx_decltype) to determine if support for the +
Use __has_feature(cxx_decltype) or +__has_extension(cxx_decltype) to determine if support for the decltype() specifier is enabled.
-Use __has_feature(cxx_access_control_sfinae) to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per C++ DR1170.
+Use __has_feature(cxx_access_control_sfinae) or __has_extension(cxx_access_control_sfinae) to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per C++ DR1170.
-Use __has_feature(cxx_alias_templates) to determine if support for +
Use __has_feature(cxx_alias_templates) or +__has_extension(cxx_alias_templates) to determine if support for C++0x's alias declarations and alias templates is enabled.
-Use __has_feature(cxx_attributes) to determine if support for -attribute parsing with C++0x's square bracket notation is enabled.
+Use __has_feature(cxx_attributes) or +__has_extension(cxx_attributes) to determine if support for attribute +parsing with C++0x's square bracket notation is enabled.
-Use __has_feature(cxx_default_function_template_args) to determine if support for default template arguments in function templates is enabled.
+Use __has_feature(cxx_default_function_template_args) or +__has_extension(cxx_default_function_template_args) to determine +if support for default template arguments in function templates is enabled.
-Use __has_feature(cxx_deleted_functions) to determine if support for +
Use __has_feature(cxx_deleted_functions) or +__has_extension(cxx_deleted_functions) to determine if support for deleted function definitions (with = delete) is enabled.
-Use __has_feature(cxx_lambdas) to determine if support for -lambdas is enabled. clang does not currently implement this feature.
+Use __has_feature(cxx_lambdas) or +__has_extension(cxx_lambdas) to determine if support for lambdas +is enabled. clang does not currently implement this feature.
-Use __has_feature(cxx_nullptr) to determine if support for +
Use __has_feature(cxx_nullptr) or +__has_extension(cxx_nullptr) to determine if support for nullptr is enabled. clang does not yet fully implement this feature.
-Use __has_feature(cxx_override_control) to determine if support for +
Use __has_feature(cxx_override_control) or +__has_extension(cxx_override_control) to determine if support for the override control keywords is enabled.
-Use __has_feature(cxx_reference_qualified_functions) to determine if support for reference-qualified functions (e.g., member functions with &
or &&
applied to *this
) is enabled.
Use __has_feature(cxx_reference_qualified_functions) or
+__has_extension(cxx_reference_qualified_functions) to determine
+if support for reference-qualified functions (e.g., member functions with
+&
or &&
applied to *this
)
+is enabled.
Use __has_feature(cxx_range_for) to determine if support for -the range-based for loop is enabled.
+Use __has_feature(cxx_range_for) or +__has_extension(cxx_range_for) to determine if support for the +range-based for loop is enabled.
-Use __has_feature(cxx_rvalue_references) to determine if support for +
Use __has_feature(cxx_rvalue_references) or +__has_extension(cxx_rvalue_references) to determine if support for rvalue references is enabled.
-Use __has_feature(cxx_static_assert) to determine if support for +
Use __has_feature(cxx_static_assert) or +__has_extension(cxx_static_assert) to determine if support for compile-time assertions using static_assert is enabled.
-Use __has_feature(cxx_auto_type) to determine C++0x type inference -is supported using the auto specifier. If this is disabled, -auto will instead be a storage class specifier, as in C or C++98.
+Use __has_feature(cxx_auto_type) or +__has_extension(cxx_auto_type) to determine C++0x type inference is +supported using the auto specifier. If this is disabled, auto +will instead be a storage class specifier, as in C or C++98.
-Use __has_feature(cxx_variadic_templates) to determine if support +
Use __has_feature(cxx_variadic_templates) or +__has_extension(cxx_variadic_templates) to determine if support for variadic templates is enabled.
-Use __has_feature(cxx_inline_namespaces) to determine if support for +
Use __has_feature(cxx_inline_namespaces) or +__has_extension(cxx_inline_namespaces) to determine if support for inline namespaces is enabled.
-Use __has_feature(cxx_trailing_return) to determine if support for -the alternate function declaration syntax with trailing return type is enabled.
+Use __has_feature(cxx_trailing_return) or +__has_extension(cxx_trailing_return) to determine if support for the +alternate function declaration syntax with trailing return type is enabled.
-Use __has_feature(cxx_noexcept) to determine if support for -noexcept exception specifications is enabled.
+Use __has_feature(cxx_noexcept) or +__has_extension(cxx_noexcept) to determine if support for noexcept +exception specifications is enabled.
-Use __has_feature(cxx_strong_enums) to determine if support for +
Use __has_feature(cxx_strong_enums) or +__has_extension(cxx_strong_enums) to determine if support for strongly typed, scoped enumerations is enabled.
+The features listed below are slated for inclusion in the upcoming +C1X standard. As a result, all these features are enabled +with the -std=c1x option when compiling C code.
+ +Use __has_feature(c_generic_selections) or +__has_extension(c_generic_selections) to determine if support for +generic selections is enabled.
+ +As an extension, the C1X generic selection expression is available in all +languages supported by Clang. The syntax is the same as that given in the +C1X draft standard.
+ +In C, type compatibility is decided according to the rules given in the +appropriate standard, but in C++, which lacks the type compatibility rules +used in C, types are considered compatible only if they are equivalent.
+ +Use __has_feature(c_static_assert) or +__has_extension(c_static_assert) to determine if support for +compile-time assertions using _Static_assert is enabled.
+Clang supports the GNU C++ type traits and a subset of the Microsoft Visual C++ Type traits. For each supported type trait __X
, __has_feature(X)
indicates the presence of the type trait. For example:
+
Clang supports the GNU C++ type traits and a subset of the Microsoft Visual C++ Type traits. For each supported type trait __X
, __has_extension(X)
indicates the presence of the type trait. For example:
-#if __has_feature(is_convertible_to) +#if __has_extension(is_convertible_to) template<typename From, typename To> struct is_convertible_to { static const bool value = __is_convertible_to(From, To); @@ -518,7 +596,7 @@ details for the clang implementation are in Block-ABI-Apple.txt. -Query for this feature with __has_feature(blocks).
+Query for this feature with __has_extension(blocks).
Function Overloading in C
@@ -618,22 +696,8 @@ caveats to this use of name mangling: C. -Query for this feature with __has_feature(attribute_overloadable).
- - - -Generic Selections
- - -The C1X generic selection expression is available in all languages -supported by Clang. The syntax is the same as that given in the C1X draft -standard.
- -In C, type compatibility is decided according to the rules given in the -appropriate standard, but in C++, which lacks the type compatibility rules -used in C, types are considered compatible only if they are equivalent.
+Query for this feature with __has_extension(attribute_overloadable).
-Query for this feature with __has_feature(generic_selections).
Builtin Functions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index fc76f1cebf..22d2569e30 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -401,6 +401,7 @@ public: void setExtensionHandlingBehavior(ExtensionHandling H) { ExtBehavior = H; } + ExtensionHandling getExtensionHandlingBehavior() const { return ExtBehavior; } /// AllExtensionsSilenced - This is a counter bumped when an __extension__ /// block is encountered. When non-zero, all extension diagnostics are diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 817fab57d3..76e3f59ef4 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -84,6 +84,7 @@ class Preprocessor : public llvm::RefCountedBase{ IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ IdentifierInfo *Ident__has_feature; // __has_feature + IdentifierInfo *Ident__has_extension; // __has_extension IdentifierInfo *Ident__has_builtin; // __has_builtin IdentifierInfo *Ident__has_attribute; // __has_attribute IdentifierInfo *Ident__has_include; // __has_include diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index bc3c9b5a59..6a9d4abef1 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -85,6 +85,7 @@ void Preprocessor::RegisterBuiltinMacros() { // Clang Extensions. Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); @@ -525,8 +526,8 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, } -/// HasFeature - Return true if we recognize and implement the specified feature -/// specified by the identifier. +/// HasFeature - Return true if we recognize and implement the feature +/// specified by the identifier as a standard language feature. static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { const LangOptions &LangOpts = PP.getLangOptions(); @@ -550,12 +551,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_exceptions", LangOpts.Exceptions) .Case("cxx_rtti", LangOpts.RTTI) .Case("enumerator_attributes", true) - .Case("generic_selections", true) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) + // C1X features + .Case("c_generic_selections", LangOpts.C1X) + .Case("c_static_assert", LangOpts.C1X) // C++0x features .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x) .Case("cxx_alias_templates", LangOpts.CPlusPlus0x) @@ -603,6 +606,35 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Default(false); } +/// HasExtension - Return true if we recognize and implement the feature +/// specified by the identifier, either as an extension or a standard language +/// feature. +static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { + if (HasFeature(PP, II)) + return true; + + // If the use of an extension results in an error diagnostic, extensions are + // effectively unavailable, so just return false here. + if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error) + return false; + + const LangOptions &LangOpts = PP.getLangOptions(); + + // Because we inherit the feature list from HasFeature, this string switch + // must be less restrictive than HasFeature's. + return llvm::StringSwitch (II->getName()) + // C1X features supported by other languages as extensions. + .Case("c_generic_selections", true) + .Case("c_static_assert", true) + // C++0x features supported by other languages as extensions. + .Case("cxx_deleted_functions", LangOpts.CPlusPlus) + .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) + .Case("cxx_override_control", LangOpts.CPlusPlus) + .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) + .Case("cxx_rvalue_references", LangOpts.CPlusPlus) + .Default(false); +} + /// HasAttribute - Return true if we recognize and implement the attribute /// specified by the given identifier. static bool HasAttribute(const IdentifierInfo *II) { @@ -851,10 +883,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); - } else if (II == Ident__has_feature || - II == Ident__has_builtin || + } else if (II == Ident__has_feature || + II == Ident__has_extension || + II == Ident__has_builtin || II == Ident__has_attribute) { - // The argument to these two builtins should be a parenthesized identifier. + // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; @@ -883,6 +916,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) Value = HasAttribute(FeatureII); + else if (II == Ident__has_extension) + Value = HasExtension(*this, FeatureII); else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); diff --git a/test/Lexer/has_extension.c b/test/Lexer/has_extension.c new file mode 100644 index 0000000000..bc75a4a1c5 --- /dev/null +++ b/test/Lexer/has_extension.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-PED-NONE %s +// RUN: %clang_cc1 -pedantic-errors -E %s -o - | FileCheck --check-prefix=CHECK-PED-ERR %s + +// CHECK-PED-NONE: no_dummy_extension +#if !__has_extension(dummy_extension) +int no_dummy_extension(); +#endif + +// Arbitrary feature to test that has_extension is a superset of has_feature +// CHECK-PED-NONE: attribute_overloadable +#if __has_extension(attribute_overloadable) +int attribute_overloadable(); +#endif + +// CHECK-PED-NONE: has_c_static_assert +// CHECK-PED-ERR: no_c_static_assert +#if __has_extension(c_static_assert) +int has_c_static_assert(); +#else +int no_c_static_assert(); +#endif + +// CHECK-PED-NONE: has_c_generic_selections +// CHECK-PED-ERR: no_c_generic_selections +#if __has_extension(c_generic_selections) +int has_c_generic_selections(); +#else +int no_c_generic_selections(); +#endif + diff --git a/test/Lexer/has_extension_cxx.cpp b/test/Lexer/has_extension_cxx.cpp new file mode 100644 index 0000000000..77efa35793 --- /dev/null +++ b/test/Lexer/has_extension_cxx.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -E %s -o - | FileCheck %s + +// CHECK: c_static_assert +#if __has_extension(c_static_assert) +int c_static_assert(); +#endif + +// CHECK: c_generic_selections +#if __has_extension(c_generic_selections) +int c_generic_selections(); +#endif + +// CHECK: has_deleted_functions +#if __has_extension(cxx_deleted_functions) +int has_deleted_functions(); +#endif + +// CHECK: has_inline_namespaces +#if __has_extension(cxx_inline_namespaces) +int has_inline_namespaces(); +#endif + +// CHECK: has_override_control +#if __has_extension(cxx_override_control) +int has_override_control(); +#endif + +// CHECK: has_reference_qualified_functions +#if __has_extension(cxx_reference_qualified_functions) +int has_reference_qualified_functions(); +#endif + +// CHECK: has_rvalue_references +#if __has_extension(cxx_rvalue_references) +int has_rvalue_references(); +#endif diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c new file mode 100644 index 0000000000..6c0fb212cc --- /dev/null +++ b/test/Lexer/has_feature_c1x.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -E -std=c1x %s -o - | FileCheck --check-prefix=CHECK-1X %s +// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s + +#if __has_feature(c_static_assert) +int has_static_assert(); +#else +int no_static_assert(); +#endif + +// CHECK-1X: has_static_assert +// CHECK-NO-1X: no_static_assert + +#if __has_feature(c_generic_selections) +int has_generic_selections(); +#else +int no_generic_selections(); +#endif + +// CHECK-1X: has_generic_selections +// CHECK-NO-1X: no_generic_selections -- 2.50.1