Blame SOURCES/gcc32-pr3581.patch

6f1b0c
2002-04-26  Richard Henderson  <rth@redhat.com>
6f1b0c
6f1b0c
	PR c/3581
6f1b0c
	* c-common.c (fix_string_type): Split out of ...
6f1b0c
	(combine_strings): ... here.  Take a varray, not a tree list.
6f1b0c
	(c_expand_builtin_printf): Use fix_string_type.
6f1b0c
	* c-common.h: Update decls.
6f1b0c
	* c-parse.in (string): Remove.  Update all uses to use STRING
6f1b0c
	instead, and not call combine_strings.
6f1b0c
	(yylexstring): New.
6f1b0c
	(_yylex): Use it.
6f1b0c
	* c-typeck.c (simple_asm_stmt): Don't call combine_strings.
6f1b0c
	(build_asm_stmt): Likewise.
6f1b0c
	* objc/objc-act.c (my_build_string): Use fix_string_type.
6f1b0c
	(build_objc_string_object): Build varray for combine_strings.
6f1b0c
cp/
6f1b0c
	* parse.y (string): Remove.  Update all uses to use STRING
6f1b0c
	instead, and not call combine_strings.
6f1b0c
	* rtti.c (tinfo_name): Use fix_string_type.
6f1b0c
	* semantics.c (finish_asm_stmt): Don't call combine_strings.
6f1b0c
	* spew.c (yylexstring): New.
6f1b0c
	(read_token): Use it.
6f1b0c
testsuite/
6f1b0c
	* g++.dg/parse/concat1.C: New test.
6f1b0c
	* gcc.dg/concat2.c: New test.
6f1b0c
6f1b0c
--- gcc/objc/objc-act.c.jj	2002-09-24 15:08:15.000000000 +0200
6f1b0c
+++ gcc/objc/objc-act.c	2004-10-05 16:08:18.744519118 +0200
6f1b0c
@@ -1207,21 +1207,7 @@ my_build_string (len, str)
6f1b0c
      int len;
6f1b0c
      const char *str;
6f1b0c
 {
6f1b0c
-  int wide_flag = 0;
6f1b0c
-  tree a_string = build_string (len, str);
6f1b0c
-
6f1b0c
-  /* Some code from combine_strings, which is local to c-parse.y.  */
6f1b0c
-  if (TREE_TYPE (a_string) == int_array_type_node)
6f1b0c
-    wide_flag = 1;
6f1b0c
-
6f1b0c
-  TREE_TYPE (a_string)
6f1b0c
-    = build_array_type (wide_flag ? integer_type_node : char_type_node,
6f1b0c
-			build_index_type (build_int_2 (len - 1, 0)));
6f1b0c
-
6f1b0c
-  TREE_CONSTANT (a_string) = 1;	/* Puts string in the readonly segment */
6f1b0c
-  TREE_STATIC (a_string) = 1;
6f1b0c
-
6f1b0c
-  return a_string;
6f1b0c
+  return fix_string_type (build_string (len, str));
6f1b0c
 }
6f1b0c
 
6f1b0c
 /* Given a chain of STRING_CST's, build a static instance of
6f1b0c
@@ -1247,7 +1233,23 @@ build_objc_string_object (strings)
6f1b0c
 
6f1b0c
   add_class_reference (constant_string_id);
6f1b0c
 
6f1b0c
-  string = combine_strings (strings);
6f1b0c
+  if (TREE_CHAIN (strings))
6f1b0c
+    {
6f1b0c
+      varray_type vstrings;
6f1b0c
+      VARRAY_TREE_INIT (vstrings, 32, "strings");
6f1b0c
+
6f1b0c
+      for (; strings ; strings = TREE_CHAIN (strings))
6f1b0c
+	VARRAY_PUSH_TREE (vstrings, strings);
6f1b0c
+
6f1b0c
+      string = combine_strings (vstrings);
6f1b0c
+
6f1b0c
+      VARRAY_FREE (vstrings);
6f1b0c
+    }
6f1b0c
+  else
6f1b0c
+    string = strings;
6f1b0c
+
6f1b0c
+  string = fix_string_type (string);
6f1b0c
+
6f1b0c
   TREE_SET_CODE (string, STRING_CST);
6f1b0c
   length = TREE_STRING_LENGTH (string) - 1;
6f1b0c
 
6f1b0c
--- gcc/c-common.h.jj	2003-09-16 16:57:44.000000000 +0200
6f1b0c
+++ gcc/c-common.h	2004-10-05 16:08:18.669532451 +0200
6f1b0c
@@ -524,8 +524,9 @@ extern void c_finish_else               
6f1b0c
 extern void c_expand_end_cond			PARAMS ((void));
6f1b0c
 /* Validate the expression after `case' and apply default promotions.  */
6f1b0c
 extern tree check_case_value			PARAMS ((tree));
