diff mbox

[C++] - SD-6 Implementation Part 1 - __has_include.

Message ID 5429785D.90506@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland Sept. 29, 2014, 3:18 p.m. UTC
On 09/25/2014 12:57 PM, Jason Merrill wrote:
> On 09/01/2014 09:34 PM, Ed Smith-Rowland wrote:
>>     (open_file_failed()): Not an error to not find a header file for
>>     __has_include__.
>
> Hmm, looks like this means that __has_include__ will silently return 
> false if a header exists but is unreadable; I would think that we want 
> it to be true (and have an error when the user tries to include it).
>
> Jason
>
Here is the new patch series.

A patch addressing C++11 [[deprecated]] is coming later when these are 
in as is a library patch for std::is_final.

I flipped the logic on the libcpp functions because there was a double 
negative of sorts - the logic was confusing to me on second look.
Also, a file that a user can't read for permissions still returns true 
with __has_include.

Built and tested on x86_64-linux.

OK?
2014-09-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement SD-6: SG10 Feature Test Recommendations
	* internal.h (lexer_state, spec_nodes): Add in__has_include__.
	* directives.c: Support __has_include__ builtin.
	* expr.c (parse_has_include): New function to parse __has_include__
	builtin; (eval_token()): Use it.
	* files.c (_cpp_has_header()): New funtion to look for header;
	(open_file_failed()): Not an error to not find a header file for
	__has_include__.
	* identifiers.c (_cpp_init_hashtable()): Add entry for __has_include__.
	* pch.c (cpp_read_state): Lookup __has_include__.
	* traditional.c (enum ls, _cpp_scan_out_logical_line()): Walk through
	__has_include__ statements.

2014-09-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement SD-6: SG10 Feature Test Recommendations
	* c-cppbuiltin.c (c_cpp_builtins()): Define language feature
	macros and the __has_header macro.
Index: c-cppbuiltin.c
===================================================================
--- c-cppbuiltin.c	(revision 215628)
+++ c-cppbuiltin.c	(working copy)
@@ -787,6 +787,12 @@
   /* For stddef.h.  They require macros defined in c-common.c.  */
   c_stddef_cpp_builtins ();
 
+  /* Set include test macros for all C/C++ (not for just C++11 etc.)
+     the builtins __has_include__ and __has_include_next__ are defined
+     in libcpp.  */
+  cpp_define (pfile, "__has_include(STR)=__has_include__(STR)");
+  cpp_define (pfile, "__has_include_next(STR)=__has_include_next__(STR)");
+
   if (c_dialect_cxx ())
     {
       if (flag_weak && SUPPORTS_ONE_ONLY)
@@ -793,12 +799,56 @@
 	cpp_define (pfile, "__GXX_WEAK__=1");
       else
 	cpp_define (pfile, "__GXX_WEAK__=0");
+
       if (warn_deprecated)
 	cpp_define (pfile, "__DEPRECATED");
+
       if (flag_rtti)
 	cpp_define (pfile, "__GXX_RTTI");
+
       if (cxx_dialect >= cxx11)
         cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__");
+
+      /* Binary literals and variable length arrays have been allowed in g++
+	 before C++11 and were standardized for C++14.  */
+      if (!pedantic || cxx_dialect > cxx11)
+	{
+	  cpp_define (pfile, "__cpp_binary_literals=201304");
+	}
+      if (cxx_dialect >= cxx11)
+	{
+	  /* Set feature test macros for C++11  */
+	  cpp_define (pfile, "__cpp_unicode_characters=200704");
+	  cpp_define (pfile, "__cpp_raw_strings=200710");
+	  cpp_define (pfile, "__cpp_unicode_literals=200710");
+	  cpp_define (pfile, "__cpp_user_defined_literals=200809");
+	  cpp_define (pfile, "__cpp_lambdas=200907");
+	  cpp_define (pfile, "__cpp_constexpr=200704");
+	  cpp_define (pfile, "__cpp_static_assert=200410");
+	  cpp_define (pfile, "__cpp_decltype=200707");
+	  cpp_define (pfile, "__cpp_attributes=200809");
+	  cpp_define (pfile, "__cpp_rvalue_reference=200610");
+	  cpp_define (pfile, "__cpp_variadic_templates=200704");
+	  cpp_define (pfile, "__cpp_alias_templates=200704");
+	}
+      if (cxx_dialect > cxx11)
+	{
+	  /* Set feature test macros for C++14  */
+	  cpp_define (pfile, "__cpp_return_type_deduction=201304");
+	  cpp_define (pfile, "__cpp_init_captures=201304");
+	  cpp_define (pfile, "__cpp_generic_lambdas=201304");
+	  //cpp_undef (pfile, "__cpp_constexpr");
+	  //cpp_define (pfile, "__cpp_constexpr=201304");
+	  cpp_define (pfile, "__cpp_decltype_auto=201304");
+	  //cpp_define (pfile, "__cpp_aggregate_nsdmi=201304");
+	  cpp_define (pfile, "__cpp_variable_templates=201304");
+	  cpp_define (pfile, "__cpp_digit_separators=201309");
+	  cpp_define (pfile, "__cpp_attribute_deprecated=201309");
+	  //cpp_define (pfile, "__cpp_sized_deallocation=201309");
+	  /* We'll have to see where runtime arrays wind up.
+	     Let's put it in C++14 for now.  */
+	  cpp_define (pfile, "__cpp_runtime_arrays=201304");
+	}
     }
   /* Note that we define this for C as well, so that we know if
      __attribute__((cleanup)) will interface with EH.  */
