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:
parent
5cedffbc32
commit
60887f8c2d
41
gcc/testsuite/c-c++-common/cpp/va-opt-2.c
Normal file
41
gcc/testsuite/c-c++-common/cpp/va-opt-2.c
Normal 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;
|
||||
}
|
94
gcc/testsuite/c-c++-common/cpp/va-opt-3.c
Normal file
94
gcc/testsuite/c-c++-common/cpp/va-opt-3.c
Normal 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;" } } */
|
@ -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
|
||||
|
135
libcpp/macro.c
135
libcpp/macro.c
@ -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];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user