aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2017-09-17 20:36:41 -0600
committerTom Tromey <tom@tromey.com>2017-09-27 07:51:33 -0600
commita9bbfbd85fddfea2db30810c33c4bb130a2ef773 (patch)
treee8e03252fbd330c15075d6d2a45520985e88c65f /gdb
parent19485196044b2521af979f1e5c4a89bfb90fba0b (diff)
downloadfsf-binutils-gdb-a9bbfbd85fddfea2db30810c33c4bb130a2ef773.zip
fsf-binutils-gdb-a9bbfbd85fddfea2db30810c33c4bb130a2ef773.tar.gz
fsf-binutils-gdb-a9bbfbd85fddfea2db30810c33c4bb130a2ef773.tar.bz2
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-27 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-27 Tom Tromey <tom@tromey.com> * gdb.base/macscp.exp: Add __VA_OPT__ tests.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/macroexp.c94
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.base/macscp.exp64
4 files changed, 157 insertions, 10 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index efe90f0..a12eebe 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-09-27 Tom Tromey <tom@tromey.com>
+
+ * macroexp.c (get_next_token_for_substitution): New function.
+ (substitute_args): Call it. Check for __VA_OPT__.
+
2017-09-26 Walfred Tedeschi <walfred.tedeschi@intel.com>
Pedro Alves <palves@redhat.com>
diff --git a/gdb/macroexp.c b/gdb/macroexp.c
index e7a0dad..8d1876e 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,64 @@ 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 (bool keep_going = true;
+ 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 +1237,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 4b6cb80..4348e76 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-09-27 Tom Tromey <tom@tromey.com>
+
+ * gdb.base/macscp.exp: Add __VA_OPT__ tests.
+
2017-09-26 Thomas Preud'homme <thomas.preudhomme@arm.com>
Pedro Alves <palves@redhat.com>
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" \