2014-09-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement SD-6: SG10 Feature Test Recommendations
	* include/bits/basic_string.h: Add __cpp_lib feature test macro.
	* include/bits/stl_algobase.h: Ditto.
	* include/bits/stl_function.h: Ditto.
	* include/bits/unique_ptr.h: Ditto.
	* include/std/chrono: Ditto.
	* include/std/complex: Ditto.
	* include/std/iomanip: Ditto.
	* include/std/shared_mutex: Ditto.
	* include/std/tuple: Ditto.
	* include/std/type_traits: Ditto.
	* include/std/utility: Ditto.
	* testsuite/experimental/feat-cxx14.cc: New.
	* testsuite/experimental/feat-lib-fund.cc: New.
	* testsuite/20_util/declval/requirements/1_neg.cc: Adjust.
	* testsuite/20_util/duration/literals/range.cc: Adjust.
	* testsuite/20_util/duration/requirements/typedefs_neg1.cc: Adjust.
	* testsuite/20_util/duration/requirements/typedefs_neg2.cc: Adjust.
	* testsuite/20_util/duration/requirements/typedefs_neg3.cc: Adjust.
	* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust.
	* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust.
	* testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust.
	* testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc:
	Adjust.
Index: include/bits/basic_string.h
===================================================================
--- include/bits/basic_string.h	(revision 215628)
+++ include/bits/basic_string.h	(working copy)
@@ -3140,6 +3140,8 @@
 
 #if __cplusplus > 201103L
 
+#define __cpp_lib_string_udls 201304
+
   inline namespace literals
   {
   inline namespace string_literals
Index: include/bits/stl_algobase.h
===================================================================
--- include/bits/stl_algobase.h	(revision 215628)
+++ include/bits/stl_algobase.h	(working copy)
@@ -1091,6 +1091,9 @@
     }
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_robust_nonmodifying_seq_ops 201304
+
   /**
    *  @brief Tests a range for element-wise equality.
    *  @ingroup non_mutating_algorithms
Index: include/bits/stl_function.h
===================================================================
--- include/bits/stl_function.h	(revision 215628)
+++ include/bits/stl_function.h	(working copy)
@@ -217,6 +217,10 @@
     };
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_transparent_operators 201210
+#define __cpp_lib_generic_associative_lookup 201304
+
   template<>
     struct plus<void>
     {
Index: include/bits/unique_ptr.h
===================================================================
--- include/bits/unique_ptr.h	(revision 215628)
+++ include/bits/unique_ptr.h	(working copy)
@@ -743,6 +743,9 @@
     };
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_make_unique 201304
+
   template<typename _Tp>
     struct _MakeUniq
     { typedef unique_ptr<_Tp> __single_object; };
Index: include/std/chrono
===================================================================
--- include/std/chrono	(revision 215628)
+++ include/std/chrono	(working copy)
@@ -782,6 +782,8 @@
 
 #if __cplusplus > 201103L
 
+#define __cpp_lib_chrono_udls 201304
+
   inline namespace literals
   {
   inline namespace chrono_literals
Index: include/std/complex
===================================================================
--- include/std/complex	(revision 215628)
+++ include/std/complex	(working copy)
@@ -1934,6 +1934,8 @@
 inline namespace literals {
 inline namespace complex_literals {
 
+#define __cpp_lib_complex_udls 201309
+
   constexpr std::complex<float>
   operator""if(long double __num)
   { return std::complex<float>{0.0F, static_cast<float>(__num)}; }
Index: include/std/iomanip
===================================================================
--- include/std/iomanip	(revision 215628)
+++ include/std/iomanip	(working copy)
@@ -339,6 +339,8 @@
 
 #if __cplusplus > 201103L
 
+#define __cpp_lib_quoted_string_io 201304
+
 _GLIBCXX_END_NAMESPACE_VERSION
   namespace __detail {
   _GLIBCXX_BEGIN_NAMESPACE_VERSION
Index: include/std/shared_mutex
===================================================================
--- include/std/shared_mutex	(revision 215628)
+++ include/std/shared_mutex	(working copy)
@@ -52,6 +52,9 @@
    */
 
 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
+
+#define __cpp_lib_shared_timed_mutex 201402
+
   /// shared_timed_mutex
   class shared_timed_mutex
   {
Index: include/std/tuple
===================================================================
--- include/std/tuple	(revision 215628)
+++ include/std/tuple	(working copy)
@@ -746,6 +746,9 @@
     }
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_tuples_by_type 201304
+
   template<typename _Head, size_t __i, typename... _Tail>
     constexpr _Head&
     __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
Index: include/std/type_traits
===================================================================
--- include/std/type_traits	(revision 215628)
+++ include/std/type_traits	(working copy)
@@ -73,6 +73,9 @@
       typedef integral_constant<_Tp, __v>   type;
       constexpr operator value_type() const { return value; }
 #if __cplusplus > 201103L
+
+#define __cpp_lib_integral_constant_callable 201304
+
       constexpr value_type operator()() const { return value; }
 #endif
     };
@@ -480,6 +483,8 @@
     struct is_function<_Res(_ArgTypes......) const volatile &&>
     : public true_type { };
 
+#define __cpp_lib_is_null_pointer 201309
+
   template<typename>
     struct __is_null_pointer_helper
     : public false_type { };
@@ -1451,6 +1456,9 @@
     };
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_transformation_trait_aliases 201304
+
   /// Alias template for remove_const
   template<typename _Tp>
     using remove_const_t = typename remove_const<_Tp>::type;
@@ -2090,6 +2098,8 @@
 
   // Sfinae-friendly result_of implementation:
 
+#define __cpp_lib_result_of_sfinae 201210
+
   // [func.require] paragraph 1 bullet 1:
   struct __result_of_memfun_ref_impl
   {
Index: include/std/utility
===================================================================
--- include/std/utility	(revision 215628)
+++ include/std/utility	(working copy)
@@ -70,6 +70,7 @@
 #include <bits/stl_pair.h>
 
 #if __cplusplus >= 201103L
+
 #include <bits/move.h>
 #include <initializer_list>
 
@@ -157,6 +158,9 @@
     { return __pair_get<_Int>::__const_get(__in); }
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_tuples_by_type 201304
+
   template <typename _Tp, typename _Up>
     constexpr _Tp&
     get(pair<_Tp, _Up>& __p) noexcept
@@ -187,6 +191,8 @@
     get(pair<_Up, _Tp>&& __p) noexcept
     { return std::move(__p.second); }
 
+#define __cpp_lib_exchange_function 201304
+
   /// Assign @p __new_val to @p __obj and return its previous value.
   template <typename _Tp, typename _Up = _Tp>
     inline _Tp
@@ -216,6 +222,9 @@
     };
 
 #if __cplusplus > 201103L
