On Sat, Apr 30, 2011 at 08:08:06PM +0200, Jean-Daniel Dupas wrote:
> 
> Le 29 avr. 2011 à 20:07, Douglas Gregor a écrit :
> 
> > 
> > On Apr 29, 2011, at 10:44 AM, Peter Collingbourne wrote:
> >> OK, I am fine with introducing a c_ prefix, for the reasons you
> >> point out.  But the way I understand it is that __has_feature in fact
> >> has 2 semi-orthogonal purposes:
> >> 
> >> 1) To test for support for Clang-specific extensions to the language.
> >>  This is the purpose of the non-language-prefixed feature test
> >>  identifiers.
> >> 
> >> 2) To test for Clang support for language features which have been
> >>  standardised in the current language.  This is the purpose of the
> >>  language-prefixed feature test identifiers.
> >> 
> >> However, there is a gap here in that there is no way to test for
> >> the existence of Clang-specific language extensions which have been
> >> standardised in other languages.  For example, generic selections
> >> can be used to implement an OpenCL runtime library using Clang.
> >> Since OpenCL is based on C99, generic selections would be classified
> >> as an extension.  This makes it impossible to test for that extension.
> >> 
> >> One solution to this problem is to have 2 feature test identifiers
> >> for each standardised feature (e.g. "c_generic_selections" and
> >> "generic_selections"), each serving the 2 purposes mentioned above.
> >> The disadvantage of this approach would obviously be the doubling up of
> >> language feature identifiers.  Also, as you point out "static_assert"
> >> would be ambiguous.
> >> 
> >> An alternative solution would be to introduce another macro, say
> >> __has_extension, which takes the same feature test identifiers
> >> as __has_feature.  __has_extension would test the features of
> >> the compiler alone (approximately serving purpose 1) while
> >> __has_feature tests the features of the compiler together
> >> with the current language (approximately serving purpose 2).
> >> 
> >> So for example __has_feature(c_generic_selections) could be
> >> used to test for support for generic selections in C1X while
> >> __has_extension(c_generic_selections) could be used in any language.
> >> I would imagine that __has_extension should act identically to
> >> __has_feature if -pedantic-errors (or perhaps -pedantic) is enabled.
> >> 
> >> Please let me know what you think.
> > 
> > I think that __has_extension is an *excellent* idea!
>
> I tried to implements this new suggestion.
> The has_feature variants are bound to the selected language and returns true 
> only when compiling as C1X, and has_extension always returns true.
> Is this what you had in mind ? 

__has_extension should be a superset of __has_feature, so it should
also include the C++ and C++0x features, as well as the Clang specific
extensions.  This can be done trivially by calling HasFeature from
HasExtension.

I began an implementation (see patch), but this is incomplete since it
includes no tests.  I also haven't surveyed all of the C++0x features
to see which are supported as extensions to C++98.  If you like,
you can extend the patch to add the correct set of C++0x features as
well as tests.

I also wonder whether we should stop adding new non-standardised
features to __has_feature (strictly speaking, under the new regime
__has_feature(X) should always be 0 if X is a non-standardised
feature, but we shouldn't do this for existing features for backwards
compatibility reasons).  That is the way I wrote the documentation in
my patch, but I suppose an argument can also be made for maintaining
the existing behaviour of __has_feature and continuing to add
non-standardised features.

Thanks,
-- 
Peter
>From 6d8fd218942488d67d4921c509b4071ecf6ee769 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <[email protected]>
Date: Sat, 30 Apr 2011 03:20:56 +0100
Subject: [PATCH] __has_extension

---
 docs/LanguageExtensions.html     |  247 +++++++++++++++++++++++---------------
 include/clang/Basic/Diagnostic.h |    1 +
 include/clang/Lex/Preprocessor.h |    1 +
 lib/Lex/PPMacroExpansion.cpp     |   44 ++++++-
 4 files changed, 192 insertions(+), 101 deletions(-)

diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index f86835a..cfb0305 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -32,28 +32,35 @@ td {
   </ul>
 <li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
   <ul>
-  <li><a href="#cxx_attributes">C++0x attributes</a></li>
-  <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
-  <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
-  <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
-  <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
-  <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
-  <li><a href="#cxx_override_control">C++0x override control</a></li>
-  <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
-  <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
-  <li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
-  <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
-  <li><a href="#cxx_auto_type">C++0x type inference</a></li>
-  <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
-  <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
-  <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
-  <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
-  <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
+  <li><a href="#cxx0x">C++0x</a>
+    <ul>
+    <li><a href="#cxx_attributes">C++0x attributes</a></li>
+    <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
+    <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
+    <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
+    <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
+    <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
+    <li><a href="#cxx_override_control">C++0x override control</a></li>
+    <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
+    <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
+    <li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
+    <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
+    <li><a href="#cxx_auto_type">C++0x type inference</a></li>
+    <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
+    <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
+    <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
+    <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
+    <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
+    </ul>
+  <li><a href="#c1x">C1X</a>
+    <ul>
+    <li><a href="#c_generic_selections">C1X generic selections</a></li>
+    <li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
+    </ul>
   </ul>
 <li><a href="#checking_type_traits">Checks for Type Traits</a></li>
 <li><a href="#blocks">Blocks</a></li>
 <li><a href="#overloading-in-c">Function Overloading in C</a></li>
-<li><a href="#generic-selections">Generic Selections</a></li>
 <li><a href="#builtins">Builtin Functions</a>
   <ul>
   <li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
@@ -115,28 +122,42 @@ not.  It can be used like this:</p>
 
 
 <!-- ======================================================================= -->
-<h3 id="__has_feature">__has_feature</h3>
+<h3 id="__has_feature_extension">__has_feature and __has_extension</h3>
 <!-- ======================================================================= -->
 
-<p>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:</p>
+<p>These function-like macros take a single identifier argument that is the
+name of a feature.  <code>__has_feature</code> evaluates to 1 if the feature
+is both supported by Clang and standardized in the current language standard
+or 0 if not, while <code>__has_extension</code> 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:</p>
 
 <blockquote>
 <pre>
 #ifndef __has_feature         // Optional of course.
   #define __has_feature(x) 0  // Compatibility with non-clang compilers.
 #endif
+#ifndef __has_extension
+  #define __has_extension(x) 0
+#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
-...
 </pre>
 </blockquote>
 
+<p>If the <code>-pedantic-errors</code> option is given,
+<code>__has_extension</code> is equivalent to <code>__has_feature</code>.</p>
+
 <p>The feature tag is described along with the language feature below.</p>
 
 <!-- ======================================================================= -->
@@ -293,7 +314,7 @@ float4 foo(float2 a, float2 b) {
 </pre>
 </blockquote>
 
-<p>Query for this feature with __has_feature(attribute_ext_vector_type).</p>
+<p>Query for this feature with __has_extension(attribute_ext_vector_type).</p>
 
 <p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
 
@@ -318,8 +339,8 @@ will be incorporated into the appropriate diagnostic:</p>
 </blockquote>
 
 <p>Query for this feature
-with <tt>__has_feature(attribute_deprecated_with_message)</tt>
-and <tt>__has_feature(attribute_unavailable_with_message)</tt>.</p>
+with <tt>__has_extension(attribute_deprecated_with_message)</tt>
+and <tt>__has_extension(attribute_unavailable_with_message)</tt>.</p>
 
 <!-- ======================================================================= -->
 <h2 id="attributes-on-enumerators">Attributes on Enumerators</h2>
@@ -342,7 +363,7 @@ initializer, like so:</p>
 <p>Attributes on the <tt>enum</tt> declaration do not apply to
 individual enumerators.</p>
 
-<p>Query for this feature with <tt>__has_feature(enumerator_attributes)</tt>.</p>
+<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
 
 <!-- ======================================================================= -->
 <h2 id="checking_language_features">Checks for Standard Language Features</h2>
@@ -365,106 +386,156 @@ compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
 <h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
 <!-- ======================================================================= -->
 
-<p>The <tt>__has_feature</tt> macro can be used to query if certain upcoming
-standard language features are enabled.  Those features are listed here.</p>
+<p>The <tt>__has_feature</tt> or <tt>__has_extension</tt> 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.</p>
 
-<p>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 <tt>-std=c++0x</tt> option when compiling C++ code. Features that are
-not yet implemented will be noted.</p>
+<h3 id="cxx0x">C++0x</h3>
 
-<h3 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
+<p>The features listed below are slated for inclusion in the upcoming
+C++0x standard. As a result, all these features are enabled
+with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
 
-<p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
+<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_decltype)</tt> or
+<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
 <tt>decltype()</tt> specifier is enabled.</p>
 
-<h3 id="cxx_attributes">C++0x attributes</h3>
+<h4 id="cxx_attributes">C++0x attributes</h3>
 
-<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
-attribute parsing with C++0x's square bracket notation is enabled.</p>
+<p>Use <tt>__has_feature(cxx_attributes)</tt> or
+<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
+parsing with C++0x's square bracket notation is enabled.</p>
 
-<h3 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
+<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
 
-<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> to determine if support for default template arguments in function templates is enabled.</p>
+<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
+<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
+if support for default template arguments in function templates is enabled.</p>
 
-<h3 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
+<h4 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
+<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
 deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
 
-<h3 id="cxx_lambdas">C++0x lambdas</h3>
+<h4 id="cxx_lambdas">C++0x lambdas</h3>
 
-<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
-lambdas is enabled. clang does not currently implement this feature.</p>
+<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
+<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
+is enabled. clang does not currently implement this feature.</p>
 
-<h3 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
+<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_nullptr)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
+<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
 <tt>nullptr</tt> is enabled. clang does not yet fully implement this
 feature.</p>
 
-<h3 id="cxx_override_control">C++0x <tt>override control</tt></h3>
+<h4 id="cxx_override_control">C++0x <tt>override control</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_override_control)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_override_control)</tt> or
+<tt>__has_extension(cxx_override_control)</tt> to determine if support for
 the override control keywords is enabled.</p>
 
