PR preprocessor/83063 - __VA_OPT__ and ##

PR preprocessor/83708
	* macro.c (vaopt_state): Reorder m_last_was_paste before m_state.
	(vaopt_state::vaopt_state): Adjust.
	(vaopt_state::update_flags): Add BEGIN and END.
	(vaopt_state::update): Return them.
	(copy_paste_flag): Factor out of replace_args.
	(last_token_is): New.
	(replace_args): Handle BEGIN and END.  Avoid padding there.
	(tokens_buff_last_token_ptr): Return NULL if no tokens.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>

From-SVN: r257696
This commit is contained in:
Jason Merrill 2018-02-15 12:43:01 -05:00 committed by Jason Merrill
parent 5cedffbc32
commit 60887f8c2d
4 changed files with 261 additions and 23 deletions

View File

@ -0,0 +1,41 @@
/* PR preprocessor/83063 */
/* { dg-do compile } */
/* { dg-options "-std=gnu99" { target c } } */
/* { dg-options "-std=c++2a" { target c++ } } */
#define f1(...) int b##__VA_OPT__(c)
#define f2(...) int __VA_OPT__(c)##d
#define f3(...) int e##__VA_OPT__()
#define f4(...) int __VA_OPT__()##f
#define f5(...) int g##__VA_OPT__(h)##i
#define f6(...) int j##__VA_OPT__()##k
#define f7(...) int l##__VA_OPT__()
#define f8(...) int __VA_OPT__()##m
#define f9(...) int n##__VA_OPT__()##o
#define f10(x, ...) int x##__VA_OPT__(x)
#define f11(x, ...) int __VA_OPT__(x)##x
#define f12(x, ...) int x##__VA_OPT__(x)##x
f1 (1, 2, 3);
f1 ();
f2 (1, 2);
f2 ();
f3 (1);
f4 (2);
f5 (6, 7);
f5 ();
f6 (8);
f7 ();
f8 ();
f9 ();
f10 (p, 5, 6);
f10 (p);
f11 (q, 7);
f11 (q);
f12 (r, 1, 2, 3, 4, 5);
f12 (r);
int
main ()
{
return bc + b + cd + d + e + f + ghi + gi + jk + l + m + no + pp + p + qq + q + rrr + rr;
}

View File