+
+#define __cpp_lib_integer_sequence 201304
+
   /// Class template integer_sequence
   template<typename _Tp, _Tp... _Idx>
     struct integer_sequence
Index: testsuite/experimental/feat-cxx14.cc
===================================================================
--- testsuite/experimental/feat-cxx14.cc	(revision 0)
+++ testsuite/experimental/feat-cxx14.cc	(working copy)
@@ -0,0 +1,113 @@
+// { dg-options "-std=gnu++14" }
+// { dg-do compile }
+
+#include <utility>
+#include <tuple>
+#include <memory>
+#include <functional>
+#include <type_traits>
+#include <chrono>
+#include <string>
+#include <complex>
+#include <iomanip>
+#include <shared_mutex>
+
+#ifndef  __cpp_lib_integer_sequence
+#  error "__cpp_lib_integer_sequence"
+#elif  __cpp_lib_integer_sequence != 201304
+#  error "__cpp_lib_integer_sequence != 201304"
+#endif
+
+#ifndef  __cpp_lib_exchange_function
+#  error "__cpp_lib_exchange_function"
+#elif  __cpp_lib_exchange_function != 201304
+#  error "__cpp_lib_exchange_function != 201304"
+#endif
+
+#ifndef  __cpp_lib_tuples_by_type
+#  error "__cpp_lib_tuples_by_type"
+#elif  __cpp_lib_tuples_by_type != 201304
+#  error "__cpp_lib_tuples_by_type != 201304"
+#endif
+
+#ifndef  __cpp_lib_make_unique
+#  error "__cpp_lib_make_unique"
+#elif  __cpp_lib_make_unique != 201304
+#  error "__cpp_lib_make_unique != 201304"
+#endif
+
+#ifndef  __cpp_lib_transparent_operators
+#  error "__cpp_lib_transparent_operators"
+#elif  __cpp_lib_transparent_operators != 201210
+#  error "__cpp_lib_transparent_operators != 201210"
+#endif
+
+#ifndef  __cpp_lib_result_of_sfinae
+#  error "__cpp_lib_result_of_sfinae"
+#elif  __cpp_lib_result_of_sfinae != 201210
+#  error "__cpp_lib_result_of_sfinae != 201210"
+#endif
+
+#ifndef  __cpp_lib_integral_constant_callable
+#  error "__cpp_lib_integral_constant_callable"
+#elif  __cpp_lib_integral_constant_callable != 201304
+#  error "__cpp_lib_integral_constant_callable != 201304"
+#endif
+
+#ifndef  __cpp_lib_transformation_trait_aliases
+#  error "__cpp_lib_transformation_trait_aliases"
+#elif  __cpp_lib_transformation_trait_aliases != 201304
+#  error "__cpp_lib_transformation_trait_aliases != 201304"
+#endif
+
+#ifndef  __cpp_lib_chrono_udls
+#  error "__cpp_lib_chrono_udls"
+#elif  __cpp_lib_chrono_udls != 201304
+#  error "__cpp_lib_chrono_udls != 201304"
+#endif
+
+#ifndef  __cpp_lib_string_udls
+#  error "__cpp_lib_string_udls"
+#elif  __cpp_lib_string_udls != 201304
+#  error "__cpp_lib_string_udls != 201304"
+#endif
+
+#ifndef __cpp_lib_complex_udls
+#  error "__cpp_lib_complex_udls"
+#elif  __cpp_lib_complex_udls != 201309
+#  error "__cpp_lib_complex_udls != 201309"
+#endif
+
+#ifndef  __cpp_lib_generic_associative_lookup
+#  error "__cpp_lib_generic_associative_lookup"
+#elif  __cpp_lib_generic_associative_lookup != 201304
+#  error "__cpp_lib_generic_associative_lookup != 201304"
+#endif
+
+//#ifndef  __cpp_lib_null_iterators
+//#  error "__cpp_lib_null_iterators"
+//#elif  __cpp_lib_null_iterators != 201304
+//#  error "__cpp_lib_null_iterators != 201304"
+//#endif
+
+#ifndef  __cpp_lib_robust_nonmodifying_seq_ops
+#  error "__cpp_lib_robust_nonmodifying_seq_ops"
+#elif  __cpp_lib_robust_nonmodifying_seq_ops != 201304
+#  error "__cpp_lib_robust_nonmodifying_seq_ops != 201304"
+#endif
+
+#ifndef  __cpp_lib_quoted_string_io
+#  error "__cpp_lib_quoted_string_io"
+#elif  __cpp_lib_quoted_string_io != 201304
+#  error "__cpp_lib_quoted_string_io != 201304"
+#endif
+
+#if !__has_include(<shared_mutex>)
+#  error "<shared_mutex>"
+#endif
+
+#ifndef  __cpp_lib_shared_timed_mutex
+#  error "__cpp_lib_shared_timed_mutex"
+#elif  __cpp_lib_shared_timed_mutex != 201402
+#  error "__cpp_lib_shared_timed_mutex != 201402"
+#endif
Index: testsuite/experimental/feat-lib-fund.cc
===================================================================
--- testsuite/experimental/feat-lib-fund.cc	(revision 0)
+++ testsuite/experimental/feat-lib-fund.cc	(working copy)
@@ -0,0 +1,25 @@
+// { dg-options "-std=gnu++14" }
+// { dg-do compile }
+
+#include <experimental/optional>
+#include <experimental/string_view>
+
+#if !__has_include(<experimental/optional>)
+#  error "<experimental/optional>"
+#endif
+
+//#if !__has_include(<experimental/net>)
+//#  error "<experimental/net>"
+//#endif
+
+//#if !__has_include(<experimental/any>)
+//#  error "<experimental/any>"
+//#endif
+
+//#if !__has_include(<experimental/memory_resource>)
+//#  error "<experimental/memory_resource>"
+//#endif
+
+#if !__has_include(<experimental/string_view>)
+#  error "<experimental/string_view>"
+#endif
Index: testsuite/20_util/declval/requirements/1_neg.cc
===================================================================
--- testsuite/20_util/declval/requirements/1_neg.cc	(revision 215628)
+++ testsuite/20_util/declval/requirements/1_neg.cc	(working copy)
@@ -19,7 +19,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 2082 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2088 }
 
 #include <utility>
 
