https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104147

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
So, from what I can see on
#define X(x,y)  x y
#define STR_(x) #x
#define STR(x)  STR_(x)
STR(X(Y,Y))
vs.
#define X(x,y)  x y
#define STR_(x) #x
#define STR(x)  STR_(x)
#define Y()
STR(X(Y,Y))
is that on the third call to funlike_invocation_p for the Y macro, the code
reads 2 padding tokens before finding a non-padding non-CPP_OPEN_PAREN one:
1365    static _cpp_buff *
1366    funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node,
1367                          _cpp_buff **pragma_buff, unsigned *num_args)
1368    {
1369      const cpp_token *token, *padding = NULL;
1370    
1371      for (;;)
1372        {
1373          token = cpp_get_token (pfile);
1374          if (token->type != CPP_PADDING)
1375            break;
1376          if (padding == NULL
1377              || (!(padding->flags & PREV_WHITE) && token->val.source ==
NULL))
1378            padding = token;
1379        }
The first padding token is pfile->avoid_paste and the second padding token is
one created by padding_token:
(gdb) p *padding
$128 = {src_loc = 0, type = CPP_PADDING, flags = 0, val = {node = {node = 0x0,
spelling = 0x0}, source = 0x0, str = {len = 0, text = 0x0}, macro_arg = {arg_no
= 0, spelling = 0x0}, 
    token_no = 0, pragma = 0}}
(gdb) p *token
$129 = {src_loc = 258816, type = CPP_PADDING, flags = 0, val = {node = {node =
0x7fffea249db0, spelling = 0x0}, source = 0x7fffea249db0, str = {len =
3928268208, text = 0x0}, 
    macro_arg = {arg_no = 3928268208, spelling = 0x0}, token_no = 3928268208,
pragma = 3928268208}}
(gdb) p *token->val.source
$130 = {src_loc = 242688, type = CPP_MACRO_ARG, flags = 1, val = {node = {node
= 0x7fff00000002, spelling = 0x7fffea38e2e8}, source = 0x7fff00000002, str =
{len = 2, 
      text = 0x7fffea38e2e8 "\260\260\070\352\377\177"}, macro_arg = {arg_no =
2, spelling = 0x7fffea38e2e8}, token_no = 2, pragma = 2}}
So, both CPP_PADDING tokens have flags of 0, but the second padding has
non-NULL val.source and that one has PREV_WHITE set on it.
Now, because of the above condition, padding is in the end the first of the 2
padding tokens, i.e. pfile->avoid_paste.
The code later will do:
1393      if (token->type != CPP_EOF || token == &pfile->endarg)
1394        {
1395          _cpp_backup_tokens (pfile, 1);
1396          if (padding)
1397            _cpp_push_token_context (pfile, NULL, padding, 1);
1398        }
so backup a single token (a CPP_NAME) and push a new context containing just
the avoid_paste token.
Later on cpp_get_token_1 is called and first hits:
2930          else if (!reached_end_of_context (context))
2931            {
2932              consume_next_token_from_context (pfile, &result,
2933                                               &virt_loc);
and so the avoid_paste token is read and next time reached_end_of_context is
true and so it will:
2945              if (pfile->context->c.macro)
2946                ++num_expanded_macros_counter;
2947              _cpp_pop_context (pfile);
2948              if (pfile->state.in_directive)
2949                continue;
2950              result = &pfile->avoid_paste;
and read avoid_paste again.
Now, if Y is not a macro, the tokens which will be read are the original ones,
i.e.
one avoid_paste followed by the padding_token one.
Now, stringify_arg is called later on, and that one ignores CPP_PADDING tokens,
except when they have val.source set on it:
      if (token->type == CPP_PADDING)
        {
          if (source == NULL
              || (!(source->flags & PREV_WHITE)
                  && token->val.source == NULL))
            source = token->val.source;
          continue;
        }
...
      /* Leading white space?  */
      if (dest - 1 != BUFF_FRONT (pfile->u_buff))
        {
          if (source == NULL)
            source = token;
          if (source->flags & PREV_WHITE)
            *dest++ = ' ';
        }
      source = NULL;
So, when Y is not a macro, we set source to the CPP_MACRO_ARG with PREV_WHITE
set on it and so emit a space in between,
while when Y is a function-like macro, source isn't set from CPP_PADDING tokens
but instead from the actual CPP_NAME
token after it which doesn't have PREV_WHITE and so we don't emit a space in
there.
Now, if the order of the CPP_PADDING tokens doesn't matter, perhaps we want
funlike_invocation_p use the
padding token with non-NULL val.source in preference of the avoid_paste token
rather than the other way around,
but not sure what that would break.  Also, not really sure how PREV_WHITE flags
on the CPP_PADDING tokens come to play with this.

Reply via email to