Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA] Add support for __VA_OPT__
@ 2017-09-18  2:42 Tom Tromey
  2017-09-20 16:43 ` Pedro Alves
  0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2017-09-18  2:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

C++2a adds a "__VA_OPT__" feature that can be used to control the
pesky "," emission when the final (variable) argument of a variadic
macro is empty.  This patch implements this feature for gdb.  (A patch
to implement it for gcc is pending.)

gdb/ChangeLog
2017-09-17  Tom Tromey  <tom@tromey.com>

	* macroexp.c (get_next_token_for_substitution): New function.
	(substitute_args): Call it.  Check for __VA_OPT__.

gdb/testsuite/ChangeLog
2017-09-17  Tom Tromey  <tom@tromey.com>

	* gdb.base/macscp.exp: Add __VA_OPT__ tests.
---
 gdb/ChangeLog                     |  5 +++
 gdb/macroexp.c                    | 73 +++++++++++++++++++++++++++++++++++----
 gdb/testsuite/ChangeLog           |  4 +++
 gdb/testsuite/gdb.base/macscp.exp | 12 +++++++
 4 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/gdb/macroexp.c b/gdb/macroexp.c
index e7a0dad..369fc78 100644
--- a/gdb/macroexp.c
+++ b/gdb/macroexp.c
@@ -946,6 +946,22 @@ find_parameter (const struct macro_buffer *tok,
   return -1;
 }
  
+/* Helper function for substitute_args that gets the next token and
+   updates the passed-in state variables.  */
+
+static int
+get_next_token_for_substitution (struct macro_buffer *replacement_list,
+				 struct macro_buffer *token,
+				 char **start,
+				 struct macro_buffer *lookahead,
+				 char **lookahead_start)
+{
+  *token = *lookahead;
+  *start = *lookahead_start;
+  *lookahead_start = replacement_list->text;
+  return get_token (lookahead, replacement_list);
+}
+
 /* Given the macro definition DEF, being invoked with the actual
    arguments given by ARGC and ARGV, substitute the arguments into the
    replacement list, and store the result in DEST.
@@ -996,8 +1012,57 @@ substitute_args (struct macro_buffer *dest,
   lookahead_rl_start = replacement_list.text;
   lookahead_valid = get_token (&lookahead, &replacement_list);
 
-  for (;;)
+  /* __VA_OPT__ state variable.  The states are:
+     0 - nothing happening
+     1 - saw __VA_OPT__
+     >= 2 in __VA_OPT__, the value encodes the parenthesis depth.  */
+  unsigned vaopt_state = 0;
+
+  for (;;
+       lookahead_valid = get_next_token_for_substitution (&replacement_list,
+							  &tok,
+							  &original_rl_start,
+							  &lookahead,
+							  &lookahead_rl_start))
     {
+      if (vaopt_state > 0)
+	{
+	  if (tok.len == 1)
+	    {
+	      if (tok.text[0] == '(')
+		{
+		  ++vaopt_state;
+		  /* We just entered __VA_OPT__, so don't emit this
+		     token.  */
+		  continue;
+		}
+	      else if (tok.text[0] == ')')
+		{
+		  --vaopt_state;
+		  if (vaopt_state == 1)
+		    {
+		      /* Done with __VA_OPT__.  */
+		      vaopt_state = 0;
+		      /* Don't emit.  */
+		      continue;
+		    }
+		}
+	    }
+
+	  /* If __VA_ARGS__ is empty, then drop the contents of
+	     __VA_OPT__.  */
+	  if (argv[argc - 1].len == 0)
+	    continue;
+	}
+      else if (is_varargs
+	       && tok.len == 10
+	       && strncmp (tok.text, "__VA_OPT__", 10) == 0)
+	{
+	  vaopt_state = 1;
+	  /* Don't emit this token.  */
+	  continue;
+	}
+
       /* Just for aesthetics.  If we skipped some whitespace, copy
          that to DEST.  */
       if (tok.text > original_rl_start)
@@ -1160,12 +1225,6 @@ substitute_args (struct macro_buffer *dest,
 
       if (! lookahead_valid)
 	break;
-
-      tok = lookahead;
-      original_rl_start = lookahead_rl_start;
-
-      lookahead_rl_start = replacement_list.text;
-      lookahead_valid = get_token (&lookahead, &replacement_list);
     }
 }
 
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
index 54b5ab2..a08ec46 100644
--- a/gdb/testsuite/gdb.base/macscp.exp
+++ b/gdb/testsuite/gdb.base/macscp.exp
@@ -620,6 +620,10 @@ gdb_test_no_output "macro define va_gnu(args...) varfunc (fixedarg, args)" \
 gdb_test_no_output "macro define va2_gnu(args...) varfunc (fixedarg, ## args)" \
   "define fourth varargs helper"
 
+gdb_test_no_output \
+    "macro define va3_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_ARGS__)" \
+    "define fifth varargs helper"
+
 gdb_test "macro expand va_c99(one, two, three)" \
   "expands to: *varfunc \\(fixedarg, *one, two, three\\)" \
   "c99 varargs expansion"
@@ -644,6 +648,14 @@ gdb_test "macro expand va2_gnu()" \
   "expands to: *varfunc \\(fixedarg\\)" \
   "gnu varargs expansion special splicing without an argument"
 
+gdb_test "macro expand va3_cxx2a(23)" \
+    "expands to: *varfunc \\(23 \\)" \
+    "C++2a __VA_OPT__ handling without variable argument"
+
+gdb_test "macro expand va3_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23, 24, 25\\)" \
+    "C++2a __VA_OPT__ handling with variable argument"
+
 # Stringification tests.
 
 gdb_test_no_output "macro define str(x) #x" \
-- 
2.9.4


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-18  2:42 [RFA] Add support for __VA_OPT__ Tom Tromey
@ 2017-09-20 16:43 ` Pedro Alves
  2017-09-21  3:42   ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2017-09-20 16:43 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