Index: testsuite/20_util/duration/literals/range.cc
===================================================================
--- testsuite/20_util/duration/literals/range.cc	(revision 215628)
+++ testsuite/20_util/duration/literals/range.cc	(working copy)
@@ -27,5 +27,5 @@
 
   // std::numeric_limits<int64_t>::max() == 9223372036854775807;
   auto h = 9223372036854775808h;
-  // { dg-error "cannot be represented" "" { target *-*-* } 794 }
+  // { dg-error "cannot be represented" "" { target *-*-* } 799 }
 }
Index: testsuite/20_util/duration/requirements/typedefs_neg1.cc
===================================================================
--- testsuite/20_util/duration/requirements/typedefs_neg1.cc	(revision 215628)
+++ testsuite/20_util/duration/requirements/typedefs_neg1.cc	(working copy)
@@ -31,5 +31,5 @@
   test_type d;
 }
 
-// { dg-error "rep cannot be a duration" "" { target *-*-* } 246 }
+// { dg-error "rep cannot be a duration" "" { target *-*-* } 249 }
 // { dg-error "required from here" "" { target *-*-* } 31 }
Index: testsuite/20_util/duration/requirements/typedefs_neg2.cc
===================================================================
--- testsuite/20_util/duration/requirements/typedefs_neg2.cc	(revision 215628)
+++ testsuite/20_util/duration/requirements/typedefs_neg2.cc	(working copy)
@@ -32,5 +32,5 @@
   test_type d;			// { dg-error "required from here" }
 }
 
-// { dg-error "must be a specialization of ratio" "" { target *-*-* } 247 }
+// { dg-error "must be a specialization of ratio" "" { target *-*-* } 250 }
 // { dg-prune-output "not a member" }
Index: testsuite/20_util/duration/requirements/typedefs_neg3.cc
===================================================================
--- testsuite/20_util/duration/requirements/typedefs_neg3.cc	(revision 215628)
+++ testsuite/20_util/duration/requirements/typedefs_neg3.cc	(working copy)
@@ -33,5 +33,5 @@
   test_type d;
 }
 
-// { dg-error "period must be positive" "" { target *-*-* } 249 }
+// { dg-error "period must be positive" "" { target *-*-* } 252 }
 // { dg-error "required from here" "" { target *-*-* } 33 }
Index: testsuite/20_util/make_signed/requirements/typedefs_neg.cc
===================================================================
--- testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(revision 215628)
+++ testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1747 }
-// { dg-error "declaration of" "" { target *-*-* } 1711 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1753 }
+// { dg-error "declaration of" "" { target *-*-* } 1717 }
Index: testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
===================================================================
--- testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(revision 215628)
+++ testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1650 }
-// { dg-error "declaration of" "" { target *-*-* } 1614 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1656 }
+// { dg-error "declaration of" "" { target *-*-* } 1620 }
Index: testsuite/23_containers/array/tuple_interface/get_neg.cc
===================================================================
--- testsuite/23_containers/array/tuple_interface/get_neg.cc	(revision 215628)
+++ testsuite/23_containers/array/tuple_interface/get_neg.cc	(working copy)
@@ -28,6 +28,6 @@
 int n2 = std::get<1>(std::move(a));
 int n3 = std::get<1>(ca);
 
-// { dg-error "static assertion failed" "" { target *-*-* } 274 }
-// { dg-error "static assertion failed" "" { target *-*-* } 283 }
-// { dg-error "static assertion failed" "" { target *-*-* } 291 }
+// { dg-error "static assertion failed" "" { target *-*-* } 277 }
+// { dg-error "static assertion failed" "" { target *-*-* } 286 }
+// { dg-error "static assertion failed" "" { target *-*-* } 294 }
Index: testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc
===================================================================
--- testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc	(revision 215628)
+++ testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc	(working copy)
@@ -23,4 +23,4 @@
 
 typedef std::tuple_element<1, std::array<int, 1>>::type type;
 
-// { dg-error "static assertion failed" "" { target *-*-* } 322 }
+// { dg-error "static assertion failed" "" { target *-*-* } 325 }
2014-09-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement SD-6: SG10 Feature Test Recommendations
	* g++.dg/cpp1y/feat-cxx11-neg.C: New.
	* g++.dg/cpp1y/feat-cxx11.C: New.
	* g++.dg/cpp1y/feat-cxx14.C: New.
	* g++.dg/cpp1y/feat-cxx98.C: New.
	* g++.dg/cpp1y/feat-cxx98-neg.C: New.
	* g++.dg/cpp1y/phoobhar.h: New.
	* g++.dg/cpp1y/testinc/phoobhar.h: New.
