This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
cpplib: Fix PR 4492
- To: gcc-patches at gcc dot gnu dot org
- Subject: cpplib: Fix PR 4492
- From: Neil Booth <neil at daikokuya dot demon dot co dot uk>
- Date: Mon, 8 Oct 2001 07:11:01 +0100
- Cc: paul dot stoeber at in dot stud dot tu-ilmenau dot de
When I rewrote cpplib to do macro expansion via pointers, with spacing
issues handled by padding tokens, there was one corner case I knew was
not yet handled: we would "forget" any padding tokens between a
funlike macro name, and the following real token, when looking for the
'(' and failing. I hadn't fixed it because I couldn't think of a
satisfactory way to solve it at the time.
Nothing in the testsuite tested this, and thinking it was fairly
obscure, I intended to come back to it later. It's already caused
something to fail compiling, though (must be using preprocessed
output?) since the bug was reported yesterday in PR 4492, so it pushed
me to fix it quicker.
This patch fixes it, and adds a few test cases.
Neil.
* cppmacro.c (funlike_invocation_p): Move some logic to caller
in enter_macro_context. Create a padding token in its own context
if necessary when the search for '(' fails.
(enter_macro_context): Update.
* gcc.dg/cpp/spacing1.c: Update test.
Index: cppmacro.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppmacro.c,v
retrieving revision 1.78
diff -u -p -r1.78 cppmacro.c
--- cppmacro.c 2001/10/02 12:57:24 1.78
+++ cppmacro.c 2001/10/08 06:08:15
@@ -75,8 +75,8 @@ static const cpp_token *stringify_arg PA
static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *));
static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
const cpp_token *));
-static int funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *));
+static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
/* #define directive parsing and handling. */
@@ -616,46 +616,41 @@ collect_args (pfile, node)
return NULL;
}
-static int
+/* Search for an opening parenthesis to the macro of NODE, in such a
+ way that, if none is found, we don't lose the information in any
+ intervening padding tokens. If we find the parenthesis, collect
+ the arguments and return the buffer containing them. */
+static _cpp_buff *
funlike_invocation_p (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
- const cpp_token *maybe_paren;
- _cpp_buff *buff = NULL;
-
- pfile->state.prevent_expansion++;
- pfile->keep_tokens++;
+ const cpp_token *token, *padding = NULL;
- pfile->state.parsing_args = 1;
- do
- maybe_paren = cpp_get_token (pfile);
- while (maybe_paren->type == CPP_PADDING);
- pfile->state.parsing_args = 2;
-
- if (maybe_paren->type == CPP_OPEN_PAREN)
- buff = collect_args (pfile, node);
- else
+ for (;;)
{
- _cpp_backup_tokens (pfile, 1);
- if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
- cpp_warning (pfile,
- "function-like macro \"%s\" must be used with arguments in traditional C",
- NODE_NAME (node));
+ token = cpp_get_token (pfile);
+ if (token->type != CPP_PADDING)
+ break;
+ if (padding == NULL
+ || (!(padding->flags & PREV_WHITE) && token->val.source == NULL))
+ padding = token;
}
-
- pfile->state.parsing_args = 0;
- pfile->keep_tokens--;
- pfile->state.prevent_expansion--;
- if (buff)
+ if (token->type == CPP_OPEN_PAREN)
{
- if (node->value.macro->paramc > 0)
- replace_args (pfile, node, (macro_arg *) buff->base);
- _cpp_release_buff (pfile, buff);
+ pfile->state.parsing_args = 2;
+ return collect_args (pfile, node);
}
+
+ /* Back up. We may have skipped padding, in which case backing up
+ more than one token when expanding macros is in general too
+ difficult. We re-insert it in its own context. */
+ _cpp_backup_tokens (pfile, 1);
+ if (padding)
+ push_token_context (pfile, NULL, padding, 1);
- return buff != 0;
+ return NULL;
}
/* Push the context of a macro onto the context stack. TOKEN is the
@@ -675,8 +670,32 @@ enter_macro_context (pfile, node)
{
cpp_macro *macro = node->value.macro;
- if (macro->fun_like && !funlike_invocation_p (pfile, node))
- return 0;
+ if (macro->fun_like)
+ {
+ _cpp_buff *buff;
+
+ pfile->state.prevent_expansion++;
+ pfile->keep_tokens++;
+ pfile->state.parsing_args = 1;
+ buff = funlike_invocation_p (pfile, node);
+ pfile->state.parsing_args = 0;
+ pfile->keep_tokens--;
+ pfile->state.prevent_expansion--;
+
+ if (buff == NULL)
+ {
+ if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
+ cpp_warning (pfile,
+ "function-like macro \"%s\" must be used with arguments in traditional C",
+ NODE_NAME (node));
+
+ return 0;
+ }
+
+ if (node->value.macro->paramc > 0)
+ replace_args (pfile, node, (macro_arg *) buff->base);
+ _cpp_release_buff (pfile, buff);
+ }
/* Disable the macro within its expansion. */
node->flags |= NODE_DISABLED;
Index: testsuite/gcc.dg/cpp/spacing1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cpp/spacing1.c,v
retrieving revision 1.2
diff -u -p -r1.2 spacing1.c
--- spacing1.c 2001/09/24 22:53:11 1.2
+++ spacing1.c 2001/10/08 06:08:15
@@ -14,11 +14,18 @@
#define f(x) x
#define glue(x, y) x ## y
#define EMPTY
+/* These are based on PR 4492, we mustn't lose padding tokens when
+ scanning ahead for a '(' and failing to find it. */
+#define A(x) B x
+#define B(x)
+#define C A
+#define D() A
/* The correct output is shown here. Note the spaces, and the way
everything after the invocation of f appears on the same line.
44 ;
+B Q B Q A Q A:
f
bar
g "1 2" bam baz
@@ -26,6 +33,7 @@ g "1 2" bam baz
*/
glue (EMPTY 4, 4) EMPTY;
+A(Q) C(Q) D()Q D():
f
bar
f (g) str
@@ -37,10 +45,11 @@ f (g) str
/*
{ dg-final { if ![file exists spacing1.i] { return } } }
- { dg-final { if \{ [grep spacing1.i " 44 ;"] != "" \} \{ } }
+ { dg-final { if \{ [grep spacing1.i " 44 ;"] != "" \} \{ } }
+ { dg-final { if \{ [grep spacing1.i "B Q B Q A Q A:"] != "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "f.*bar"] == "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "^bar"] != "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "g \"1 2\" bam baz"] != "" \} \{ } }
- { dg-final { return \} \} \} \} } }
+ { dg-final { return \} \} \} \} \} } }
{ dg-final { fail "spacing1.c: spacing and new-line preservation" } }
*/