W00t, thanks for doing this (and the gcc side as well!)

On 09/18/2017 03:42 AM, Tom Tromey wrote:

> diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
> index 54b5ab2..a08ec46 100644
> --- a/gdb/testsuite/gdb.base/macscp.exp
> +++ b/gdb/testsuite/gdb.base/macscp.exp
> @@ -620,6 +620,10 @@ gdb_test_no_output "macro define va_gnu(args...) varfunc (fixedarg, args)" \
>  gdb_test_no_output "macro define va2_gnu(args...) varfunc (fixedarg, ## args)" \
>    "define fourth varargs helper"
>  
> +gdb_test_no_output \
> +    "macro define va3_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_ARGS__)" \
> +    "define fifth varargs helper"
> +
>  gdb_test "macro expand va_c99(one, two, three)" \
>    "expands to: *varfunc \\(fixedarg, *one, two, three\\)" \
>    "c99 varargs expansion"
> @@ -644,6 +648,14 @@ gdb_test "macro expand va2_gnu()" \
>    "expands to: *varfunc \\(fixedarg\\)" \
>    "gnu varargs expansion special splicing without an argument"
>  
> +gdb_test "macro expand va3_cxx2a(23)" \
> +    "expands to: *varfunc \\(23 \\)" \
> +    "C++2a __VA_OPT__ handling without variable argument"
> +
> +gdb_test "macro expand va3_cxx2a(23, 24, 25)" \
> +    "expands to: *varfunc \\(23, 24, 25\\)" \
> +    "C++2a __VA_OPT__ handling with variable argument"
> +

The patch looks good to me, though I think it'd be nice to see
tests that make sure that ill-formed input doesn't send us
to the weeds.  Like:

 - does the state machine handle "__VA_OPT__)" gracefully?
   I.e., ')' before '('.
 - similarly: "__VA_OPT__)(,)"
 - does the state machine handle multiple occurrences of
   __VA_OPT__ in the same macro expansion?  It looks like
   it, but....