Index: g++.dg/cpp1y/feat-cxx11-neg.C
===================================================================
--- g++.dg/cpp1y/feat-cxx11-neg.C	(revision 0)
+++ g++.dg/cpp1y/feat-cxx11-neg.C	(working copy)
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++11_only } }
+// { dg-options "-pedantic-errors" }
+
+// These *are* defined in C++14 onwards.
+
+#ifndef __cpp_binary_literals
+#  error "__cpp_binary_literals" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_init_captures
+#  error "__cpp_init_captures" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_generic_lambdas
+#  error "__cpp_generic_lambdas" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_decltype_auto
+#  error "__cpp_decltype_auto" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_return_type_deduction
+#  error "__cpp_return_type_deduction" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_variable_templates
+#  error "__cpp_variable_templates" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_digit_separators
+#  error "__cpp_digit_separators" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_attribute_deprecated
+#  error "__cpp_attribute_deprecated" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_runtime_arrays
+#  error "__cpp_runtime_arrays" // { dg-error "error" }
+#endif
Index: g++.dg/cpp1y/feat-cxx11.C
===================================================================
--- g++.dg/cpp1y/feat-cxx11.C	(revision 0)
+++ g++.dg/cpp1y/feat-cxx11.C	(working copy)
@@ -0,0 +1,81 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+#ifndef __cpp_unicode_characters
+#  error "__cpp_unicode_characters"
+#elif __cpp_unicode_characters != 200704
+#  error "__cpp_unicode_characters != 200704"
+#endif
+
+#ifndef __cpp_raw_strings
+#  error "__cpp_raw_strings"
+#elif __cpp_raw_strings != 200710
+#  error "__cpp_raw_strings != 200710"
+#endif
+
+#ifndef __cpp_unicode_literals
+#  error "__cpp_unicode_literals"
+#elif __cpp_unicode_literals != 200710
+#  error "__cpp_unicode_literals != 200710"
+#endif
+
+#ifndef __cpp_user_defined_literals
+#  error "__cpp_user_defined_literals"
+#elif __cpp_user_defined_literals != 200809
+#  error "__cpp_user_defined_literals != 200809"
+#endif
+
+#ifndef __cpp_lambdas
+#  error "__cpp_lambdas"
+#elif __cpp_lambdas != 200907
+#  error "__cpp_lambdas != 200907"
+#endif
+
+#ifndef __cpp_constexpr
+#  error "__cpp_constexpr"
+#elif __cpp_constexpr != 200704
+#  error "__cpp_constexpr != 200704"
+#endif
+
+#ifndef __cpp_static_assert
+#  error "__cpp_static_assert"
+#elif __cpp_static_assert != 200410
+#  error "__cpp_static_assert != 200410"
+#endif
+
+#ifndef __cpp_decltype
+#  error "__cpp_decltype"
+#elif __cpp_decltype != 200707
+#  error "__cpp_decltype != 200707"
+#endif
+
+#ifndef __cpp_attributes
+#  error "__cpp_attributes"
+#elif __cpp_attributes != 200809
+#  error "__cpp_attributes != 200809"
+#endif
+
+#ifndef __cpp_rvalue_reference
+#  error "__cpp_rvalue_reference"
+#elif __cpp_rvalue_reference != 200610
+#  error "__cpp_rvalue_reference != 200610"
+#endif
+
+#ifndef __cpp_variadic_templates
+#  error "__cpp_variadic_templates"
+#elif __cpp_variadic_templates != 200704
+#  error "__cpp_variadic_templates != 200704"
+#endif
+
+#ifndef __cpp_alias_templates
+#  error "__cpp_alias_templates"
+#elif __cpp_alias_templates != 200704
+#  error "__cpp_alias_templates != 200704"
+#endif
+
+//  These C++14 features are allowed in C++11 in non-ANSI modes.
+#ifndef __cpp_binary_literals
+#  error "__cpp_binary_literals"
+#elif __cpp_binary_literals != 201304
+#  error "__cpp_binary_literals != 201304"
+#endif
Index: g++.dg/cpp1y/feat-cxx14.C
===================================================================
--- g++.dg/cpp1y/feat-cxx14.C	(revision 0)
+++ g++.dg/cpp1y/feat-cxx14.C	(working copy)
@@ -0,0 +1,232 @@
+// { dg-do compile { target c++14 } }
+// { dg-options "-I${srcdir}/g++.dg/cpp1y -I${srcdir}/g++.dg/cpp1y/testinc" }
+
+// Begin C++11 tests.
+
+#ifndef __cpp_unicode_characters
+#  error "__cpp_unicode_characters"
+#elif __cpp_unicode_characters != 200704
+#  error "__cpp_unicode_characters != 200704"
+#endif
+
+#ifndef __cpp_raw_strings
+#  error "__cpp_raw_strings"
+#elif __cpp_raw_strings != 200710
+#  error "__cpp_raw_strings != 200710"
+#endif
+
+#ifndef __cpp_unicode_literals
+#  error "__cpp_unicode_literals"
+#elif __cpp_unicode_literals != 200710
+#  error "__cpp_unicode_literals != 200710"
+#endif
+
+#ifndef __cpp_user_defined_literals
+#  error "__cpp_user_defined_literals"
+#elif __cpp_user_defined_literals != 200809
+#  error "__cpp_user_defined_literals != 200809"
+#endif
+
+#ifndef __cpp_lambdas
+#  error "__cpp_lambdas"
+#elif __cpp_lambdas != 200907
+#  error "__cpp_lambdas != 200907"
+#endif
+
+#ifndef __cpp_constexpr
+#  error "__cpp_constexpr"
+#elif __cpp_constexpr != 200704
+#  error "__cpp_constexpr != 200704"
+#endif
+
+#ifndef __cpp_static_assert
+#  error "__cpp_static_assert"
+#elif __cpp_static_assert != 200410
+#  error "__cpp_static_assert != 200410"
+#endif
+
+#ifndef __cpp_decltype
+#  error "__cpp_decltype"
+#elif __cpp_decltype != 200707
+#  error "__cpp_decltype != 200707"
+#endif
+
+#ifndef __cpp_attributes
+#  error "__cpp_attributes"
+#elif __cpp_attributes != 200809
+#  error "__cpp_attributes != 200809"
+#endif
+
+#ifndef __cpp_rvalue_reference
+#  error "__cpp_rvalue_reference"
+#elif __cpp_rvalue_reference != 200610
+#  error "__cpp_rvalue_reference != 200610"
+#endif
+
+#ifndef __cpp_variadic_templates
+#  error "__cpp_variadic_templates"
+#elif __cpp_variadic_templates != 200704
+#  error "__cpp_variadic_templates != 200704"
+#endif
+
+#ifndef __cpp_alias_templates
+#  error "__cpp_alias_templates"
+#elif __cpp_alias_templates != 200704
+#  error "__cpp_alias_templates != 200704"
+#endif
+
+// Begin C++14 tests.
+
+#ifndef __cpp_binary_literals
+#  error "__cpp_binary_literals"
+#elif __cpp_binary_literals != 201304
+#  error "__cpp_binary_literals != 201304"
+#endif
+
+#ifndef __cpp_init_captures
+#  error "__cpp_init_captures"
+#elif __cpp_init_captures != 201304
+#  error "__cpp_init_captures != 201304"
+#endif
+
+#ifndef __cpp_generic_lambdas
+#  error "__cpp_generic_lambdas"
+#elif __cpp_generic_lambdas != 201304
+#  error "__cpp_generic_lambdas != 201304"
+#endif
+
+//  TODO: Change 200704 to 201304 when C++14 constexpr goes in.
+#ifndef __cpp_constexpr
+#  error "__cpp_constexpr"
+#elif __cpp_constexpr != 200704
+#  error "__cpp_constexpr != 200704"
+#endif
+
+#ifndef __cpp_decltype_auto
+#  error "__cpp_decltype_auto"
+#elif __cpp_decltype_auto != 201304
+#  error "__cpp_decltype_auto != 201304"
+#endif
+
+#ifndef __cpp_return_type_deduction
+#  error "__cpp_return_type_deduction"
+#elif __cpp_return_type_deduction != 201304
+#  error "__cpp_return_type_deduction != 201304"
+#endif
+
+#ifndef __cpp_runtime_arrays
+#  error "__cpp_runtime_arrays"
+#elif __cpp_runtime_arrays != 201304
+#  error "__cpp_runtime_arrays != 201304"
+#endif
+
+//  Aggregate initializers not in yet.
+#ifdef __cpp_aggregate_nsdmi
+#  error "__cpp_aggregate_nsdmi"
+#endif
+
+#ifndef __cpp_variable_templates
+#  error "__cpp_variable_templates"
+#elif __cpp_variable_templates != 201304
+#  error "__cpp_variable_templates != 201304"
+#endif
+
+#ifndef __cpp_digit_separators
+#  error "__cpp_digit_separators"
+#elif __cpp_digit_separators != 201309
+#  error "__cpp_digit_separators != 201309"
+#endif
+
+#ifndef __cpp_attribute_deprecated
+#  error "__cpp_attribute_deprecated"
+#elif __cpp_attribute_deprecated != 201309
+#  error "__cpp_attribute_deprecated != 201309"
+#endif
+
+//  Sized deallocation not in yet.
+#ifdef __cpp_sized_deallocation
+#  error "__cpp_sized_deallocation"
+#endif
+
+// Begin include checks.
+
+//  Check for __has_include macro.
+#ifndef __has_include
+#  error "__has_include"
+#endif
+
+//  Quoted complex.h should find at least the bracket version (use operator).
+#if __has_include__ "complex.h"
+#else
+#  error "complex.h"
+#endif
+
+//  Try known bracket header (use operator).
+#if __has_include__(<complex>)
+#else
+#  error "<complex>"
+#endif
+
+//  Define and use a macro to invoke the operator.
+#define sluggo(TXT) __has_include__(TXT)
+
+#if sluggo(<complex>)
+#else
+#  error "<complex>"
+#endif
+
+#if ! sluggo(<complex>)
+#  error "<complex>"
+#else
+#endif
+
+//  Quoted complex.h should find at least the bracket version.
+#if __has_include("complex.h")
+#else
+#  error "complex.h"
+#endif
+
+//  Try known local quote header.
+#if __has_include("complex_literals.h")
+#else
+#  error "\"complex_literals.h\""
+#endif
+
+//  Try nonexistent bracket header.
+#if __has_include(<stuff>)
+#  error "<stuff>"
+#else
+#endif
+
+//  Try nonexistent quote header.
+#if __has_include("phlegm")
+#  error "\"phlegm\""
+#else
+#endif
+
+//  Test __has_include_next.
+#if __has_include("phoobhar.h")
+#  include "phoobhar.h"
+#else
+#  error "__has_include(\"phoobhar.h\")"
+#endif
+
+//  Try a macro.
+#define COMPLEX_INC "complex.h"
+#if __has_include(COMPLEX_INC)
+#else
+#  error COMPLEX_INC
+#endif
+
+//  Realistic use of __has_include.
+#if __has_include(<array>)
+#  define STD_ARRAY 1
+#  include <array>
+  template<typename _Tp, size_t _Num>
+    using array = std::array<_Tp, _Num>;
+#elif __has_include(<tr1/array>)
+#  define TR1_ARRAY 1
+#  include <tr1/array>
+  template<typename _Tp, size_t _Num>
+    typedef std::tr1::array<_Tp, _Num> array;
+#endif
Index: g++.dg/cpp1y/feat-cxx98.C
===================================================================
--- g++.dg/cpp1y/feat-cxx98.C	(revision 0)
+++ g++.dg/cpp1y/feat-cxx98.C	(working copy)
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++98_only } }
+// { dg-options "" }
+
+//  These C++14 features are allowed in C++98 in non-ANSI modes.
+#ifndef __cpp_binary_literals
+#  error "__cpp_binary_literals"
+#elif  __cpp_binary_literals != 201304
+#  error "__cpp_binary_literals != 201304"
+#endif
Index: g++.dg/cpp1y/feat-cxx98-neg.C
===================================================================
--- g++.dg/cpp1y/feat-cxx98-neg.C	(revision 0)
+++ g++.dg/cpp1y/feat-cxx98-neg.C	(working copy)
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++98_only } }
+// { dg-options "-ansi" }
+
+#ifdef __cpp_runtime_arrays
+#  error "__cpp_runtime_arrays" // { dg-error "error" }
+#endif
Index: g++.dg/cpp1y/phoobhar.h
===================================================================
--- g++.dg/cpp1y/phoobhar.h	(revision 0)
+++ g++.dg/cpp1y/phoobhar.h	(working copy)
@@ -0,0 +1,16 @@
+
+int
+phoo();
+
+int
+bhar();
+
+#ifndef __has_include_next
+#  error "__has_include_next"
+#else
+#  if __has_include_next("phoobhar.h")
+#    include_next "phoobhar.h"
+#  else
+#    error "__has_include_next(\"phoobhar.h\")"
+#  endif
+#endif
Index: g++.dg/cpp1y/testinc/phoobhar.h
===================================================================

