From e235031d490e8ed2aa0bc229694975493fd58977 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 14 Feb 2020 09:04:14 +0100 Subject: [PATCH] c++: Partially implement P1042R1: __VA_OPT__ wording clarifications [PR92319] I've noticed we claim in cxx-status.html that we implement P1042R1, but it seems we don't implement any of the changes from there. The following patch implements just the change that __VA_OPT__ determines whether to expand to nothing or the enclosed tokens no longer based on whether there were any tokens passed to __VA_ARGS__, but whether __VA_ARGS__ expands to any tokens (from testing apparently it has to be non-CPP_PADDING tokens). I'm afraid I'm completely lost about the padding preservation/removal changes that are also in the paper, so haven't touched that part. 2020-02-14 Jakub Jelinek Partially implement P1042R1: __VA_OPT__ wording clarifications PR preprocessor/92319 * macro.c (expand_arg): Move declarations before vaopt_state definition. (class vaopt_state): Move enum update_type definition earlier. Remove m_allowed member, add m_arg and m_update members. (vaopt_state::vaopt_state): Change last argument from bool any_args to macro_arg *arg, initialize m_arg and m_update instead of m_allowed. (vaopt_state::update): When bumping m_state from 1 to 2 and m_update is ERROR, determine if __VA_ARGS__ expansion has any non-CPP_PADDING tokens and set m_update to INCLUDE if it has any, DROP otherwise. Return m_update instead of m_allowed ? INCLUDE : DROP in m_state >= 2. (replace_args, create_iso_definition): Adjust last argument to vaopt_state ctor. * c-c++-common/cpp/va-opt-4.c: New test. --- gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/c-c++-common/cpp/va-opt-4.c | 20 ++++++++ libcpp/ChangeLog | 17 +++++++ libcpp/macro.c | 61 ++++++++++++++++------- 4 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/cpp/va-opt-4.c diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a262bdde886..e42751e5658 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-02-14 Jakub Jelinek + + Partially implement P1042R1: __VA_OPT__ wording clarifications + PR preprocessor/92319 + * c-c++-common/cpp/va-opt-4.c: New test. + 2020-02-13 Jakub Jelinek PR c/93576 diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-4.c b/gcc/testsuite/c-c++-common/cpp/va-opt-4.c new file mode 100644 index 00000000000..57241bc80fa --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-4.c @@ -0,0 +1,20 @@ +/* PR preprocessor/92319 */ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++2a" { target c++ } } */ + +#define f1(...) b##__VA_OPT__(c) +#define e +#define e2 e +#define e3 1 +#define e5 e3 +t1 f1 (e); +/* { dg-final { scan-file va-opt-4.i "t1 b;" } } */ +t2 f1 (e2); +/* { dg-final { scan-file va-opt-4.i "t2 b;" } } */ +t3 f1 (e3); +/* { dg-final { scan-file va-opt-4.i "t3 bc;" } } */ +t4 f1 (e4); +/* { dg-final { scan-file va-opt-4.i "t4 bc;" } } */ +t5 f1 (e5); +/* { dg-final { scan-file va-opt-4.i "t5 bc;" } } */ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 65e8f400679..307cf3add94 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,20 @@ +2020-02-14 Jakub Jelinek + + Partially implement P1042R1: __VA_OPT__ wording clarifications + PR preprocessor/92319 + * macro.c (expand_arg): Move declarations before vaopt_state + definition. + (class vaopt_state): Move enum update_type definition earlier. Remove + m_allowed member, add m_arg and m_update members. + (vaopt_state::vaopt_state): Change last argument from bool any_args + to macro_arg *arg, initialize m_arg and m_update instead of m_allowed. + (vaopt_state::update): When bumping m_state from 1 to 2 and m_update + is ERROR, determine if __VA_ARGS__ expansion has any non-CPP_PADDING + tokens and set m_update to INCLUDE if it has any, DROP otherwise. + Return m_update instead of m_allowed ? INCLUDE : DROP in m_state >= 2. + (replace_args, create_iso_definition): Adjust last argument to + vaopt_state ctor. + 2020-02-05 Martin Sebor * include/cpplib.h (cpp_builtin_type): Remove trailing comma to diff --git a/libcpp/macro.c b/libcpp/macro.c index ec0030742c0..2573f316bf5 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -93,6 +93,8 @@ struct macro_arg_saved_data { static const char *vaopt_paste_error = N_("'##' cannot appear at either end of __VA_OPT__"); +static void expand_arg (cpp_reader *, macro_arg *); + /* A class for tracking __VA_OPT__ state while iterating over a sequence of tokens. This is used during both macro definition and expansion. */ @@ -100,28 +102,29 @@ class vaopt_state { public: + enum update_type + { + ERROR, + DROP, + INCLUDE, + BEGIN, + END + }; + /* Initialize the state tracker. ANY_ARGS is true if variable arguments were provided to the macro invocation. */ - vaopt_state (cpp_reader *pfile, bool is_variadic, bool any_args) + vaopt_state (cpp_reader *pfile, bool is_variadic, macro_arg *arg) : m_pfile (pfile), - m_allowed (any_args), + m_arg (arg), m_variadic (is_variadic), m_last_was_paste (false), m_state (0), m_paste_location (0), - m_location (0) + m_location (0), + m_update (ERROR) { } - enum update_type - { - ERROR, - DROP, - INCLUDE, - BEGIN, - END - }; - /* Given a token, update the state of this tracker and return a boolean indicating whether the token should be be included in the expansion. */ @@ -154,6 +157,23 @@ class vaopt_state { return ERROR; } ++m_state; + if (m_update == ERROR) + { + if (m_arg == NULL) + m_update = INCLUDE; + else + { + m_update = DROP; + if (!m_arg->expanded) + expand_arg (m_pfile, m_arg); + for (unsigned idx = 0; idx < m_arg->expanded_count; ++idx) + if (m_arg->expanded[idx]->type != CPP_PADDING) + { + m_update = INCLUDE; + break; + } + } + } return DROP; } else if (m_state >= 2) @@ -197,7 +217,7 @@ class vaopt_state { return END; } } - return m_allowed ? INCLUDE : DROP; + return m_update; } /* Nothing to do with __VA_OPT__. */ @@ -219,8 +239,9 @@ class vaopt_state { /* The cpp_reader. */ cpp_reader *m_pfile; - /* True if there were varargs. */ - bool m_allowed; + /* The __VA_ARGS__ argument. */ + macro_arg *m_arg; + /* True if the macro is variadic. */ bool m_variadic; /* If true, the previous token was ##. This is used to detect when @@ -239,6 +260,10 @@ class vaopt_state { /* Location of the __VA_OPT__ token. */ location_t m_location; + + /* If __VA_ARGS__ substitutes to no preprocessing tokens, + INCLUDE, otherwise DROP. ERROR when unknown yet. */ + update_type m_update; }; /* Macro expansion. */ @@ -256,7 +281,6 @@ static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *, _cpp_buff **, unsigned *); static cpp_context *next_context (cpp_reader *); static const cpp_token *padding_token (cpp_reader *, const cpp_token *); -static void expand_arg (cpp_reader *, macro_arg *); static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int); static const cpp_token *stringify_arg (cpp_reader *, macro_arg *); static void paste_all_tokens (cpp_reader *, const cpp_token *); @@ -1924,8 +1948,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, num_macro_tokens); } i = 0; - vaopt_state vaopt_tracker (pfile, macro->variadic, - args[macro->paramc - 1].count > 0); + vaopt_state vaopt_tracker (pfile, macro->variadic, &args[macro->paramc - 1]); const cpp_token **vaopt_start = NULL; for (src = macro->exp.tokens; src < limit; src++) { @@ -3424,7 +3447,7 @@ create_iso_definition (cpp_reader *pfile) macro->count = 1; } - for (vaopt_state vaopt_tracker (pfile, macro->variadic, true);; token = NULL) + for (vaopt_state vaopt_tracker (pfile, macro->variadic, NULL);; token = NULL) { if (!token) { -- 2.30.2