Also, does this handle:

 __VA_OPT__(__VA_ARGS__)

correctly?  I think so, but...

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-20 16:43 ` Pedro Alves
@ 2017-09-21  3:42   ` Tom Tromey
  2017-09-21  9:01     ` Pedro Alves
  0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2017-09-21  3:42 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tom Tromey, gdb-patches

Pedro> The patch looks good to me, though I think it'd be nice to see
Pedro> tests that make sure that ill-formed input doesn't send us
Pedro> to the weeds.  Like:
Pedro>  - does the state machine handle "__VA_OPT__)" gracefully?
Pedro>    I.e., ')' before '('.
Pedro>  - similarly: "__VA_OPT__)(,)"
Pedro>  - does the state machine handle multiple occurrences of
Pedro>    __VA_OPT__ in the same macro expansion?  It looks like
Pedro>    it, but....
Pedro> Also, does this handle:
Pedro>  __VA_OPT__(__VA_ARGS__)
Pedro> correctly?  I think so, but...

I've added all of these.

But I wonder if gdb should just error() on the invalid ones.
My first thought was no, why make life harder -- but at the same time,
the invalid cases really aren't that useful either.

Tom

commit 635411e81e8ce24fcc8887755b1520baf9044205
Author: Tom Tromey <tom@tromey.com>
Date:   Sun Sep 17 20:36:41 2017 -0600

    Add support for __VA_OPT__
    
    C++2a adds a "__VA_OPT__" feature that can be used to control the
    pesky "," emission when the final (variable) argument of a variadic
    macro is empty.  This patch implements this feature for gdb.  (A patch
    to implement it for gcc is pending.)
    
    gdb/ChangeLog
    2017-09-17  Tom Tromey  <tom@tromey.com>
    
            * macroexp.c (get_next_token_for_substitution): New function.
            (substitute_args): Call it.  Check for __VA_OPT__.
    
    gdb/testsuite/ChangeLog
    2017-09-17  Tom Tromey  <tom@tromey.com>
    
            * gdb.base/macscp.exp: Add __VA_OPT__ tests.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4de6da2..34c9810 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-09-17  Tom Tromey  <tom@tromey.com>
+
+	* macroexp.c (get_next_token_for_substitution): New function.
+	(substitute_args): Call it.  Check for __VA_OPT__.
+
 2017-09-20  Pedro Alves  <palves@redhat.com>
 
 	* eval.c (make_params): Delete, refactored as ...
diff --git a/gdb/macroexp.c b/gdb/macroexp.c
index e7a0dad..369fc78 100644
--- a/gdb/macroexp.c
+++ b/gdb/macroexp.c
@@ -946,6 +946,22 @@ find_parameter (const struct macro_buffer *tok,
   return -1;
 }
  
+/* Helper function for substitute_args that gets the next token and
+   updates the passed-in state variables.  */
+
+static int
+get_next_token_for_substitution (struct macro_buffer *replacement_list,
+				 struct macro_buffer *token,
+				 char **start,
+				 struct macro_buffer *lookahead,
+				 char **lookahead_start)
+{
+  *token = *lookahead;
+  *start = *lookahead_start;
+  *lookahead_start = replacement_list->text;
+  return get_token (lookahead, replacement_list);
+}
+
 /* Given the macro definition DEF, being invoked with the actual
    arguments given by ARGC and ARGV, substitute the arguments into the
    replacement list, and store the result in DEST.
@@ -996,8 +1012,57 @@ substitute_args (struct macro_buffer *dest,
   lookahead_rl_start = replacement_list.text;
   lookahead_valid = get_token (&lookahead, &replacement_list);
 
-  for (;;)
+  /* __VA_OPT__ state variable.  The states are:
+     0 - nothing happening
+     1 - saw __VA_OPT__
+     >= 2 in __VA_OPT__, the value encodes the parenthesis depth.  */
+  unsigned vaopt_state = 0;
+
+  for (;;
+       lookahead_valid = get_next_token_for_substitution (&replacement_list,
+							  &tok,
+							  &original_rl_start,
+							  &lookahead,
+							  &lookahead_rl_start))
     {
+      if (vaopt_state > 0)
+	{
+	  if (tok.len == 1)
+	    {
+	      if (tok.text[0] == '(')
+		{
+		  ++vaopt_state;
+		  /* We just entered __VA_OPT__, so don't emit this
+		     token.  */
+		  continue;
+		}
+	      else if (tok.text[0] == ')')
+		{
+		  --vaopt_state;
+		  if (vaopt_state == 1)
+		    {
+		      /* Done with __VA_OPT__.  */
+		      vaopt_state = 0;
+		      /* Don't emit.  */
+		      continue;
+		    }
+		}
+	    }
+
+	  /* If __VA_ARGS__ is empty, then drop the contents of
+	     __VA_OPT__.  */
+	  if (argv[argc - 1].len == 0)
+	    continue;
+	}
+      else if (is_varargs
+	       && tok.len == 10
+	       && strncmp (tok.text, "__VA_OPT__", 10) == 0)
+	{
+	  vaopt_state = 1;
+	  /* Don't emit this token.  */
+	  continue;
+	}
+
       /* Just for aesthetics.  If we skipped some whitespace, copy
          that to DEST.  */
       if (tok.text > original_rl_start)
@@ -1160,12 +1225,6 @@ substitute_args (struct macro_buffer *dest,
 
       if (! lookahead_valid)
 	break;
-
-      tok = lookahead;
-      original_rl_start = lookahead_rl_start;
-
-      lookahead_rl_start = replacement_list.text;
-      lookahead_valid = get_token (&lookahead, &replacement_list);
     }
 }
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 721bd81..3e16b5a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-17  Tom Tromey  <tom@tromey.com>
+
+	* gdb.base/macscp.exp: Add __VA_OPT__ tests.
+
 2017-09-20  Pedro Alves  <palves@redhat.com>
 
 	* gdb.base/list-ambiguous.exp (test_list_ambiguous_symbol): Expect
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
index 54b5ab2..96674f3 100644
--- a/gdb/testsuite/gdb.base/macscp.exp
+++ b/gdb/testsuite/gdb.base/macscp.exp
@@ -620,6 +620,18 @@ gdb_test_no_output "macro define va_gnu(args...) varfunc (fixedarg, args)" \
 gdb_test_no_output "macro define va2_gnu(args...) varfunc (fixedarg, ## args)" \
   "define fourth varargs helper"
 
+gdb_test_no_output \
+    "macro define va3_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_ARGS__)" \
+    "define fifth varargs helper"
+
+gdb_test_no_output \
+    "macro define va4_cxx2a(x, ...) varfunc (x __VA_OPT__(, __VA_ARGS__))" \
+    "define sixth varargs helper"
+
+gdb_test_no_output \
+    "macro define va5_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_OPT__(__VA_ARGS__))" \
+    "define seventh varargs helper"
+
 gdb_test "macro expand va_c99(one, two, three)" \
   "expands to: *varfunc \\(fixedarg, *one, two, three\\)" \
   "c99 varargs expansion"
@@ -644,6 +656,50 @@ gdb_test "macro expand va2_gnu()" \
   "expands to: *varfunc \\(fixedarg\\)" \
   "gnu varargs expansion special splicing without an argument"
 
+gdb_test "macro expand va3_cxx2a(23)" \
+    "expands to: *varfunc \\(23 \\)" \
+    "C++2a __VA_OPT__ handling without variable argument"
+
+gdb_test "macro expand va3_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23, 24, 25\\)" \
+    "C++2a __VA_OPT__ handling with variable argument"
+
+gdb_test "macro expand va4_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23, 24, 25\\)" \
+    "C++2a __VA_OPT__ conditional __VA_ARGS__ handling with variable argument"
+
+gdb_test "macro expand va4_cxx2a(23)" \
+    "expands to: *varfunc \\(23\\)" \
+    "C++2a __VA_OPT__ conditional __VA_ARGS__ handling without variable argument"
+
+gdb_test "macro expand va5_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23,24, 25\\)" \
+    "C++2a double __VA_OPT__ conditional __VA_ARGS__ handling with variable argument"
+
+gdb_test "macro expand va5_cxx2a(23)" \
+    "expands to: *varfunc \\(23\\)" \
+    "C++2a double __VA_OPT__ conditional __VA_ARGS__ handling without variable argument"
+
+#
+# Invalid __VA_OPT__ tests are not intended to define gdb's output,
+# but rather to ensure that gdb at least doesn't crash when presented
+# with something invalid.
+#
+
+gdb_test_no_output \
+    "macro define badopt1(x, ...) __VA_OPT__) x" \
+    "define first invalid varargs helper"
+gdb_test "macro expand badopt1(5)" \
+    "expands to:  5" \
+    "Test that first invalid __VA_OPT__ doesn't crash"
+
+gdb_test_no_output \
+    "macro define badopt1(x, ...) __VA_OPT__)(,) x" \
+    "define second invalid varargs helper"
+gdb_test "macro expand badopt1(5)" \
+    "expands to: \\(,\\) 5" \
+    "Test that second invalid __VA_OPT__ doesn't crash"
+
 # Stringification tests.
 
 gdb_test_no_output "macro define str(x) #x" \


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-21  3:42   ` Tom Tromey
@ 2017-09-21  9:01     ` Pedro Alves
  2017-09-23  3:03       ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2017-09-21  9:01 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 09/21/2017 04:42 AM, Tom Tromey wrote:
> Pedro> The patch looks good to me, though I think it'd be nice to see
> Pedro> tests that make sure that ill-formed input doesn't send us
> Pedro> to the weeds.  Like:
> Pedro>  - does the state machine handle "__VA_OPT__)" gracefully?
> Pedro>    I.e., ')' before '('.
> Pedro>  - similarly: "__VA_OPT__)(,)"
> Pedro>  - does the state machine handle multiple occurrences of
> Pedro>    __VA_OPT__ in the same macro expansion?  It looks like
> Pedro>    it, but....
> Pedro> Also, does this handle:
> Pedro>  __VA_OPT__(__VA_ARGS__)
> Pedro> correctly?  I think so, but...
> 
> I've added all of these.

Great, thanks!

> 
> But I wonder if gdb should just error() on the invalid ones.
> My first thought was no, why make life harder -- but at the same time,
> the invalid cases really aren't that useful either.

Yeah, error might be better - e.g., for someone trying
to write a "macro define" interactively (without
going via the compiler first), and puzzling about why it
doesn't exactly work [due to some typo].  But we can
decide to do that incrementally.  Fine with me to push
as is if you'd like.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-21  9:01     ` Pedro Alves
@ 2017-09-23  3:03       ` Tom Tromey
  2017-09-27 11:32         ` Pedro Alves
  0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2017-09-23  3:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tom Tromey, gdb-patches

