This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

cpplib: Fix PR 4492


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"      } }
 */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]