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.
This commit is contained in:
Tom Tromey
2017-09-17 20:36:41 -06:00
parent 1948519604
commit a9bbfbd85f
4 changed files with 157 additions and 10 deletions

View File

@ -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> 2017-09-26 Walfred Tedeschi <walfred.tedeschi@intel.com>
Pedro Alves <palves@redhat.com> Pedro Alves <palves@redhat.com>

View File

@ -946,6 +946,30 @@ find_parameter (const struct macro_buffer *tok,
return -1; 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 /* Given the macro definition DEF, being invoked with the actual
arguments given by ARGC and ARGV, substitute the arguments into the arguments given by ARGC and ARGV, substitute the arguments into the
replacement list, and store the result in DEST. 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_rl_start = replacement_list.text;
lookahead_valid = get_token (&lookahead, &replacement_list); 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 /* Just for aesthetics. If we skipped some whitespace, copy
that to DEST. */ that to DEST. */
if (tok.text > original_rl_start) if (tok.text > original_rl_start)
@ -1157,16 +1237,10 @@ substitute_args (struct macro_buffer *dest,
if (! substituted) if (! substituted)
append_tokens_without_splicing (dest, &tok); 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__"));
} }

View File

@ -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> 2017-09-26 Thomas Preud'homme <thomas.preudhomme@arm.com>
Pedro Alves <palves@redhat.com> Pedro Alves <palves@redhat.com>

View File

@ -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)" \ gdb_test_no_output "macro define va2_gnu(args...) varfunc (fixedarg, ## args)" \
"define fourth varargs helper" "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)" \ gdb_test "macro expand va_c99(one, two, three)" \
"expands to: *varfunc \\(fixedarg, *one, two, three\\)" \ "expands to: *varfunc \\(fixedarg, *one, two, three\\)" \
"c99 varargs expansion" "c99 varargs expansion"
@ -644,6 +656,58 @@ gdb_test "macro expand va2_gnu()" \
"expands to: *varfunc \\(fixedarg\\)" \ "expands to: *varfunc \\(fixedarg\\)" \
"gnu varargs expansion special splicing without an argument" "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. # Stringification tests.
gdb_test_no_output "macro define str(x) #x" \ gdb_test_no_output "macro define str(x) #x" \