diff mbox series

[RFA] Implement __VA_OPT__

Message ID 20170916214918.14930-1-tom@tromey.com
State New
Headers show
Series [RFA] Implement __VA_OPT__ | expand

Commit Message

Tom Tromey Sept. 16, 2017, 9:49 p.m. UTC
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

I am not completely sure that I have handled the error reporting
correctly.  I chose to allow __VA_OPT__ generally, on the theory that,
because it is a reserved identifier, programs should not be referring
to it anyway.  Also, this approach makes it possible for __VA_OPT__ to
be used in system headers even when the -std/-pedantic settings may
otherwise disallow it.

Bootstrapped and regression tested on x86-64 Fedora 25.

gcc/ChangeLog
2017-09-16  Tom Tromey  <tom@tromey.com>

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

gcc/testsuite/ChangeLog
2017-09-16  Tom Tromey  <tom@tromey.com>

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

libcpp/ChangeLog
2017-09-16  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.
	* 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 (enum c_lang) <CLK_GNUCXX2A, CLK_CXX2A>: New
	constants.
	(struct cpp_options) <va_opt>: New field.
	* identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.
---
 gcc/ChangeLog                                 |   4 +
 gcc/doc/cpp.texi                              |  46 +++++--
 gcc/testsuite/ChangeLog                       |   5 +
 gcc/testsuite/c-c++-common/cpp/va-opt-error.c |  28 +++++
 gcc/testsuite/c-c++-common/cpp/va-opt.c       |  42 +++++++
 libcpp/ChangeLog                              |  20 +++
 libcpp/identifiers.c                          |   2 +
 libcpp/include/cpplib.h                       |   3 +
 libcpp/init.c                                 |  40 +++---
 libcpp/internal.h                             |   3 +-
 libcpp/lex.c                                  |  30 +++++
 libcpp/macro.c                                | 170 +++++++++++++++++++++++++-
 libcpp/pch.c                                  |   1 +
 13 files changed, 362 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/cpp/va-opt-error.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/va-opt.c

Comments

Alexander Monakov Sept. 17, 2017, 9:43 a.m. UTC | #1
On Sat, 16 Sep 2017, Tom Tromey wrote:
> --- a/gcc/doc/cpp.texi
> +++ b/gcc/doc/cpp.texi
> @@ -1675,20 +1675,27 @@ macro.  We could define @code{eprintf} like this, instead:
[snip]
> +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++20, and never existed in GNU C; see
> +below.)

Shouldn't this say 'C++2a' (more instances follow)?


> +Historically, GNU has also had another extension to handle the

'GNU CPP'?

> --- a/libcpp/init.c
> +++ b/libcpp/init.c
> @@ -91,28 +91,29 @@ struct lang_flags
>  static const struct lang_flags lang_defaults[] =
> -{ /*              c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit */
[snip]
> -  /* 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 */
[snip]
> +  /* GNUCXX1Z */  { 1,  1,  1,  1,  1,  0,  1,   1,   1,   1,    1,     1,     0,   1,      0 },
> +  /* CXX1Z    */  { 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 }
>  };

This hunk reverts CXX17 back to CXX1Z.

> --- a/libcpp/lex.c
> +++ b/libcpp/lex.c
> @@ -1396,6 +1396,21 @@ lex_identifier_intern (cpp_reader *pfile, const uchar *base)
>  		       " 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__
> +	  && !pfile->state.va_args_ok)
> +	{
> +	  if (CPP_OPTION (pfile, cplusplus))
> +	    cpp_error (pfile, CPP_DL_ERROR,
> +		       "__VA_OPT__ can only appear in the expansion"
> +		       " of a C++11 variadic macro");
> +	  else
> +	    cpp_error (pfile, CPP_DL_ERROR,
> +		       "__VA_OPT__ can only appear in the expansion"
> +		       " of a C99 variadic macro");
> +	}
> +
>        /* 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 +1500,21 @@ 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__
> +	  && !pfile->state.va_args_ok)
> +	{
> +	  if (CPP_OPTION (pfile, cplusplus))
> +	    cpp_error (pfile, CPP_DL_ERROR,
> +		       "__VA_OPT__ can only appear in the expansion"
> +		       " of a C++11 variadic macro");
> +	  else
> +	    cpp_error (pfile, CPP_DL_ERROR,
> +		       "__VA_OPT__ can only appear in the expansion"
> +		       " of a C99 variadic macro");
> +	}
> +
>        /* For -Wc++-compat, warn about use of C++ named operators.  */
>        if (result->flags & NODE_WARN_OPERATOR)
>  	cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,

