glcpp: prevent accidental token pasting

Explicit token pasting is handled specially, but the token
printing code can accidentally paste identifiers. Check for
this accidental pasting and prevent it by inserting a space
if necessary.

Supersedes a similar but much more limited test to prevent pasting
`+` and `-` to make `++` and `--`.

A test is provided in glcpp/tests/150-token-accidental-concatenation.
The accidental pasting test in 068-accidental-pasting is also updated
to cover some of the other cases.

Signed-off-by: Eric R. Smith <eric.smith@collabora.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37214>
This commit is contained in:
Eric R. Smith 2025-09-06 16:04:51 -03:00 committed by Marge Bot
parent 6d00e95b2e
commit 475222b022
5 changed files with 65 additions and 16 deletions

View file

@ -1450,6 +1450,21 @@ _token_paste(glcpp_parser_t *parser, token_t *token, token_t *other)
return token;
}
/*
* Check to see if we need a space in between two tokens, for example to
* keep "+ +" from collapsing to "++"
*/
static bool
need_space_between(int token1, int token2)
{
if ( (token1 == '+' || token1 == '-') && token2 == token1 )
return true;
if (token1 == IDENTIFIER &&
(token2 == IDENTIFIER || token2 == INTEGER))
return true;
return false;
}
static void
_token_list_print(glcpp_parser_t *parser, token_list_t *list)
{
@ -1458,8 +1473,13 @@ _token_list_print(glcpp_parser_t *parser, token_list_t *list)
if (list == NULL)
return;
for (node = list->head; node; node = node->next)
for (node = list->head; node; node = node->next) {
_token_print(parser->output, node->token);
/* avoid accidental token concatenation */
if (node->next &&
need_space_between(node->token->type, node->next->token->type))
_mesa_string_buffer_append_char(parser->output, ' ');
}
}
void
@ -2030,21 +2050,6 @@ _glcpp_parser_expand_node(glcpp_parser_t *parser, token_node_t *node,
replacement = _token_list_copy(parser, macro->replacements);
/* If needed insert space in front of replacements to isolate them from
* the code they will be inserted into. For example:
*
* #define VALUE -1.0
* int a = -VALUE;
*
* Should be evaluated to int a = - -1.0; not int a = --1.0;
*/
if (node_prev &&
(node_prev->token->type == '-' || node_prev->token->type == '+') &&
node_prev->token->type == replacement->head->token->type) {
token_t *new_token = _token_create_ival(parser, SPACE, SPACE);
_token_list_prepend(parser, replacement, new_token);
}
_glcpp_parser_apply_pastes(parser, replacement);
return replacement;
}

View file

@ -1,3 +1,6 @@
#define VALUE1 -1.0
#define VALUE2 +2
#define ONEPLUS(x) 1+x
#define empty
<empty<
<empty=
@ -9,3 +12,6 @@
|empty|
+empty+
-empty-
-VALUE1
+VALUE2
ONEPLUS(+1)

View file

@ -1,4 +1,7 @@
< <
< =
> >
@ -9,3 +12,6 @@
| |
+ +
- -
- -1.0
+ +2
1+ +1

View file

@ -0,0 +1,16 @@
/*
* avoid accidental concatenation of strings
* but make sure deliberate concatenation works
*/
#define a xa
#define b xb
#define A(x, y) x y
#define B(x, y) x ## y
#define C(x) x
A(r, s)
B(r, s)
C(r)s
A(a, b)
//B(a, b) // not working yet; gcc and clang give `ab`, we give `xaxb`
C(a)b

View file

@ -0,0 +1,16 @@
r s
rs
r s
xa xb
xa xb