c-common.c (fix_string_type): Split out of ...
authorRichard Henderson <rth@redhat.com>
Fri, 26 Apr 2002 07:40:12 +0000 (00:40 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 26 Apr 2002 07:40:12 +0000 (00:40 -0700)
        * c-common.c (fix_string_type): Split out of ...
        (combine_strings): ... here.  Take a varray, not a tree list.
        (c_expand_builtin_printf): Use fix_string_type.
        * c-common.h: Update decls.
        * c-parse.in (string): Remove.  Update all uses to use STRING
        instead, and not call combine_strings.
        (yylexstring): New.
        (_yylex): Use it.
        * c-typeck.c (simple_asm_stmt): Don't call combine_strings.
        (build_asm_stmt): Likewise.
        * objc/objc-act.c (my_build_string): Use fix_string_type.
        (build_objc_string_object): Build varray for combine_strings.

        * parse.y (string): Remove.  Update all uses to use STRING
        instead, and not call combine_strings.
        * rtti.c (tinfo_name): Use fix_string_type.
        * semantics.c (finish_asm_stmt): Don't call combine_strings.
        * spew.c (yylexstring): New.
        (read_token): Use it.

* g++.dg/parse/concat1.C: New.
* gcc.dg/concat2.c: New.

From-SVN: r52790

13 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-parse.in
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/parse.y
gcc/cp/rtti.c
gcc/cp/semantics.c
gcc/cp/spew.c
gcc/objc/objc-act.c
gcc/testsuite/g++.dg/parse/concat1.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/concat2.c [new file with mode: 0644]

index 185b49a73d1047201155df90d8a301d5b40fda36..667ec4f77d8f409e887812419e5a5b21dab014ae 100644 (file)
@@ -1,3 +1,19 @@
+2002-04-26  Richard Henderson  <rth@redhat.com>
+
+       PR c/3581
+       * c-common.c (fix_string_type): Split out of ...
+       (combine_strings): ... here.  Take a varray, not a tree list.
+       (c_expand_builtin_printf): Use fix_string_type.
+       * c-common.h: Update decls.
+       * c-parse.in (string): Remove.  Update all uses to use STRING
+       instead, and not call combine_strings.
+       (yylexstring): New.
+       (_yylex): Use it.
+       * c-typeck.c (simple_asm_stmt): Don't call combine_strings.
+       (build_asm_stmt): Likewise.
+       * objc/objc-act.c (my_build_string): Use fix_string_type.
+       (build_objc_string_object): Build varray for combine_strings.
+
 2002-04-26  Bo Thorsen  <bo@suse.co.uk>
 
        * config/i386/linux64.h (MD_FALLBACK_FRAME_STATE_FOR): Define for
index f9337df907f298d5cbc198fcc1ece6d2f9ca0830..86fc75938178e13726e3eec8417c93ccbe2317c4 100644 (file)
@@ -683,105 +683,17 @@ fname_decl (rid, id)
   return decl;
 }
 
-/* Given a chain of STRING_CST nodes,
-   concatenate them into one STRING_CST
-   and give it a suitable array-of-chars data type.  */
+/* Given a STRING_CST, give it a suitable array-of-chars data type.  */
 
 tree