6f1b0c
-/* Concatenate a list of STRING_CST nodes into one STRING_CST.  */
6f1b0c
-extern tree combine_strings			PARAMS ((tree));
6f1b0c
+extern tree fix_string_type			PARAMS ((tree));
6f1b0c
+struct varray_head_tag;
6f1b0c
+extern tree combine_strings		PARAMS ((struct varray_head_tag *));
6f1b0c
 extern void constant_expression_warning		PARAMS ((tree));
6f1b0c
 extern tree convert_and_check			PARAMS ((tree, tree));
6f1b0c
 extern void overflow_warning			PARAMS ((tree));
6f1b0c
--- gcc/cp/rtti.c.jj	2002-12-08 21:43:27.000000000 +0100
6f1b0c
+++ gcc/cp/rtti.c	2004-10-05 16:08:18.721523207 +0200
6f1b0c
@@ -298,7 +298,7 @@ tinfo_name (type)
6f1b0c
   tree name_string;
6f1b0c
 
6f1b0c
   name = mangle_type_string (type);
6f1b0c
-  name_string = combine_strings (build_string (strlen (name) + 1, name));
6f1b0c
+  name_string = fix_string_type (build_string (strlen (name) + 1, name));
6f1b0c
   return name_string;
6f1b0c
 }
6f1b0c
 
6f1b0c
--- gcc/cp/semantics.c.jj	2003-03-28 22:03:02.000000000 +0100
6f1b0c
+++ gcc/cp/semantics.c	2004-10-05 16:08:18.723522851 +0200
6f1b0c
@@ -879,9 +879,6 @@ finish_asm_stmt (cv_qualifier, string, o
6f1b0c
   tree r;
6f1b0c
   tree t;
6f1b0c
 
6f1b0c
-  if (TREE_CHAIN (string))
6f1b0c
-    string = combine_strings (string);
6f1b0c
-
6f1b0c
   if (cv_qualifier != NULL_TREE
6f1b0c
       && cv_qualifier != ridpointers[(int) RID_VOLATILE])
6f1b0c
     {
6f1b0c
--- gcc/cp/parse.y.jj	2003-01-17 18:33:10.000000000 +0100
6f1b0c
+++ gcc/cp/parse.y	2004-10-05 16:08:18.717523918 +0200
6f1b0c
@@ -349,7 +349,7 @@ cp_parse_init ()
6f1b0c
 %type <ttype> PFUNCNAME maybe_identifier
6f1b0c
 %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
6f1b0c
 %type <ttype> expr_no_commas expr_no_comma_rangle
6f1b0c
-%type <ttype> cast_expr unary_expr primary string STRING
6f1b0c
+%type <ttype> cast_expr unary_expr primary STRING
6f1b0c
 %type <ttype> reserved_declspecs boolean.literal
6f1b0c
 %type <ttype> reserved_typespecquals
6f1b0c
 %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
6f1b0c
@@ -514,9 +514,8 @@ extdef:
6f1b0c
 		{ do_pending_inlines (); }
6f1b0c
 	| template_def
6f1b0c
 		{ do_pending_inlines (); }
6f1b0c
-	| asm_keyword '(' string ')' ';'
6f1b0c
-		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
6f1b0c
-		  assemble_asm ($3); }
6f1b0c
+	| asm_keyword '(' STRING ')' ';'
6f1b0c
+		{ assemble_asm ($3); }
6f1b0c
 	| extern_lang_string '{' extdefs_opt '}'
6f1b0c
 		{ pop_lang_context (); }
6f1b0c
 	| extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
6f1b0c
@@ -1587,10 +1586,10 @@ primary:
6f1b0c
 		}		
6f1b0c
 	| CONSTANT
6f1b0c
 	| boolean.literal
6f1b0c
-	| string
6f1b0c
+	| STRING
6f1b0c
 		{
6f1b0c
-		  $$ = combine_strings ($$);
6f1b0c
-		  /* combine_strings doesn't set up TYPE_MAIN_VARIANT of
6f1b0c
+		  $$ = fix_string_type ($$);
6f1b0c
+		  /* fix_string_type doesn't set up TYPE_MAIN_VARIANT of
6f1b0c
 		     a const array the way we want, so fix it.  */
6f1b0c
 		  if (flag_const_strings)
6f1b0c
 		    TREE_TYPE ($$) = build_cplus_array_type
6f1b0c
@@ -1791,13 +1790,6 @@ boolean.literal:
6f1b0c
 		{ $$ = boolean_false_node; }
6f1b0c
 	;
6f1b0c
 
6f1b0c
-/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
6f1b0c
-string:
6f1b0c
-	  STRING
6f1b0c
-	| string STRING
6f1b0c
-		{ $$ = chainon ($$, $2); }
6f1b0c
-	;
6f1b0c
-
6f1b0c
 nodecls:
6f1b0c
 	  /* empty */
6f1b0c
 		{
6f1b0c
@@ -2091,8 +2083,8 @@ nomods_initdecls:
6f1b0c
 maybeasm:
6f1b0c
 	  /* empty */
6f1b0c
 		{ $$ = NULL_TREE; }
6f1b0c
-	| asm_keyword '(' string ')'
6f1b0c
-		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
6f1b0c
+	| asm_keyword '(' STRING ')'
6f1b0c
+		{ $$ = $3; }
6f1b0c
 	;
6f1b0c
 
6f1b0c
 initdcl:
6f1b0c
@@ -3489,27 +3481,27 @@ simple_stmt:
6f1b0c
                 { $$ = finish_return_stmt (NULL_TREE); }
6f1b0c
 	| RETURN_KEYWORD expr ';'
6f1b0c
                 { $$ = finish_return_stmt ($2); }
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string ')' ';'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
6f1b0c
 					NULL_TREE);
6f1b0c
 		  ASM_INPUT_P ($$) = 1; }