>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

>> But I wonder if gdb should just error() on the invalid ones.
>> My first thought was no, why make life harder -- but at the same time,
>> the invalid cases really aren't that useful either.

Pedro> Yeah, error might be better - e.g., for someone trying
Pedro> to write a "macro define" interactively (without
Pedro> going via the compiler first), and puzzling about why it
Pedro> doesn't exactly work [due to some typo].  But we can
Pedro> decide to do that incrementally.  Fine with me to push
Pedro> as is if you'd like.

I've switched it; and good thing, too, because this caught a bug in the
previous patch that could cause an infinite loop.

Tom

commit dbaa7cadd373972d362c10cedc8f34f5cf1d6e2a
Author: Tom Tromey <tom@tromey.com>
Date:   Sun Sep 17 20:36:41 2017 -0600

    Add support for __VA_OPT__
    
    C++2a adds a "__VA_OPT__" feature that can be used to control the
    pesky "," emission when the final (variable) argument of a variadic
    macro is empty.  This patch implements this feature for gdb.  (A patch
    to implement it for gcc is pending.)
    
    ChangeLog
    2017-09-17  Tom Tromey  <tom@tromey.com>
    
            * macroexp.c (get_next_token_for_substitution): New function.
            (substitute_args): Call it.  Check for __VA_OPT__.
    
    testsuite/ChangeLog
    2017-09-17  Tom Tromey  <tom@tromey.com>
    
            * gdb.base/macscp.exp: Add __VA_OPT__ tests.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index aa50dc9..d660fb0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-09-17  Tom Tromey  <tom@tromey.com>