-combine_strings (strings)
-     tree strings;
+fix_string_type (value)
+      tree value;
 {
-  tree value, t;
-  int length = 1;
-  int wide_length = 0;
-  int wide_flag = 0;
-  int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
-  int nchars;
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  const int wide_flag = TREE_TYPE (value) == wchar_array_type_node;
   const int nchars_max = flag_isoc99 ? 4095 : 509;
-
-  if (TREE_CHAIN (strings))
-    {
-      /* More than one in the chain, so concatenate.  */
-      char *p, *q;
-
-      /* Don't include the \0 at the end of each substring,
-        except for the last one.
-        Count wide strings and ordinary strings separately.  */
-      for (t = strings; t; t = TREE_CHAIN (t))
-       {
-         if (TREE_TYPE (t) == wchar_array_type_node)
-           {
-             wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
-             wide_flag = 1;
-           }
-         else
-           {
-             length += (TREE_STRING_LENGTH (t) - 1);
-             if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
-               warning ("concatenation of string literals with __FUNCTION__ is deprecated.  This feature will be removed in future"); 
-           }
-       }
-
-      /* If anything is wide, the non-wides will be converted,
-        which makes them take more space.  */
-      if (wide_flag)
-       length = length * wchar_bytes + wide_length;
-
-      p = alloca (length);
-
-      /* Copy the individual strings into the new combined string.
-        If the combined string is wide, convert the chars to ints
-        for any individual strings that are not wide.  */
-
-      q = p;
-      for (t = strings; t; t = TREE_CHAIN (t))
-       {
-         int len = (TREE_STRING_LENGTH (t)
-                    - ((TREE_TYPE (t) == wchar_array_type_node)
-                       ? wchar_bytes : 1));
-         if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
-           {
-             memcpy (q, TREE_STRING_POINTER (t), len);
-             q += len;
-           }
-         else
-           {
-             int i, j;
-             for (i = 0; i < len; i++)
-               {
-                 if (BYTES_BIG_ENDIAN)
-                   {
-                     for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
-                       *q++ = 0;
-                     *q++ = TREE_STRING_POINTER (t)[i];
-                   }
-                 else
-                   {
-                     *q++ = TREE_STRING_POINTER (t)[i];
-                     for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
-                       *q++ = 0;
-                   }
-               }
-           }
-       }
-      if (wide_flag)
-       {
-         int i;
-         for (i = 0; i < wchar_bytes; i++)
-           *q++ = 0;
-       }
-      else
-       *q = 0;
-
-      value = build_string (length, p);
-    }
-  else
-    {
-      value = strings;
-      length = TREE_STRING_LENGTH (value);
-      if (TREE_TYPE (value) == wchar_array_type_node)
-       wide_flag = 1;
-    }
+  int length = TREE_STRING_LENGTH (value);
+  int nchars;
 
   /* Compute the number of elements, for the array type.  */
   nchars = wide_flag ? length / wchar_bytes : length;
@@ -813,6 +725,111 @@ combine_strings (strings)
   TREE_STATIC (value) = 1;
   return value;
 }
+
+/* Given a VARRAY of STRING_CST nodes, concatenate them into one
+   STRING_CST.  */
+
+tree
+combine_strings (strings)
+     varray_type strings;
+{
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  const int nstrings = VARRAY_ACTIVE_SIZE (strings);
+  tree value, t;
+  int length = 1;
+  int wide_length = 0;
+  int wide_flag = 0;
+  int i;
+  char *p, *q;
+
+  /* Don't include the \0 at the end of each substring.  Count wide
+     strings and ordinary strings separately.  */
+  for (i = 0; i < nstrings; ++i)
+    {
+      t = VARRAY_TREE (strings, i);
+
+      if (TREE_TYPE (t) == wchar_array_type_node)
+       {
+         wide_length += TREE_STRING_LENGTH (t) - wchar_bytes;
+         wide_flag = 1;
+       }
+      else
+       {
+         length += (TREE_STRING_LENGTH (t) - 1);
+         if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
+           warning ("concatenation of string literals with __FUNCTION__ is deprecated"); 
+       }
+    }
+
+  /* If anything is wide, the non-wides will be converted,
+     which makes them take more space.  */
+  if (wide_flag)
+    length = length * wchar_bytes + wide_length;
+
+  p = xmalloc (length);
+
+  /* Copy the individual strings into the new combined string.
+     If the combined string is wide, convert the chars to ints
+     for any individual strings that are not wide.  */
+
+  q = p;
+  for (i = 0; i < nstrings; ++i)
+    {
+      int len, this_wide;
+
+      t = VARRAY_TREE (strings, i);
+      this_wide = TREE_TYPE (t) == wchar_array_type_node;
+      len = TREE_STRING_LENGTH (t) - (this_wide ? wchar_bytes : 1);
+      if (this_wide == wide_flag)
+       {
+         memcpy (q, TREE_STRING_POINTER (t), len);
+         q += len;
+       }
+      else
+       {
+         const int nzeros = (WCHAR_TYPE_SIZE / BITS_PER_UNIT) - 1;
+         int j, k;
+
+         if (BYTES_BIG_ENDIAN)
+           {
+             for (k = 0; k < len; k++)
+               {
+                 for (j = 0; j < nzeros; j++)
+                   *q++ = 0;
+                 *q++ = TREE_STRING_POINTER (t)[k];
+               }
+           }
+         else
+           {
+             for (k = 0; k < len; k++)
+               {
+                 *q++ = TREE_STRING_POINTER (t)[k];
+                 for (j = 0; j < nzeros; j++)
+                   *q++ = 0;
+               }
+           }
+       }
+    }
+
+  /* Nul terminate the string.  */
+  if (wide_flag)
+    {
+      for (i = 0; i < wchar_bytes; i++)
+       *q++ = 0;
+    }
+  else
+    *q = 0;
+
+  value = build_string (length, p);
+  free (p);
+
+  if (wide_flag)
+    TREE_TYPE (value) = wchar_array_type_node;
+  else
+    TREE_TYPE (value) = char_array_type_node;
+
+  return value;
+}
 \f
 static int is_valid_printf_arglist PARAMS ((tree));
 static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