-<h3 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
-<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> to determine if support for reference-qualified functions (e.g., member functions with <code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>) is enabled.</p>
+<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
+<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
+<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
+if support for reference-qualified functions (e.g., member functions with
+<code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>)
+is enabled.</p>
 
-<h3 id="cxx_range_for">C++0x range-based for loop</tt></h3>
+<h4 id="cxx_range_for">C++0x range-based for loop</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_range_for)</tt> to determine if support for
-the range-based for loop is enabled. </p>
+<p>Use <tt>__has_feature(cxx_range_for)</tt> or
+<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
+range-based for loop is enabled. </p>
 
-<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
+<h4 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
+<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
 rvalue references is enabled. </p>
 
-<h3 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
+<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
 
-<p>Use <tt>__has_feature(cxx_static_assert)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
+<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
 compile-time assertions using <tt>static_assert</tt> is enabled.</p>
 
-<h3 id="cxx_auto_type">C++0x type inference</h3>
+<h4 id="cxx_auto_type">C++0x type inference</h3>
 
-<p>Use <tt>__has_feature(cxx_auto_type)</tt> to determine C++0x type inference
-is supported using the <tt>auto</tt> specifier. If this is disabled,
-<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.</p>
+<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
+<tt>__has_extension(cxx_auto_type)</tt> to determine C++0x type inference is
+supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
+will instead be a storage class specifier, as in C or C++98.</p>
 
-<h3 id="cxx_variadic_templates">C++0x variadic templates</h3>
+<h4 id="cxx_variadic_templates">C++0x variadic templates</h3>
 
-<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> to determine if support
+<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
+<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
 for variadic templates is enabled.</p>
 
-<h3 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
+<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
 
-<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
+<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
 inline namespaces is enabled.</p>
 
-<h3 id="cxx_trailing_return">C++0x trailing return type</h3>
+<h4 id="cxx_trailing_return">C++0x trailing return type</h3>
 
-<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for
-the alternate function declaration syntax with trailing return type is enabled.</p>
+<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
+<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
+alternate function declaration syntax with trailing return type is enabled.</p>
 
-<h3 id="cxx_noexcept">C++0x noexcept</h3>
+<h4 id="cxx_noexcept">C++0x noexcept</h3>
 
-<p>Use <tt>__has_feature(cxx_noexcept)</tt> to determine if support for
-noexcept exception specifications is enabled.</p>
+<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
+<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
+exception specifications is enabled.</p>
 
-<h3 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
+<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
 
-<p>Use <tt>__has_feature(cxx_strong_enums)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
+<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
 strongly typed, scoped enumerations is enabled.</p>
 
+<h3 id="c1x">C1X</h3>
+
+<p>The features listed below are slated for inclusion in the upcoming
+C1X standard. As a result, all these features are enabled
+with the <tt>-std=c1x</tt> option when compiling C code.</p>
+
+<h4 id="c_generic_selections">C1X generic selections</h2>
+
+<p>Use <tt>__has_feature(c_generic_selections)</tt> or
+<tt>__has_extension(c_generic_selections)</tt> to determine if support for
+generic selections is enabled.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h3>
+
+<p>Use <tt>__has_feature(c_static_assert)</tt> or
+<tt>__has_extension(c_static_assert)</tt> to determine if support for
+compile-time assertions using <tt>_Static_assert</tt> is enabled.</p>
+
 <!-- ======================================================================= -->
 <h2 id="checking_type_traits">Checks for Type Traits</h2>
 <!-- ======================================================================= -->
 
-<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html";>GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_feature(X)</code> indicates the presence of the type trait. For example:
+<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html";>GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_extension(X)</code> indicates the presence of the type trait. For example:
 <blockquote>
 <pre>
-#if __has_feature(is_convertible_to)
+#if __has_extension(is_convertible_to)
 template&lt;typename From, typename To&gt;
 struct is_convertible_to {
   static const bool value = __is_convertible_to(From, To);
@@ -507,7 +578,7 @@ details for the clang implementation are in <a
 href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
 
 
-<p>Query for this feature with __has_feature(blocks).</p>
+<p>Query for this feature with __has_extension(blocks).</p>
 
 <!-- ======================================================================= -->
 <h2 id="overloading-in-c">Function Overloading in C</h2>
@@ -607,22 +678,8 @@ caveats to this use of name mangling:</p>
   C.</li>
 </ul>
 
-<p>Query for this feature with __has_feature(attribute_overloadable).</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="generic-selections">Generic Selections</h2>
-<!-- ======================================================================= -->
-
-<p>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.</p>
-
-<p>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.</p>
+<p>Query for this feature with __has_extension(attribute_overloadable).</p>
 
-<p>Query for this feature with __has_feature(generic_selections).</p>
 
 <!-- ======================================================================= -->
 <h2 id="builtins">Builtin Functions</h2>
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 7fc400f..3c8a933 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -400,6 +400,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 616507a..a26c15f 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -84,6 +84,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
   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 bacd624..3059428 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_attributes", LangOpts.CPlusPlus0x)
            .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
@@ -598,6 +601,32 @@ 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<bool>(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_override_control", 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) {
@@ -846,10 +875,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;
@@ -878,6 +908,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);
-- 
1.7.1

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to