6f1b0c
 	/* This is the case with just output operands.  */
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
6f1b0c
 	/* This is the case with input operands as well.  */
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
6f1b0c
 	  asm_operands ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ')' ';'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
6f1b0c
 	/* This is the case with clobbered registers as well.  */
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
6f1b0c
 	  asm_operands ':' asm_clobbers ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, $6, $8, $10); }
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ':'
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ':'
6f1b0c
 	  asm_clobbers ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); }
6f1b0c
-	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands SCOPE
6f1b0c
+	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands SCOPE
6f1b0c
 	  asm_clobbers ')' ';'
6f1b0c
 		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
6f1b0c
 	| GOTO '*' expr ';'
6f1b0c
@@ -3670,10 +3662,10 @@ asm_operand:
6f1b0c
 	;
6f1b0c
 
6f1b0c
 asm_clobbers:
6f1b0c
-	  string
6f1b0c
-		{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE);}
6f1b0c
-	| asm_clobbers ',' string
6f1b0c
-		{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
6f1b0c
+	  STRING
6f1b0c
+		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE);}
6f1b0c
+	| asm_clobbers ',' STRING
6f1b0c
+		{ $$ = tree_cons (NULL_TREE, $3, $1); }
6f1b0c
 	;
6f1b0c
 
6f1b0c
 /* This is what appears inside the parens in a function declarator.
6f1b0c
--- gcc/cp/spew.c.jj	2002-11-09 18:39:59.000000000 +0100
6f1b0c
+++ gcc/cp/spew.c	2004-10-05 16:08:18.725522496 +0200
6f1b0c
@@ -102,6 +102,7 @@ static SPEW_INLINE int identifier_type P
6f1b0c
 static void scan_tokens PARAMS ((int));
6f1b0c
 static void feed_defarg PARAMS ((tree));
6f1b0c
 static void finish_defarg PARAMS ((void));
6f1b0c
+static void yylexstring PARAMS ((struct token *));
6f1b0c
 static int read_token PARAMS ((struct token *));
6f1b0c
 
6f1b0c
 static SPEW_INLINE int num_tokens PARAMS ((void));
6f1b0c
@@ -244,6 +245,43 @@ read_process_identifier (pyylval)
6f1b0c
   return IDENTIFIER;
6f1b0c
 }
6f1b0c
 
6f1b0c
+/* Concatenate strings before returning them to the parser.  This isn't quite
6f1b0c
+   as good as having it done in the lexer, but it's better than nothing.  */
6f1b0c
+
6f1b0c
+static void
6f1b0c
+yylexstring (t)
6f1b0c
+     struct token *t;
6f1b0c
+{
6f1b0c
+  enum cpp_ttype next_type;
6f1b0c
+  tree next;
6f1b0c
+
6f1b0c
+  next_type = c_lex (&next;;
6f1b0c
+  if (next_type == CPP_STRING || next_type == CPP_WSTRING)
6f1b0c
+    {
6f1b0c
+      varray_type strings;
6f1b0c
+
6f1b0c
+      VARRAY_TREE_INIT (strings, 32, "strings");
6f1b0c
+      VARRAY_PUSH_TREE (strings, t->yylval.ttype);
6f1b0c
+
6f1b0c
+      do
6f1b0c
+	{
6f1b0c
+	  VARRAY_PUSH_TREE (strings, next);
6f1b0c
+	  next_type = c_lex (&next;;
6f1b0c
+	}
6f1b0c
+      while (next_type == CPP_STRING || next_type == CPP_WSTRING);
6f1b0c
+
6f1b0c
+      t->yylval.ttype = combine_strings (strings);
6f1b0c
+      last_token_id = t->yylval.ttype;
6f1b0c
+
6f1b0c
+      VARRAY_FREE (strings);
6f1b0c
+    }
6f1b0c
+
6f1b0c
+  /* We will have always read one token too many.  */
6f1b0c
+  _cpp_backup_tokens (parse_in, 1);
6f1b0c
+
6f1b0c
+  t->yychar = STRING;
6f1b0c
+}
6f1b0c
+
6f1b0c
 /* Read the next token from the input file.  The token is written into
6f1b0c
    T, and its type number is returned.  */
6f1b0c
 static int
6f1b0c
@@ -338,7 +376,7 @@ read_token (t)
6f1b0c
 
6f1b0c
     case CPP_STRING:
6f1b0c
     case CPP_WSTRING:
6f1b0c
-      t->yychar = STRING;
6f1b0c
+      yylexstring (t);
6f1b0c
       break;
6f1b0c
 
6f1b0c
     default:
6f1b0c
--- gcc/c-common.c.jj	2004-10-05 16:07:28.426465214 +0200
6f1b0c
+++ gcc/c-common.c	2004-10-05 16:08:18.646536539 +0200
6f1b0c
@@ -554,106 +554,17 @@ fname_decl (rid, id)
6f1b0c
   return decl;
6f1b0c
 }
6f1b0c
 
6f1b0c
-/* Given a chain of STRING_CST nodes,
6f1b0c
-   concatenate them into one STRING_CST
6f1b0c
-   and give it a suitable array-of-chars data type.  */
6f1b0c
+/* Given a STRING_CST, give it a suitable array-of-chars data type.  */
6f1b0c
 
6f1b0c
 tree
6f1b0c
-combine_strings (strings)
6f1b0c
-     tree strings;
6f1b0c
+fix_string_type (value)
6f1b0c
+     tree value;
6f1b0c
 {
6f1b0c
-  tree value, t;
6f1b0c
-  int length = 1;
6f1b0c
-  int wide_length = 0;
6f1b0c
-  int wide_flag = 0;
6f1b0c
-  int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
6f1b0c
-  int nchars;
6f1b0c
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
6f1b0c
+  const int wide_flag = TREE_TYPE (value) == wchar_array_type_node;
6f1b0c
   const int nchars_max = flag_isoc99 ? 4095 : 509;
6f1b0c
-
6f1b0c
-  if (TREE_CHAIN (strings))
6f1b0c
-    {
6f1b0c
-      /* More than one in the chain, so concatenate.  */
6f1b0c
-      char *p, *q;
6f1b0c
-
6f1b0c
-      /* Don't include the \0 at the end of each substring,
6f1b0c
-	 except for the last one.
6f1b0c
-	 Count wide strings and ordinary strings separately.  */
6f1b0c
-      for (t = strings; t; t = TREE_CHAIN (t))
6f1b0c
-	{
6f1b0c
-	  if (TREE_TYPE (t) == wchar_array_type_node)
6f1b0c
-	    {
6f1b0c
-	      wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
6f1b0c
-	      wide_flag = 1;
6f1b0c
-	    }
6f1b0c
-	  else
6f1b0c
-	    {
6f1b0c
-	      length += (TREE_STRING_LENGTH (t) - 1);
6f1b0c
-	      if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
6f1b0c
-		warning ("concatenation of string literals with __FUNCTION__ is deprecated"); 
6f1b0c
-	    }
6f1b0c
-	}
6f1b0c
-
6f1b0c
-      /* If anything is wide, the non-wides will be converted,
6f1b0c
-	 which makes them take more space.  */
6f1b0c
-      if (wide_flag)
6f1b0c
-	length = length * wchar_bytes + wide_length;
6f1b0c
-
6f1b0c
-      p = xmalloc (length);
6f1b0c
-
6f1b0c
-      /* Copy the individual strings into the new combined string.
6f1b0c
-	 If the combined string is wide, convert the chars to ints
6f1b0c
-	 for any individual strings that are not wide.  */
6f1b0c
-
6f1b0c
-      q = p;
6f1b0c
-      for (t = strings; t; t = TREE_CHAIN (t))
6f1b0c
-	{
6f1b0c
-	  int len = (TREE_STRING_LENGTH (t)
6f1b0c
-		     - ((TREE_TYPE (t) == wchar_array_type_node)
6f1b0c
-			? wchar_bytes : 1));
6f1b0c
-	  if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
6f1b0c
-	    {
6f1b0c
-	      memcpy (q, TREE_STRING_POINTER (t), len);
6f1b0c
-	      q += len;
6f1b0c
-	    }
6f1b0c
-	  else
6f1b0c
-	    {
6f1b0c
-	      int i, j;
6f1b0c
-	      for (i = 0; i < len; i++)
6f1b0c
-		{
6f1b0c
-		  if (BYTES_BIG_ENDIAN)
6f1b0c
-		    {
6f1b0c
-		      for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
6f1b0c
-			*q++ = 0;
6f1b0c
-		      *q++ = TREE_STRING_POINTER (t)[i];
6f1b0c
-		    }
6f1b0c
-		  else
6f1b0c
-		    {
6f1b0c
-		      *q++ = TREE_STRING_POINTER (t)[i];
6f1b0c
-		      for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
6f1b0c
-			*q++ = 0;
6f1b0c
-		    }
6f1b0c
-		}
6f1b0c
-	    }
6f1b0c
-	}
6f1b0c
-      if (wide_flag)
6f1b0c
-	{
6f1b0c
-	  int i;
6f1b0c
-	  for (i = 0; i < wchar_bytes; i++)
6f1b0c
-	    *q++ = 0;
6f1b0c
-	}
6f1b0c
-      else
6f1b0c
-	*q = 0;
6f1b0c
-
6f1b0c
-      value = build_string (length, p);
6f1b0c
-      free (p);
6f1b0c
-    }
6f1b0c
-  else
6f1b0c
-    {
6f1b0c
-      value = strings;
6f1b0c
-      length = TREE_STRING_LENGTH (value);
6f1b0c
-      if (TREE_TYPE (value) == wchar_array_type_node)
6f1b0c
-	wide_flag = 1;
6f1b0c
-    }
6f1b0c
+  int length = TREE_STRING_LENGTH (value);
6f1b0c
+  int nchars;
6f1b0c
 
6f1b0c
   /* Compute the number of elements, for the array type.  */
6f1b0c
   nchars = wide_flag ? length / wchar_bytes : length;
6f1b0c
@@ -686,6 +597,111 @@ combine_strings (strings)
6f1b0c
   TREE_STATIC (value) = 1;
6f1b0c
   return value;
6f1b0c
 }
6f1b0c
+
6f1b0c
+/* Given a VARRAY of STRING_CST nodes, concatenate them into one
6f1b0c
+   STRING_CST.  */
6f1b0c
+
6f1b0c
+tree
6f1b0c
+combine_strings (strings)
6f1b0c
+     varray_type strings;
6f1b0c
+{
6f1b0c
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
6f1b0c
+  const int nstrings = VARRAY_ACTIVE_SIZE (strings);
6f1b0c
+  tree value, t;
6f1b0c
+  int length = 1;
6f1b0c
+  int wide_length = 0;
6f1b0c
+  int wide_flag = 0;
6f1b0c
+  int i;
6f1b0c
+  char *p, *q;
6f1b0c
+
6f1b0c
+  /* Don't include the \0 at the end of each substring.  Count wide
6f1b0c
+     strings and ordinary strings separately.  */
6f1b0c
+  for (i = 0; i < nstrings; ++i)
6f1b0c
+    {
6f1b0c
+      t = VARRAY_TREE (strings, i);
6f1b0c
+
6f1b0c
+      if (TREE_TYPE (t) == wchar_array_type_node)
6f1b0c
+	{
6f1b0c
+	  wide_length += TREE_STRING_LENGTH (t) - wchar_bytes;
6f1b0c
+	  wide_flag = 1;
6f1b0c
+	}
6f1b0c
+      else
6f1b0c
+	{
6f1b0c
+	  length += (TREE_STRING_LENGTH (t) - 1);
6f1b0c
+	  if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
6f1b0c
+	    warning ("concatenation of string literals with __FUNCTION__ is deprecated"); 
6f1b0c
+	}
6f1b0c
+    }
6f1b0c
+
6f1b0c
+  /* If anything is wide, the non-wides will be converted,
6f1b0c
+     which makes them take more space.  */
6f1b0c
+  if (wide_flag)
6f1b0c
+    length = length * wchar_bytes + wide_length;
6f1b0c
+
6f1b0c
+  p = xmalloc (length);
6f1b0c
+
6f1b0c
+  /* Copy the individual strings into the new combined string.
6f1b0c
+     If the combined string is wide, convert the chars to ints
6f1b0c
+     for any individual strings that are not wide.  */
6f1b0c
+
6f1b0c
+  q = p;
6f1b0c
+  for (i = 0; i < nstrings; ++i)
6f1b0c
+    {
6f1b0c
+      int len, this_wide;
6f1b0c
+
6f1b0c
+      t = VARRAY_TREE (strings, i);
6f1b0c
+      this_wide = TREE_TYPE (t) == wchar_array_type_node;
6f1b0c
+      len = TREE_STRING_LENGTH (t) - (this_wide ? wchar_bytes : 1);
6f1b0c
+      if (this_wide == wide_flag)
6f1b0c
+	{
6f1b0c
+	  memcpy (q, TREE_STRING_POINTER (t), len);
6f1b0c
+	  q += len;
6f1b0c
+	}
6f1b0c
+      else
6f1b0c
+	{
6f1b0c
+	  const int nzeros = (WCHAR_TYPE_SIZE / BITS_PER_UNIT) - 1;
6f1b0c
+	  int j, k;
6f1b0c
+
6f1b0c
+	  if (BYTES_BIG_ENDIAN)
6f1b0c
+	    {
6f1b0c
+	      for (k = 0; k < len; k++)
6f1b0c
+		{
6f1b0c
+		  for (j = 0; j < nzeros; j++)
6f1b0c
+		    *q++ = 0;
6f1b0c
+		  *q++ = TREE_STRING_POINTER (t)[k];
6f1b0c
+		}
6f1b0c
+	    }
6f1b0c
+	  else
6f1b0c
+	    {
6f1b0c
+	      for (k = 0; k < len; k++)
6f1b0c
+		{
6f1b0c
+		  *q++ = TREE_STRING_POINTER (t)[k];
6f1b0c
+		  for (j = 0; j < nzeros; j++)
6f1b0c
+		    *q++ = 0;
6f1b0c
+		}
6f1b0c
+	    }
6f1b0c
+	}
6f1b0c
+    }
6f1b0c
+
6f1b0c
+  /* Nul terminate the string.  */
6f1b0c
+  if (wide_flag)
6f1b0c
+    {
6f1b0c
+      for (i = 0; i < wchar_bytes; i++)
6f1b0c
+	*q++ = 0;
6f1b0c
+    }
6f1b0c
+  else
6f1b0c
+    *q = 0;
6f1b0c
+
6f1b0c
+  value = build_string (length, p);
6f1b0c
+  free (p);
6f1b0c
+
6f1b0c
+  if (wide_flag)
6f1b0c
+    TREE_TYPE (value) = wchar_array_type_node;
6f1b0c
+  else
6f1b0c
+    TREE_TYPE (value) = char_array_type_node;
6f1b0c
+
6f1b0c
+  return value;
6f1b0c
+}
6f1b0c
 
6f1b0c
 static int is_valid_printf_arglist PARAMS ((tree));
6f1b0c
 static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
6f1b0c
@@ -4062,7 +4078,7 @@ c_expand_builtin_printf (arglist, target
6f1b0c
 	  memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
6f1b0c
 	  newstr[newlen - 1] = 0;
6f1b0c
 	  
6f1b0c
-	  arglist = combine_strings (build_string (newlen, newstr));
6f1b0c
+	  arglist = fix_string_type (build_string (newlen, newstr));
6f1b0c
 	  arglist = build_tree_list (NULL_TREE, arglist);
6f1b0c
 	  fn = fn_puts;
6f1b0c
 	}
6f1b0c
--- gcc/testsuite/gcc.dg/concat2.c.jj	2004-10-05 16:08:18.746518763 +0200
6f1b0c
+++ gcc/testsuite/gcc.dg/concat2.c	2004-10-05 16:08:18.746518763 +0200
6f1b0c
@@ -0,0 +1,16 @@
6f1b0c
+/* PR c/3581 */
6f1b0c
+/* { dg-do compile } */
6f1b0c
+/* { dg-options "" } */
6f1b0c
+
6f1b0c
+/* Intended as a compile-time test for string literal concatenation.
6f1b0c
+   The fact that the string isn't actually used in the resulting program
6f1b0c
+   should allow this to compile for any target.  */
6f1b0c
+
6f1b0c
+#define e0	"a"
6f1b0c
+#define e1	e0 e0 e0 e0 e0 e0 e0 e0 e0 e0
6f1b0c
+#define e2	e1 e1 e1 e1 e1 e1 e1 e1 e1 e1
6f1b0c
+#define e3	e2 e2 e2 e2 e2 e2 e2 e2 e2 e2
6f1b0c
+#define e4	e3 e3 e3 e3 e3 e3 e3 e3 e3 e3
6f1b0c
+#define e5	e4 e4 e4 e4 e4 e4 e4 e4 e4 e4
6f1b0c
+
6f1b0c
+void foo() { (void)(e5); }
6f1b0c
--- gcc/testsuite/g++.dg/parse/concat1.C.jj	2004-10-05 16:08:18.745518941 +0200
6f1b0c
+++ gcc/testsuite/g++.dg/parse/concat1.C	2004-10-05 16:08:18.745518941 +0200
6f1b0c
@@ -0,0 +1,15 @@
6f1b0c
+/* PR c/3581 */
6f1b0c
+/* { dg-do compile } */
6f1b0c
+
6f1b0c
+/* Intended as a compile-time test for string literal concatenation.
6f1b0c
+   The fact that the string isn't actually used in the resulting program
6f1b0c
+   should allow this to compile for any target.  */
6f1b0c
+
6f1b0c
+#define e0	"a"
6f1b0c
+#define e1	e0 e0 e0 e0 e0 e0 e0 e0 e0 e0
6f1b0c
+#define e2	e1 e1 e1 e1 e1 e1 e1 e1 e1 e1
6f1b0c
+#define e3	e2 e2 e2 e2 e2 e2 e2 e2 e2 e2
6f1b0c
+#define e4	e3 e3 e3 e3 e3 e3 e3 e3 e3 e3
6f1b0c
+#define e5	e4 e4 e4 e4 e4 e4 e4 e4 e4 e4
6f1b0c
+
6f1b0c
+void foo() { (void)(e5); }
6f1b0c
--- gcc/c-parse.in.jj	2003-08-02 01:21:40.000000000 +0200
6f1b0c
+++ gcc/c-parse.in	2004-10-05 16:08:18.682530140 +0200
6f1b0c
@@ -148,7 +148,7 @@ end ifobjc
6f1b0c
 %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
6f1b0c
 
6f1b0c
 %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
6f1b0c
-%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
6f1b0c
+%type <ttype> expr_no_commas cast_expr unary_expr primary STRING
6f1b0c
 %type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
6f1b0c
 %type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
6f1b0c
 %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
6f1b0c
@@ -296,6 +296,7 @@ end ifc
6f1b0c
 static void yyprint	  PARAMS ((FILE *, int, YYSTYPE));
6f1b0c
 static void yyerror	  PARAMS ((const char *));
6f1b0c
 static int yylexname	  PARAMS ((void));
6f1b0c
+static int yylexstring	  PARAMS ((void));
6f1b0c
 static inline int _yylex  PARAMS ((void));
6f1b0c
 static int  yylex	  PARAMS ((void));
6f1b0c
 static void init_reswords PARAMS ((void));
6f1b0c
@@ -623,8 +624,8 @@ primary:
6f1b0c
 		  $$ = build_external_ref ($1, yychar == '(');
6f1b0c
 		}
6f1b0c
 	| CONSTANT
6f1b0c
-	| string
6f1b0c
-		{ $$ = combine_strings ($1); }
6f1b0c
+	| STRING
6f1b0c
+		{ $$ = fix_string_type ($$); }
6f1b0c
 	| VAR_FUNC_NAME
6f1b0c
 		{ $$ = fname_decl (C_RID_CODE ($$), $$); }
6f1b0c
 	| '(' typename ')' '{' 
6f1b0c
@@ -735,29 +736,6 @@ ifobjc
6f1b0c
 end ifobjc
6f1b0c
 	;
6f1b0c
 
6f1b0c
-/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
6f1b0c
-string:
6f1b0c
-	  STRING
6f1b0c
-	| string STRING
6f1b0c
-		{
6f1b0c
-ifc
6f1b0c
-                  static int last_lineno = 0;
6f1b0c
-                  static const char *last_input_filename = 0;
6f1b0c
-end ifc
6f1b0c
-                  $$ = chainon ($1, $2);
6f1b0c
-ifc
6f1b0c
-		  if (warn_traditional && !in_system_header
6f1b0c
-		      && (lineno != last_lineno || !last_input_filename ||
6f1b0c
-			  strcmp (last_input_filename, input_filename)))
6f1b0c
-		    {
6f1b0c
-		      warning ("traditional C rejects string concatenation");
6f1b0c
-		      last_lineno = lineno;
6f1b0c
-		      last_input_filename = input_filename;
6f1b0c
-		    }
6f1b0c
-end ifc
6f1b0c
-		}
6f1b0c
-	;
6f1b0c
-
6f1b0c
 ifobjc