@@ -4058,7 +4075,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
          memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
          newstr[newlen - 1] = 0;
          
-         arglist = combine_strings (build_string (newlen, newstr));
+         arglist = fix_string_type (build_string (newlen, newstr));
          arglist = build_tree_list (NULL_TREE, arglist);
          fn = fn_puts;
        }
index f44b0c3a46ccde6efbb3d13d34c89d14673a8f0f..873fa4a2919b6dd9a008e9365c4a0d5a491b576e 100644 (file)
@@ -530,12 +530,13 @@ extern tree c_expand_expr_stmt                    PARAMS ((tree));
 extern void c_expand_start_cond                        PARAMS ((tree, int, tree));
 extern void c_finish_then                       PARAMS ((void));
 extern void c_expand_start_else                        PARAMS ((void));
-extern void c_finish_else                   PARAMS ((void));
+extern void c_finish_else                      PARAMS ((void));
 extern void c_expand_end_cond                  PARAMS ((void));
 /* Validate the expression after `case' and apply default promotions.  */
 extern tree check_case_value                   PARAMS ((tree));
-/* Concatenate a list of STRING_CST nodes into one STRING_CST.  */
-extern tree combine_strings                    PARAMS ((tree));
+extern tree fix_string_type                    PARAMS ((tree));
+struct varray_head_tag;
+extern tree combine_strings            PARAMS ((struct varray_head_tag *));
 extern void constant_expression_warning                PARAMS ((tree));
 extern tree convert_and_check                  PARAMS ((tree, tree));
 extern void overflow_warning                   PARAMS ((tree));
index f3a3da8f9995a66a531c9f06959ee748061d77ee..f7cc49283b6445a72b247b7c1954b153345b3462 100644 (file)
@@ -181,7 +181,7 @@ do {                                                                        \
 %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
 
 %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
-%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> expr_no_commas cast_expr unary_expr primary STRING
 %type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
 %type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
 %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
@@ -329,6 +329,7 @@ end ifc
 static void yyprint      PARAMS ((FILE *, int, YYSTYPE));
 static void yyerror      PARAMS ((const char *));
 static int yylexname     PARAMS ((void));
+static int yylexstring   PARAMS ((void));
 static inline int _yylex  PARAMS ((void));
 static int  yylex        PARAMS ((void));
 static void init_reswords PARAMS ((void));
@@ -658,8 +659,8 @@ primary:
                  $$ = build_external_ref ($1, yychar == '(');
                }
        | CONSTANT