Comments

Jason Merrill Sept. 30, 2014, 2:20 p.m. UTC | #1
On 09/29/2014 11:18 AM, Ed Smith-Rowland wrote:
> +  /* Nonzero to prevent macro expansion.  */
> +  unsigned char in__has_include__;

I don't see anything checking this flag to prevent macro expansion. 
Does the comment just need a change?

> +      /* Binary literals and variable length arrays have been allowed in g++
> +	 before C++11 and were standardized for C++14.  */
> +      if (!pedantic || cxx_dialect > cxx11)
> +	{
> +	  cpp_define (pfile, "__cpp_binary_literals=201304");
> +	}

This comment also needs an update.

> +//  Try a macro.
> +#define COMPLEX_INC "complex.h"
> +#if __has_include(COMPLEX_INC)
> +#else
> +#  error COMPLEX_INC
> +#endif

Are you sure this is what SD-6 means?  I interpret it as trying to 
specify something equivalent to the #include directive, namely that 
first we look for an explicit header-name, then try a more flexible 
parse that should include macro expansion.  But this can wait for a 
clarification from SG10.

The patch is OK with those comment tweaks.

Jason
diff mbox

Patch

Index: internal.h
===================================================================
--- internal.h	(revision 215628)
+++ internal.h	(working copy)
@@ -258,6 +258,9 @@ 
   /* Nonzero when parsing arguments to a function-like macro.  */
   unsigned char parsing_args;
 
