public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Nathan Sidwell <nathan@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc/devel/c++-modules] preprocessor: Make __has_include a builtin macro [PR93452]
Date: Fri, 31 Jan 2020 17:47:00 -0000	[thread overview]
Message-ID: <20200131174630.12992.qmail@sourceware.org> (raw)

https://gcc.gnu.org/g:3d056cbfb3484f4037b34c908b26e1c6776c86b5

commit 3d056cbfb3484f4037b34c908b26e1c6776c86b5
Author: Nathan Sidwell <nathan@acm.org>
Date:   Tue Jan 28 07:58:29 2020 -0800

    preprocessor: Make __has_include a builtin macro [PR93452]
    
    The clever hack of '#define __has_include __has_include' breaks -dD
    and -fdirectives-only, because that emits definitions.  This turns
    __has_include into a proper builtin macro.  Thus it's never emitted
    via -dD, and because use outside of directive processing is undefined,
    we can just expand it anywhere.
    
    	PR preprocessor/93452
    	* internal.h (struct spec_nodes): Drop n__has_include{,_next}.
    	* directives.c (lex_macro_node): Don't check __has_include redef.
    	* expr.c (eval_token): Drop __has_include eval.
    	(parse_has_include): Move to ...
    	* macro.c (builtin_has_include): ... here.
    	(_cpp_builtin_macro_text): Eval __has_include{,_next}.
    	* include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_INCLUDE{,_NEXT}.
    	* init.c (builtin_array): Add them.
    	(cpp_init_builtins): Drop __has_include{,_next} init here ...
    	* pch.c (cpp_read_state): ... and here.
    	* traditional.c (enum ls): Drop has_include states ...
    	(_cpp_scan_out_logical_line): ... and here.

Diff:
---
 gcc/testsuite/c-c++-common/cpp/pr93452-1.c | 10 ++++++
 gcc/testsuite/c-c++-common/cpp/pr93452-2.c | 11 ++++++
 libcpp/ChangeLog                           | 16 +++++++++
 libcpp/directives.c                        |  4 +--
 libcpp/expr.c                              | 58 ------------------------------
 libcpp/include/cpplib.h                    |  4 ++-
 libcpp/init.c                              | 13 ++-----
 libcpp/internal.h                          |  2 --
 libcpp/macro.c                             | 56 +++++++++++++++++++++++++++++
 libcpp/pch.c                               |  2 --
 libcpp/traditional.c                       | 20 +++--------
 11 files changed, 103 insertions(+), 93 deletions(-)

diff --git a/gcc/testsuite/c-c++-common/cpp/pr93452-1.c b/gcc/testsuite/c-c++-common/cpp/pr93452-1.c
new file mode 100644
index 0000000..f0986e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr93452-1.c
@@ -0,0 +1,10 @@
+/* { dg-do preprocess } */
+/* { dg-additional-options "-fdirectives-only" } */
+
+int main ()
+{
+  return 0;
+}
+
+/* A regexp that doesn't match itself!  */
+/* { dg-final { scan-file-not pr93452-1.i {_[_]has_include} } } */
diff --git a/gcc/testsuite/c-c++-common/cpp/pr93452-2.c b/gcc/testsuite/c-c++-common/cpp/pr93452-2.c
new file mode 100644
index 0000000..c9ab0e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr93452-2.c
@@ -0,0 +1,11 @@
+/* { dg-do preprocess } */
+/* { dg-additional-options "-dD" } */
+
+#if __has_include ("who cares" )
+#endif
+int main ()
+{
+  return 0;
+}
+
+/* { dg-final { scan-file-not pr93452-2.i {__has_include} } } */
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index ea9d602..f749622 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,19 @@
+2020-01-28  Nathan Sidwell  <nathan@acm.org>
+
+	PR preprocessor/93452
+	* internal.h (struct spec_nodes): Drop n__has_include{,_next}.
+	* directives.c (lex_macro_node): Don't check __has_include redef.
+	* expr.c (eval_token): Drop __has_include eval.
+	(parse_has_include): Move to ...
+	* macro.c (builtin_has_include): ... here.
+	(_cpp_builtin_macro_text): Eval __has_include{,_next}.
+	* include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_INCLUDE{,_NEXT}.
+	* init.c (builtin_array): Add them.
+	(cpp_init_builtins): Drop __has_include{,_next} init here ...
+	* pch.c (cpp_read_state): ... and here.
+	* traditional.c (enum ls): Drop has_include states ...
+	(_cpp_scan_out_logical_line): ... and here.
+
 2020-01-27  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* configure: Regenerate.
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 10735c8..bbfdfcd 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -596,9 +596,7 @@ lex_macro_node (cpp_reader *pfile, bool is_def_or_undef)
       cpp_hashnode *node = token->val.node.node;
 
       if (is_def_or_undef
-	  && (node == pfile->spec_nodes.n_defined
-	      || node == pfile->spec_nodes.n__has_include
-	      || node == pfile->spec_nodes.n__has_include_next))
+	  && node == pfile->spec_nodes.n_defined)
 	cpp_error (pfile, CPP_DL_ERROR,
 		   "\"%s\" cannot be used as a macro name",
 		   NODE_NAME (node));
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 6c56803..2ae9be0 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -64,8 +64,6 @@ static unsigned int interpret_float_suffix (cpp_reader *, const uchar *, size_t)
 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 *, cpp_hashnode *, 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))
