Implement __VA_OPT__

This implements __VA_OPT__, a new preprocessor feature added in C++2A.
The paper can be found here:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0306r4.html

gcc/ChangeLog

        * doc/cpp.texi (Variadic Macros): Document __VA_OPT__.

gcc/testsuite/ChangeLog

        * c-c++-common/cpp/va-opt-pedantic.c: New file.
        * c-c++-common/cpp/va-opt.c: New file.
        * c-c++-common/cpp/va-opt-error.c: New file.

libcpp/ChangeLog

        * pch.c (cpp_read_state): Set n__VA_OPT__.
        * macro.c (vaopt_state): New class.
        (_cpp_arguments_ok): Check va_opt flag.
        (replace_args, create_iso_definition): Use vaopt_state.
        * lex.c (lex_identifier_intern): Possibly issue errors for
        __VA_OPT__.
        (lex_identifier): Likewise.
        (maybe_va_opt_error): New function.
        * internal.h (struct lexer_state) <va_args_ok>: Update comment.
        (struct spec_nodes) <n__VA_OPT__>: New field.
        * init.c (struct lang_flags) <va_opt>: New field.
        (lang_defaults): Add entries for C++2A.  Update all entries for
        va_opt.
        (cpp_set_lang): Initialize va_opt.
        * include/cpplib.h (struct cpp_options) <va_opt>: New field.
        * identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.

From-SVN: r254707
This commit is contained in:
Tom Tromey 2017-11-13 20:17:42 +00:00 committed by Tom Tromey
parent 4d85d48027
commit fb771b9dad
14 changed files with 369 additions and 34 deletions

View File

@ -1,3 +1,7 @@
2017-11-13 Tom Tromey <tom@tromey.com>
* doc/cpp.texi (Variadic Macros): Document __VA_OPT__.
2017-11-13 Carl Love <cel@us.ibm.com>
* config/rs6000/rs6000-c.c (altivec_overloaded_builtins):

View File

@ -1675,20 +1675,27 @@ macro. We could define @code{eprintf} like this, instead:
@end smallexample
@noindent
This formulation looks more descriptive, but unfortunately it is less
flexible: you must now supply at least one argument after the format
string. In standard C, you cannot omit the comma separating the named
argument from the variable arguments. Furthermore, if you leave the
variable argument empty, you will get a syntax error, because
there will be an extra comma after the format string.
This formulation looks more descriptive, but historically it was less
flexible: you had to supply at least one argument after the format
string. In standard C, you could not omit the comma separating the
named argument from the variable arguments. (Note that this
restriction has been lifted in C++2a, and never existed in GNU C; see
below.)
Furthermore, if you left the variable argument empty, you would have
gotten a syntax error, because there would have been an extra comma
after the format string.
@smallexample
eprintf("success!\n", );
@expansion{} fprintf(stderr, "success!\n", );
@end smallexample
GNU CPP has a pair of extensions which deal with this problem. First,
you are allowed to leave the variable argument out entirely:
This has been fixed in C++2a, and GNU CPP also has a pair of
extensions which deal with this problem.
First, in GNU CPP, and in C++ beginning in C++2a, you are allowed to
leave the variable argument out entirely:
@smallexample
eprintf ("success!\n")
@ -1696,8 +1703,24 @@ eprintf ("success!\n")
@end smallexample
@noindent
Second, the @samp{##} token paste operator has a special meaning when
placed between a comma and a variable argument. If you write
Second, C++2a introduces the @code{@w{__VA_OPT__}} function macro.
This macro may only appear in the definition of a variadic macro. If
the variable argument has any tokens, then a @code{@w{__VA_OPT__}}
invocation expands to its argument; but if the variable argument does
not have any tokens, the @code{@w{__VA_OPT__}} expands to nothing:
@smallexample
#define eprintf(format, @dots{}) \\
fprintf (stderr, format __VA_OPT__(,) __VA_ARGS__)
@end smallexample
@code{@w{__VA_OPT__}} is also available in GNU C and GNU C++.
Historically, GNU CPP has also had another extension to handle the
trailing comma: the @samp{##} token paste operator has a special
meaning when placed between a comma and a variable argument. Despite
the introduction of @code{@w{__VA_OPT__}}, this extension remains
supported in GNU CPP, for backward compatibility. If you write
@smallexample
#define eprintf(format, @dots{}) fprintf (stderr, format, ##__VA_ARGS__)
@ -1730,6 +1753,9 @@ of macro. It may also be forbidden in open text; the standard is
ambiguous. We recommend you avoid using it except for its defined
purpose.
Likewise, C++ forbids @code{@w{__VA_OPT__}} anywhere outside the
replacement list of a variadic macro.
Variadic macros became a standard part of the C language with C99.
GNU CPP previously supported them
with a named variable argument

View File

@ -1,3 +1,9 @@
2017-11-13 Tom Tromey <tom@tromey.com>
* c-c++-common/cpp/va-opt-pedantic.c: New file.
* c-c++-common/cpp/va-opt.c: New file.
* c-c++-common/cpp/va-opt-error.c: New file.
2017-11-13 Carl Love <cel@us.ibm.com>
* gcc.target/powerpc/builtins-6-p9-runnable.c: Add new runnable test.

View File

@ -0,0 +1,28 @@
/* { dg-do preprocess }*/
/* { dg-options "-std=gnu99" { target c } } */
/* { dg-options "-std=c++2a" { target c++ } } */
#define ERR1(x) __VA_OPT__ /* { dg-warning "__VA_OPT__ can only appear" } */
#define ERR2(x) __VA_OPT__( /* { dg-warning "can only appear" } */
#define ERR3(x) __VA_OPT__() /* { dg-warning "can only appear" } */
#define ERR4(x,...) __VA_OPT__ /* { dg-error "unterminated __VA_OPT__" } */
#define ERR5(x,...) __VA_OPT__( /* { dg-error "unterminated" } */
#define ERR6(x,...) __VA_OPT__(() /* { dg-error "unterminated" } */
#define ERR7(x,...) __VA_OPT__(__VA_OPT__) /* { dg-error "may not appear" } */
#define ERR7(x,...) __VA_OPT__(__VA_OPT__()) /* { dg-error "may not appear" } */
#define ERR8(x, y,...) x __VA_OPT__(##) y /* { dg-error "either end" } */
#define ERR9(x, y,...) x __VA_OPT__(x ##) y /* { dg-error "either end" } */
#define ERRA(x, y,...) x x __VA_OPT__(## y) /* { dg-error "either end" } */
#define ERRB __VA_OPT__ /* { dg-warning "can only appear" } */
#define ERRC(__VA_OPT__) x /* { dg-warning "can only appear" } */
__VA_OPT__ /* { dg-warning "can only appear" } */
#define ERRD(x)
ERRD(__VA_OPT__) /* { dg-warning "can only appear" } */
#define __VA_OPT__ /* { dg-warning "can only appear" } */

View File

@ -0,0 +1,5 @@
/* { dg-do preprocess }*/
/* { dg-options "-std=c11 -pedantic-errors" { target c } } */
/* { dg-options "-std=c++17 -pedantic-errors" { target c++ } } */
#define CALL(F, ...) F (7 __VA_OPT__(,) __VA_ARGS__) /* { dg-error "__VA_OPT__ is not available" } */

View File

@ -0,0 +1,42 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu99" { target c } } */
/* { dg-options "-std=c++2a" { target c++ } } */
extern void f0 (void);
extern void f1 (int);
extern void f2 (int, int);
extern void f3 (int, int, int);
extern void f4 (int, int, int, int);
extern int s (const char *);
#define CALL(F, ...) F (7 __VA_OPT__(,) __VA_ARGS__)
#define CP(F, X, Y, ...) F (__VA_OPT__(X ## Y,) __VA_ARGS__)
#define CS(F, ...) F(__VA_OPT__(s(# __VA_ARGS__)))
#define D(F, ...) F(__VA_OPT__(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__)
#define CALL0(...) __VA_OPT__(f2)(0 __VA_OPT__(,)__VA_ARGS__)
void t (void)
{
CALL (f1);
CALL (f1, );
CALL (f2, 1);
CALL (f3, 1, 2);
int one = 1;
int two = 2;
int onetwo = 23;
CP (f0, one, two);
CP (f0, one, two, );
CP (f2, one, two, 3);
CS (f0);
CS (f1, 1, 2, 3, 4);
D (f0);
D (f2, 1);
D (f4, 1, 2);
CALL0 ();
CALL0 (23);
}

View File

@ -1,3 +1,22 @@
2017-11-13 Tom Tromey <tom@tromey.com>
* pch.c (cpp_read_state): Set n__VA_OPT__.
* macro.c (vaopt_state): New class.
(_cpp_arguments_ok): Check va_opt flag.
(replace_args, create_iso_definition): Use vaopt_state.
* lex.c (lex_identifier_intern): Possibly issue errors for
__VA_OPT__.
(lex_identifier): Likewise.
(maybe_va_opt_error): New function.
* internal.h (struct lexer_state) <va_args_ok>: Update comment.
(struct spec_nodes) <n__VA_OPT__>: New field.
* init.c (struct lang_flags) <va_opt>: New field.
(lang_defaults): Add entries for C++2A. Update all entries for
va_opt.
(cpp_set_lang): Initialize va_opt.
* include/cpplib.h (struct cpp_options) <va_opt>: New field.
* identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.
2017-11-13 David Malcolm <dmalcolm@redhat.com>
* include/line-map.h (linenum_type): Move this typedef and the

View File

@ -70,6 +70,8 @@ _cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
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__VA_OPT__ = cpp_lookup (pfile, DSC("__VA_OPT__"));
s->n__VA_OPT__->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__"));
}

View File

@ -478,6 +478,9 @@ struct cpp_options
/* Nonzero for C++ 2014 Standard digit separators. */
unsigned char digit_separators;
/* Nonzero for C++2a __VA_OPT__ feature. */
unsigned char va_opt;
/* Holds the name of the target (execution) character set. */
const char *narrow_charset;

View File

@ -91,30 +91,31 @@ struct lang_flags
char digit_separators;
char trigraphs;
char utf8_char_literals;
char va_opt;
};
static const struct lang_flags lang_defaults[] =
{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit */
/* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
/* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
/* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
/* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
/* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 },
/* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
/* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
/* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
/* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
/* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
/* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 },
/* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 },
/* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 },
/* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 },
/* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
/* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
/* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
/* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
/* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
/* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt */
/* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
/* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
/* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
/* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
/* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
/* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
/* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
/* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 },
/* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 },
/* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
/* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
/* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1 },
/* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 },
/* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1 },
/* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
/* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
/* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0 },
/* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
/* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
/* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* Sets internal flags correctly for a given language. */
@ -139,6 +140,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, digit_separators) = l->digit_separators;
CPP_OPTION (pfile, trigraphs) = l->trigraphs;
CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals;
CPP_OPTION (pfile, va_opt) = l->va_opt;
}
/* Initialize library global state. */

View File

@ -246,7 +246,7 @@ struct lexer_state
all directives apart from #define. */
unsigned char save_comments;
/* Nonzero if lexing __VA_ARGS__ is valid. */
/* Nonzero if lexing __VA_ARGS__ and __VA_OPT__ are valid. */
unsigned char va_args_ok;
/* Nonzero if lexing poisoned identifiers is valid. */
@ -282,6 +282,7 @@ struct spec_nodes
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__VA_OPT__; /* C++ vararg macros */
cpp_hashnode *n__has_include__; /* __has_include__ operator */
cpp_hashnode *n__has_include_next__; /* __has_include_next__ operator */
};

View File

@ -1352,6 +1352,28 @@ forms_identifier_p (cpp_reader *pfile, int first,
return false;
}
/* Helper function to issue error about improper __VA_OPT__ use. */
static void
maybe_va_opt_error (cpp_reader *pfile)
{
if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, va_opt))
{
/* __VA_OPT__ should not be accepted at all, but allow it in
system headers. */
if (!cpp_in_system_header (pfile))
cpp_error (pfile, CPP_DL_PEDWARN,
"__VA_OPT__ is not available until C++2a");
}
else if (!pfile->state.va_args_ok)
{
/* __VA_OPT__ should only appear in the replacement list of a
variadic macro. */
cpp_error (pfile, CPP_DL_PEDWARN,
"__VA_OPT__ can only appear in the expansion"
" of a C++2a variadic macro");
}
}
/* Helper function to get the cpp_hashnode of the identifier BASE. */
static cpp_hashnode *
lex_identifier_intern (cpp_reader *pfile, const uchar *base)
@ -1396,6 +1418,9 @@ lex_identifier_intern (cpp_reader *pfile, const uchar *base)
" of a C99 variadic macro");
}
if (result == pfile->spec_nodes.n__VA_OPT__)
maybe_va_opt_error (pfile);
/* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
@ -1485,6 +1510,11 @@ lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
" of a C99 variadic macro");
}
/* __VA_OPT__ should only appear in the replacement list of a
variadic macro. */
if (result == pfile->spec_nodes.n__VA_OPT__)
maybe_va_opt_error (pfile);
/* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,

View File

@ -89,6 +89,155 @@ struct macro_arg_saved_data {
union _cpp_hashnode_value value;
};
static const char *vaopt_paste_error =
N_("'##' cannot appear at either end of __VA_OPT__");
/* A class for tracking __VA_OPT__ state while iterating over a
sequence of tokens. This is used during both macro definition and
expansion. */
class vaopt_state {
public:
/* 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)
: m_pfile (pfile),
m_allowed (any_args),
m_variadic (is_variadic),
m_state (0),
m_last_was_paste (false),
m_paste_location (0),
m_location (0)
{
}
enum update_type
{
ERROR,
DROP,
INCLUDE
};
/* Given a token, update the state of this tracker and return a
boolean indicating whether the token should be be included in the
expansion. */
update_type update (const cpp_token *token)
{
/* If the macro isn't variadic, just don't bother. */
if (!m_variadic)
return INCLUDE;
if (token->type == CPP_NAME
&& token->val.node.node == m_pfile->spec_nodes.n__VA_OPT__)
{
if (m_state > 0)
{
cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
"__VA_OPT__ may not appear in a __VA_OPT__");
return ERROR;
}
++m_state;
m_location = token->src_loc;
return DROP;
}
else if (m_state == 1)
{
if (token->type != CPP_OPEN_PAREN)
{
cpp_error_at (m_pfile, CPP_DL_ERROR, m_location,
"__VA_OPT__ must be followed by an "
"open parenthesis");
return ERROR;
}
++m_state;
return DROP;
}
else if (m_state >= 2)
{
if (m_state == 2 && token->type == CPP_PASTE)
{
cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
vaopt_paste_error);
return ERROR;
}
/* Advance states before further considering this token, in
case we see a close paren immediately after the open
paren. */
if (m_state == 2)
++m_state;
bool was_paste = m_last_was_paste;
m_last_was_paste = false;
if (token->type == CPP_PASTE)
{
m_last_was_paste = true;
m_paste_location = token->src_loc;
}
else if (token->type == CPP_OPEN_PAREN)
++m_state;
else if (token->type == CPP_CLOSE_PAREN)
{
--m_state;
if (m_state == 2)
{
/* Saw the final paren. */
m_state = 0;
if (was_paste)
{
cpp_error_at (m_pfile, CPP_DL_ERROR, token->src_loc,
vaopt_paste_error);
return ERROR;
}
return DROP;
}
}
return m_allowed ? INCLUDE : DROP;
}
/* Nothing to do with __VA_OPT__. */
return INCLUDE;
}
/* Ensure that any __VA_OPT__ was completed. If ok, return true.
Otherwise, issue an error and return false. */
bool completed ()
{
if (m_variadic && m_state != 0)
cpp_error_at (m_pfile, CPP_DL_ERROR, m_location,
"unterminated __VA_OPT__");
return m_state == 0;
}
private:
/* The cpp_reader. */
cpp_reader *m_pfile;
/* True if there were varargs. */
bool m_allowed;
/* True if the macro is variadic. */
bool m_variadic;
/* The state variable:
0 means not parsing
1 means __VA_OPT__ seen, looking for "("
2 means "(" seen (so the next token can't be "##")
>= 3 means looking for ")", the number encodes the paren depth. */
int m_state;
/* If true, the previous token was ##. This is used to detect when
a paste occurs at the end of the sequence. */
bool m_last_was_paste;
/* The location of the paste token. */
source_location m_paste_location;
/* Location of the __VA_OPT__ token. */
source_location m_location;
};
/* Macro expansion. */
static int enter_macro_context (cpp_reader *, cpp_hashnode *,
@ -776,7 +925,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
if (argc < macro->paramc)
{
/* As an extension, variadic arguments are allowed to not appear in
/* In C++2a (here the va_opt flag is used), and also as a GNU
extension, variadic arguments are allowed to not appear in
the invocation at all.
e.g. #define debug(format, args...) something
debug("string");
@ -786,7 +936,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
if (argc + 1 == macro->paramc && macro->variadic)
{
if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
if (CPP_PEDANTIC (pfile) && ! macro->syshdr
&& ! CPP_OPTION (pfile, va_opt))
{
if (CPP_OPTION (pfile, cplusplus))
cpp_error (pfile, CPP_DL_PEDWARN,
@ -1678,6 +1829,8 @@ 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);
for (src = macro->exp.tokens; src < limit; src++)
{
unsigned int arg_tokens_count;
@ -1685,6 +1838,10 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
const cpp_token **paste_flag = NULL;
const cpp_token **tmp_token_ptr;
/* __VA_OPT__ handling. */
if (vaopt_tracker.update (src) != vaopt_state::INCLUDE)
continue;
if (src->type != CPP_MACRO_ARG)
{
/* Allocate a virtual location for token SRC, and add that
@ -3076,6 +3233,9 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
*token = *ctoken;
}
/* The argument doesn't matter here. */
vaopt_state vaopt_tracker (pfile, macro->variadic, true);
for (;;)
{
/* Check the stringifying # constraint 6.10.3.2.1 of
@ -3144,10 +3304,16 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
}
}
if (vaopt_tracker.update (token) == vaopt_state::ERROR)
return false;
following_paste_op = (token->type == CPP_PASTE);
token = lex_expansion_token (pfile, macro);
}
if (!vaopt_tracker.completed ())
return false;
macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
macro->traditional = 0;

View File

@ -835,6 +835,7 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
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__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__"));
}