+
+	* macroexp.c (get_next_token_for_substitution): New function.
+	(substitute_args): Call it.  Check for __VA_OPT__.
+
 2017-09-22  Tom Tromey  <tom@tromey.com>
 
 	* utils.c (class scoped_input_handler) <m_quit_handler>: Change
diff --git a/gdb/macroexp.c b/gdb/macroexp.c
index e7a0dad..7d5b876 100644
--- a/gdb/macroexp.c
+++ b/gdb/macroexp.c
@@ -946,6 +946,30 @@ find_parameter (const struct macro_buffer *tok,
   return -1;
 }
  
+/* Helper function for substitute_args that gets the next token and
+   updates the passed-in state variables.  */
+
+static void
+get_next_token_for_substitution (struct macro_buffer *replacement_list,
+				 struct macro_buffer *token,
+				 char **start,
+				 struct macro_buffer *lookahead,
+				 char **lookahead_start,
+				 int *lookahead_valid,
+				 bool *keep_going)
+{
+  if (!*lookahead_valid)
+    *keep_going = false;
+  else
+    {
+      *keep_going = true;
+      *token = *lookahead;
+      *start = *lookahead_start;
+      *lookahead_start = replacement_list->text;
+      *lookahead_valid = get_token (lookahead, replacement_list);
+    }
+}
+
 /* Given the macro definition DEF, being invoked with the actual
    arguments given by ARGC and ARGV, substitute the arguments into the
    replacement list, and store the result in DEST.
@@ -996,8 +1020,67 @@ substitute_args (struct macro_buffer *dest,
   lookahead_rl_start = replacement_list.text;
   lookahead_valid = get_token (&lookahead, &replacement_list);
 
-  for (;;)
+  /* __VA_OPT__ state variable.  The states are:
+     0 - nothing happening
+     1 - saw __VA_OPT__
+     >= 2 in __VA_OPT__, the value encodes the parenthesis depth.  */
+  unsigned vaopt_state = 0;
+
+  /* Whether the loop should keep going.  */
+  bool keep_going = true;
+
+  for (;
+       keep_going;
+       get_next_token_for_substitution (&replacement_list,
+					&tok,
+					&original_rl_start,
+					&lookahead,
+					&lookahead_rl_start,
+					&lookahead_valid,
+					&keep_going))
     {
+      bool token_is_vaopt = (tok.len == 10
+			     && strncmp (tok.text, "__VA_OPT__", 10) == 0);
+
+      if (vaopt_state > 0)
+	{
+	  if (token_is_vaopt)
+	    error (_("__VA_OPT__ cannot appear inside __VA_OPT__"));
+	  else if (tok.len == 1 && tok.text[0] == '(')
+	    {
+	      ++vaopt_state;
+	      /* We just entered __VA_OPT__, so don't emit this
+		 token.  */
+	      continue;
+	    }
+	  else if (vaopt_state == 1)
+	    error (_("__VA_OPT__ must be followed by an open parenthesis"));
+	  else if (tok.len == 1 && tok.text[0] == ')')
+	    {
+	      --vaopt_state;
+	      if (vaopt_state == 1)
+		{
+		  /* Done with __VA_OPT__.  */
+		  vaopt_state = 0;
+		  /* Don't emit.  */
+		  continue;
+		}
+	    }
+
+	  /* If __VA_ARGS__ is empty, then drop the contents of
+	     __VA_OPT__.  */
+	  if (argv[argc - 1].len == 0)
+	    continue;
+	}
+      else if (token_is_vaopt)
+	{
+	  if (!is_varargs)
+	    error (_("__VA_OPT__ is only valid in a variadic macro"));
+	  vaopt_state = 1;
+	  /* Don't emit this token.  */
+	  continue;
+	}
+
       /* Just for aesthetics.  If we skipped some whitespace, copy
          that to DEST.  */
       if (tok.text > original_rl_start)
@@ -1157,16 +1240,10 @@ substitute_args (struct macro_buffer *dest,
 	  if (! substituted)
 	    append_tokens_without_splicing (dest, &tok);
 	}
-
-      if (! lookahead_valid)
-	break;
-
-      tok = lookahead;
-      original_rl_start = lookahead_rl_start;
-
-      lookahead_rl_start = replacement_list.text;
-      lookahead_valid = get_token (&lookahead, &replacement_list);
     }