These two hunks add more duplication in already-duplicated 'if' statement
bodies.  Is it possible to move the whole body to a separate function?

I guess the references to C++11 and C99 are duplicated from the preceding 'if',
but is that correct here?  And why is it useful to distinguish between C and C++
for this error in the first place, why not simply say 'cpp_error (...,
"__VA_OPT__ can only appear in the expansion of a variadic macro");'?

> --- a/libcpp/macro.c
> +++ b/libcpp/macro.c
> @@ -1670,6 +1821,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
>  				 num_macro_tokens);
>      }
>    i = 0;
> +  vaopt_state state_tracker (pfile, macro->variadic,
> +			     args[macro->paramc - 1].count > 0);

The name 'state_tracker' seems too general for what it does, I think
'vaopt_st' or such would have been a better fit (sorry for the bikeshed).

Thanks.
Alexander
Tom Tromey Sept. 17, 2017, 3:12 p.m. UTC | #2
>>>>> "Alexander" == Alexander Monakov <amonakov@ispras.ru> writes:

Alexander> This hunk reverts CXX17 back to CXX1Z.

Thanks for noticing, I'd written this before Jakub's patch and so the
error came in during the rebase.

Alexander> These two hunks add more duplication in already-duplicated 'if' statement
Alexander> bodies.  Is it possible to move the whole body to a separate function?

I suppose, but this is just copying what pre-existing code does.

Alexander> I guess the references to C++11 and C99 are duplicated from the preceding 'if',
Alexander> but is that correct here?  And why is it useful to distinguish between C and C++
Alexander> for this error in the first place, why not simply say 'cpp_error (...,
Alexander> "__VA_OPT__ can only appear in the expansion of a variadic macro");'?

I don't really understand the rationale for why the errors are phrased
the way they are, but I notice the C errors generally mention C99 and
the C++ errors generally mention C++11.  So, since I didn't have a
rationale, I copied what is already there.  I thought maybe GCC is just
emitting the default standard choice for each language.

Tom
Tom Tromey Sept. 17, 2017, 3:42 p.m. UTC | #3
Tom> I don't really understand the rationale for why the errors are phrased
Tom> the way they are, but I notice the C errors generally mention C99 and
Tom> the C++ errors generally mention C++11.  So, since I didn't have a
Tom> rationale, I copied what is already there.  I thought maybe GCC is just
Tom> emitting the default standard choice for each language.

Here's an updated version of the patch.  I've tried to address your
comments (except the one about the text of the error message, see above)
and also some comments I got off-list.

thanks,
Tom

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e213db6..362f50e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-16  Tom Tromey  <tom@tromey.com>
+
+	* doc/cpp.texi (Variadic Macros): Document __VA_OPT__.
+
 2017-09-16  Richard Sandiford  <richard.sandiford@linaro.org>
 
 	PR tree-optimization/82228
diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 52f2606..5647d26f 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 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 1a94535..2538c4b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-09-16  Tom Tromey  <tom@tromey.com>
+
+	* c-c++-common/cpp/va-opt.c: New file.
+	* c-c++-common/cpp/va-opt-error.c: New file.
+
 2017-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
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..7718916
--- /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-error "__VA_OPT__ can only appear" } */
+#define ERR2(x) __VA_OPT__( /* { dg-error "can only appear" } */
+#define ERR3(x) __VA_OPT__() /* { dg-error "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-error "can only appear" } */
+#define ERRC(__VA_OPT__) x /* { dg-error "can only appear" } */
+
+__VA_OPT__ /* { dg-error "can only appear" } */
+
+#define ERRD(x)
+ERRD(__VA_OPT__) /* { dg-error "can only appear" } */
+
+#define __VA_OPT__ /* { dg-error "can only appear" } */
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);
+}
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 0621074..65ce80c 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,23 @@
+2017-09-16  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.
+	* 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 (enum c_lang) <CLK_GNUCXX2A, CLK_CXX2A>: New
+	constants.
+	(struct cpp_options) <va_opt>: New field.
+	* identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.
+
 2017-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 220f9b9..e456fd3 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -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__"));
 }
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 804132a..fc98175 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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;
 
diff --git a/libcpp/init.c b/libcpp/init.c
index 16ff202..49500b7 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -91,28 +91,29 @@ 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 },
-  /* 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 },
-  /* 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,      0 },
+  /* GNUC99   */  { 1,  0,  1,  1,  0,  0,  1,   1,   1,   0,    0,     0,     0,   0,      0 },
+  /* GNUC11   */  { 1,  0,  1,  1,  1,  0,  1,   1,   1,   0,    0,     0,     0,   0,      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,      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 },
+  /* GNUCXX   */  { 0,  1,  1,  1,  0,  0,  1,   0,   0,   0,    0,     0,     0,   0,      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,      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,      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,      0 },
+  /* 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.  */
@@ -137,6 +138,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.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index f24e85c..0a33aba 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -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 */
 };
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 40ff801..9cfc693 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1352,6 +1352,25 @@ 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, cpp_hashnode *node)
+{
+  /* __VA_OPT__ should only appear in the replacement list of a
+     variadic macro.  */
+  if (node == pfile->spec_nodes.n__VA_OPT__ && !pfile->state.va_args_ok)
+    {
+      if (CPP_OPTION (pfile, cplusplus))
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "__VA_OPT__ can only appear in the expansion"
+		   " of a C++11 variadic macro");
+      else
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "__VA_OPT__ can only appear in the expansion"
+		   " of a C99 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 +1415,8 @@ lex_identifier_intern (cpp_reader *pfile, const uchar *base)
 		       " of a C99 variadic macro");
 	}
 
+      maybe_va_opt_error (pfile, result);
+
       /* 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 +1506,10 @@ 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.  */
+      maybe_va_opt_error (pfile, result);
+
       /* For -Wc++-compat, warn about use of C++ named operators.  */
       if (result->flags & NODE_WARN_OPERATOR)
 	cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
diff --git a/libcpp/macro.c b/libcpp/macro.c
index de18c22..35ec59a 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -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 *,
@@ -768,7 +917,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");
@@ -778,7 +928,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,
@@ -1670,6 +1821,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;
@@ -1677,6 +1830,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
@@ -3068,6 +3225,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
@@ -3136,10 +3296,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;
 
diff --git a/libcpp/pch.c b/libcpp/pch.c
index cad4b87..b685a38 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -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__"));
   }
Tom Tromey Sept. 17, 2017, 3:44 p.m. UTC | #4
And, darn it, I forgot to save cpp.texi, leaving out a couple of tweaks
there.

Here's v3.  Sorry about the noise.

Tom

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e213db6..362f50e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-16  Tom Tromey  <tom@tromey.com>
+
+	* doc/cpp.texi (Variadic Macros): Document __VA_OPT__.
+
 2017-09-16  Richard Sandiford  <richard.sandiford@linaro.org>
 
 	PR tree-optimization/82228
diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 52f2606..33e72c6 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 1a94535..2538c4b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-09-16  Tom Tromey  <tom@tromey.com>
+
+	* c-c++-common/cpp/va-opt.c: New file.
+	* c-c++-common/cpp/va-opt-error.c: New file.
+
 2017-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
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..7718916
--- /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-error "__VA_OPT__ can only appear" } */
+#define ERR2(x) __VA_OPT__( /* { dg-error "can only appear" } */
+#define ERR3(x) __VA_OPT__() /* { dg-error "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-error "can only appear" } */
+#define ERRC(__VA_OPT__) x /* { dg-error "can only appear" } */
+
+__VA_OPT__ /* { dg-error "can only appear" } */
+
+#define ERRD(x)
+ERRD(__VA_OPT__) /* { dg-error "can only appear" } */
+
+#define __VA_OPT__ /* { dg-error "can only appear" } */
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);
+}
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 0621074..65ce80c 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,23 @@
+2017-09-16  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.
+	* 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 (enum c_lang) <CLK_GNUCXX2A, CLK_CXX2A>: New
+	constants.
+	(struct cpp_options) <va_opt>: New field.
+	* identifiers.c (_cpp_init_hashtable): Initialize n__VA_OPT__.
+
 2017-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 220f9b9..e456fd3 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -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__"));
 }
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 804132a..fc98175 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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;
 
diff --git a/libcpp/init.c b/libcpp/init.c
index 16ff202..49500b7 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -91,28 +91,29 @@ 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 },
-  /* 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 },
-  /* 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,      0 },
+  /* GNUC99   */  { 1,  0,  1,  1,  0,  0,  1,   1,   1,   0,    0,     0,     0,   0,      0 },
+  /* GNUC11   */  { 1,  0,  1,  1,  1,  0,  1,   1,   1,   0,    0,     0,     0,   0,      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,      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 },
+  /* GNUCXX   */  { 0,  1,  1,  1,  0,  0,  1,   0,   0,   0,    0,     0,     0,   0,      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,      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,      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,      0 },
+  /* 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.  */
@@ -137,6 +138,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.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index f24e85c..0a33aba 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -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 */
 };
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 40ff801..9cfc693 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1352,6 +1352,25 @@ 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, cpp_hashnode *node)
+{
+  /* __VA_OPT__ should only appear in the replacement list of a
+     variadic macro.  */
+  if (node == pfile->spec_nodes.n__VA_OPT__ && !pfile->state.va_args_ok)
+    {
+      if (CPP_OPTION (pfile, cplusplus))
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "__VA_OPT__ can only appear in the expansion"
+		   " of a C++11 variadic macro");
+      else
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "__VA_OPT__ can only appear in the expansion"
+		   " of a C99 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 +1415,8 @@ lex_identifier_intern (cpp_reader *pfile, const uchar *base)
 		       " of a C99 variadic macro");
 	}
 
+      maybe_va_opt_error (pfile, result);
+
       /* 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 +1506,10 @@ 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.  */
+      maybe_va_opt_error (pfile, result);
+
       /* For -Wc++-compat, warn about use of C++ named operators.  */
       if (result->flags & NODE_WARN_OPERATOR)
 	cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
diff --git a/libcpp/macro.c b/libcpp/macro.c
index de18c22..35ec59a 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -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 *,
@@ -768,7 +917,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");
@@ -778,7 +928,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,
@@ -1670,6 +1821,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;
@@ -1677,6 +1830,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
@@ -3068,6 +3225,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
@@ -3136,10 +3296,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;
 
diff --git a/libcpp/pch.c b/libcpp/pch.c
index cad4b87..b685a38 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -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__"));
   }
Tom Tromey Oct. 9, 2017, 3:32 p.m. UTC | #5
>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

[ __VA_OPT__ ]
Tom> Here's v3.

Ping.

Tom
Tom Tromey Oct. 19, 2017, 9:48 p.m. UTC | #6
>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> [ __VA_OPT__ ]
Tom> Here's v3.

Tom> Ping.

Ping #2.

Tom
Tom Tromey Nov. 2, 2017, 4:03 p.m. UTC | #7
Tom> [ __VA_OPT__ ]
Tom> Here's v3.

Tom> Ping.

Tom> Ping #2.

Ping #3.

Tom
Jason Merrill Nov. 2, 2017, 6:02 p.m. UTC | #8
On 09/17/2017 11:44 AM, Tom Tromey wrote:
> +@code{@w{__VA_OPT__}} is also available in GNU C and GNU C++.

> +{ /*              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,      0 },
> +  /* GNUC99   */  { 1,  0,  1,  1,  0,  0,  1,   1,   1,   0,    0,     0,     0,   0,      0 },
> +  /* GNUC11   */  { 1,  0,  1,  1,  1,  0,  1,   1,   1,   0,    0,     0,     0,   0,      0 },
[...]

Do we want 1s for vaopt in the GNU rows, then?  It seems to only be used 
for controlling the pedwarn about needing at least one argument for the 
variadic parameter.

> +maybe_va_opt_error (cpp_reader *pfile, cpp_hashnode *node)

Do we also want to look at the va_opt option in this function, to 
complain if pedantic and it isn't set?

Jason
Tom Tromey Nov. 12, 2017, 7:33 a.m. UTC | #9
>>>>> "Jason" == Jason Merrill <jason@redhat.com> writes:

Jason> Do we want 1s for vaopt in the GNU rows, then?  It seems to only be
Jason> used for controlling the pedwarn about needing at least one argument
Jason> for the variadic parameter.

It seems reasonable to me, but I wasn't sure.  I've made the change.

>> +maybe_va_opt_error (cpp_reader *pfile, cpp_hashnode *node)

Jason> Do we also want to look at the va_opt option in this function, to
Jason> complain if pedantic and it isn't set?

Thanks for noticing that.  I also made it suppress the error for system
headers.

I'm still too happy with the error message, so if you have any
suggestions there, please let me know.  I removed the "C99" branch from
the earlier error message as well, since this isn't a C feature at all.
Again, please check the wording.

thanks,
Tom

commit f163032782a1b5ed05ff3a3bab5a2e76c203d124
Author: Tom Tromey <tom@tromey.com>
Date:   Thu Sep 14 12:41:51 2017 -0600

    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
    
    I am not completely sure that I have handled the error reporting
    correctly.  I chose to allow __VA_OPT__ generally, on the theory that,
    because it is a reserved identifier, programs should not be referring
    to it anyway.  Also, this approach makes it possible for __VA_OPT__ to
    be used in system headers even when the -std/-pedantic settings may
    otherwise disallow it.
    
    Bootstrapped and regression tested on x86-64 Fedora 25.
    
    gcc/ChangeLog
    2017-09-16  Tom Tromey  <tom@tromey.com>
    
            * doc/cpp.texi (Variadic Macros): Document __VA_OPT__.
    
    gcc/testsuite/ChangeLog
    2017-11-11  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.
    
    libcpp/ChangeLog
    2017-09-16  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__.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e213db6e2a0..362f50ecb98 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-16  Tom Tromey  <tom@tromey.com>
+
+	* doc/cpp.texi (Variadic Macros): Document __VA_OPT__.
+
 2017-09-16  Richard Sandiford  <richard.sandiford@linaro.org>
 
 	PR tree-optimization/82228
diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 52f2606eadc..33e72c63f59 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 1a94535b0ee..f40350a3e4e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2017-11-11  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-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
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 00000000000..f32f0551723
--- /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 00000000000..5887bf5a484
--- /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 00000000000..243d33b2cf1
--- /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);
+}
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 0621074b53b..4dfa5aa77b8 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,22 @@
+2017-09-16  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-09-15  Andrew Sutton  <andrew.n.sutton@gmail.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 220f9b97f0d..e456fd3a4fc 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -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__"));
 }
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 804132a44da..fc98175fb08 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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;
 
diff --git a/libcpp/init.c b/libcpp/init.c
index 16ff202c8cf..c3b4641d49d 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -91,28 +91,29 @@ 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 },
-  /* 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 },
-  /* 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 },
+  /* 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 },
+  /* 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.  */
@@ -137,6 +138,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.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index f24e85cfb11..0a33abafd43 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -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 */
 };
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 40ff801e8e3..38a9f3c6614 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -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,
diff --git a/libcpp/macro.c b/libcpp/macro.c
index de18c2210cf..35ec59a7c87 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -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 *,
@@ -768,7 +917,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");
@@ -778,7 +928,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,
@@ -1670,6 +1821,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;
@@ -1677,6 +1830,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
@@ -3068,6 +3225,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
@@ -3136,10 +3296,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;
 
diff --git a/libcpp/pch.c b/libcpp/pch.c
index cad4b872cda..b685a38a854 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -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__"));
   }
Jason Merrill Nov. 13, 2017, 4:52 p.m. UTC | #10
On Sun, Nov 12, 2017 at 2:33 AM, Tom Tromey <tom@tromey.com> wrote:
> I'm still [not] too happy with the error message, so if you have any
> suggestions there, please let me know.  I removed the "C99" branch from
> the earlier error message as well, since this isn't a C feature at all.
> Again, please check the wording.

I'm ambivalent about mentioning the standard level.  And I find the
use of "expansion" in this and the existing __VA_ARGS__ error odd, as
expansion is what you *do* with a macro; I'd prefer "definition".

But I suppose we might as well be consistent with the existing error.

The patch is OK, thanks.

Jason
diff mbox series

Patch

diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 52f2606..3990165 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++20, 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 een 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++20, and GNU CPP also has a pair of
+extensions which deal with this problem.
+
+First, in GNU CPP, and in C++ beginning in C++20, 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++20 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 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/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..7718916
--- /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-error "__VA_OPT__ can only appear" } */
+#define ERR2(x) __VA_OPT__( /* { dg-error "can only appear" } */
+#define ERR3(x) __VA_OPT__() /* { dg-error "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-error "can only appear" } */
+#define ERRC(__VA_OPT__) x /* { dg-error "can only appear" } */
+
+__VA_OPT__ /* { dg-error "can only appear" } */
+
+#define ERRD(x)
+ERRD(__VA_OPT__) /* { dg-error "can only appear" } */
+
+#define __VA_OPT__ /* { dg-error "can only appear" } */
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);
+}
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 220f9b9..e456fd3 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -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__"));
 }
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 804132a..fc98175 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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;
 
diff --git a/libcpp/init.c b/libcpp/init.c
index 16ff202..2bf76a7 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -91,28 +91,29 @@  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 },
-  /* 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 },
-  /* 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,      0 },
+  /* GNUC99   */  { 1,  0,  1,  1,  0,  0,  1,   1,   1,   0,    0,     0,     0,   0,      0 },
+  /* GNUC11   */  { 1,  0,  1,  1,  1,  0,  1,   1,   1,   0,    0,     0,     0,   0,      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,      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 },
+  /* GNUCXX   */  { 0,  1,  1,  1,  0,  0,  1,   0,   0,   0,    0,     0,     0,   0,      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,      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,      0 },
+  /* CXX14    */  { 1,  1,  0,  1,  1,  1,  1,   1,   1,   1,    1,     1,     1,   0,      0 },
+  /* GNUCXX1Z */  { 1,  1,  1,  1,  1,  0,  1,   1,   1,   1,    1,     1,     0,   1,      0 },
+  /* CXX1Z    */  { 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.  */
@@ -137,6 +138,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.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index f24e85c..0a33aba 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -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 */
 };
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 40ff801..eca4a23 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1396,6 +1396,21 @@  lex_identifier_intern (cpp_reader *pfile, const uchar *base)
 		       " 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__
+	  && !pfile->state.va_args_ok)
+	{
+	  if (CPP_OPTION (pfile, cplusplus))
+	    cpp_error (pfile, CPP_DL_ERROR,
+		       "__VA_OPT__ can only appear in the expansion"
+		       " of a C++11 variadic macro");
+	  else
+	    cpp_error (pfile, CPP_DL_ERROR,
+		       "__VA_OPT__ can only appear in the expansion"
+		       " of a C99 variadic macro");
+	}
+
       /* 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 +1500,21 @@  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__
+	  && !pfile->state.va_args_ok)
+	{
+	  if (CPP_OPTION (pfile, cplusplus))
+	    cpp_error (pfile, CPP_DL_ERROR,
+		       "__VA_OPT__ can only appear in the expansion"
+		       " of a C++11 variadic macro");
+	  else
+	    cpp_error (pfile, CPP_DL_ERROR,
+		       "__VA_OPT__ can only appear in the expansion"
+		       " of a C99 variadic macro");
+	}
+
       /* For -Wc++-compat, warn about use of C++ named operators.  */
       if (result->flags & NODE_WARN_OPERATOR)
 	cpp_warning (pfile, CPP_W_CXX_OPERATOR_NAMES,
diff --git a/libcpp/macro.c b/libcpp/macro.c
index de18c22..b16a24e 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -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 *,
@@ -768,7 +917,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");
@@ -778,7 +928,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,
@@ -1670,6 +1821,8 @@  replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
 				 num_macro_tokens);
     }
   i = 0;
+  vaopt_state state_tracker (pfile, macro->variadic,
+			     args[macro->paramc - 1].count > 0);
   for (src = macro->exp.tokens; src < limit; src++)
     {
       unsigned int arg_tokens_count;
@@ -1677,6 +1830,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 (state_tracker.update (src) != vaopt_state::INCLUDE)
+	continue;
+
       if (src->type != CPP_MACRO_ARG)
 	{
 	  /* Allocate a virtual location for token SRC, and add that
@@ -3068,6 +3225,9 @@  create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
       *token = *ctoken;
     }
 
+  /* The argument doesn't matter here.  */
+  vaopt_state state_tracker (pfile, macro->variadic, true);
+
   for (;;)
     {
       /* Check the stringifying # constraint 6.10.3.2.1 of
@@ -3136,10 +3296,16 @@  create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
 	    }
 	}
 
+      if (state_tracker.update (token) == vaopt_state::ERROR)
+	return false;
+
       following_paste_op = (token->type == CPP_PASTE);
       token = lex_expansion_token (pfile, macro);
     }
 
+  if (!state_tracker.completed ())
+    return false;
+
   macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
   macro->traditional = 0;
 
diff --git a/libcpp/pch.c b/libcpp/pch.c
index cad4b87..b685a38 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -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__"));
   }