@@ -1159,10 +1157,6 @@ eval_token (cpp_reader *pfile, const cpp_token *token,
     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, token->val.node.node, IT_INCLUDE);
-      else if (token->val.node.node == pfile->spec_nodes.n__has_include_next)
-	return parse_has_include (pfile, token->val.node.node, 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))
@@ -2189,55 +2183,3 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
   return lhs;
 }
 
-/* Handle meeting "__has_include" in a preprocessor expression.  */
-static cpp_num
-parse_has_include (cpp_reader *pfile, cpp_hashnode *op, include_type type)
-{
-  cpp_num result;
-
-  result.unsignedp = false;
-  result.high = 0;
-  result.overflow = false;
-  result.low = 0;
-
-  pfile->state.angled_headers = true;
-  const cpp_token *token = cpp_get_token (pfile);
-  bool paren = token->type == CPP_OPEN_PAREN;
-  if (paren)
-    token = cpp_get_token (pfile);
-  else
-    cpp_error (pfile, CPP_DL_ERROR,
-	       "missing '(' before \"%s\" operand", NODE_NAME (op));
-  pfile->state.angled_headers = false;
-
-  bool bracket = token->type != CPP_STRING;
-  char *fname = NULL;
-  if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
-    {
-      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';
-    }
-  else if (token->type == CPP_LESS)
-    fname = _cpp_bracket_include (pfile);
-  else
-    cpp_error (pfile, CPP_DL_ERROR,
-	       "operator \"%s\" requires a header-name", NODE_NAME (op));
-
-  if (fname)
-    {
-      /* Do not do the lookup if we're skipping, that's unnecessary
-	 IO.  */
-      if (!pfile->state.skip_eval
-	  && _cpp_has_header (pfile, fname, bracket, type))
-	result.low = 1;
-
-      XDELETEVEC (fname);
-    }
-
-  if (paren && !SEEN_EOL () && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
-    cpp_error (pfile, CPP_DL_ERROR,
-	       "missing ')' after \"%s\" operand", NODE_NAME (op));
-
-  return result;
-}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 56cbbd8..07caadb 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -860,7 +860,9 @@ enum cpp_builtin_type
   BT_TIMESTAMP,			/* `__TIMESTAMP__' */
   BT_COUNTER,			/* `__COUNTER__' */
   BT_HAS_ATTRIBUTE,		/* `__has_attribute(x)' */
-  BT_HAS_BUILTIN		/* `__has_builtin(x)' */
+  BT_HAS_BUILTIN,		/* `__has_builtin(x)' */
+  BT_HAS_INCLUDE,		/* `__has_include(x)' */
+  BT_HAS_INCLUDE_NEXT,		/* `__has_include_next(x)' */
 };
 
 #define CPP_HASHNODE(HNODE)	((cpp_hashnode *) (HNODE))
diff --git a/libcpp/init.c b/libcpp/init.c
index e798140..a3cd8e2 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -404,6 +404,8 @@ static const struct builtin_macro builtin_array[] =
   B("__has_attribute",	 BT_HAS_ATTRIBUTE, true),
   B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, true),
   B("__has_builtin",	 BT_HAS_BUILTIN,   true),
+  B("__has_include",	 BT_HAS_INCLUDE,   true),
+  B("__has_include_next",BT_HAS_INCLUDE_NEXT,   true),
   /* Keep builtins not used for -traditional-cpp at the end, and
      update init_builtins() if any more are added.  */
   B("_Pragma",		 BT_PRAGMA,        true),
@@ -578,17 +580,6 @@ cpp_init_builtins (cpp_reader *pfile, int hosted)
 
   if (CPP_OPTION (pfile, objc))
     _cpp_define_builtin (pfile, "__OBJC__ 1");