@ -0,0 +1,94 @@
/* PR preprocessor/83063 */
/* PR preprocessor/83708 */
/* { dg-do preprocess } */
/* { dg-options "-std=gnu99" { target c } } */
/* { dg-options "-std=c++2a" { target c++ } } */
#define f1(...) b##__VA_OPT__(c)
#define f2(...) __VA_OPT__(c)##d
#define f3(...) e##__VA_OPT__()
#define f4(...) __VA_OPT__()##f
#define f5(...) g##__VA_OPT__(h)##i
#define f6(...) j##__VA_OPT__()##k
#define f7(...) l##__VA_OPT__()
#define f8(...) __VA_OPT__()##m
#define f9(...) n##__VA_OPT__()##o
#define f10(x, ...) x##__VA_OPT__(x)
#define f11(x, ...) __VA_OPT__(x)##x
#define f12(x, ...) x##__VA_OPT__(x)##x
#define f13(...) __VA_OPT__(a)__VA_OPT__(b)c
#define f14(a, b, c, ...) __VA_OPT__(a)__VA_OPT__(b)c
#define f15(a, b, c, ...) __VA_OPT__(a b)__VA_OPT__(b c)a/**/__VA_OPT__(c a)a
#define m1 (
#define f16() f17 m1 )
#define f17() f18 m1 )
#define f18() m2 m1 )
#define m3f17() g
#define f19(x, ...) m3 ## __VA_OPT__(x x f16() #x)
#define f20(x, ...) __VA_OPT__(x x)##m4()
#define f21() f17
#define f17m4() h
#define f22(x,...) 1 ## __VA_OPT__(x ## x 2) ## 3
#define f23(x,...) 1 ## __VA_OPT__(x 2) ## 3
#define f24(x,...) 1 ## __VA_OPT__(2 x) ## 3
#define f25(x,...) 1 ## __VA_OPT__(2 x ## x) ## 3
t1 f1 (1, 2, 3);
/* { dg-final { scan-file va-opt-3.i "t1 bc;" } } */
t2 f1 ();
/* { dg-final { scan-file va-opt-3.i "t2 b;" } } */
t3 f2 (1, 2);
/* { dg-final { scan-file va-opt-3.i "t3 cd;" } } */
t4 f2 ();
/* { dg-final { scan-file va-opt-3.i "t4 d;" } } */
t5 f3 (1);
/* { dg-final { scan-file va-opt-3.i "t5 e;" } } */
t6 f4 (2);
/* { dg-final { scan-file va-opt-3.i "t6 f;" } } */
t7 f5 (6, 7);
/* { dg-final { scan-file va-opt-3.i "t7 ghi;" } } */
t8 f5 ();
/* { dg-final { scan-file va-opt-3.i "t8 gi;" } } */
t9 f6 (8);
/* { dg-final { scan-file va-opt-3.i "t9 jk;" } } */
t10 f7 ();
/* { dg-final { scan-file va-opt-3.i "t10 l;" } } */
t11 f8 ();
/* { dg-final { scan-file va-opt-3.i "t11 m;" } } */
t12 f9 ();
/* { dg-final { scan-file va-opt-3.i "t12 no;" } } */
t13 f10 (p, 5, 6);
/* { dg-final { scan-file va-opt-3.i "t13 pp;" } } */
t14 f10 (p);
/* { dg-final { scan-file va-opt-3.i "t14 p;" } } */
t15 f11 (q, 7);
/* { dg-final { scan-file va-opt-3.i "t15 qq;" } } */
t16 f11 (q);
/* { dg-final { scan-file va-opt-3.i "t16 q;" } } */
t17 f12 (r, 1, 2, 3, 4, 5);
/* { dg-final { scan-file va-opt-3.i "t17 rrr;" } } */
t18 f12 (r);
/* { dg-final { scan-file va-opt-3.i "t18 rr;" } } */
t19 f13 (1, 2);
/* { dg-final { scan-file va-opt-3.i "t19 a b c;" } } */
t20 f13 ();
/* { dg-final { scan-file va-opt-3.i "t20 c;" } } */
t21 f14 (3, 4, 5, 2);
/* { dg-final { scan-file va-opt-3.i "t21 3 4 5;" } } */
t22 f14 (3, 4, 5);
/* { dg-final { scan-file va-opt-3.i "t22 5;" } } */
t23 f15 (6, 7, 8, 9);
/* { dg-final { scan-file va-opt-3.i "t23 6 7 7 8 6 8 6 6;" } } */
t24 f15 (6, 7, 8);
/* { dg-final { scan-file va-opt-3.i "t24 6 6;" } } */
t25 f19 (f16 (), 1);
/* { dg-final { scan-file va-opt-3.i {t25 g f18 \( \) f17 \( \) "f16 \(\)";} } } */
t26 f20 (f21 (), 2);
/* { dg-final { scan-file va-opt-3.i "t26 f17 h;" } } */
t27 f22 (, x);
/* { dg-final { scan-file va-opt-3.i "t27 123;" } } */
t28 f23 (, x);
/* { dg-final { scan-file va-opt-3.i "t28 123;" } } */
t29 f24 (, x);
/* { dg-final { scan-file va-opt-3.i "t29 123;" } } */
t30 f25 (, x);
/* { dg-final { scan-file va-opt-3.i "t30 123;" } } */

View File