+
+  if (vaopt_state > 0)
+    error (_("Unterminated __VA_OPT__"));
 }
 
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 6584a23..ddc17d2 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-17  Tom Tromey  <tom@tromey.com>
+
+	* gdb.base/macscp.exp: Add __VA_OPT__ tests.
+
 2017-09-21  Kevin Buettner  <kevinb@redhat.com>
 
 	* gdb.python/py-thrhandle.c, gdb.python/py-thrhandle.exp: New
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
index 54b5ab2..c5cd899 100644
--- a/gdb/testsuite/gdb.base/macscp.exp
+++ b/gdb/testsuite/gdb.base/macscp.exp
@@ -620,6 +620,18 @@ gdb_test_no_output "macro define va_gnu(args...) varfunc (fixedarg, args)" \
 gdb_test_no_output "macro define va2_gnu(args...) varfunc (fixedarg, ## args)" \
   "define fourth varargs helper"
 
+gdb_test_no_output \
+    "macro define va3_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_ARGS__)" \
+    "define fifth varargs helper"
+
+gdb_test_no_output \
+    "macro define va4_cxx2a(x, ...) varfunc (x __VA_OPT__(, __VA_ARGS__))" \
+    "define sixth varargs helper"
+
+gdb_test_no_output \
+    "macro define va5_cxx2a(x, ...) varfunc (x __VA_OPT__(,) __VA_OPT__(__VA_ARGS__))" \
+    "define seventh varargs helper"
+
 gdb_test "macro expand va_c99(one, two, three)" \
   "expands to: *varfunc \\(fixedarg, *one, two, three\\)" \
   "c99 varargs expansion"
