On 7/28/23 07:14, Lewis Hyatt wrote:
On Thu, Jul 27, 2023 at 06:18:33PM -0700, Jason Merrill wrote:
On 7/27/23 18:59, Lewis Hyatt wrote:
In order to support processing #pragma in preprocess-only mode (-E or
-save-temps for gcc/g++), we need a way to obtain the #pragma tokens from
libcpp. In full compilation modes, this is accomplished by calling
pragma_lex (), which is a symbol that must be exported by the frontend, and
which is currently implemented for C and C++. Neither of those frontends
initializes its parser machinery in preprocess-only mode, and consequently
pragma_lex () does not work in this case.

Address that by adding a new function c_init_preprocess () for the frontends
to implement, which arranges for pragma_lex () to work in preprocess-only
mode, and adjusting pragma_lex () accordingly.

In preprocess-only mode, the preprocessor is accustomed to controlling the
interaction with libcpp, and it only knows about tokens that it has called
into libcpp itself to obtain. Since it still needs to see the tokens
obtained by pragma_lex () so that they can be streamed to the output, also
adjust c_lex_with_flags () and related functions in c-family/c-lex.cc to
inform the preprocessor about any tokens it won't be aware of.

Currently, there is one place where we are already supporting #pragma in
preprocess-only mode, namely the handling of `#pragma GCC diagnostic'.  That
was done by directly interfacing with libcpp, rather than making use of
pragma_lex (). Now that pragma_lex () works, that code is no longer
necessary; remove it.

gcc/c-family/ChangeLog:

        * c-common.h (c_init_preprocess): Declare.
        (c_lex_enable_token_streaming): Declare.
        * c-opts.cc (c_common_init): Call c_init_preprocess ().
        * c-lex.cc (stream_tokens_to_preprocessor): New static variable.
        (c_lex_enable_token_streaming): New function.
        (cb_def_pragma): Add a comment.
        (get_token): New function wrapping cpp_get_token.
        (c_lex_with_flags): Use the new wrapper function to support
        obtaining tokens in preprocess_only mode.
        (lex_string): Likewise.
        * c-ppoutput.cc (preprocess_file): Call c_lex_enable_token_streaming
        when needed.
        * c-pragma.cc (pragma_diagnostic_lex_normal): Rename to...
        (pragma_diagnostic_lex): ...this.
        (pragma_diagnostic_lex_pp): Remove.
        (handle_pragma_diagnostic_impl): Call pragma_diagnostic_lex () in
        all modes.
        (c_pp_invoke_early_pragma_handler): Adapt to support pragma_lex ()
        usage.
        * c-pragma.h (pragma_lex_discard_to_eol): Declare.

gcc/c/ChangeLog:

        * c-parser.cc (pragma_lex_discard_to_eol): New function.
        (c_init_preprocess): New function.

gcc/cp/ChangeLog:

        * parser.cc (c_init_preprocess): New function.
        (maybe_read_tokens_for_pragma_lex): New function.
        (pragma_lex): Support preprocess-only mode.
        (pragma_lex_discard_to_eol): New function.
---

Notes:
      Hello-
      Here is version 2 of the patch, incorporating Jason's feedback from
      https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625591.html
      Thanks again, please let me know if it's OK? Bootstrap + regtest all
      languages on x86-64 Linux looks good.
      -Lewis

   gcc/c-family/c-common.h    |  4 +++
   gcc/c-family/c-lex.cc      | 49 +++++++++++++++++++++++++++++----
   gcc/c-family/c-opts.cc     |  1 +
   gcc/c-family/c-ppoutput.cc | 17 +++++++++---
   gcc/c-family/c-pragma.cc   | 56 ++++++--------------------------------
   gcc/c-family/c-pragma.h    |  2 ++
   gcc/c/c-parser.cc          | 21 ++++++++++++++
   gcc/cp/parser.cc           | 45 ++++++++++++++++++++++++++++++
   8 files changed, 138 insertions(+), 57 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index b5ef5ff6b2c..2fe2f194660 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -990,6 +990,9 @@ extern void c_parse_file (void);
   extern void c_parse_final_cleanups (void);
+/* This initializes for preprocess-only mode.  */
+extern void c_init_preprocess (void);
+
   /* These macros provide convenient access to the various _STMT nodes.  */
   /* Nonzero if a given STATEMENT_LIST represents the outermost binding
@@ -1214,6 +1217,7 @@ extern tree c_build_bind_expr (location_t, tree, tree);
   /* In c-lex.cc.  */
   extern enum cpp_ttype
   conflict_marker_get_final_tok_kind (enum cpp_ttype tok1_kind);
+extern void c_lex_enable_token_streaming (bool enabled);
   /* In c-pch.cc  */
   extern void pch_init (void);
diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc
index dcd061c7cb1..ac4c018d863 100644
--- a/gcc/c-family/c-lex.cc
+++ b/gcc/c-family/c-lex.cc
@@ -57,6 +57,17 @@ static void cb_ident (cpp_reader *, unsigned int, const 
cpp_string *);
   static void cb_def_pragma (cpp_reader *, unsigned int);
   static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *);
   static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *);
+
+/* Flag to remember if we are in a mode (such as flag_preprocess_only) in which
+   tokens obtained here need to be streamed to the preprocessor.  */
+static bool stream_tokens_to_preprocessor = false;
+
+void
+c_lex_enable_token_streaming (bool enabled)
+{
+  stream_tokens_to_preprocessor = enabled;
+}
+
   
   void
   init_c_lex (void)
@@ -249,6 +260,10 @@ cb_def_pragma (cpp_reader *pfile, location_t loc)
         location_t fe_loc = loc;
         space = name = (const unsigned char *) "";
+
+      /* N.B.  It's fine to call cpp_get_token () directly here (rather than 
our
+        local wrapper get_token ()), because this callback is not used with
+        flag_preprocess_only==true.  */
         s = cpp_get_token (pfile);
         if (s->type != CPP_EOF)
        {
@@ -284,8 +299,32 @@ cb_undef (cpp_reader *pfile, location_t loc, cpp_hashnode 
*node)
                         (const char *) NODE_NAME (node));
   }
+/* Wrapper around cpp_get_token_with_location to stream the token to the
+   preprocessor so it can output it.  This is necessary with
+   flag_preprocess_only if we are obtaining tokens here instead of from the 
loop
+   in c-ppoutput.cc, such as while processing a #pragma.  */
+
+static const cpp_token *
+get_token (cpp_reader *pfile, location_t *loc = nullptr)
+{
+  if (stream_tokens_to_preprocessor)

We can't use flag_preprocess_only here?

Thanks, I had thought there could be a potential issue with needing to also
check cpp_get_options(pfile)->traditional. But looking at it more, there's no
code path currently that can end up here in traditional mode, so yes we can
eliminate stream_tokens_to_preprocessor and just check flag_preprocess_only.

The attached simplified patch does this, bootstrap + regtest look good as
well.

LGTM, I'll let the C maintainers comment on the C parser change.

Jason

Reply via email to