@ -1,3 +1,17 @@
2018-02-15 Jason Merrill <jason@redhat.com>
Jakub Jelinek <jakub@redhat.com>
PR preprocessor/83063 - __VA_OPT__ and ##
PR preprocessor/83708
* macro.c (vaopt_state): Reorder m_last_was_paste before m_state.
(vaopt_state::vaopt_state): Adjust.
(vaopt_state::update_flags): Add BEGIN and END.
(vaopt_state::update): Return them.
(copy_paste_flag): Factor out of replace_args.
(last_token_is): New.
(replace_args): Handle BEGIN and END. Avoid padding there.
(tokens_buff_last_token_ptr): Return NULL if no tokens.
2018-01-31 Jakub Jelinek <jakub@redhat.com>
PR preprocessor/69869

View File

@ -105,8 +105,8 @@ class vaopt_state {
: m_pfile (pfile),
m_allowed (any_args),
m_variadic (is_variadic),
m_state (0),
m_last_was_paste (false),
m_state (0),
m_paste_location (0),
m_location (0)
{
@ -116,7 +116,9 @@ class vaopt_state {
{
ERROR,
DROP,
INCLUDE
INCLUDE,
BEGIN,
END
};
/* Given a token, update the state of this tracker and return a
@ -139,7 +141,7 @@ class vaopt_state {
}
++m_state;
m_location = token->src_loc;
return DROP;
return BEGIN;
}
else if (m_state == 1)
{
@ -191,7 +193,7 @@ class vaopt_state {
return ERROR;
}
return DROP;
return END;
}
}
return m_allowed ? INCLUDE : DROP;
@ -220,6 +222,9 @@ class vaopt_state {
bool m_allowed;
/* True if the macro is variadic. */
bool m_variadic;
/* 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 state variable:
0 means not parsing
@ -228,9 +233,6 @@ class vaopt_state {
>= 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;
@ -1701,6 +1703,30 @@ expanded_token_index (cpp_reader *pfile, cpp_macro *macro,
return cur_replacement_token - macro->exp.tokens;
}
/* Copy whether PASTE_LEFT is set from SRC to *PASTE_FLAG. */
static void
copy_paste_flag (cpp_reader *pfile, const cpp_token **paste_flag,
const cpp_token *src)
{
cpp_token *token = _cpp_temp_token (pfile);
token->type = (*paste_flag)->type;
token->val = (*paste_flag)->val;
if (src->flags & PASTE_LEFT)
token->flags = (*paste_flag)->flags | PASTE_LEFT;
else
token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
*paste_flag = token;
}
/* True IFF the last token emitted into BUFF (if any) is PTR. */
static bool
last_token_is (_cpp_buff *buff, const cpp_token **ptr)
{
return (ptr && tokens_buff_last_token_ptr (buff) == ptr);
}
/* Replace the parameters in a function-like macro of NODE with the
actual ARGS, and place the result in a newly pushed token context.
Expand each argument before replacing, unless it is operated upon
@ -1833,6 +1859,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
i = 0;
vaopt_state vaopt_tracker (pfile, macro->variadic,
args[macro->paramc - 1].count > 0);
const cpp_token **vaopt_start = NULL;
for (src = macro->exp.tokens; src < limit; src++)
{
unsigned int arg_tokens_count;
@ -1841,8 +1868,58 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
const cpp_token **tmp_token_ptr;
/* __VA_OPT__ handling. */
if (vaopt_tracker.update (src) != vaopt_state::INCLUDE)
continue;
vaopt_state::update_type vostate = vaopt_tracker.update (src);
if (vostate != vaopt_state::INCLUDE)
{
if (vostate == vaopt_state::BEGIN)
{
/* Padding on the left of __VA_OPT__ (unless RHS of ##). */
if (src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
{
const cpp_token *t = padding_token (pfile, src);
unsigned index = expanded_token_index (pfile, macro, src, i);
/* Allocate a virtual location for the padding token and
append the token and its location to BUFF and
VIRT_LOCS. */
tokens_buff_add_token (buff, virt_locs, t,
t->src_loc, t->src_loc,
map, index);
}
vaopt_start = tokens_buff_last_token_ptr (buff);
}
else if (vostate == vaopt_state::END)
{
const cpp_token **start = vaopt_start;
vaopt_start = NULL;
/* Remove any tail padding from inside the __VA_OPT__. */
paste_flag = tokens_buff_last_token_ptr (buff);
while (paste_flag && paste_flag != start
&& (*paste_flag)->type == CPP_PADDING)
{
tokens_buff_remove_last_token (buff);
paste_flag = tokens_buff_last_token_ptr (buff);
}
if (src->flags & PASTE_LEFT)
{
/* With a non-empty __VA_OPT__ on the LHS of ##, the last
token should be flagged PASTE_LEFT. */
if (paste_flag && (*paste_flag)->type != CPP_PADDING)
copy_paste_flag (pfile, paste_flag, src);
}
else
{
/* Otherwise, avoid paste on RHS, __VA_OPT__(c)d or
__VA_OPT__(c)__VA_OPT__(d). */
const cpp_token *t = &pfile->avoid_paste;
tokens_buff_add_token (buff, virt_locs,
t, t->src_loc, t->src_loc,
NULL, 0);
}
}
continue;
}
if (src->type != CPP_MACRO_ARG)
{
@ -1921,8 +1998,11 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
else
paste_flag = tmp_token_ptr;
}
/* Remove the paste flag if the RHS is a placemarker. */
else if (arg_tokens_count == 0)
/* Remove the paste flag if the RHS is a placemarker, unless the
previous emitted token is at the beginning of __VA_OPT__;
placemarkers within __VA_OPT__ are ignored in that case. */
else if (arg_tokens_count == 0
&& tmp_token_ptr != vaopt_start)
paste_flag = tmp_token_ptr;
}
}
@ -1934,11 +2014,26 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
track_macro_expansion),
MACRO_ARG_TOKEN_EXPANDED,
arg, arg->expanded);
if (last_token_is (buff, vaopt_start))
{
/* We're expanding an arg at the beginning of __VA_OPT__.
Skip padding. */
while (arg_tokens_count)
{
const cpp_token *t = macro_arg_token_iter_get_token (&from);
if (t->type != CPP_PADDING)
break;
macro_arg_token_iter_forward (&from);
--arg_tokens_count;
}
}
}
/* Padding on the left of an argument (unless RHS of ##). */
if ((!pfile->state.in_directive || pfile->state.directive_wants_padding)
&& src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
&& src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT)
&& !last_token_is (buff, vaopt_start))
{
const cpp_token *t = padding_token (pfile, src);
unsigned index = expanded_token_index (pfile, macro, src, i);
@ -2023,7 +2118,8 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
NODE_NAME (node), src->val.macro_arg.arg_no);
/* Avoid paste on RHS (even case count == 0). */
if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT))
if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT)
&& !last_token_is (buff, vaopt_start))
{
const cpp_token *t = &pfile->avoid_paste;
tokens_buff_add_token (buff, virt_locs,
@ -2033,16 +2129,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
/* Add a new paste flag, or remove an unwanted one. */
if (paste_flag)
{
cpp_token *token = _cpp_temp_token (pfile);
token->type = (*paste_flag)->type;
token->val = (*paste_flag)->val;
if (src->flags & PASTE_LEFT)
token->flags = (*paste_flag)->flags | PASTE_LEFT;
else
token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
*paste_flag = token;
}
copy_paste_flag (pfile, paste_flag, src);
i += arg_tokens_count;
}
@ -2213,6 +2300,8 @@ tokens_buff_count (_cpp_buff *buff)
static const cpp_token **
tokens_buff_last_token_ptr (_cpp_buff *buff)
{
if (BUFF_FRONT (buff) == buff->base)
return NULL;
return &((const cpp_token **) BUFF_FRONT (buff))[-1];
}