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