Here is the libcpp portion.

2014-05-31  Ed Smith-Rowland  <3dw...@verizon.net>

        Implement SD-6: SG10 Feature Test Recommendations
        * 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__.
        * internal.h (lexer_state, spec_nodes): Add in__has_include__.
        * pch.c (cpp_read_state): Lookup __has_include__.
        * traditional.c (enum ls, _cpp_scan_out_logical_line()): Walk through
        __has_include__ statements.
Index: directives.c
===================================================================
--- directives.c        (revision 211078)
+++ directives.c        (working copy)
@@ -549,6 +549,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;
     }
@@ -2601,3 +2606,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 211078)
+++ 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))
@@ -1041,6 +1043,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))
@@ -2065,3 +2071,71 @@
 
   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 = 0;
+      else
+       result.low = 1;
+
+      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 211078)
+++ 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,17 @@
   return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
                  pchf_compare) != NULL;
 }
+
+/* Return true if the file FNAME is found in te 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);
+  return _cpp_find_failed (_cpp_find_file (pfile, fname, start_dir,
+                          /*fake=*/false, angle_brackets,
+                          /*implicit_preinclude=*/false));
+}
+
Index: identifiers.c
===================================================================
--- identifiers.c       (revision 211078)
+++ 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: internal.h
===================================================================
--- internal.h  (revision 211078)
+++ 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: pch.c
===================================================================
--- pch.c       (revision 211078)
+++ 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 211078)
+++ 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 ')'.  */

Reply via email to