+  /* Nonzero to prevent macro expansion.  */
+  unsigned char in__has_include__;
+
   /* Nonzero if prevent_expansion is true only because output is
      being discarded.  */
   unsigned char discarding_output;
@@ -279,6 +282,8 @@ 
   cpp_hashnode *n_true;			/* C++ keyword true */
   cpp_hashnode *n_false;		/* C++ keyword false */
   cpp_hashnode *n__VA_ARGS__;		/* C99 vararg macros */
+  cpp_hashnode *n__has_include__;	/* __has_include__ operator */
+  cpp_hashnode *n__has_include_next__;	/* __has_include_next__ operator */
 };
 
 typedef struct _cpp_line_note _cpp_line_note;
@@ -645,6 +650,8 @@ 
 extern bool _cpp_read_file_entries (cpp_reader *, FILE *);
 extern const char *_cpp_get_file_name (_cpp_file *);
 extern struct stat *_cpp_get_file_stat (_cpp_file *);
+extern bool _cpp_has_header (cpp_reader *, const char *, int,
+			     enum include_type);
 
 /* In expr.c */
 extern bool _cpp_parse_expr (cpp_reader *, bool);
@@ -680,6 +687,7 @@ 
 extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *,
 				 linenum_type, unsigned int);
 extern void _cpp_pop_buffer (cpp_reader *);
+extern char *_cpp_bracket_include (cpp_reader *);
 
 /* In directives.c */
 struct _cpp_dir_only_callbacks
Index: directives.c
===================================================================
--- directives.c	(revision 215628)
+++ directives.c	(working copy)
@@ -566,6 +566,11 @@ 
       if (is_def_or_undef && node == pfile->spec_nodes.n_defined)
 	cpp_error (pfile, CPP_DL_ERROR,
 		   "\"defined\" cannot be used as a macro name");
+      else if (is_def_or_undef
+	    && (node == pfile->spec_nodes.n__has_include__
+	     || node == pfile->spec_nodes.n__has_include_next__))
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "\"__has_include__\" cannot be used as a macro name");
       else if (! (node->flags & NODE_POISONED))
 	return node;
     }
@@ -2623,3 +2628,12 @@ 
       node->directive_index = i;
     }
 }
+
+/* Extract header file from a bracket include. Parsing starts after '<'.
+   The string is malloced and must be freed by the caller.  */
+char *
+_cpp_bracket_include(cpp_reader *pfile)
+{
+  return glue_header_name (pfile);
+}
+
Index: expr.c
===================================================================
--- expr.c	(revision 215628)
+++ expr.c	(working copy)
@@ -64,6 +64,8 @@ 
 static unsigned int interpret_int_suffix (cpp_reader *, const uchar *, size_t);
 static void check_promotion (cpp_reader *, const struct op *);
 
+static cpp_num parse_has_include (cpp_reader *, enum include_type);
+
 /* Token type abuse to create unary plus and minus operators.  */
 #define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
 #define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
@@ -1048,6 +1050,10 @@ 
     case CPP_NAME:
       if (token->val.node.node == pfile->spec_nodes.n_defined)
 	return parse_defined (pfile);
+      else if (token->val.node.node == pfile->spec_nodes.n__has_include__)
+	return parse_has_include (pfile, IT_INCLUDE);
+      else if (token->val.node.node == pfile->spec_nodes.n__has_include_next__)
+	return parse_has_include (pfile, IT_INCLUDE_NEXT);
       else if (CPP_OPTION (pfile, cplusplus)
 	       && (token->val.node.node == pfile->spec_nodes.n_true
 		   || token->val.node.node == pfile->spec_nodes.n_false))
@@ -2072,3 +2078,72 @@ 
 
   return lhs;
 }
