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] Fix PR preprocessor/20077: GCC accepts macro definitions that fail a constraint


Hello all.

With the current version, the preprocessor accepts the following invalid code:

=== cut here ===
#define a a ## ##
#define a() a ## ##
=== cut here ===

This is not valid because the token-pasting operator cannot appear at the 
beginning or the end of a macro.

The function in charge of creating the definition of a macro and checking that 
this constraint is verified is create_iso_definition in libcpp/macro.c. The 
problem is that with the current version, in our cases, when the first 
CPP_PASTE is found, 'macro->count' is stricly positive, so 
'lex_expansion_token' is called. In the test that follows, 'macro->count' is 
not equal to 0, and the current token is not CPP_EOF, so no error is emitted. 
'lex_expansion_token' is called once again at the very end of the loop, the 
current token becomes CPP_EOF, and the loop is exited normally.

The following patch fixes this the following way:
 - When a token-pasting operator is encountered, if macro->count is equal to 
one, then it is the first token in the macro, and an error is emitted.
 - At each loop iteration, we store whether the token that was just processed 
was a token-pasting operator; when the end of the macro is reached, if the 
previous token was a token-pasting operator, an error is emitted.

Another difference is that with the current version, when a CPP_PASTE is 
encountered and macro->count is strictly positive, 'lex_expansion_token' is 
called, so token[-1] is the CPP_PASTE, not the token preceding it; I think 
that the "token[-1].flags |= PASTE_LEFT;" probably does not do what was 
intended (according to include/cpplib.h, PASTE_LEFT means that the token is 
on the LHS of a token-pasting operator). This is not the case with the patch; 
I hope it is OK.

This has been successfully bootstrapped and regested with no new unexpected 
failures on i686-pc-linux-gnu.

Is it OK? If so, could someone commit it for me please?

Thanks in advance.

Best regards,
Simon

:ADDPATCH preprocessor:
2006-10-16  Simon Martin  <simartin@users.sourceforge.net>

	PR preprocessor/20077
	* macro.c (create_iso_definition): Fixed the method to determine whether
	the token-pasting operator appears at the beginning or the end of a macro:
	one checks that macro->count is not equal to one when a token-pasting
	operator is encountered (if it is, the token is the first one in the
	macro) and that the previous token was not a token-pasting operator when
	the end of the macro is reached.
Index: libcpp/macro.c
===================================================================
--- libcpp/macro.c	(revision 117789)
+++ libcpp/macro.c	(working copy)
@@ -1422,6 +1422,9 @@ create_iso_definition (cpp_reader *pfile
 {
   cpp_token *token;
   const cpp_token *ctoken;
+  bool following_paste_op = false;
+  const char *paste_op_error_msg =
+    "'##' cannot appear at either end of a macro expansion";
 
   /* Get the first token of the expansion (or the '(' of a
      function-like macro).  */
@@ -1515,26 +1518,34 @@ create_iso_definition (cpp_reader *pfile
 	}
 
       if (token->type == CPP_EOF)
-	break;
+	{
+	  /* Paste operator constraint 6.10.3.3.1:
+	     Token-paste ##, can appear in both object-like and
+	     function-like macros, but not at the end.  */
+	  if (following_paste_op)
+	    {
+	      cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
+	      return false;
+	    }
+	  break;
+	}
 
       /* Paste operator constraint 6.10.3.3.1.  */
       if (token->type == CPP_PASTE)
 	{
 	  /* Token-paste ##, can appear in both object-like and
-	     function-like macros, but not at the ends.  */
-	  if (--macro->count > 0)
-	    token = lex_expansion_token (pfile, macro);
-
-	  if (macro->count == 0 || token->type == CPP_EOF)
+	     function-like macros, but not at the beginning.  */
+	  if (macro->count == 1)
 	    {
-	      cpp_error (pfile, CPP_DL_ERROR,
-		 "'##' cannot appear at either end of a macro expansion");
+	      cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
 	      return false;
 	    }
 
+	  --macro->count;
 	  token[-1].flags |= PASTE_LEFT;
 	}
 
+      following_paste_op = (token->type == CPP_PASTE);
       token = lex_expansion_token (pfile, macro);
     }
 
2006-10-16  Simon Martin  <simartin@users.sourceforge.net>

	PR preprocessor/20077
	* gcc.dg/cpp/paste15.c: New test.
/* PR preprocessor/20077 */
/* { dg-do preprocess } */

#define a   a ## ## /* { dg-error "end of a macro expansion" } */
#define b() b ## ## /* { dg-error "end of a macro expansion" } */
#define c   c ##    /* { dg-error "end of a macro expansion" } */
#define d() d ##    /* { dg-error "end of a macro expansion" } */


#define e   ## ## e /* { dg-error "end of a macro expansion" } */
#define f() ## ## f /* { dg-error "end of a macro expansion" } */
#define g   ## g    /* { dg-error "end of a macro expansion" } */
#define h() ## h    /* { dg-error "end of a macro expansion" } */
#define i   ##      /* { dg-error "end of a macro expansion" } */
#define j() ##      /* { dg-error "end of a macro expansion" } */

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