@@ -644,6 +656,58 @@ gdb_test "macro expand va2_gnu()" \
   "expands to: *varfunc \\(fixedarg\\)" \
   "gnu varargs expansion special splicing without an argument"
 
+gdb_test "macro expand va3_cxx2a(23)" \
+    "expands to: *varfunc \\(23 \\)" \
+    "C++2a __VA_OPT__ handling without variable argument"
+
+gdb_test "macro expand va3_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23, 24, 25\\)" \
+    "C++2a __VA_OPT__ handling with variable argument"
+
+gdb_test "macro expand va4_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23, 24, 25\\)" \
+    "C++2a __VA_OPT__ conditional __VA_ARGS__ handling with variable argument"
+
+gdb_test "macro expand va4_cxx2a(23)" \
+    "expands to: *varfunc \\(23\\)" \
+    "C++2a __VA_OPT__ conditional __VA_ARGS__ handling without variable argument"
+
+gdb_test "macro expand va5_cxx2a(23, 24, 25)" \
+    "expands to: *varfunc \\(23,24, 25\\)" \
+    "C++2a double __VA_OPT__ conditional __VA_ARGS__ handling with variable argument"
+
+gdb_test "macro expand va5_cxx2a(23)" \
+    "expands to: *varfunc \\(23\\)" \
+    "C++2a double __VA_OPT__ conditional __VA_ARGS__ handling without variable argument"
+
+gdb_test_no_output \
+    "macro define badopt1(x, ...) __VA_OPT__) x" \
+    "define first invalid varargs helper"
+gdb_test "macro expand badopt1(5)" \
+    "__VA_OPT__ must be followed by an open parenthesis" \
+    "__VA_OPT__ without open paren"
+
+gdb_test_no_output \
+    "macro define badopt2(x, ...) __VA_OPT__(__VA_OPT__(,)) x" \
+    "define second invalid varargs helper"
+gdb_test "macro expand badopt2(5)" \
+    "__VA_OPT__ cannot appear inside __VA_OPT__" \
+    "__VA_OPT__ inside __VA_OPT__"
+
+gdb_test_no_output \
+    "macro define badopt3(x) __VA_OPT__" \
+    "define third invalid varargs helper"
+gdb_test "macro expand badopt3(5)" \
+    "__VA_OPT__ is only valid in a variadic macro" \
+    "__VA_OPT__ not in variadic macro"
+
+gdb_test_no_output \
+    "macro define badopt4(x, ...) __VA_OPT__(x" \
+    "define fourth invalid varargs helper"
+gdb_test "macro expand badopt4(5)" \
+    "Unterminated __VA_OPT__" \
+    "__VA_OPT__ without closing paren"
+
 # Stringification tests.
 
 gdb_test_no_output "macro define str(x) #x" \


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-23  3:03       ` Tom Tromey
@ 2017-09-27 11:32         ` Pedro Alves
  2017-09-27 14:19           ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2017-09-27 11:32 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 09/23/2017 04:03 AM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> 
