Commit fb771b9d by Tom Tromey Committed by Tom Tromey

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
parent 4d85d480
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> 2017-11-13 Carl Love <cel@us.ibm.com>
* config/rs6000/rs6000-c.c (altivec_overloaded_builtins): * config/rs6000/rs6000-c.c (altivec_overloaded_builtins):
...@@ -1675,20 +1675,27 @@ macro. We could define @code{eprintf} like this, instead: ...@@ -1675,20 +1675,27 @@ macro. We could define @code{eprintf} like this, instead:
@end smallexample @end smallexample
@noindent @noindent
This formulation looks more descriptive, but unfortunately it is less This formulation looks more descriptive, but historically it was less
flexible: you must now supply at least one argument after the format flexible: you had to supply at least one argument after the format
string. In standard C, you cannot omit the comma separating the named string. In standard C, you could not omit the comma separating the
argument from the variable arguments. Furthermore, if you leave the named argument from the variable arguments. (Note that this
variable argument empty, you will get a syntax error, because restriction has been lifted in C++2a, and never existed in GNU C; see
there will be an extra comma after the format string. 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 @smallexample
eprintf("success!\n", ); eprintf("success!\n", );
@expansion{} fprintf(stderr, "success!\n", ); @expansion{} fprintf(stderr, "success!\n", );
@end smallexample @end smallexample
GNU CPP has a pair of extensions which deal with this problem. First, This has been fixed in C++2a, and GNU CPP also has a pair of
you are allowed to leave the variable argument out entirely: 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 @smallexample
eprintf ("success!\n") eprintf ("success!\n")
...@@ -1696,8 +1703,24 @@ eprintf ("success!\n") ...@@ -1696,8 +1703,24 @@ eprintf ("success!\n")
@end smallexample @end smallexample
@noindent @noindent
Second, the @samp{##} token paste operator has a special meaning when Second, C++2a introduces the @code{@w{__VA_OPT__}} function macro.
placed between a comma and a variable argument. If you write 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 @smallexample
#define eprintf(format, @dots{}) fprintf (stderr, format, ##__VA_ARGS__) #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 ...@@ -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 ambiguous. We recommend you avoid using it except for its defined
purpose. 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. Variadic macros became a standard part of the C language with C99.
GNU CPP previously supported them GNU CPP previously supported them
with a named variable argument with a named variable argument
......
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> 2017-11-13 Carl Love <cel@us.ibm.com>
* gcc.target/powerpc/builtins-6-p9-runnable.c: Add new runnable test. * gcc.target/powerpc/builtins-6-p9-runnable.c: Add new runnable test.
......
/* { 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" } */
/* { 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" } */
/* { 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);
}
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> 2017-11-13 David Malcolm <dmalcolm@redhat.com>
* include/line-map.h (linenum_type): Move this typedef and the * include/line-map.h (linenum_type): Move this typedef and the
......
...@@ -70,6 +70,8 @@ _cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table) ...@@ -70,6 +70,8 @@ _cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
s->n_false = cpp_lookup (pfile, DSC("false")); s->n_false = cpp_lookup (pfile, DSC("false"));
s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__")); s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC; 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__ = cpp_lookup (pfile, DSC("__has_include__"));
s->n__has_include_next__ = cpp_lookup (pfile, DSC("__has_include_next__")); s->n__has_include_next__ = cpp_lookup (pfile, DSC("__has_include_next__"));
} }
......
...@@ -478,6 +478,9 @@ struct cpp_options ...@@ -478,6 +478,9 @@ struct cpp_options
/* Nonzero for C++ 2014 Standard digit separators. */ /* Nonzero for C++ 2014 Standard digit separators. */
unsigned char 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. */ /* Holds the name of the target (execution) character set. */
const char *narrow_charset; const char *narrow_charset;
......
...@@ -91,30 +91,31 @@ struct lang_flags ...@@ -91,30 +91,31 @@ struct lang_flags
char digit_separators; char digit_separators;
char trigraphs; char trigraphs;
char utf8_char_literals; char utf8_char_literals;
char va_opt;
}; };
static const struct lang_flags lang_defaults[] = static const struct lang_flags lang_defaults[] =
{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit */ { /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 } /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}; };
/* Sets internal flags correctly for a given language. */ /* Sets internal flags correctly for a given language. */
...@@ -139,6 +140,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang) ...@@ -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, digit_separators) = l->digit_separators;
CPP_OPTION (pfile, trigraphs) = l->trigraphs; CPP_OPTION (pfile, trigraphs) = l->trigraphs;
CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals; CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals;
CPP_OPTION (pfile, va_opt) = l->va_opt;
} }
/* Initialize library global state. */ /* Initialize library global state. */
......
...@@ -246,7 +246,7 @@ struct lexer_state ...@@ -246,7 +246,7 @@ struct lexer_state
all directives apart from #define. */ all directives apart from #define. */
unsigned char save_comments; 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; unsigned char va_args_ok;
/* Nonzero if lexing poisoned identifiers is valid. */ /* Nonzero if lexing poisoned identifiers is valid. */
...@@ -282,6 +282,7 @@ struct spec_nodes ...@@ -282,6 +282,7 @@ struct spec_nodes
cpp_hashnode *n_true; /* C++ keyword true */ cpp_hashnode *n_true; /* C++ keyword true */
cpp_hashnode *n_false; /* C++ keyword false */ cpp_hashnode *n_false; /* C++ keyword false */
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ 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__; /* __has_include__ operator */
cpp_hashnode *n__has_include_next__; /* __has_include_next__ operator */ cpp_hashnode *n__has_include_next__; /* __has_include_next__ operator */
}; };
......
...@@ -1352,6 +1352,28 @@ forms_identifier_p (cpp_reader *pfile, int first, ...@@ -1352,6 +1352,28 @@ forms_identifier_p (cpp_reader *pfile, int first,
return false; 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. */ /* Helper function to get the cpp_hashnode of the identifier BASE. */
static cpp_hashnode * static cpp_hashnode *
lex_identifier_intern (cpp_reader *pfile, const uchar *base) lex_identifier_intern (cpp_reader *pfile, const uchar *base)
...@@ -1396,6 +1418,9 @@ 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"); " 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. */ /* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR) if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES, cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
...@@ -1485,6 +1510,11 @@ lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn, ...@@ -1485,6 +1510,11 @@ lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
" of a C99 variadic macro"); " 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. */ /* For -Wc++-compat, warn about use of C++ named operators. */
if (result->flags & NODE_WARN_OPERATOR) if (result->flags & NODE_WARN_OPERATOR)
cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES, cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
......
...@@ -89,6 +89,155 @@ struct macro_arg_saved_data { ...@@ -89,6 +89,155 @@ struct macro_arg_saved_data {
union _cpp_hashnode_value value; 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. */ /* Macro expansion. */
static int enter_macro_context (cpp_reader *, cpp_hashnode *, 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 ...@@ -776,7 +925,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
if (argc < macro->paramc) 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. the invocation at all.
e.g. #define debug(format, args...) something e.g. #define debug(format, args...) something
debug("string"); debug("string");
...@@ -786,7 +936,8 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node ...@@ -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 (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)) if (CPP_OPTION (pfile, cplusplus))
cpp_error (pfile, CPP_DL_PEDWARN, cpp_error (pfile, CPP_DL_PEDWARN,
...@@ -1678,6 +1829,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, ...@@ -1678,6 +1829,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
num_macro_tokens); num_macro_tokens);
} }
i = 0; i = 0;
vaopt_state vaopt_tracker (pfile, macro->variadic,
args[macro->paramc - 1].count > 0);
for (src = macro->exp.tokens; src < limit; src++) for (src = macro->exp.tokens; src < limit; src++)
{ {
unsigned int arg_tokens_count; unsigned int arg_tokens_count;
...@@ -1685,6 +1838,10 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, ...@@ -1685,6 +1838,10 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
const cpp_token **paste_flag = NULL; const cpp_token **paste_flag = NULL;
const cpp_token **tmp_token_ptr; const cpp_token **tmp_token_ptr;
/* __VA_OPT__ handling. */
if (vaopt_tracker.update (src) != vaopt_state::INCLUDE)
continue;
if (src->type != CPP_MACRO_ARG) if (src->type != CPP_MACRO_ARG)
{ {
/* Allocate a virtual location for token SRC, and add that /* Allocate a virtual location for token SRC, and add that
...@@ -3076,6 +3233,9 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro) ...@@ -3076,6 +3233,9 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
*token = *ctoken; *token = *ctoken;
} }
/* The argument doesn't matter here. */
vaopt_state vaopt_tracker (pfile, macro->variadic, true);
for (;;) for (;;)
{ {
/* Check the stringifying # constraint 6.10.3.2.1 of /* Check the stringifying # constraint 6.10.3.2.1 of
...@@ -3144,10 +3304,16 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro) ...@@ -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); following_paste_op = (token->type == CPP_PASTE);
token = lex_expansion_token (pfile, macro); token = lex_expansion_token (pfile, macro);
} }
if (!vaopt_tracker.completed ())
return false;
macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff); macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
macro->traditional = 0; macro->traditional = 0;
......
...@@ -835,6 +835,7 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f, ...@@ -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_true = cpp_lookup (r, DSC("true"));
s->n_false = cpp_lookup (r, DSC("false")); s->n_false = cpp_lookup (r, DSC("false"));
s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__")); 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__ = cpp_lookup (r, DSC("__has_include__"));
s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__")); s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__"));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment