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]

some bug fixes and some tidy ups


This patch fixes an entertaining bug having to do with token paste and
macro invocation, plus it rearranges the way the token types get
defined.  That will make future changes to these easier.  A fringe
benefit is we get rid of a large seldom-used array of strings.

Bootstrapped i386-linux.

zw

	* cpplib.h (TTYPE_TABLE): Rearrange to use only two per-entry
          macros, not five.

	* cpphash.h (TOKEN_NAME): New macro.
	(_cpp_spell_operator): Deleted.
	(token_spellings): Now _cpp_token_spellings.

	* cppexp.c: Use TOKEN_NAME or TYPE_NAME, not _cpp_spell_operator.
	* cpplex.c: Use OP and TK macros when expanding the
	TTYPE_TABLE.  Eliminate token_names.  For non-OPERATOR tokens,
	store the stringification of the enumeration name (CPP_CHAR,
	etc.) in the name slot of token_spellings.
	Use TOKEN_NAME and/or TOKEN_SPELL, do not reference
	token_spellings directly.
	* cpplib.c: Use TOKEN_SPELL.
	
	* cpplex.c (_cpp_push_token): If the token being pushed back
	is the previous token in this context, just subtract one from
	context->posn.
	* cppmacro.c (save_expansion): Clear aux field when storing a
	placemarker.

	* gcc.dg/cpp/paste5.c: New test.
	* gcc.dg/cpp/vararg1.c: New test.

===================================================================
Index: cppexp.c
--- cppexp.c	2000/07/13 02:32:41	1.68
+++ cppexp.c	2000/07/18 23:17:48
@@ -397,7 +397,6 @@ lex (pfile, skip_evaluation)
   switch (tok->type)
     {
     case CPP_PLACEMARKER:
-      /* XXX These shouldn't be visible outside cpplex.c.  */
       goto retry;
 
     case CPP_INT:
@@ -443,8 +442,7 @@ lex (pfile, skip_evaluation)
 	  return op;
 	}
 
-      SYNTAX_ERROR2("'%s' is not valid in #if expressions",
-		    _cpp_spell_operator (tok->type));
+      SYNTAX_ERROR2("'%s' is not valid in #if expressions", TOKEN_NAME (tok));
   }
 
  syntax_error:
@@ -718,6 +716,8 @@ op_to_prio[] =
 /* Parse and evaluate a C expression, reading from PFILE.
    Returns the truth value of the expression.  */
 
+#define TYPE_NAME(t) _cpp_token_spellings[t].name
+
 int
 _cpp_parse_expr (pfile)
      cpp_reader *pfile;
@@ -804,7 +804,7 @@ _cpp_parse_expr (pfile)
 		SYNTAX_ERROR ("void expression between '(' and ')'");
 	      else
 		SYNTAX_ERROR2 ("operator '%s' has no right operand",
-			       _cpp_spell_operator (top->op));
+			       TYPE_NAME (top->op));
 	    }
 
 	  unsigned2 = top->unsignedp, v2 = top->value;
@@ -815,8 +815,7 @@ _cpp_parse_expr (pfile)
 	  switch (top[1].op)
 	    {
 	    default:
-	      cpp_ice (pfile, "impossible operator type %s",
-		       _cpp_spell_operator (op.op));
+	      cpp_ice (pfile, "impossible operator type %s", TYPE_NAME (op.op));
 	      goto syntax_error;
 
 	    case CPP_NOT:	 UNARY(!);	break;
@@ -969,13 +968,13 @@ _cpp_parse_expr (pfile)
 	{
 	  if (top->flags & HAVE_VALUE)
 	    SYNTAX_ERROR2 ("missing binary operator before '%s'",
-			   _cpp_spell_operator (op.op));
+			   TYPE_NAME (op.op));
 	}
       else
 	{
 	  if (!(top->flags & HAVE_VALUE))
 	    SYNTAX_ERROR2 ("operator '%s' has no left operand",
-			   _cpp_spell_operator (op.op));
+			   TYPE_NAME (op.op));
 	}
 
       /* Check for and handle stack overflow.  */
===================================================================
Index: cpphash.h
--- cpphash.h	2000/07/18 00:59:48	1.65
+++ cpphash.h	2000/07/18 23:17:48
@@ -38,12 +38,13 @@ enum spell_type
 
 struct token_spelling
 {
-  ENUM_BITFIELD(spell_type) type : CHAR_BIT;
-  const U_CHAR *spelling;
+  enum spell_type category;
+  const U_CHAR *name;
 };
 
-extern const struct token_spelling token_spellings[];
-#define TOKEN_SPELL(token) (token_spellings[(token)->type].type)
+extern const struct token_spelling _cpp_token_spellings[];
+#define TOKEN_SPELL(token) (_cpp_token_spellings[(token)->type].category)
+#define TOKEN_NAME(token) (_cpp_token_spellings[(token)->type].name)
 
 /* Chained list of answers to an assertion.  */
 struct answer
@@ -267,7 +268,6 @@ extern const cpp_token *_cpp_get_token P
 extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *));
 extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*));
 extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *));
-extern const U_CHAR *_cpp_spell_operator PARAMS ((enum cpp_ttype));
 
 /* In cpplib.c */
 extern const struct directive *_cpp_check_directive
===================================================================
Index: cpplex.c
--- cpplex.c	2000/07/18 19:30:18	1.78
+++ cpplex.c	2000/07/18 23:17:49
@@ -209,35 +209,14 @@ static void process_directive PARAMS ((c
       if ((f) & BOL) {(d)->col = (s)->col; (d)->line = (s)->line;} \
   } while (0)
 
-#define T(e, s) {SPELL_OPERATOR, (const U_CHAR *) s},
-#define I(e, s) {SPELL_IDENT, s},
-#define S(e, s) {SPELL_STRING, s},
-#define C(e, s) {SPELL_CHAR, s},
-#define N(e, s) {SPELL_NONE, s},
+#define OP(e, s) { SPELL_OPERATOR, U s           },
+#define TK(e, s) { s,              U STRINGX (e) },
 
 const struct token_spelling
-token_spellings [N_TTYPES + 1] = {TTYPE_TABLE {0, 0} };
+_cpp_token_spellings [N_TTYPES] = {TTYPE_TABLE };
 
-#undef T
-#undef I
-#undef S
-#undef C
-#undef N
-
-/* For debugging: the internal names of the tokens.  */
-#define T(e, s) U STRINGX(e),
-#define I(e, s) U STRINGX(e),
-#define S(e, s) U STRINGX(e),
-#define C(e, s) U STRINGX(e),
-#define N(e, s) U STRINGX(e),
-
-const U_CHAR *const token_names[N_TTYPES] = { TTYPE_TABLE };
-
-#undef T
-#undef I
-#undef S
-#undef C
-#undef N
+#undef OP
+#undef TK
 
 /* The following table is used by trigraph_ok/trigraph_replace.  If we
    have designated initializers, it can be constant data; otherwise,
@@ -579,7 +558,7 @@ _cpp_expand_name_space (list, len)
       unsigned int i;
 
       for (i = 0; i < list->tokens_used; i++)
-	if (token_spellings[list->tokens[i].type].type == SPELL_STRING)
+	if (TOKEN_SPELL (&list->tokens[i]) == SPELL_STRING)
 	  list->tokens[i].val.str.text += (list->namebuf - old_namebuf);
     }
 }
@@ -684,7 +663,7 @@ _cpp_equiv_tokens (a, b)
      const cpp_token *a, *b;
 {
   if (a->type == b->type && a->flags == b->flags)
-    switch (token_spellings[a->type].type)
+    switch (TOKEN_SPELL (a))
       {
       default:			/* Keep compiler happy.  */
       case SPELL_OPERATOR:
@@ -1966,7 +1945,7 @@ spell_token (pfile, token, buffer)
      const cpp_token *token;
      unsigned char *buffer;
 {
-  switch (token_spellings[token->type].type)
+  switch (TOKEN_SPELL (token))
     {
     case SPELL_OPERATOR:
       {
@@ -1976,7 +1955,7 @@ spell_token (pfile, token, buffer)
 	if (token->flags & DIGRAPH)
 	  spelling = digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
 	else
-	  spelling = token_spellings[token->type].spelling;
+	  spelling = TOKEN_NAME (token);
 	
 	while ((c = *spelling++) != '\0')
 	  *buffer++ = c;
@@ -2013,26 +1992,13 @@ spell_token (pfile, token, buffer)
       break;
 
     case SPELL_NONE:
-      cpp_ice (pfile, "Unspellable token %s", token_names[token->type]);
+      cpp_ice (pfile, "Unspellable token %s", TOKEN_NAME (token));
       break;
     }
 
   return buffer;
 }
 
-/* Return the spelling of a token known to be an operator.
-   Does not distinguish digraphs from their counterparts.  */
-const unsigned char *
-_cpp_spell_operator (type)
-     enum cpp_ttype type;
-{
-  if (token_spellings[type].type == SPELL_OPERATOR)
-    return token_spellings[type].spelling;
-  else
-    return token_names[type];
-}
-
-
 /* Macro expansion algorithm.
 
 Macro expansion is implemented by a single-pass algorithm; there are
@@ -2554,7 +2520,7 @@ release_temp_tokens (pfile)
     {
       cpp_token *token = pfile->temp_tokens[--pfile->temp_used];
 
-      if (token_spellings[token->type].type == SPELL_STRING)
+      if (TOKEN_SPELL (token) == SPELL_STRING)
 	{
 	  free ((char *) token->val.str.text);
 	  token->val.str.text = 0;
@@ -2595,7 +2561,7 @@ duplicate_token (pfile, token)
   cpp_token *result = get_temp_token (pfile);
 
   *result = *token;
-  if (token_spellings[token->type].type == SPELL_STRING)
+  if (TOKEN_SPELL (token) == SPELL_STRING)
     {
       U_CHAR *buff = (U_CHAR *) xmalloc (token->val.str.len);
       memcpy (buff, token->val.str.text, token->val.str.len);
@@ -2837,6 +2803,9 @@ stringify_arg (pfile, token)
       unsigned char *buf;
       unsigned int len = TOKEN_LEN (token);
 
+      if (token->type == CPP_PLACEMARKER)
+	continue;
+
       escape = (token->type == CPP_STRING || token->type == CPP_WSTRING
 		|| token->type == CPP_CHAR || token->type == CPP_WCHAR);
       if (escape)
@@ -3008,6 +2977,22 @@ _cpp_push_token (pfile, token)
      const cpp_token *token;
 {
   cpp_context *context = CURRENT_CONTEXT (pfile);
+
+  if (context->posn > 0)
+    {
+      const cpp_token *prev;
+      if (IS_ARG_CONTEXT (context))
+	prev = context->u.arg[context->posn - 1];
+      else
+	prev = &context->u.list->tokens[context->posn - 1];
+
+      if (prev == token)
+	{
+	  context->posn--;
+	  return;
+	}
+    }
+
   if (context->pushed_token)
     cpp_ice (pfile, "two tokens pushed in a row");
   if (token->type != CPP_EOF)
@@ -3031,8 +3016,7 @@ process_directive (pfile, token)
   if (token[1].type == CPP_NAME)
     _cpp_get_raw_token (pfile);
   else if (token[1].type != CPP_NUMBER)
-    cpp_ice (pfile, "directive begins with %s?!",
-	     token_names[token[1].type]);
+    cpp_ice (pfile, "directive begins with %s?!", TOKEN_NAME (token));
 
   /* Flush pending tokens at this point, in case the directive produces
      output.  XXX Directive output won't be visible to a direct caller of
@@ -3491,7 +3475,7 @@ _cpp_dump_list (pfile, list, token, flus
 	    CPP_PUTC (pfile, '#');
 	  dump_param_spelling (pfile, list, token->val.aux);
 	}
-      else
+      else if (token->type != CPP_PLACEMARKER)
 	output_token (pfile, token, prev);
       if (token->flags & PASTE_LEFT)
 	CPP_PUTS (pfile, " ##", 3);
===================================================================
Index: cpplib.c
--- cpplib.c	2000/07/18 00:59:49	1.190
+++ cpplib.c	2000/07/18 23:17:50
@@ -1252,7 +1252,7 @@ _cpp_parse_assertion (pfile, answerp)
       dest = &list->tokens[list->tokens_used++];
       *dest = *token;
 
-      if (token_spellings[token->type].type == SPELL_STRING)
+      if (TOKEN_SPELL (token) == SPELL_STRING)
 	{
 	  _cpp_expand_name_space (list, token->val.str.len);
 	  dest->val.str.text = list->namebuf + list->name_used;
===================================================================
Index: cpplib.h
--- cpplib.h	2000/07/18 00:59:49	1.111
+++ cpplib.h	2000/07/18 23:17:50
@@ -50,96 +50,92 @@ typedef struct cpp_hashnode cpp_hashnode
 #define CPP_FIRST_DIGRAPH CPP_HASH
 
 #define TTYPE_TABLE				\
-  T(CPP_EQ = 0,		"=")			\
-  T(CPP_NOT,		"!")			\
-  T(CPP_GREATER,	">")	/* compare */	\
-  T(CPP_LESS,		"<")			\
-  T(CPP_PLUS,		"+")	/* math */	\
-  T(CPP_MINUS,		"-")			\
-  T(CPP_MULT,		"*")			\
-  T(CPP_DIV,		"/")			\
-  T(CPP_MOD,		"%")			\
-  T(CPP_AND,		"&")	/* bit ops */	\
-  T(CPP_OR,		"|")			\
-  T(CPP_XOR,		"^")			\
-  T(CPP_RSHIFT,		">>")			\
-  T(CPP_LSHIFT,		"<<")			\
-\
-  T(CPP_COMPL,		"~")			\
-  T(CPP_AND_AND,	"&&")	/* logical */	\
-  T(CPP_OR_OR,		"||")			\
-  T(CPP_QUERY,		"?")			\
-  T(CPP_COLON,		":")			\
-  T(CPP_COMMA,		",")	/* grouping */	\
-  T(CPP_OPEN_PAREN,	"(")			\
-  T(CPP_CLOSE_PAREN,	")")			\
-  T(CPP_EQ_EQ,		"==")	/* compare */	\
-  T(CPP_NOT_EQ,		"!=")			\
-  T(CPP_GREATER_EQ,	">=")			\
-  T(CPP_LESS_EQ,	"<=")			\
-\
-  T(CPP_PLUS_EQ,	"+=")	/* math */	\
-  T(CPP_MINUS_EQ,	"-=")			\
-  T(CPP_MULT_EQ,	"*=")			\
-  T(CPP_DIV_EQ,		"/=")			\
-  T(CPP_MOD_EQ,		"%=")			\
-  T(CPP_AND_EQ,		"&=")	/* bit ops */	\
-  T(CPP_OR_EQ,		"|=")			\
-  T(CPP_XOR_EQ,		"^=")			\
-  T(CPP_RSHIFT_EQ,	">>=")			\
-  T(CPP_LSHIFT_EQ,	"<<=")			\
+  OP(CPP_EQ = 0,	"=")			\
+  OP(CPP_NOT,		"!")			\
+  OP(CPP_GREATER,	">")	/* compare */	\
+  OP(CPP_LESS,		"<")			\
+  OP(CPP_PLUS,		"+")	/* math */	\
+  OP(CPP_MINUS,		"-")			\
+  OP(CPP_MULT,		"*")			\
+  OP(CPP_DIV,		"/")			\
+  OP(CPP_MOD,		"%")			\
+  OP(CPP_AND,		"&")	/* bit ops */	\
+  OP(CPP_OR,		"|")			\
+  OP(CPP_XOR,		"^")			\
+  OP(CPP_RSHIFT,	">>")			\
+  OP(CPP_LSHIFT,	"<<")			\
+\
+  OP(CPP_COMPL,		"~")			\
+  OP(CPP_AND_AND,	"&&")	/* logical */	\
+  OP(CPP_OR_OR,		"||")			\
+  OP(CPP_QUERY,		"?")			\
+  OP(CPP_COLON,		":")			\
+  OP(CPP_COMMA,		",")	/* grouping */	\
+  OP(CPP_OPEN_PAREN,	"(")			\
+  OP(CPP_CLOSE_PAREN,	")")			\
+  OP(CPP_EQ_EQ,		"==")	/* compare */	\
+  OP(CPP_NOT_EQ,	"!=")			\
+  OP(CPP_GREATER_EQ,	">=")			\
+  OP(CPP_LESS_EQ,	"<=")			\
+\
+  OP(CPP_PLUS_EQ,	"+=")	/* math */	\
+  OP(CPP_MINUS_EQ,	"-=")			\
+  OP(CPP_MULT_EQ,	"*=")			\
+  OP(CPP_DIV_EQ,	"/=")			\
+  OP(CPP_MOD_EQ,	"%=")			\
+  OP(CPP_AND_EQ,	"&=")	/* bit ops */	\
+  OP(CPP_OR_EQ,		"|=")			\
+  OP(CPP_XOR_EQ,	"^=")			\
+  OP(CPP_RSHIFT_EQ,	">>=")			\
+  OP(CPP_LSHIFT_EQ,	"<<=")			\
   /* Digraphs together, beginning with CPP_FIRST_DIGRAPH.  */	\
-  T(CPP_HASH,		"#")	/* digraphs */	\
-  T(CPP_PASTE,		"##")			\
-  T(CPP_OPEN_SQUARE,	"[")			\
-  T(CPP_CLOSE_SQUARE,	"]")			\
-  T(CPP_OPEN_BRACE,	"{")			\
-  T(CPP_CLOSE_BRACE,	"}")			\
-  /* The remainder of the punctuation.  Order is not significant. */	\
-  T(CPP_SEMICOLON,	";")	/* structure */	\
-  T(CPP_ELLIPSIS,	"...")			\
-  T(CPP_BACKSLASH,	"\\")			\
-  T(CPP_PLUS_PLUS,	"++")	/* increment */	\
-  T(CPP_MINUS_MINUS,	"--")			\
-  T(CPP_DEREF,		"->")	/* accessors */	\
-  T(CPP_DOT,		".")			\
-  T(CPP_SCOPE,		"::")			\
-  T(CPP_DEREF_STAR,	"->*")			\
-  T(CPP_DOT_STAR,	".*")			\
-  T(CPP_MIN,		"<?")	/* extension */	\
-  T(CPP_MAX,		">?")			\
-  T(CPP_PLACEMARKER,	"")	/* Placemarker token.  */  \
-  C(CPP_OTHER,		0)	/* stray punctuation */    \
-\
-  I(CPP_NAME,		0)	/* word */	\
-  S(CPP_INT,		0)	/* 23 */	\
-  S(CPP_FLOAT,		0)	/* 3.14159 */	\
-  S(CPP_NUMBER,		0)	/* 34_be+ta  */	\
-  S(CPP_CHAR,		0)	/* 'char' */	\
-  S(CPP_WCHAR,		0)	/* L'char' */	\
-  S(CPP_STRING,		0)	/* "string" */	\
-  S(CPP_WSTRING,	0)	/* L"string" */	\
-\
-  S(CPP_COMMENT,	0)	/* Only if output comments.  */ \
-  N(CPP_MACRO_ARG,      0)	/* Macro argument.  */          \
-  N(CPP_EOF,		0)	/* End of file.  */		\
-  S(CPP_HEADER_NAME,	0)	/* <stdio.h> in #include */
+  OP(CPP_HASH,		"#")	/* digraphs */	\
+  OP(CPP_PASTE,		"##")			\
+  OP(CPP_OPEN_SQUARE,	"[")			\
+  OP(CPP_CLOSE_SQUARE,	"]")			\
+  OP(CPP_OPEN_BRACE,	"{")			\
+  OP(CPP_CLOSE_BRACE,	"}")			\
+  /* The remainder of the punctuation.  Order is not significant.  */	\
+  OP(CPP_SEMICOLON,	";")	/* structure */	\
+  OP(CPP_ELLIPSIS,	"...")			\
+  OP(CPP_BACKSLASH,	"\\")			\
+  OP(CPP_PLUS_PLUS,	"++")	/* increment */	\
+  OP(CPP_MINUS_MINUS,	"--")			\
+  OP(CPP_DEREF,		"->")	/* accessors */	\
+  OP(CPP_DOT,		".")			\
+  OP(CPP_SCOPE,		"::")			\
+  OP(CPP_DEREF_STAR,	"->*")			\
+  OP(CPP_DOT_STAR,	".*")			\
+  OP(CPP_MIN,		"<?")	/* extension */	\
+  OP(CPP_MAX,		">?")			\
+\
+  TK(CPP_NAME,		SPELL_IDENT)	/* word */			\
+  TK(CPP_INT,		SPELL_STRING)	/* 23 */			\
+  TK(CPP_FLOAT,		SPELL_STRING)	/* 3.14159 */			\
+  TK(CPP_NUMBER,	SPELL_STRING)	/* 34_be+ta  */			\
+\
+  TK(CPP_CHAR,		SPELL_STRING)	/* 'char' */			\
+  TK(CPP_WCHAR,		SPELL_STRING)	/* L'char' */			\
+  TK(CPP_OTHER,		SPELL_CHAR)	/* stray punctuation */		\
+\
+  TK(CPP_STRING,	SPELL_STRING)	/* "string" */			\
+  TK(CPP_WSTRING,	SPELL_STRING)	/* L"string" */			\
+  TK(CPP_HEADER_NAME,	SPELL_STRING)	/* <stdio.h> in #include */	\
+\
+  TK(CPP_COMMENT,	SPELL_STRING)	/* Only if output comments.  */ \
+  TK(CPP_MACRO_ARG,	SPELL_NONE)	/* Macro argument.  */		\
+  TK(CPP_PLACEMARKER,	SPELL_NONE)	/* Placemarker token.  */	\
+  TK(CPP_EOF,		SPELL_NONE)	/* End of file.	 */
 
-#define T(e, s) e,
-#define I(e, s) e,
-#define S(e, s) e,
-#define C(e, s) e,
-#define N(e, s) e,
+#define OP(e, s) e,
+#define TK(e, s) e,
 enum cpp_ttype
 {
   TTYPE_TABLE
   N_TTYPES
 };
-#undef T
-#undef I
-#undef S
-#undef C
-#undef N
+#undef OP
+#undef TK
 
 /* Payload of a NUMBER, FLOAT, STRING, or COMMENT token.  */
 struct cpp_string
===================================================================
Index: cppmacro.c
--- cppmacro.c	2000/07/18 00:59:49	1.1
+++ cppmacro.c	2000/07/18 23:17:50
@@ -495,6 +495,7 @@ save_expansion (pfile, info)
     {
       dest->type = CPP_PLACEMARKER;
       dest->flags = 0;
+      dest->val.aux = 0;
     }
 
   return list;
===================================================================
Index: testsuite/gcc.dg/cpp/paste5.c
--- testsuite/gcc.dg/cpp/paste5.c	Tue May  5 13:32:27 1998
+++ testsuite/gcc.dg/cpp/paste5.c	Tue Jul 18 16:17:51 2000
@@ -0,0 +1,24 @@
+/* Regression test for bug in convoluted situation involving token paste
+   plus function-like macros used outside function context.  It may be
+   easier to understand if you mentally replace 'struct' with 'A'
+   throughout this file; 'struct' is used only to get the code to compile
+   when preprocessed correctly.
+
+   The original problem was seen in the Linux kernel and reported by
+   Jakub Jelinek <jakub@redhat.com>; this test is synthetic.  */
+
+/* { dg-do compile } */
+
+#define glue(a,b) a##b
+#define struct(x) B(x)
+#define E(x) struct x
+#define FG (22)
+
+extern void B(int);
+
+void foo(void)
+{
+  E(glue(F,*)) dummy;  /* { dg-warning "valid preprocessing token" } */
+
+  E(glue(F,G)) ;
+}
===================================================================
Index: testsuite/gcc.dg/cpp/vararg1.c
--- testsuite/gcc.dg/cpp/vararg1.c	Tue May  5 13:32:27 1998
+++ testsuite/gcc.dg/cpp/vararg1.c	Tue Jul 18 16:17:51 2000
@@ -0,0 +1,19 @@
+/* Test for changed behavior of the GNU varargs extension.
+   ##args, where args is a rest argument which received zero tokens,
+   used to delete the previous sequence of nonwhitespace characters.
+   Now it deletes the previous token.  */
+
+/* { dg-do run } */
+/* { dg-options -w } */
+
+#include <string.h>
+
+#define S(str, args...) "  " str "\n", ##args
+
+int
+main()
+{
+  const char *s = S("foo");
+  return strchr (s, '\n') == NULL;
+}
+

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