>>> But I wonder if gdb should just error() on the invalid ones.
>>> My first thought was no, why make life harder -- but at the same time,
>>> the invalid cases really aren't that useful either.
> 
> Pedro> Yeah, error might be better - e.g., for someone trying
> Pedro> to write a "macro define" interactively (without
> Pedro> going via the compiler first), and puzzling about why it
> Pedro> doesn't exactly work [due to some typo].  But we can
> Pedro> decide to do that incrementally.  Fine with me to push
> Pedro> as is if you'd like.
> 
> I've switched it; and good thing, too, because this caught a bug in the
> previous patch that could cause an infinite loop.
> 

Nice.  Patch looks good.  Please push.


> +  /* Whether the loop should keep going.  */
> +  bool keep_going = true;

'keep_going' doesn't appear used after the loop.  Could it be
declared in the for's init statement ?

  for (bool keep_going = true;
       keep_going;
       ...

> +
> +  for (;
> +       keep_going;
> +       get_next_token_for_substitution (&replacement_list,
> +					&tok,
> +					&original_rl_start,
> +					&lookahead,
> +					&lookahead_rl_start,
> +					&lookahead_valid,
> +					&keep_going))
>      {

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFA] Add support for __VA_OPT__
  2017-09-27 11:32         ` Pedro Alves
@ 2017-09-27 14:19           ` Tom Tromey
  0 siblings, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2017-09-27 14:19 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tom Tromey, gdb-patches

Pedro> 'keep_going' doesn't appear used after the loop.  Could it be
Pedro> declared in the for's init statement ?

Yes.  I made this change, and I'm going to push it in now.

thanks,
Tom


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-09-27 14:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-18  2:42 [RFA] Add support for __VA_OPT__ Tom Tromey
2017-09-20 16:43 ` Pedro Alves
2017-09-21  3:42   ` Tom Tromey
2017-09-21  9:01     ` Pedro Alves
2017-09-23  3:03       ` Tom Tromey
2017-09-27 11:32         ` Pedro Alves
2017-09-27 14:19           ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox