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 obscure paste bug


Thomas Pornin pointed out a paste bug to me in private mail.  Pasting
"." and "0" would result in "0".  There was actually a test for this
in the testsuite, but it tested for success by comparing the value
to 0, so no-one noticed :-)

Fixing this made me notice that objective C pasting of "@" and "name"
would segfault, for much the same reason.

I updated the testsuite to test pasting "." and "1" instead, so we
would notice in future, and with an objective C paste test.

Neil.

	* cppmacro.c (paste_tokens): Rename from paste_payloads.
	Change token type after pasting spellings.
	(paste_all_tokens): Use it.
	* gcc.dg/cpp/paste2.c: Update tests.

Index: cppmacro.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppmacro.c,v
retrieving revision 1.27
diff -u -p -r1.27 cppmacro.c
--- cppmacro.c	2000/11/19 13:15:50	1.27
+++ cppmacro.c	2000/11/20 19:25:03
@@ -75,8 +75,7 @@ static void make_string_token PARAMS ((c
 static void make_number_token PARAMS ((cpp_reader *, cpp_token *, int));
 static void stringify_arg PARAMS ((cpp_reader *, macro_arg *));
 static void paste_all_tokens PARAMS ((cpp_reader *, cpp_token *));
-static void paste_payloads PARAMS ((cpp_reader *, cpp_token *,
-				    const cpp_token *));
+static int paste_tokens PARAMS ((cpp_reader *, cpp_token *, cpp_token *));
 static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *,
 					  struct toklist *));
 static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *,
@@ -260,40 +259,6 @@ unlock_pools (pfile)
   _cpp_unlock_pool (&pfile->argument_pool);
 }
 
-static void
-paste_payloads (pfile, lhs, rhs)
-     cpp_reader *pfile;
-     cpp_token *lhs;
-     const cpp_token *rhs;
-{
-  unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
-  unsigned char *result, *end;
-  cpp_pool *pool;
-
-  pool = lhs->type == CPP_NAME ? &pfile->ident_pool: pfile->string_pool;
-  result = _cpp_pool_alloc (pool, total_len + 1);
-
-  /* Paste the spellings and null terminate.  */
-  end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
-  *end = '\0';
-  total_len = end - result;
-
-  if (lhs->type == CPP_NAME)
-    {
-      lhs->val.node = cpp_lookup (pfile, result, total_len);
-      if (lhs->val.node->flags & NODE_OPERATOR)
-	{
-	  lhs->flags |= NAMED_OP;
-	  lhs->type = lhs->val.node->value.operator;
-	}
-    }
-  else
-    {
-      lhs->val.str.text = result;
-      lhs->val.str.len = total_len;
-    }
-}
-
 /* Adds backslashes before all backslashes and double quotes appearing
    in strings.  Non-printable characters are converted to octal.  */
 static U_CHAR *
@@ -398,64 +363,109 @@ stringify_arg (pfile, arg)
   arg->stringified->val.str.len = total_len;
 }
 
