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]

Fix # and ## spelling and whitespace issues with macro redefinitions


This patch fixes problems with the preprocessor losing information
about the spelling of # and ## tokens, and about whitespace around
them, and about whether there are multiple consecutive ## tokens, so
failing to diagnose duplicate macro definitions that are not
sufficiently identical in ISO C terms.

The original bug report, PR 20078, was only about the spelling issue,
and as such appeared to be the one remaining known target-independent
C90 Amendment 1 conformance bug (Amendment 1 introduced digraphs, so
anything involving them is not a C90 issue).  In the course of
investigating it, the other issues with whitespace and consecutive ##
tokens showed up (which are also bugs for C90; all the issues are also
bugs for C99).

The spelling and whitespace issues are reasonably straightforward to
fix; two new token flags SP_DIGRAPH and SP_PREV_WHITE are added to
track the relevant information and then the existing checks for flag
consistency ensure that duplicates differing in this regard are
diagnosed.  The flags field had to be enlarged from unsigned char to
unsigned short, but there's padding to spare for that (now 6 bits of
the short are unused and there are still 8 bits of padding).

More problems arise when there are multiple consecutive ## tokens.
ISO C is silent about this possibility - there is nothing to disallow
it, and the most sensible interpretation of the existing wording is
that multiple consecutive ## tokens act like one such token.  However,
the constraints for duplicate macro definitions require that
variations in whether consecutive such tokens have space between them,
or are spelt as digraphs, or in how many such tokens are in a
sequence, must be diagnosed (and there is certainly no undefined
behavior simply in defining such macros without expanding them, even
if you could argue that silence makes expanding such a macro
undefined).

Simply using extra flags on the token being marked with PASTE_LEFT
cannot work for tracking this information about a sequence of such
tokens of unbounded length; you need two bits of information for each
successive ## or %:%: token, associated with the relevant position in
the token sequence.  Rather than leave special tokens in the middle of
the sequence of the macro expansion and so require them to be taken
out of the middle at expansion time, this patch arranges for the
second and subsequent ## tokens to go at the end of the token
sequence, and most places using a macro expansion (but not the checks
for duplicate definitions) are made to use macro_real_token_count to
determine the number of real tokens in the macro definition.  In the
normal case where there were not consecutive ## tokens in the
definition, macro_real_token_count just returns macro->count.

In turn, moving the tokens to the end requires keeping track of where
they were in the original expansion, so that macros with the same
total number of ## tokens but varying in how many were in each
sequence of such tokens are diagnosed.  Operators did not previously
use the val field of a cpp_token at all; val.arg_no is now used for
CPP_PASTE to track this information.

This patch does not make cpp_macro_definition use the newly preserved
information to produce a more accurate rendering of the definition;
this affects PCH, -d options for dumping macros and putting macro
definitions in debug information.  I'll file a separate PR for this.

Bootstrapped with no regressions on i686-pc-linux-gnu.  Applied to
mainline.  I don't now know of any target-independent C90 or C90
Amendment 1 conformance bugs on mainline (although of course more may
yet be discovered just as I found the C90 issues this patch fixes in
the course of investigating PR 20078).

libcpp:
2009-04-19  Joseph Myers  <joseph@codesourcery.com>

	PR preprocessor/20078
	* include/cpp-id-data.h (struct cpp_macro): Add extra_tokens
	field.
	* include/cpplib.h (SP_DIGRAPH, SP_PREV_WHITE): Define.
	(struct cpp_token): Change flags to unsigned short.
	* lex.c (_cpp_lex_direct): Initialize arg_no for CPP_PASTE tokens.
	(_cpp_equiv_tokens): Check arg_no for CPP_PASTE tokens.
	(cpp_token_val_index): Return CPP_TOKEN_FLD_ARG_NO for CPP_PASTE
	tokens.
	* macro.c (macro_real_token_count): New.
	(enter_macro_context, replace_args): Use macro_real_token_count.
	(create_iso_definition): Record whitespace surrounding and digraph
	spelling of # and ## tokens using SP_PREV_WHITE and SP_DIGRAPH.
	Set extra_tokens and save CPP_PASTE tokens with arg_no set for
	multiple consecutive ## tokens.
	(_cpp_create_definition): Initialize extra_tokens.
	(cpp_macro_definition): Use macro_real_token_count.