-
-  /* These two behave as macros for #ifdef, but are evaluated
-     specially inside #if.  */
-  _cpp_define_builtin (pfile, "__has_include __has_include");
-  _cpp_define_builtin (pfile, "__has_include_next __has_include_next");
-  pfile->spec_nodes.n__has_include
-    = cpp_lookup (pfile, DSC("__has_include"));
-  pfile->spec_nodes.n__has_include->flags |= NODE_DIAGNOSTIC;
-  pfile->spec_nodes.n__has_include_next
-    = cpp_lookup (pfile, DSC("__has_include_next"));
-  pfile->spec_nodes.n__has_include_next->flags |= NODE_DIAGNOSTIC;
 }
 
 /* Sanity-checks are dependent on command-line options, so it is
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 5453c3b..97d9bdb 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -290,8 +290,6 @@ struct spec_nodes
   cpp_hashnode *n_false;		/* C++ keyword false */
   cpp_hashnode *n__VA_ARGS__;		/* C99 vararg macros */
   cpp_hashnode *n__VA_OPT__;		/* C++ 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;
diff --git a/libcpp/macro.c b/libcpp/macro.c
index dbd7a28..ec3f8b7 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -336,6 +336,56 @@ unsigned num_expanded_macros_counter = 0;
    from macro expansion.  */
 unsigned num_macro_tokens_counter = 0;
 
+/* Handle meeting "__has_include" builtin macro.  */
+
+static int
+builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next)
+{
+  int result = 0;
+
+  pfile->state.angled_headers = true;
+  const cpp_token *token = cpp_get_token (pfile);
+  bool paren = token->type == CPP_OPEN_PAREN;
+  if (paren)
+    token = cpp_get_token (pfile);
+  else
+    cpp_error (pfile, CPP_DL_ERROR,
+	       "missing '(' before \"%s\" operand", NODE_NAME (op));
+  pfile->state.angled_headers = false;
+
+  bool bracket = token->type != CPP_STRING;
+  char *fname = NULL;
+  if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
+    {
+      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';
+    }
+  else if (token->type == CPP_LESS)
+    fname = _cpp_bracket_include (pfile);
+  else
+    cpp_error (pfile, CPP_DL_ERROR,
+	       "operator \"%s\" requires a header-name", NODE_NAME (op));
+
+  if (fname)
+    {
+      /* Do not do the lookup if we're skipping, that's unnecessary
+	 IO.  */
+      if (!pfile->state.skip_eval
+	  && _cpp_has_header (pfile, fname, bracket,
+			      has_next ? IT_INCLUDE_NEXT : IT_INCLUDE))
+	result = 1;
+
+      XDELETEVEC (fname);
+    }
+
+  if (paren && !SEEN_EOL () && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+    cpp_error (pfile, CPP_DL_ERROR,
+	       "missing ')' after \"%s\" operand", NODE_NAME (op));
+
+  return result;
+}
+
 /* Emits a warning if NODE is a macro defined in the main file that
    has not been used.  */
 int
@@ -572,6 +622,12 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
     case BT_HAS_BUILTIN:
       number = pfile->cb.has_builtin (pfile);
       break;
+
+    case BT_HAS_INCLUDE:
+    case BT_HAS_INCLUDE_NEXT:
+      number = builtin_has_include (pfile, node,
+				    node->value.builtin == BT_HAS_INCLUDE_NEXT);
+      break;
     }
 
   if (result == NULL)
diff --git a/libcpp/pch.c b/libcpp/pch.c
index e631050..fcdf387 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -811,8 +811,6 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
     s->n_false		= cpp_lookup (r, DSC("false"));
     s->n__VA_ARGS__     = cpp_lookup (r, DSC("__VA_ARGS__"));
     s->n__VA_OPT__      = cpp_lookup (r, DSC("__VA_OPT__"));
-    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;
diff --git a/libcpp/traditional.c b/libcpp/traditional.c
index ff06d31..039fcfe 100644
--- a/libcpp/traditional.c
+++ b/libcpp/traditional.c
@@ -77,9 +77,8 @@ enum ls {ls_none = 0,		/* Normal state.  */
 	 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_has_include,	/* After __has_include.  */
-	 ls_has_include_close};	/* Looking for ')' of __has_include.  */
+	 ls_answer		/* In answer to predicate.  */
+};
 
 /* Lexing TODO: Maybe handle space in escaped newlines.  Stop lex.c
    from recognizing comments and directives during its lexing pass.  */
@@ -564,13 +563,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
 		  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;
 
@@ -594,8 +586,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
 		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;
 
@@ -729,8 +719,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
 		      goto new_context;
 		    }
 		}
-	      else if (lex_state == ls_answer || lex_state == ls_defined_close
-			|| lex_state == ls_has_include_close)
+	      else if (lex_state == ls_answer || lex_state == ls_defined_close)
 		lex_state = ls_none;
 	    }
 	  break;
@@ -811,8 +800,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
 	lex_state = ls_none;
       else if (lex_state == ls_hash
 	       || lex_state == ls_predicate
-	       || lex_state == ls_defined
-	       || lex_state == ls_has_include)
+	       || lex_state == ls_defined)
 	lex_state = ls_none;
 
       /* ls_answer and ls_defined_close keep going until ')'.  */


                 reply	other threads:[~2020-01-31 17:47 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200131174630.12992.qmail@sourceware.org \
    --to=nathan@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).