6f1b0c
 /* Produces an STRING_CST with perhaps more STRING_CSTs chained
6f1b0c
    onto it, which is to be read as an ObjC string object.  */
6f1b0c
@@ -1398,10 +1376,8 @@ notype_initdecls:
6f1b0c
 maybeasm:
6f1b0c
 	  /* empty */
6f1b0c
 		{ $$ = NULL_TREE; }
6f1b0c
-	| ASM_KEYWORD '(' string ')'
6f1b0c
-		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
6f1b0c
-		  $$ = $3;
6f1b0c
-		}
6f1b0c
+	| ASM_KEYWORD '(' STRING ')'
6f1b0c
+		{ $$ = $3; }
6f1b0c
 	;
6f1b0c
 
6f1b0c
 initdcl:
6f1b0c
@@ -2482,10 +2458,10 @@ asm_operand:
6f1b0c
 	;
6f1b0c
 
6f1b0c
 asm_clobbers:
6f1b0c
-	  string
6f1b0c
-		{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
6f1b0c
-	| asm_clobbers ',' string
6f1b0c
-		{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
6f1b0c
+	  STRING
6f1b0c
+		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
6f1b0c
+	| asm_clobbers ',' STRING
6f1b0c
+		{ $$ = tree_cons (NULL_TREE, $3, $1); }
6f1b0c
 	;
6f1b0c
 
6f1b0c
 /* This is what appears inside the parens in a function declarator.
6f1b0c
@@ -3683,6 +3659,59 @@ end ifobjc
6f1b0c
   return IDENTIFIER;
6f1b0c
 }
6f1b0c
 
6f1b0c
+/* Concatenate strings before returning them to the parser.  This isn't quite
6f1b0c
+   as good as having it done in the lexer, but it's better than nothing.  */
6f1b0c
+
6f1b0c
+static int
6f1b0c
+yylexstring ()
6f1b0c
+{
6f1b0c
+  enum cpp_ttype next_type;
6f1b0c
+  tree orig = yylval.ttype;
6f1b0c
+
6f1b0c
+  next_type = c_lex (&yylval.ttype);
6f1b0c
+  if (next_type == CPP_STRING
6f1b0c
+      || next_type == CPP_WSTRING
6f1b0c
+      || (next_type == CPP_NAME && yylexname () == STRING))
6f1b0c
+    {
6f1b0c
+      varray_type strings;
6f1b0c
+
6f1b0c
+ifc
6f1b0c
+      static int last_lineno = 0;
6f1b0c
+      static const char *last_input_filename = 0;
6f1b0c
+      if (warn_traditional && !in_system_header
6f1b0c
+	  && (lineno != last_lineno || !last_input_filename ||
6f1b0c
+	      strcmp (last_input_filename, input_filename)))
6f1b0c
+	{
6f1b0c
+	  warning ("traditional C rejects string concatenation");
6f1b0c
+	  last_lineno = lineno;
6f1b0c
+	  last_input_filename = input_filename;
6f1b0c
+	}
6f1b0c
+end ifc
6f1b0c
+
6f1b0c
+      VARRAY_TREE_INIT (strings, 32, "strings");
6f1b0c
+      VARRAY_PUSH_TREE (strings, orig);
6f1b0c
+
6f1b0c
+      do
6f1b0c
+	{
6f1b0c
+	  VARRAY_PUSH_TREE (strings, yylval.ttype);
6f1b0c
+	  next_type = c_lex (&yylval.ttype);
6f1b0c
+	}
6f1b0c
+      while (next_type == CPP_STRING
6f1b0c
+	     || next_type == CPP_WSTRING
6f1b0c
+	     || (next_type == CPP_NAME && yylexname () == STRING));
6f1b0c
+
6f1b0c
+      yylval.ttype = combine_strings (strings);
6f1b0c
+
6f1b0c
+      VARRAY_FREE (strings);
6f1b0c
+    }
6f1b0c
+  else
6f1b0c
+    yylval.ttype = orig;
6f1b0c
+
6f1b0c
+  /* We will have always read one token too many.  */
6f1b0c
+  _cpp_backup_tokens (parse_in, 1);
6f1b0c
+
6f1b0c
+  return STRING;
6f1b0c
+}
6f1b0c
 
6f1b0c
 static inline int
6f1b0c
 _yylex ()
6f1b0c
@@ -3749,7 +3778,13 @@ _yylex ()
6f1b0c
       return 0;
6f1b0c
 
6f1b0c
     case CPP_NAME:
6f1b0c
-      return yylexname ();
6f1b0c
+      {
6f1b0c
+	int ret = yylexname ();
6f1b0c
+	if (ret == STRING)
6f1b0c
+	  return yylexstring ();
6f1b0c
+	else
6f1b0c
+	  return ret;
6f1b0c
+      }
6f1b0c
 
6f1b0c
     case CPP_NUMBER:
6f1b0c
     case CPP_CHAR:
6f1b0c
@@ -3758,7 +3793,7 @@ _yylex ()
6f1b0c
 
6f1b0c
     case CPP_STRING:
6f1b0c
     case CPP_WSTRING:
6f1b0c
-      return STRING;
6f1b0c
+      return yylexstring ();
6f1b0c
       
6f1b0c
       /* This token is Objective-C specific.  It gives the next token
6f1b0c
 	 special significance.  */
6f1b0c
--- gcc/c-typeck.c.jj	2003-03-10 17:42:06.000000000 +0100
6f1b0c
+++ gcc/c-typeck.c	2004-10-05 16:08:48.926153031 +0200
6f1b0c
@@ -6890,9 +6890,6 @@ simple_asm_stmt (expr)
6f1b0c
     {
6f1b0c
       tree stmt;
6f1b0c
 
6f1b0c
-      if (TREE_CHAIN (expr))
6f1b0c
-	expr = combine_strings (expr);
6f1b0c
-
6f1b0c
       /* Simple asm statements are treated as volatile.  */
6f1b0c
       stmt = add_stmt (build_stmt (ASM_STMT, ridpointers[(int) RID_VOLATILE],
6f1b0c
       				   expr, NULL_TREE, NULL_TREE, NULL_TREE));
6f1b0c
@@ -6917,8 +6914,6 @@ build_asm_stmt (cv_qualifier, string, ou
6f1b0c
 {
6f1b0c
   tree tail;
6f1b0c
 
6f1b0c
-  if (TREE_CHAIN (string))
6f1b0c
-    string = combine_strings (string);
6f1b0c
   if (TREE_CODE (string) != STRING_CST)
6f1b0c
     {
6f1b0c
       error ("asm template is not a string constant");