gcc/testsuite:
2009-04-19  Joseph Myers  <joseph@codesourcery.com>

	PR preprocessor/20078
	* gcc.dg/cpp/paste16.c, gcc.dg/cpp/redef4.c: New tests.

Index: libcpp/include/cpp-id-data.h
===================================================================
--- libcpp/include/cpp-id-data.h	(revision 146336)
+++ libcpp/include/cpp-id-data.h	(working copy)
@@ -75,4 +75,9 @@ struct cpp_macro GTY(())
 
   /* Indicate which field of 'exp' is in use.  */
   unsigned int traditional : 1;
+
+  /* Indicate whether the tokens include extra CPP_PASTE tokens at the
+     end to track invalid redefinitions with consecutive CPP_PASTE
+     tokens.  */
+  unsigned int extra_tokens : 1;
 };
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 146336)
+++ libcpp/include/cpplib.h	(working copy)
@@ -178,6 +178,10 @@ struct cpp_string GTY(())
 #define BOL		(1 << 6) /* Token at beginning of line.  */
 #define PURE_ZERO	(1 << 7) /* Single 0 digit, used by the C++ frontend,
 				    set in c-lex.c.  */
+#define SP_DIGRAPH	(1 << 8) /* # or ## token was a digraph.  */
+#define SP_PREV_WHITE	(1 << 9) /* If whitespace before a ##
+				    operator, or before this token
+				    after a # operator.  */
 
 /* Specify which field, if any, of the cpp_token union is used.  */
 