-       | string
-               { $$ = combine_strings ($1); }
+       | STRING
+               { $$ = fix_string_type ($$); }
        | VAR_FUNC_NAME
                { $$ = fname_decl (C_RID_CODE ($$), $$); }
        | '(' typename ')' '{' 
@@ -770,29 +771,6 @@ ifobjc
 end ifobjc
        ;
 
-/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
-string:
-         STRING
-       | string STRING
-               {
-ifc
-                  static int last_lineno = 0;
-                  static const char *last_input_filename = 0;
-end ifc
-                  $$ = chainon ($1, $2);
-ifc
-                 if (warn_traditional && !in_system_header
-                     && (lineno != last_lineno || !last_input_filename ||
-                         strcmp (last_input_filename, input_filename)))
-                   {
-                     warning ("traditional C rejects string concatenation");
-                     last_lineno = lineno;
-                     last_input_filename = input_filename;
-                   }
-end ifc
-               }
-       ;
-
 ifobjc
 /* Produces an STRING_CST with perhaps more STRING_CSTs chained
    onto it, which is to be read as an ObjC string object.  */
@@ -1433,10 +1411,8 @@ notype_initdecls:
 maybeasm:
          /* empty */
                { $$ = NULL_TREE; }
-       | ASM_KEYWORD '(' string ')'
-               { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
-                 $$ = $3;
-               }
+       | ASM_KEYWORD '(' STRING ')'
+               { $$ = $3; }
        ;
 
 initdcl:
@@ -2508,10 +2484,10 @@ asm_operand:
        ;
 
 asm_clobbers:
-         string
-               { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
-       | asm_clobbers ',' string
-               { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
+         STRING
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+       | asm_clobbers ',' STRING
+               { $$ = tree_cons (NULL_TREE, $3, $1); }
        ;
 \f
 /* This is what appears inside the parens in a function declarator.
@@ -3703,6 +3679,59 @@ end ifobjc
   return IDENTIFIER;
 }
 
+/* Concatenate strings before returning them to the parser.  This isn't quite
+   as good as having it done in the lexer, but it's better than nothing.  */
+
+static int
+yylexstring ()
+{
+  enum cpp_ttype next_type;
+  tree orig = yylval.ttype;
+
+  next_type = c_lex (&yylval.ttype);
+  if (next_type == CPP_STRING
+      || next_type == CPP_WSTRING
+      || (next_type == CPP_NAME && yylexname () == STRING))
+    {
+      varray_type strings;
+
+ifc
+      static int last_lineno = 0;
+      static const char *last_input_filename = 0;
+      if (warn_traditional && !in_system_header
+         && (lineno != last_lineno || !last_input_filename ||
+             strcmp (last_input_filename, input_filename)))
+       {
+         warning ("traditional C rejects string concatenation");
+         last_lineno = lineno;
+         last_input_filename = input_filename;
+       }
+end ifc
+
+      VARRAY_TREE_INIT (strings, 32, "strings");
+      VARRAY_PUSH_TREE (strings, orig);
+
+      do
+       {
+         VARRAY_PUSH_TREE (strings, yylval.ttype);
+         next_type = c_lex (&yylval.ttype);
+       }
+      while (next_type == CPP_STRING
+            || next_type == CPP_WSTRING
+            || (next_type == CPP_NAME && yylexname () == STRING));
+
+      yylval.ttype = combine_strings (strings);
+
+      VARRAY_FREE (strings);
+    }
+  else
+    yylval.ttype = orig;
+
+  /* We will have always read one token too many.  */
+  _cpp_backup_tokens (parse_in, 1);
+
+  return STRING;
+}
 
 static inline int
 _yylex ()
@@ -3769,7 +3798,13 @@ _yylex ()
       return 0;
 
     case CPP_NAME:
-      return yylexname ();
+      {
+       int ret = yylexname ();
+       if (ret == STRING)
+         return yylexstring ();
+       else
+         return ret;
+      }
 
     case CPP_NUMBER:
     case CPP_CHAR:
@@ -3778,7 +3813,7 @@ _yylex ()
 
     case CPP_STRING:
     case CPP_WSTRING:
-      return STRING;
+      return yylexstring ();
       
       /* This token is Objective-C specific.  It gives the next token
         special significance.  */
index 47fa1855ad332e228a8c65163b4398c152018124..f883801955722f2ee6823e8d4b04e12dc6399cd5 100644 (file)
@@ -6849,8 +6849,6 @@ simple_asm_stmt (expr)
     {
       tree stmt;
 
-      if (TREE_CHAIN (expr))
-       expr = combine_strings (expr);
       stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr,
                                   NULL_TREE, NULL_TREE,
                                   NULL_TREE));
@@ -6875,8 +6873,6 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
 {
   tree tail;
 
-  if (TREE_CHAIN (string))
-    string = combine_strings (string);
   if (TREE_CODE (string) != STRING_CST)
     {
       error ("asm template is not a string constant");
index 38b2f2255f3b2578a38446febf44306abd2cc2e8..607aa433fdbddd899c7db0f3eaf467970d5eb0ed 100644 (file)
@@ -1,3 +1,13 @@
+2002-04-26  Richard Henderson  <rth@redhat.com>
+
+       PR c/3581
+       * parse.y (string): Remove.  Update all uses to use STRING
+       instead, and not call combine_strings.
+       * rtti.c (tinfo_name): Use fix_string_type.
+       * semantics.c (finish_asm_stmt): Don't call combine_strings.
+       * spew.c (yylexstring): New.
+       (read_token): Use it.
+
 2002-04-25  Richard Henderson  <rth@redhat.com>
 
        PR c/2161
index 5454353d8744092d69166ea7c9550132776581e1..2d8d0465cfb43b415f4eb27d64cbbdbd35a552c1 100644 (file)
@@ -378,7 +378,7 @@ cp_parse_init ()
 %type <ttype> PFUNCNAME maybe_identifier
 %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
 %type <ttype> expr_no_commas expr_no_comma_rangle
-%type <ttype> cast_expr unary_expr primary string STRING
+%type <ttype> cast_expr unary_expr primary STRING
 %type <ttype> reserved_declspecs boolean.literal
 %type <ttype> reserved_typespecquals
 %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
@@ -543,9 +543,8 @@ extdef:
                { do_pending_inlines (); }
        | template_def
                { do_pending_inlines (); }
-       | asm_keyword '(' string ')' ';'
-               { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
-                 assemble_asm ($3); }
+       | asm_keyword '(' STRING ')' ';'
+               { assemble_asm ($3); }
        | extern_lang_string '{' extdefs_opt '}'
                { pop_lang_context (); }
        | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
@@ -1608,10 +1607,10 @@ primary:
                }               
        | CONSTANT
        | boolean.literal
-       | string
+       | STRING
                {
-                 $$ = combine_strings ($$);
-                 /* combine_strings doesn't set up TYPE_MAIN_VARIANT of
+                 $$ = fix_string_type ($$);
+                 /* fix_string_type doesn't set up TYPE_MAIN_VARIANT of
                     a const array the way we want, so fix it.  */
                  if (flag_const_strings)
                    TREE_TYPE ($$) = build_cplus_array_type
@@ -1812,13 +1811,6 @@ boolean.literal:
                { $$ = boolean_false_node; }
        ;
 
-/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
-string:
-         STRING
-       | string STRING
-               { $$ = chainon ($$, $2); }
-       ;
-
 nodecls:
          /* empty */
                {
@@ -2098,8 +2090,8 @@ nomods_initdecls:
 maybeasm:
          /* empty */
                { $$ = NULL_TREE; }
-       | asm_keyword '(' string ')'
-               { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
+       | asm_keyword '(' STRING ')'
+               { $$ = $3; }
        ;
 
 initdcl:
@@ -3494,27 +3486,27 @@ simple_stmt:
                 { $$ = finish_return_stmt (NULL_TREE); }
        | RETURN_KEYWORD expr ';'
                 { $$ = finish_return_stmt ($2); }
-       | asm_keyword maybe_cv_qualifier '(' string ')' ';'
+       | asm_keyword maybe_cv_qualifier '(' STRING ')' ';'
                { $$ = finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
                                        NULL_TREE);
                  ASM_INPUT_P ($$) = 1; }
        /* This is the case with just output operands.  */
-       | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';'
+       | asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ')' ';'
                { $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
        /* This is the case with input operands as well.  */
-       | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
+       | asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
          asm_operands ')' ';'
                { $$ = finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
-       | asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ')' ';'
+       | asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ')' ';'
                { $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
        /* This is the case with clobbered registers as well.  */
-       | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
+       | asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
          asm_operands ':' asm_clobbers ')' ';'
                { $$ = finish_asm_stmt ($2, $4, $6, $8, $10); }
-       | asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ':'
+       | asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ':'
          asm_clobbers ')' ';'
                { $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); }
-       | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands SCOPE
+       | asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands SCOPE
          asm_clobbers ')' ';'
                { $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
        | GOTO '*' expr ';'
@@ -3677,10 +3669,10 @@ asm_operand:
        ;
 
 asm_clobbers:
-         string
-               { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE);}
-       | asm_clobbers ',' string
-               { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
+         STRING
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);}
+       | asm_clobbers ',' STRING
+               { $$ = tree_cons (NULL_TREE, $3, $1); }
        ;
 
 /* This is what appears inside the parens in a function declarator.
index 8c9b1c14f7fd40f48cf5423e6b7ebeba7479b690..16df801b0d0390727c1fa6fb57d8f6abef4d2213 100644 (file)
@@ -259,7 +259,7 @@ tinfo_name (type)
   tree name_string;
 
   name = mangle_type_string (type);
-  name_string = combine_strings (build_string (strlen (name) + 1, name));
+  name_string = fix_string_type (build_string (strlen (name) + 1, name));
   return name_string;
 }
 
index 0f53f6b1ece069c559c9e99cec0854d5f180ce7b..ce1cbaca68a4532ebc128901c7a8e0819cb414fc 100644 (file)
@@ -863,9 +863,6 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
   tree r;
   tree t;
 
-  if (TREE_CHAIN (string))
-    string = combine_strings (string);
-
   if (cv_qualifier != NULL_TREE
       && cv_qualifier != ridpointers[(int) RID_VOLATILE])
     {
index 212dada088c2c2254a5c48639c47723b64333bd3..9607e975f117b5758e1c5a64c587b5fa7a744c29 100644 (file)
@@ -102,6 +102,7 @@ static SPEW_INLINE int identifier_type PARAMS ((tree));
 static void scan_tokens PARAMS ((int));
 static void feed_defarg PARAMS ((tree));
 static void finish_defarg PARAMS ((void));
+static void yylexstring PARAMS ((struct token *));
 static int read_token PARAMS ((struct token *));
 
 static SPEW_INLINE int num_tokens PARAMS ((void));
@@ -242,6 +243,43 @@ read_process_identifier (pyylval)
   return IDENTIFIER;
 }
 
+/* Concatenate strings before returning them to the parser.  This isn't quite
+   as good as having it done in the lexer, but it's better than nothing.  */
+
+static void
+yylexstring (t)
+     struct token *t;
+{
+  enum cpp_ttype next_type;
+  tree next;
+
+  next_type = c_lex (&next);
+  if (next_type == CPP_STRING || next_type == CPP_WSTRING)
+    {
+      varray_type strings;
+
+      VARRAY_TREE_INIT (strings, 32, "strings");
+      VARRAY_PUSH_TREE (strings, t->yylval.ttype);
+
+      do
+       {
+         VARRAY_PUSH_TREE (strings, next);
+         next_type = c_lex (&next);
+       }
+      while (next_type == CPP_STRING || next_type == CPP_WSTRING);
+
+      t->yylval.ttype = combine_strings (strings);
+      last_token_id = t->yylval.ttype;
+
+      VARRAY_FREE (strings);
+    }
+
+  /* We will have always read one token too many.  */
+  _cpp_backup_tokens (parse_in, 1);
+
+  t->yychar = STRING;
+}
+
 /* Read the next token from the input file.  The token is written into
    T, and its type number is returned.  */
 static int
@@ -336,7 +374,7 @@ read_token (t)
 
     case CPP_STRING:
     case CPP_WSTRING:
-      t->yychar = STRING;
+      yylexstring (t);
       break;
 
     default:
index 827a5a7166f4dd82ae30447abd5e99d5c555917f..4795160f09f98afb63784fe0b7d80abbd7915554 100644 (file)
@@ -1201,21 +1201,7 @@ my_build_string (len, str)
      int len;
      const char *str;
 {
-  int wide_flag = 0;
-  tree a_string = build_string (len, str);
-
-  /* Some code from combine_strings, which is local to c-parse.y.  */
-  if (TREE_TYPE (a_string) == int_array_type_node)
-    wide_flag = 1;
-
-  TREE_TYPE (a_string)
-    = build_array_type (wide_flag ? integer_type_node : char_type_node,
-                       build_index_type (build_int_2 (len - 1, 0)));
-
-  TREE_CONSTANT (a_string) = 1;        /* Puts string in the readonly segment */
-  TREE_STATIC (a_string) = 1;
-
-  return a_string;
+  return fix_string_type (build_string (len, str));
 }
 
 /* Given a chain of STRING_CST's, build a static instance of
@@ -1241,7 +1227,23 @@ build_objc_string_object (strings)
 
   add_class_reference (constant_string_id);
 
-  string = combine_strings (strings);
+  if (TREE_CHAIN (strings))
+    {
+      varray_type vstrings;
+      VARRAY_TREE_INIT (vstrings, 32, "strings");
+
+      for (; strings ; strings = TREE_CHAIN (strings))
+       VARRAY_PUSH_TREE (vstrings, strings);
+
+      string = combine_strings (vstrings);
+
+      VARRAY_FREE (vstrings);
+    }
+  else
+    string = strings;
+
+  string = fix_string_type (string);
+
   TREE_SET_CODE (string, STRING_CST);
   length = TREE_STRING_LENGTH (string) - 1;
 
diff --git a/gcc/testsuite/g++.dg/parse/concat1.C b/gcc/testsuite/g++.dg/parse/concat1.C
new file mode 100644 (file)
index 0000000..7bf97a6
--- /dev/null
@@ -0,0 +1,15 @@
+/* PR c/3581 */
+/* { dg-do compile } */
+
+/* Intended as a compile-time test for string literal concatenation.
+   The fact that the string isn't actually used in the resulting program
+   should allow this to compile for any target.  */
+
+#define e0     "a"
+#define e1     e0 e0 e0 e0 e0 e0 e0 e0 e0 e0
+#define e2     e1 e1 e1 e1 e1 e1 e1 e1 e1 e1
+#define e3     e2 e2 e2 e2 e2 e2 e2 e2 e2 e2
+#define e4     e3 e3 e3 e3 e3 e3 e3 e3 e3 e3
+#define e5     e4 e4 e4 e4 e4 e4 e4 e4 e4 e4
+
+void foo() { (void)(e5); }
diff --git a/gcc/testsuite/gcc.dg/concat2.c b/gcc/testsuite/gcc.dg/concat2.c
new file mode 100644 (file)
index 0000000..1e92400
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR c/3581 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Intended as a compile-time test for string literal concatenation.
+   The fact that the string isn't actually used in the resulting program
+   should allow this to compile for any target.  */
+
+#define e0     "a"
+#define e1     e0 e0 e0 e0 e0 e0 e0 e0 e0 e0
+#define e2     e1 e1 e1 e1 e1 e1 e1 e1 e1 e1
+#define e3     e2 e2 e2 e2 e2 e2 e2 e2 e2 e2
+#define e4     e3 e3 e3 e3 e3 e3 e3 e3 e3 e3
+#define e5     e4 e4 e4 e4 e4 e4 e4 e4 e4 e4
+
+void foo() { (void)(e5); }