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]
Other format: [Raw text]

Patch: FYI: PR preprocessor/30363


I'm checking this in.

This fixes PR preprocessor/30363.  The bug is a failure when using
traditional preprocessing and substituting inside of quotes.

This is just the patch from the PR, with one minor change.

Bootstrapped and regtested on x86 F8.  New test included.

Tom

libcpp/ChangeLog:
2008-01-07  Fred Fish  <fnf@specifix.com>

	PR preprocessor/30363:
	* traditional.c (replace_args_and_push): Add local variable
	cxtquote, calculate the replacement text size assuming a
	worst case of every input character quoted with backslash,
	and properly handle output quoting of quote characters in
	actual arguments used in function-like macros.

gcc/testsuite/ChangeLog:
2008-01-07  Fred Fish  <fnf@specifix.com>

	PR preprocessor/30363:
	* gcc.dg/cpp/trad/macroargs.c: Add code to test quoting in
	macro expansions.

Index: libcpp/traditional.c
===================================================================
--- libcpp/traditional.c	(revision 131303)
+++ libcpp/traditional.c	(working copy)
@@ -1,5 +1,5 @@
 /* CPP Library - traditional lexical analysis and macro expansion.
-   Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Neil Booth, May 2002
 
 This program is free software; you can redistribute it and/or modify it
@@ -832,8 +832,11 @@
       uchar *p;
       _cpp_buff *buff;
       size_t len = 0;
+      int cxtquote = 0;
 
-      /* Calculate the length of the argument-replaced text.  */
+      /* Get an estimate of the length of the argument-replaced text.
+	 This is a worst case estimate, assuming that every replacement
+	 text character needs quoting.  */
       for (exp = macro->exp.text;;)
 	{
 	  struct block *b = (struct block *) exp;
@@ -841,8 +844,8 @@
 	  len += b->text_len;
 	  if (b->arg_index == 0)
 	    break;
-	  len += (fmacro->args[b->arg_index]
-		  - fmacro->args[b->arg_index - 1] - 1);
+	  len += 2 * (fmacro->args[b->arg_index]
+		      - fmacro->args[b->arg_index - 1] - 1);
 	  exp += BLOCK_LEN (b->text_len);
 	}
 
@@ -850,21 +853,69 @@
       buff = _cpp_get_buff (pfile, len + 1);
 
       /* Copy the expansion and replace arguments.  */
+      /* Accumulate actual length, including quoting as necessary */
       p = BUFF_FRONT (buff);
+      len = 0;
       for (exp = macro->exp.text;;)
 	{
 	  struct block *b = (struct block *) exp;
 	  size_t arglen;
+	  int argquote;
+	  uchar *base;
+	  uchar *in;
 
-	  memcpy (p, b->text, b->text_len);
-	  p += b->text_len;
+	  len += b->text_len;
+	  /* Copy the non-argument text literally, keeping
+	     track of whether matching quotes have been seen. */
+	  for (arglen = b->text_len, in = b->text; arglen > 0; arglen--)
+	    {
+	      if (*in == '"')
+		cxtquote = ! cxtquote;
+	      *p++ = *in++;
+	    }
+	  /* Done if no more arguments */
 	  if (b->arg_index == 0)
 	    break;
 	  arglen = (fmacro->args[b->arg_index]
 		    - fmacro->args[b->arg_index - 1] - 1);
-	  memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1],
-		  arglen);
-	  p += arglen;
+	  base = pfile->out.base + fmacro->args[b->arg_index - 1];
+	  in = base;
+#if 0
+	  /* Skip leading whitespace in the text for the argument to
+	     be substituted. To be compatible with gcc 2.95, we would
+	     also need to trim trailing whitespace. Gcc 2.95 trims
+	     leading and trailing whitespace, which may be a bug.  The
+	     current gcc testsuite explicitly checks that this leading
+	     and trailing whitespace in actual arguments is
+	     preserved. */
+	  while (arglen > 0 && is_space (*in))
+	    {
+	      in++;
+	      arglen--;
+	    }
+#endif
+	  for (argquote = 0; arglen > 0; arglen--)
+	    {
+	      if (cxtquote && *in == '"')
+		{
+		  if (in > base && *(in-1) != '\\')
+		    argquote = ! argquote;
+		  /* Always add backslash before double quote if argument
+		     is expanded in a quoted context */
+		  *p++ = '\\';
+		  len++;
+		}
+	      else if (cxtquote && argquote && *in == '\\')
+		{
+		  /* Always add backslash before a backslash in an argument
+		     that is expanded in a quoted context and also in the
+		     range of a quoted context in the argument itself. */
+		  *p++ = '\\';
+		  len++;
+		}
+	      *p++ = *in++;
+	      len++;
+	    }
 	  exp += BLOCK_LEN (b->text_len);
 	}
 
Index: gcc/testsuite/gcc.dg/cpp/trad/macroargs.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/trad/macroargs.c	(revision 131310)
+++ gcc/testsuite/gcc.dg/cpp/trad/macroargs.c	(working copy)
@@ -8,6 +8,17 @@
 
 extern void abort (void);
 
+void testquoting ()
+{
+  const char *str1 = f("a", "\"a\"");
+  const char *str2 = f( \t, " \t");
+
+  if (strcmp (str1, "\"a\"  \"\\\"a\\\"\""))
+    abort ();
+  if (strcmp (str2, " \t  \" \\t\""))
+    abort ();
+}
+
 int main ()
 {
   const char *str1 = f( foo ,bar);
@@ -26,5 +37,7 @@
 , 2"), "1 , 2"))	
     abort ();
 
+  testquoting ();
+
   return 0;
 }


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