From c1b5fa41f09512c74030b9a2a0d1564535e22a76 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 13 May 2011 20:54:45 +0000 Subject: [PATCH] Introduce __has_extension macro __has_extension is a function-like macro which takes the same set of feature identifiers as __has_feature. It 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. At the same time, add support for the C1X feature identifiers c_generic_selections (renamed from generic_selections) and c_static_assert, and document them. Patch by myself and Jean-Daniel Dupas. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131308 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LanguageExtensions.html | 266 +++++++++++++++++++------------ include/clang/Basic/Diagnostic.h | 1 + include/clang/Lex/Preprocessor.h | 1 + lib/Lex/PPMacroExpansion.cpp | 47 +++++- test/Lexer/has_extension.c | 30 ++++ test/Lexer/has_extension_cxx.cpp | 36 +++++ test/Lexer/has_feature_c1x.c | 20 +++ 7 files changed, 294 insertions(+), 107 deletions(-) create mode 100644 test/Lexer/has_extension.c create mode 100644 test/Lexer/has_extension_cxx.cpp create mode 100644 test/Lexer/has_feature_c1x.c diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index f07830a6bf..066677c3d7 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -32,30 +32,37 @@ td {
  • Checks for Upcoming Standard Language Features
  • Checks for Type Traits
  • Blocks
  • Function Overloading in C
  • -
  • Generic Selections
  • Builtin Functions -

    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