@@ -196,7 +200,7 @@ struct cpp_token GTY(())
 {
   source_location src_loc;	/* Location of first char of token.  */
   ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT;  /* token type */
-  unsigned char flags;		/* flags - see above */
+  unsigned short flags;		/* flags - see above */
 
   union cpp_token_u
   {
Index: libcpp/lex.c
===================================================================
--- libcpp/lex.c	(revision 146336)
+++ libcpp/lex.c	(working copy)
@@ -1244,7 +1244,7 @@ _cpp_lex_direct (cpp_reader *pfile)
 	      result->flags |= DIGRAPH;
 	      result->type = CPP_HASH;
 	      if (*buffer->cur == '%' && buffer->cur[1] == ':')
-		buffer->cur += 2, result->type = CPP_PASTE;
+		buffer->cur += 2, result->type = CPP_PASTE, result->val.arg_no = 0;
 	    }
 	  else if (*buffer->cur == '>')
 	    {
@@ -1325,7 +1325,7 @@ _cpp_lex_direct (cpp_reader *pfile)
     case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
     case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
     case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break;
-    case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break;
+    case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); result->val.arg_no = 0; break;
 
     case '?': result->type = CPP_QUERY; break;
     case '~': result->type = CPP_COMPL; break;
@@ -1572,7 +1572,9 @@ _cpp_equiv_tokens (const cpp_token *a, c
       {
       default:			/* Keep compiler happy.  */
       case SPELL_OPERATOR:
-	return 1;
+	/* arg_no is used to track where multiple consecutive ##
+	   tokens were originally located.  */
+	return (a->type != CPP_PASTE || a->val.arg_no == b->val.arg_no);
       case SPELL_NONE:
 	return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no);
       case SPELL_IDENT:
@@ -1886,6 +1888,11 @@ cpp_token_val_index (cpp_token *tok)
       return CPP_TOKEN_FLD_NODE;
     case SPELL_LITERAL:
       return CPP_TOKEN_FLD_STR;
+    case SPELL_OPERATOR:
+      if (tok->type == CPP_PASTE)
+	return CPP_TOKEN_FLD_ARG_NO;
+      else
+	return CPP_TOKEN_FLD_NONE;
     case SPELL_NONE:
       if (tok->type == CPP_MACRO_ARG)
 	return CPP_TOKEN_FLD_ARG_NO;
Index: libcpp/macro.c
===================================================================
--- libcpp/macro.c	(revision 146336)
+++ libcpp/macro.c	(working copy)
@@ -802,6 +802,19 @@ funlike_invocation_p (cpp_reader *pfile,
   return NULL;
 }
 
+/* Return the real number of tokens in the expansion of MACRO.  */
+static inline unsigned int
+macro_real_token_count (const cpp_macro *macro)
+{
+  unsigned int i;
+  if (__builtin_expect (!macro->extra_tokens, true))
+    return macro->count;
+  for (i = 0; i < macro->count; i++)
+    if (macro->exp.tokens[i].type == CPP_PASTE)
+      return i;
+  abort ();
+}
+
 /* Push the context of a macro with hash entry NODE onto the context
    stack.  If we can successfully expand the macro, we push a context
    containing its yet-to-be-rescanned replacement list and return one.
@@ -874,7 +887,8 @@ enter_macro_context (cpp_reader *pfile, 
       macro->used = 1;
 
       if (macro->paramc == 0)
-	_cpp_push_token_context (pfile, node, macro->exp.tokens, macro->count);
+	_cpp_push_token_context (pfile, node, macro->exp.tokens,
+				 macro_real_token_count (macro));
 
       if (pragma_buff)
 	{
@@ -914,13 +928,15 @@ replace_args (cpp_reader *pfile, cpp_has
   const cpp_token **dest, **first;
   macro_arg *arg;
   _cpp_buff *buff;
+  unsigned int count;
 
   /* First, fully macro-expand arguments, calculating the number of
      tokens in the final expansion as we go.  The ordering of the if
      statements below is subtle; we must handle stringification before
      pasting.  */
-  total = macro->count;
-  limit = macro->exp.tokens + macro->count;
+  count = macro_real_token_count (macro);
+  total = count;
+  limit = macro->exp.tokens + count;
 
   for (src = macro->exp.tokens; src < limit; src++)
     if (src->type == CPP_MACRO_ARG)
@@ -1630,6 +1646,7 @@ create_iso_definition (cpp_reader *pfile
   bool following_paste_op = false;
   const char *paste_op_error_msg =
     N_("'##' cannot appear at either end of a macro expansion");
+  unsigned int num_extra_tokens = 0;
 
   /* Get the first token of the expansion (or the '(' of a
      function-like macro).  */
@@ -1707,6 +1724,10 @@ create_iso_definition (cpp_reader *pfile
 	{
 	  if (token->type == CPP_MACRO_ARG)
 	    {
+	      if (token->flags & PREV_WHITE)
+		token->flags |= SP_PREV_WHITE;
+	      if (token[-1].flags & DIGRAPH)
+		token->flags |= SP_DIGRAPH;
 	      token->flags &= ~PREV_WHITE;
 	      token->flags |= STRINGIFY_ARG;
 	      token->flags |= token[-1].flags & PREV_WHITE;
@@ -1746,8 +1767,21 @@ create_iso_definition (cpp_reader *pfile
 	      return false;
 	    }
 
-	  --macro->count;
-	  token[-1].flags |= PASTE_LEFT;
+	  if (token[-1].flags & PASTE_LEFT)
+	    {
+	      macro->extra_tokens = 1;
+	      num_extra_tokens++;
+	      token->val.arg_no = macro->count - 1;
+	    }
+	  else
+	    {
+	      --macro->count;
+	      token[-1].flags |= PASTE_LEFT;
+	      if (token->flags & DIGRAPH)
+		token[-1].flags |= SP_DIGRAPH;
+	      if (token->flags & PREV_WHITE)
+		token[-1].flags |= SP_PREV_WHITE;
+	    }
 	}
 
       following_paste_op = (token->type == CPP_PASTE);
@@ -1770,7 +1804,27 @@ create_iso_definition (cpp_reader *pfile
       cpp_token *tokns =
         (cpp_token *) pfile->hash_table->alloc_subobject (sizeof (cpp_token)
                                                           * macro->count);
-      memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count);
+      if (num_extra_tokens)
+	{
+	  /* Place second and subsequent ## or %:%: tokens in
+	     sequences of consecutive such tokens at the end of the
+	     list to preserve information about where they appear, how
+	     they are spelt and whether they are preceded by
+	     whitespace without otherwise interfering with macro
+	     expansion.  */
+	  cpp_token *normal_dest = tokns;
+	  cpp_token *extra_dest = tokns + macro->count - num_extra_tokens;
+	  unsigned int i;
+	  for (i = 0; i < macro->count; i++)
+	    {
+	      if (macro->exp.tokens[i].type == CPP_PASTE)
+		*extra_dest++ = macro->exp.tokens[i];
+	      else
+		*normal_dest++ = macro->exp.tokens[i];
+	    }
+	}
+      else
+	memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count);
       macro->exp.tokens = tokns;
     }
   else
@@ -1799,6 +1853,7 @@ _cpp_create_definition (cpp_reader *pfil
   macro->used = !CPP_OPTION (pfile, warn_unused_macros);
   macro->count = 0;
   macro->fun_like = 0;
+  macro->extra_tokens = 0;
   /* To suppress some diagnostics.  */
   macro->syshdr = pfile->buffer && pfile->buffer->sysp != 0;
 
@@ -1946,7 +2001,8 @@ cpp_macro_definition (cpp_reader *pfile,
     len += _cpp_replacement_text_len (macro);
   else
     {
-      for (i = 0; i < macro->count; i++)
+      unsigned int count = macro_real_token_count (macro);
+      for (i = 0; i < count; i++)
 	{
 	  cpp_token *token = &macro->exp.tokens[i];
 
@@ -2010,7 +2066,8 @@ cpp_macro_definition (cpp_reader *pfile,
   else if (macro->count)
   /* Expansion tokens.  */
     {
-      for (i = 0; i < macro->count; i++)
+      unsigned int count = macro_real_token_count (macro);
+      for (i = 0; i < count; i++)
 	{
 	  cpp_token *token = &macro->exp.tokens[i];
 
Index: gcc/testsuite/gcc.dg/cpp/paste16.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/paste16.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/paste16.c	(revision 0)
@@ -0,0 +1,6 @@
+/* Test multiple consecutive ## tokens.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+#define cat(x,y) x##########y
+int abcd;
+int *p = &cat(ab,cd);
Index: gcc/testsuite/gcc.dg/cpp/redef4.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/redef4.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/redef4.c	(revision 0)
@@ -0,0 +1,499 @@
+/* Test redefinitions differing only in the spelling of paste and
+   stringify tokens, whitespace around them, or the number of
+   consecutive paste tokens.  */
+/* { dg-do preprocess } */
+/* { dg-options "" } */
+
+#define str(x) #x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) #x /* { dg-message "previous definition" } */
+#define str(x) # x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) #x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %:x /* { dg-message "previous definition" } */
+#define str(x) #x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %:x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %:x /* { dg-message "previous definition" } */
+#define str(x) # x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %:x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) # x /* { dg-message "previous definition" } */
+#define str(x) #x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) # x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) # x /* { dg-message "previous definition" } */
+#define str(x) %: x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %: x /* { dg-message "previous definition" } */
+#define str(x) #x /* { dg-warning "redefined" } */
+#undef str
+#define str(x) %: x /* { dg-message "previous definition" } */
+#define str(x) # x /* { dg-warning "redefined" } */
+#undef str
+
+#define str(x) #x
+#define str(x) #x
+#undef str
+#define str(x) # x
+#define str(x) # x
+#undef str
+#define str(x) %: x
+#define str(x) %: x
+#undef str
+#define str(x) %: x
+#define str(x) %: x
+#undef str
+
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a#x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%:x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a# x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a%: x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a #x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %:x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a # x /* { dg-message "previous definition" } */
+#define astr(x) a %: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a#x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a# x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a%: x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a #x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a %:x /* { dg-warning "redefined" } */
+#undef astr
+#define astr(x) a %: x /* { dg-message "previous definition" } */
+#define astr(x) a # x /* { dg-warning "redefined" } */
+#undef astr
+
+#define astr(x) a#x
+#define astr(x) a#x
+#undef astr
+#define astr(x) a# x
+#define astr(x) a# x
+#undef astr
+#define astr(x) a%: x
+#define astr(x) a%: x
+#undef astr
+#define astr(x) a%: x
+#define astr(x) a%: x
+#undef astr
+#define astr(x) a #x
+#define astr(x) a #x
+#undef astr
+#define astr(x) a %:x
+#define astr(x) a %:x
+#undef astr
+#define astr(x) a # x
+#define astr(x) a # x
+#undef astr
+#define astr(x) a %: x
+#define astr(x) a %: x
+#undef astr
+
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x##y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x## y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x%:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ##y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%:y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x ## y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x## y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x%:%: y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x ##y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x %:%:y /* { dg-warning "redefined" } */
+#undef cat
+#define cat(x,y) x %:%: y /* { dg-message "previous definition" } */
+#define cat(x,y) x ## y /* { dg-warning "redefined" } */
+#undef cat
+
+#define cat(x,y) x##y
+#define cat(x,y) x##y
+#undef cat
+#define cat(x,y) x## y
+#define cat(x,y) x## y
+#undef cat
+#define cat(x,y) x%:%: y
+#define cat(x,y) x%:%: y
+#undef cat
+#define cat(x,y) x%:%: y
+#define cat(x,y) x%:%: y
+#undef cat
+#define cat(x,y) x ##y
+#define cat(x,y) x ##y
+#undef cat
+#define cat(x,y) x %:%:y
+#define cat(x,y) x %:%:y
+#undef cat
+#define cat(x,y) x ## y
+#define cat(x,y) x ## y
+#undef cat
+#define cat(x,y) x %:%: y
+#define cat(x,y) x %:%: y
+#undef cat
+
+#define cat3(x,y,z) x##y##z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x##y####z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y####z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x####y##z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y####z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x##y## ##z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y####z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x##y##%:%:z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y######## ####z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x##y############z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y############z /* { dg-message "previous definition" } */
+#define cat3(x,y,z) x##y########%:%:##z /* { dg-warning "redefined" } */
+#undef cat3
+
+#define cat3(x,y,z) x##y##z
+#define cat3(x,y,z) x##y##z
+#undef cat3
+
+#define cat3(x,y,z) x##y####z
+#define cat3(x,y,z) x##y####z
+#undef cat3
+
+#define cat3(x,y,z) x####y##z
+#define cat3(x,y,z) x####y##z
+#undef cat3
+
+#define cat3(x,y,z) x##y## ##z
+#define cat3(x,y,z) x##y## ##z
+#undef cat3
+
+#define cat3(x,y,z) x##y##%:%:z
+#define cat3(x,y,z) x##y##%:%:z
+#undef cat3
+
+#define cat3(x,y,z) x##y######## ####z
+#define cat3(x,y,z) x##y######## ####z
+#undef cat3
+
+#define cat3(x,y,z) x##y############z
+#define cat3(x,y,z) x##y############z
+#undef cat3
+
+#define cat3(x,y,z) x##y########%:%:##z
+#define cat3(x,y,z) x##y########%:%:##z
+#undef cat3

-- 
Joseph S. Myers
joseph@codesourcery.com


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