+
+/* Handle meeting "__has_include__" in a preprocessor expression.  */
+static cpp_num
+parse_has_include (cpp_reader *pfile, enum include_type type)
+{
+  cpp_num result;
+  bool paren = false;
+  cpp_hashnode *node = 0;
+  const cpp_token *token;
+  bool bracket = false;
+  char *fname = 0;
+
+  result.unsignedp = false;
+  result.high = 0;
+  result.overflow = false;
+  result.low = 0;
+
+  pfile->state.in__has_include__++;
+
+  token = cpp_get_token (pfile);
+  if (token->type == CPP_OPEN_PAREN)
+    {
+      paren = true;
+      token = cpp_get_token (pfile);
+    }
+
+  if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
+    {
+      if (token->type == CPP_HEADER_NAME)
+	bracket = true;
+      fname = XNEWVEC (char, token->val.str.len - 1);
+      memcpy (fname, token->val.str.text + 1, token->val.str.len - 2);
+      fname[token->val.str.len - 2] = '\0';
+      node = token->val.node.node;
+    }
+  else if (token->type == CPP_LESS)
+    {
+      bracket = true;
+      fname = _cpp_bracket_include (pfile);
+    }
+  else
+    cpp_error (pfile, CPP_DL_ERROR,
+	       "operator \"__has_include__\" requires a header string");
+
+  if (fname)
+    {
+      int angle_brackets = (bracket ? 1 : 0);
+
+      if (_cpp_has_header (pfile, fname, angle_brackets, type))
+	result.low = 1;
+      else
+	result.low = 0;
+
+      XDELETEVEC (fname);
+    }
+
+  if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+    cpp_error (pfile, CPP_DL_ERROR,
+	       "missing ')' after \"__has_include__\"");
+
+  /* A possible controlling macro of the form #if !__has_include__ ().
+     _cpp_parse_expr checks there was no other junk on the line.  */
+  if (node)
+    pfile->mi_ind_cmacro = node;
+
+  pfile->state.in__has_include__--;
+
+  return result;
+}
Index: files.c
===================================================================
--- files.c	(revision 215628)
+++ files.c	(working copy)
@@ -1029,6 +1029,9 @@ 
   int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0;
   bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp);
 
+  if (pfile->state.in__has_include__)
+    return;
+
   errno = file->err_no;
   if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
     {
@@ -1945,3 +1948,18 @@ 
   return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
 		  pchf_compare) != NULL;
 }
+
+/* Return true if the file FNAME is found in the appropriate include file path
+   as indicated by ANGLE_BRACKETS.  */
+
+bool
+_cpp_has_header (cpp_reader *pfile, const char *fname, int angle_brackets,
+		 enum include_type type)
+{
+  cpp_dir *start_dir = search_path_head (pfile, fname, angle_brackets, type);
+  _cpp_file *file = _cpp_find_file (pfile, fname, start_dir,
+				    /*fake=*/false, angle_brackets,
+				    /*implicit_preinclude=*/false);
+  return file->err_no != ENOENT;
+}
+
Index: identifiers.c
===================================================================
--- identifiers.c	(revision 215628)
+++ identifiers.c	(working copy)
@@ -72,6 +72,8 @@ 
   s->n_false		= cpp_lookup (pfile, DSC("false"));
   s->n__VA_ARGS__       = cpp_lookup (pfile, DSC("__VA_ARGS__"));
   s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
+  s->n__has_include__   = cpp_lookup (pfile, DSC("__has_include__"));
+  s->n__has_include_next__ = cpp_lookup (pfile, DSC("__has_include_next__"));
 }
 
 /* Tear down the identifier hash table.  */
Index: pch.c
===================================================================
--- pch.c	(revision 215628)
+++ pch.c	(working copy)
@@ -833,6 +833,8 @@ 
     s->n_true		= cpp_lookup (r, DSC("true"));
     s->n_false		= cpp_lookup (r, DSC("false"));
     s->n__VA_ARGS__     = cpp_lookup (r, DSC("__VA_ARGS__"));
+    s->n__has_include__ = cpp_lookup (r, DSC("__has_include__"));
+    s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__"));
   }
 
   old_state = r->state;
Index: traditional.c
===================================================================
--- traditional.c	(revision 215628)
+++ traditional.c	(working copy)
@@ -74,7 +74,9 @@ 
 	 ls_defined_close,	/* Looking for ')' of defined().  */
 	 ls_hash,		/* After # in preprocessor conditional.  */
 	 ls_predicate,		/* After the predicate, maybe paren?  */
-	 ls_answer};		/* In answer to predicate.  */
+	 ls_answer,		/* In answer to predicate.  */
+	 ls_has_include,	/* After __has_include__.  */
+	 ls_has_include_close};	/* Looking for ')' of __has_include__.  */
 
 /* Lexing TODO: Maybe handle space in escaped newlines.  Stop lex.c
    from recognizing comments and directives during its lexing pass.  */
@@ -524,6 +526,13 @@ 
 		  lex_state = ls_defined;
 		  continue;
 		}
+	      else if (pfile->state.in_expression
+		       && (node == pfile->spec_nodes.n__has_include__
+			|| node == pfile->spec_nodes.n__has_include_next__))
+		{
+		  lex_state = ls_has_include;
+		  continue;
+		}
 	    }
 	  break;
 
@@ -547,6 +556,8 @@ 
 		lex_state = ls_answer;
 	      else if (lex_state == ls_defined)
 		lex_state = ls_defined_close;
+	      else if (lex_state == ls_has_include)
+		lex_state = ls_has_include_close;
 	    }
 	  break;
 
@@ -584,7 +595,8 @@ 
 		      goto new_context;
 		    }
 		}
-	      else if (lex_state == ls_answer || lex_state == ls_defined_close)
+	      else if (lex_state == ls_answer || lex_state == ls_defined_close
+			|| lex_state == ls_has_include_close)
 		lex_state = ls_none;
 	    }
 	  break;
@@ -665,7 +677,8 @@ 
 	lex_state = ls_none;
       else if (lex_state == ls_hash
 	       || lex_state == ls_predicate
-	       || lex_state == ls_defined)
+	       || lex_state == ls_defined
+	       || lex_state == ls_has_include)
 	lex_state = ls_none;
 
       /* ls_answer and ls_defined_close keep going until ')'.  */