+/* Try to paste two tokens.  On success, the LHS becomes the pasted
+   token, and 0 is returned.  For failure, we update the flags of the
+   RHS appropriately and return non-zero.  */
+static int
+paste_tokens (pfile, lhs, rhs)
+     cpp_reader *pfile;
+     cpp_token *lhs, *rhs;
+{
+  unsigned char flags;
+  int digraph = 0;
+  enum cpp_ttype type;
+
+  type = cpp_can_paste (pfile, lhs, rhs, &digraph);
+  
+  if (type == CPP_EOF)
+    {
+      if (CPP_OPTION (pfile, warn_paste))
+	cpp_warning (pfile,
+	 "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
+		     cpp_token_as_text (pfile, lhs),
+		     cpp_token_as_text (pfile, rhs));
+
+      /* The standard states that behaviour is undefined.  By the
+	 principle of least surpise, we step back before the RHS, and
+	 mark it to prevent macro expansion.  Tests in the testsuite
+	 rely on clearing PREV_WHITE here, though you could argue we
+	 should actually set it.  */
+      rhs->flags &= ~PREV_WHITE;
+      rhs->flags |= NO_EXPAND;
+      return 1;
+    }
+
+  flags = lhs->flags & ~DIGRAPH;
+  if (digraph)
+    flags |= DIGRAPH;
+
+  /* Identifiers and numbers need spellings to be pasted.  */
+  if (type == CPP_NAME || type == CPP_NUMBER)
+    {
+      unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
+      unsigned char *result, *end;
+      cpp_pool *pool;
+
+      pool = type == CPP_NAME ? &pfile->ident_pool: pfile->string_pool;
+      result = _cpp_pool_alloc (pool, total_len + 1);
+
+      /* Paste the spellings and null terminate.  */
+      end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
+      *end = '\0';
+      total_len = end - result;
+
+      if (type == CPP_NAME)
+	{
+	  lhs->val.node = cpp_lookup (pfile, result, total_len);
+	  if (lhs->val.node->flags & NODE_OPERATOR)
+	    {
+	      flags |= NAMED_OP;
+	      lhs->type = lhs->val.node->value.operator;
+	    }
+	}
+      else
+	{
+	  lhs->val.str.text = result;
+	  lhs->val.str.len = total_len;
+	}
+    }
+  else if (type == CPP_WCHAR || type == CPP_WSTRING)
+    lhs->val.str = rhs->val.str;
+
+  /* Set type and flags after pasting spellings.  */
+  lhs->type = type;
+  lhs->flags = flags;
+
+  return 0;
+}
+
 /* Handles an arbitrarily long sequence of ## operators.  This
    implementation is left-associative, non-recursive, and finishes a
-   paste before handling succeeding ones.  If the paste fails, the
-   right hand side of the ## operator is placed in the then-current
-   context's lookahead buffer, with the effect that it appears in the
-   output stream normally.  */
+   paste before handling succeeding ones.  If the paste fails, we back
+   up a token to just after the ## operator, with the effect that it
+   appears in the output stream normally.  */
 static void
 paste_all_tokens (pfile, lhs)
      cpp_reader *pfile;
      cpp_token *lhs;
 {
-  unsigned char orig_flags = lhs->flags;
   cpp_token *rhs;
+  unsigned char orig_flags = lhs->flags;
 
   do
     {
-      int digraph = 0;
-      enum cpp_ttype type;
-
       /* Take the token directly from the current context.  We can do
 	 this, because we are in the replacement list of either an
 	 object-like macro, or a function-like macro with arguments
 	 inserted.  In either case, the constraints to #define
-	 guarantee we have at least one more token (empty arguments
-	 become placemarkers).  */
+	 guarantee we have at least one more token.  */
       rhs = pfile->context->list.first++;
-
-      type = cpp_can_paste (pfile, lhs, rhs, &digraph);
-      if (type == CPP_EOF)
+      if (paste_tokens (pfile, lhs, rhs))
 	{
-	  if (CPP_OPTION (pfile, warn_paste))
-	    cpp_warning (pfile,
-	 "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
-			 cpp_token_as_text (pfile, lhs),
-			 cpp_token_as_text (pfile, rhs));
-
-	  /* The standard states that behaviour is undefined.  By the
-	     principle of least surpise, we step back before the RHS,
-	     and mark it to prevent macro expansion.  Tests in the
-	     testsuite rely on clearing PREV_WHITE here, though you
-	     could argue we should actually set it.  */
-	  rhs->flags &= ~PREV_WHITE;
-	  rhs->flags |= NO_EXPAND;
-
-	  /* Step back so we read the RHS in next.  */
+	  /* We failed.  Step back so we read the RHS in next.  */
 	  pfile->context->list.first--;
 	  break;
 	}
-
-      lhs->type = type;
-      lhs->flags &= ~DIGRAPH;
-      if (digraph)
-	lhs->flags |= DIGRAPH;
-
-      if (type == CPP_NAME || type == CPP_NUMBER)
-	paste_payloads (pfile, lhs, rhs);
-      else if (type == CPP_WCHAR || type == CPP_WSTRING)
-	lhs->val.str = rhs->val.str;
     }
   while (rhs->flags & PASTE_LEFT);
 
Index: testsuite/gcc.dg/cpp/paste2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cpp/paste2.c,v
retrieving revision 1.3
diff -u -p -r1.3 paste2.c
--- paste2.c	2000/10/28 18:01:40	1.3
+++ paste2.c	2000/11/20 19:25:03
@@ -1,7 +1,7 @@
 /* Copyright (C) 2000 Free Software Foundation, Inc.  */
 
 /* { dg-do run } */
-/* { dg-options "-std=c99 -pedantic-errors" } */
+/* { dg-options "-std=c99 -pedantic-errors -lang-objc" } */
 
 /* Test ## behaviour and corner cases thoroughly.  The macro expander
    failed many of these during development.  */
@@ -106,10 +106,16 @@ int main ()
       err ("Various operator pasting");
     if (strcmp (hh, "%:%:"))
       err ("Pasted digraph spelling");
+    if ((glue (., 1) glue (!, =) .1))
+      err ("Pasted numbers 1");
     /* glue3 here will only work if we paste left-to-right.  If a
        future implementation does not do this, change the test.  */
-    if ((glue (., 0) glue (=, =) .0) + (glue3 (1.0e, +, 1) == 10.0) != 2)
-      err ("Pasted numbers");
+    if ((glue3 (1.0e, +, 1) == 10.0) != 2)
+      err ("Pasted numbers 2");
+
+    /* Finally, Objective C names.  */
+    if (strcmp (xstr (glue (@, ident)), "@ident"))
+      err ("Objective C names");
   }
 
   return 0;



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