diff options
author | Tom Tromey <tom@tromey.com> | 2017-11-13 20:17:42 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2017-11-13 20:17:42 +0000 |
commit | fb771b9dad6ef78a985353128cea48e620eb4324 (patch) | |
tree | d94251e8c98cb3a0a9bfd711707dea469e857c6b /gcc | |
parent | 4d85d480272fb7331924f04534e0f5f14b60421e (diff) | |
download | gcc-fb771b9dad6ef78a985353128cea48e620eb4324.zip gcc-fb771b9dad6ef78a985353128cea48e620eb4324.tar.gz gcc-fb771b9dad6ef78a985353128cea48e620eb4324.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/doc/cpp.texi | 46 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/cpp/va-opt-error.c | 28 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/cpp/va-opt-pedantic.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/cpp/va-opt.c | 42 |
6 files changed, 121 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b393e0d..b7ac84c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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): diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index 8cafb65..94437d5 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 69633de..b1c2f3e0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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. diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-error.c b/gcc/testsuite/c-c++-common/cpp/va-opt-error.c new file mode 100644 index 0000000..f32f055 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-error.c @@ -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" } */ diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-pedantic.c b/gcc/testsuite/c-c++-common/cpp/va-opt-pedantic.c new file mode 100644 index 0000000..5887bf5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-pedantic.c @@ -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" } */ diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt.c b/gcc/testsuite/c-c++-common/cpp/va-opt.c new file mode 100644 index 0000000..243d33b --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt.c @@ -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); +} |