Commit b84a3874 by Richard Henderson Committed by Richard Henderson

c-common.c (fix_string_type): Split out of ...

        * 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
parent 4d7ea4fc
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> 2002-04-26 Bo Thorsen <bo@suse.co.uk>
* config/i386/linux64.h (MD_FALLBACK_FRAME_STATE_FOR): Define for * config/i386/linux64.h (MD_FALLBACK_FRAME_STATE_FOR): Define for
......
...@@ -683,42 +683,81 @@ fname_decl (rid, id) ...@@ -683,42 +683,81 @@ fname_decl (rid, id)
return decl; return decl;
} }
/* Given a chain of STRING_CST nodes, /* Given a STRING_CST, give it a suitable array-of-chars data type. */
concatenate them into one STRING_CST
and give it a suitable array-of-chars data type. */ tree
fix_string_type (value)
tree value;
{
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;
int length = TREE_STRING_LENGTH (value);
int nchars;
/* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
/* Create the array type for the string constant.
-Wwrite-strings says make the string constant an array of const char
so that copying it to a non-const pointer will get a warning.
For C++, this is the standard behavior. */
if (flag_const_strings && ! flag_writable_strings)
{
tree elements
= build_type_variant (wide_flag ? wchar_type_node : char_type_node,
1, 0);
TREE_TYPE (value)
= build_array_type (elements,
build_index_type (build_int_2 (nchars - 1, 0)));
}
else
TREE_TYPE (value)
= build_array_type (wide_flag ? wchar_type_node : char_type_node,
build_index_type (build_int_2 (nchars - 1, 0)));
TREE_CONSTANT (value) = 1;
TREE_READONLY (value) = ! flag_writable_strings;
TREE_STATIC (value) = 1;
return value;
}
/* Given a VARRAY of STRING_CST nodes, concatenate them into one
STRING_CST. */
tree tree
combine_strings (strings) combine_strings (strings)
tree 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; tree value, t;
int length = 1; int length = 1;
int wide_length = 0; int wide_length = 0;
int wide_flag = 0; int wide_flag = 0;
int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT; int i;
int nchars;
const int nchars_max = flag_isoc99 ? 4095 : 509;
if (TREE_CHAIN (strings))
{
/* More than one in the chain, so concatenate. */
char *p, *q; char *p, *q;
/* Don't include the \0 at the end of each substring, /* Don't include the \0 at the end of each substring. Count wide
except for the last one. strings and ordinary strings separately. */
Count wide strings and ordinary strings separately. */ for (i = 0; i < nstrings; ++i)
for (t = strings; t; t = TREE_CHAIN (t))
{ {
t = VARRAY_TREE (strings, i);
if (TREE_TYPE (t) == wchar_array_type_node) if (TREE_TYPE (t) == wchar_array_type_node)
{ {
wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes); wide_length += TREE_STRING_LENGTH (t) - wchar_bytes;
wide_flag = 1; wide_flag = 1;
} }
else else
{ {
length += (TREE_STRING_LENGTH (t) - 1); length += (TREE_STRING_LENGTH (t) - 1);
if (C_ARTIFICIAL_STRING_P (t) && !in_system_header) 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"); warning ("concatenation of string literals with __FUNCTION__ is deprecated");
} }
} }
...@@ -727,46 +766,54 @@ combine_strings (strings) ...@@ -727,46 +766,54 @@ combine_strings (strings)
if (wide_flag) if (wide_flag)
length = length * wchar_bytes + wide_length; length = length * wchar_bytes + wide_length;
p = alloca (length); p = xmalloc (length);
/* Copy the individual strings into the new combined string. /* Copy the individual strings into the new combined string.
If the combined string is wide, convert the chars to ints If the combined string is wide, convert the chars to ints
for any individual strings that are not wide. */ for any individual strings that are not wide. */
q = p; q = p;
for (t = strings; t; t = TREE_CHAIN (t)) for (i = 0; i < nstrings; ++i)
{ {
int len = (TREE_STRING_LENGTH (t) int len, this_wide;
- ((TREE_TYPE (t) == wchar_array_type_node)
? wchar_bytes : 1)); t = VARRAY_TREE (strings, i);
if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag) 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); memcpy (q, TREE_STRING_POINTER (t), len);
q += len; q += len;
} }
else else
{ {
int i, j; const int nzeros = (WCHAR_TYPE_SIZE / BITS_PER_UNIT) - 1;
for (i = 0; i < len; i++) int j, k;
{
if (BYTES_BIG_ENDIAN) if (BYTES_BIG_ENDIAN)
{ {
for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++) for (k = 0; k < len; k++)
{
for (j = 0; j < nzeros; j++)
*q++ = 0; *q++ = 0;
*q++ = TREE_STRING_POINTER (t)[i]; *q++ = TREE_STRING_POINTER (t)[k];
}
} }
else else
{ {
*q++ = TREE_STRING_POINTER (t)[i]; for (k = 0; k < len; k++)
for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++) {
*q++ = TREE_STRING_POINTER (t)[k];
for (j = 0; j < nzeros; j++)
*q++ = 0; *q++ = 0;
} }
} }
} }
} }
/* Nul terminate the string. */
if (wide_flag) if (wide_flag)
{ {
int i;
for (i = 0; i < wchar_bytes; i++) for (i = 0; i < wchar_bytes; i++)
*q++ = 0; *q++ = 0;
} }
...@@ -774,43 +821,13 @@ combine_strings (strings) ...@@ -774,43 +821,13 @@ combine_strings (strings)
*q = 0; *q = 0;
value = build_string (length, p); value = build_string (length, p);
} free (p);
else
{
value = strings;
length = TREE_STRING_LENGTH (value);
if (TREE_TYPE (value) == wchar_array_type_node)
wide_flag = 1;
}
/* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
/* Create the array type for the string constant. if (wide_flag)
-Wwrite-strings says make the string constant an array of const char TREE_TYPE (value) = wchar_array_type_node;
so that copying it to a non-const pointer will get a warning.
For C++, this is the standard behavior. */
if (flag_const_strings && ! flag_writable_strings)
{
tree elements
= build_type_variant (wide_flag ? wchar_type_node : char_type_node,
1, 0);
TREE_TYPE (value)
= build_array_type (elements,
build_index_type (build_int_2 (nchars - 1, 0)));
}
else else
TREE_TYPE (value) TREE_TYPE (value) = char_array_type_node;
= build_array_type (wide_flag ? wchar_type_node : char_type_node,
build_index_type (build_int_2 (nchars - 1, 0)));
TREE_CONSTANT (value) = 1;
TREE_READONLY (value) = ! flag_writable_strings;
TREE_STATIC (value) = 1;
return value; return value;
} }
...@@ -4058,7 +4075,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked) ...@@ -4058,7 +4075,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1); memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
newstr[newlen - 1] = 0; 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); arglist = build_tree_list (NULL_TREE, arglist);
fn = fn_puts; fn = fn_puts;
} }
......
...@@ -534,8 +534,9 @@ extern void c_finish_else PARAMS ((void)); ...@@ -534,8 +534,9 @@ extern void c_finish_else PARAMS ((void));
extern void c_expand_end_cond PARAMS ((void)); extern void c_expand_end_cond PARAMS ((void));
/* Validate the expression after `case' and apply default promotions. */ /* Validate the expression after `case' and apply default promotions. */
extern tree check_case_value PARAMS ((tree)); extern tree check_case_value PARAMS ((tree));
/* Concatenate a list of STRING_CST nodes into one STRING_CST. */ extern tree fix_string_type PARAMS ((tree));
extern tree combine_strings PARAMS ((tree)); struct varray_head_tag;
extern tree combine_strings PARAMS ((struct varray_head_tag *));
extern void constant_expression_warning PARAMS ((tree)); extern void constant_expression_warning PARAMS ((tree));
extern tree convert_and_check PARAMS ((tree, tree)); extern tree convert_and_check PARAMS ((tree, tree));
extern void overflow_warning PARAMS ((tree)); extern void overflow_warning PARAMS ((tree));
......
...@@ -181,7 +181,7 @@ do { \ ...@@ -181,7 +181,7 @@ do { \
%type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist %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_nosa_noea declspecs_nosc_nots_nosa_ea
%type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_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 %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
...@@ -329,6 +329,7 @@ end ifc ...@@ -329,6 +329,7 @@ end ifc
static void yyprint PARAMS ((FILE *, int, YYSTYPE)); static void yyprint PARAMS ((FILE *, int, YYSTYPE));
static void yyerror PARAMS ((const char *)); static void yyerror PARAMS ((const char *));
static int yylexname PARAMS ((void)); static int yylexname PARAMS ((void));
static int yylexstring PARAMS ((void));
static inline int _yylex PARAMS ((void)); static inline int _yylex PARAMS ((void));
static int yylex PARAMS ((void)); static int yylex PARAMS ((void));
static void init_reswords PARAMS ((void)); static void init_reswords PARAMS ((void));
...@@ -658,8 +659,8 @@ primary: ...@@ -658,8 +659,8 @@ primary:
$$ = build_external_ref ($1, yychar == '('); $$ = build_external_ref ($1, yychar == '(');
} }
| CONSTANT | CONSTANT
| string | STRING
{ $$ = combine_strings ($1); } { $$ = fix_string_type ($$); }
| VAR_FUNC_NAME | VAR_FUNC_NAME
{ $$ = fname_decl (C_RID_CODE ($$), $$); } { $$ = fname_decl (C_RID_CODE ($$), $$); }
| '(' typename ')' '{' | '(' typename ')' '{'
...@@ -770,29 +771,6 @@ ifobjc ...@@ -770,29 +771,6 @@ ifobjc
end 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 ifobjc
/* Produces an STRING_CST with perhaps more STRING_CSTs chained /* Produces an STRING_CST with perhaps more STRING_CSTs chained
onto it, which is to be read as an ObjC string object. */ onto it, which is to be read as an ObjC string object. */
...@@ -1433,10 +1411,8 @@ notype_initdecls: ...@@ -1433,10 +1411,8 @@ notype_initdecls:
maybeasm: maybeasm:
/* empty */ /* empty */
{ $$ = NULL_TREE; } { $$ = NULL_TREE; }
| ASM_KEYWORD '(' string ')' | ASM_KEYWORD '(' STRING ')'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); { $$ = $3; }
$$ = $3;
}
; ;
initdcl: initdcl:
...@@ -2508,10 +2484,10 @@ asm_operand: ...@@ -2508,10 +2484,10 @@ asm_operand:
; ;
asm_clobbers: asm_clobbers:
string STRING
{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); } { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
| asm_clobbers ',' string | asm_clobbers ',' STRING
{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); } { $$ = tree_cons (NULL_TREE, $3, $1); }
; ;
/* This is what appears inside the parens in a function declarator. /* This is what appears inside the parens in a function declarator.
...@@ -3703,6 +3679,59 @@ end ifobjc ...@@ -3703,6 +3679,59 @@ end ifobjc
return IDENTIFIER; 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 static inline int
_yylex () _yylex ()
...@@ -3769,7 +3798,13 @@ _yylex () ...@@ -3769,7 +3798,13 @@ _yylex ()
return 0; return 0;
case CPP_NAME: case CPP_NAME:
return yylexname (); {
int ret = yylexname ();
if (ret == STRING)
return yylexstring ();
else
return ret;
}
case CPP_NUMBER: case CPP_NUMBER:
case CPP_CHAR: case CPP_CHAR:
...@@ -3778,7 +3813,7 @@ _yylex () ...@@ -3778,7 +3813,7 @@ _yylex ()
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
return STRING; return yylexstring ();
/* This token is Objective-C specific. It gives the next token /* This token is Objective-C specific. It gives the next token
special significance. */ special significance. */
......
...@@ -6849,8 +6849,6 @@ simple_asm_stmt (expr) ...@@ -6849,8 +6849,6 @@ simple_asm_stmt (expr)
{ {
tree stmt; tree stmt;
if (TREE_CHAIN (expr))
expr = combine_strings (expr);
stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr, stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr,
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
NULL_TREE)); NULL_TREE));
...@@ -6875,8 +6873,6 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers) ...@@ -6875,8 +6873,6 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
{ {
tree tail; tree tail;
if (TREE_CHAIN (string))
string = combine_strings (string);
if (TREE_CODE (string) != STRING_CST) if (TREE_CODE (string) != STRING_CST)
{ {
error ("asm template is not a string constant"); error ("asm template is not a string constant");
......
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> 2002-04-25 Richard Henderson <rth@redhat.com>
PR c/2161 PR c/2161
......
...@@ -378,7 +378,7 @@ cp_parse_init () ...@@ -378,7 +378,7 @@ cp_parse_init ()
%type <ttype> PFUNCNAME maybe_identifier %type <ttype> PFUNCNAME maybe_identifier
%type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
%type <ttype> expr_no_commas expr_no_comma_rangle %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_declspecs boolean.literal
%type <ttype> reserved_typespecquals %type <ttype> reserved_typespecquals
%type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
...@@ -543,9 +543,8 @@ extdef: ...@@ -543,9 +543,8 @@ extdef:
{ do_pending_inlines (); } { do_pending_inlines (); }
| template_def | template_def
{ do_pending_inlines (); } { do_pending_inlines (); }
| asm_keyword '(' string ')' ';' | asm_keyword '(' STRING ')' ';'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); { assemble_asm ($3); }
assemble_asm ($3); }
| extern_lang_string '{' extdefs_opt '}' | extern_lang_string '{' extdefs_opt '}'
{ pop_lang_context (); } { pop_lang_context (); }
| extern_lang_string .hush_warning fndef .warning_ok eat_saved_input | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
...@@ -1608,10 +1607,10 @@ primary: ...@@ -1608,10 +1607,10 @@ primary:
} }
| CONSTANT | CONSTANT
| boolean.literal | boolean.literal
| string | STRING
{ {
$$ = combine_strings ($$); $$ = fix_string_type ($$);
/* combine_strings doesn't set up TYPE_MAIN_VARIANT of /* fix_string_type doesn't set up TYPE_MAIN_VARIANT of
a const array the way we want, so fix it. */ a const array the way we want, so fix it. */
if (flag_const_strings) if (flag_const_strings)
TREE_TYPE ($$) = build_cplus_array_type TREE_TYPE ($$) = build_cplus_array_type
...@@ -1812,13 +1811,6 @@ boolean.literal: ...@@ -1812,13 +1811,6 @@ boolean.literal:
{ $$ = boolean_false_node; } { $$ = boolean_false_node; }
; ;
/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
string:
STRING
| string STRING
{ $$ = chainon ($$, $2); }
;
nodecls: nodecls:
/* empty */ /* empty */
{ {
...@@ -2098,8 +2090,8 @@ nomods_initdecls: ...@@ -2098,8 +2090,8 @@ nomods_initdecls:
maybeasm: maybeasm:
/* empty */ /* empty */
{ $$ = NULL_TREE; } { $$ = NULL_TREE; }
| asm_keyword '(' string ')' | asm_keyword '(' STRING ')'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; } { $$ = $3; }
; ;
initdcl: initdcl:
...@@ -3494,27 +3486,27 @@ simple_stmt: ...@@ -3494,27 +3486,27 @@ simple_stmt:
{ $$ = finish_return_stmt (NULL_TREE); } { $$ = finish_return_stmt (NULL_TREE); }
| RETURN_KEYWORD expr ';' | RETURN_KEYWORD expr ';'
{ $$ = finish_return_stmt ($2); } { $$ = 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, { $$ = finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
NULL_TREE); NULL_TREE);
ASM_INPUT_P ($$) = 1; } ASM_INPUT_P ($$) = 1; }
/* This is the case with just output operands. */ /* 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); } { $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
/* This is the case with input operands as well. */ /* 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 ')' ';' asm_operands ')' ';'
{ $$ = finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); } { $$ = 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); } { $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
/* This is the case with clobbered registers as well. */ /* 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 ')' ';' asm_operands ':' asm_clobbers ')' ';'
{ $$ = finish_asm_stmt ($2, $4, $6, $8, $10); } { $$ = 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 ')' ';' asm_clobbers ')' ';'
{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); } { $$ = 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 ')' ';' asm_clobbers ')' ';'
{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); } { $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
| GOTO '*' expr ';' | GOTO '*' expr ';'
...@@ -3677,10 +3669,10 @@ asm_operand: ...@@ -3677,10 +3669,10 @@ asm_operand:
; ;
asm_clobbers: asm_clobbers:
string STRING
{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE);} { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);}
| asm_clobbers ',' string | asm_clobbers ',' STRING
{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); } { $$ = tree_cons (NULL_TREE, $3, $1); }
; ;
/* This is what appears inside the parens in a function declarator. /* This is what appears inside the parens in a function declarator.
......
...@@ -259,7 +259,7 @@ tinfo_name (type) ...@@ -259,7 +259,7 @@ tinfo_name (type)
tree name_string; tree name_string;
name = mangle_type_string (type); 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; return name_string;
} }
......
...@@ -863,9 +863,6 @@ finish_asm_stmt (cv_qualifier, string, output_operands, ...@@ -863,9 +863,6 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
tree r; tree r;
tree t; tree t;
if (TREE_CHAIN (string))
string = combine_strings (string);
if (cv_qualifier != NULL_TREE if (cv_qualifier != NULL_TREE
&& cv_qualifier != ridpointers[(int) RID_VOLATILE]) && cv_qualifier != ridpointers[(int) RID_VOLATILE])
{ {
......
...@@ -102,6 +102,7 @@ static SPEW_INLINE int identifier_type PARAMS ((tree)); ...@@ -102,6 +102,7 @@ static SPEW_INLINE int identifier_type PARAMS ((tree));
static void scan_tokens PARAMS ((int)); static void scan_tokens PARAMS ((int));
static void feed_defarg PARAMS ((tree)); static void feed_defarg PARAMS ((tree));
static void finish_defarg PARAMS ((void)); static void finish_defarg PARAMS ((void));
static void yylexstring PARAMS ((struct token *));
static int read_token PARAMS ((struct token *)); static int read_token PARAMS ((struct token *));
static SPEW_INLINE int num_tokens PARAMS ((void)); static SPEW_INLINE int num_tokens PARAMS ((void));
...@@ -242,6 +243,43 @@ read_process_identifier (pyylval) ...@@ -242,6 +243,43 @@ read_process_identifier (pyylval)
return IDENTIFIER; 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 /* Read the next token from the input file. The token is written into
T, and its type number is returned. */ T, and its type number is returned. */
static int static int
...@@ -336,7 +374,7 @@ read_token (t) ...@@ -336,7 +374,7 @@ read_token (t)
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
t->yychar = STRING; yylexstring (t);
break; break;
default: default:
......
...@@ -1201,21 +1201,7 @@ my_build_string (len, str) ...@@ -1201,21 +1201,7 @@ my_build_string (len, str)
int len; int len;
const char *str; const char *str;
{ {
int wide_flag = 0; return fix_string_type (build_string (len, str));
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;
} }
/* Given a chain of STRING_CST's, build a static instance of /* Given a chain of STRING_CST's, build a static instance of
...@@ -1241,7 +1227,23 @@ build_objc_string_object (strings) ...@@ -1241,7 +1227,23 @@ build_objc_string_object (strings)
add_class_reference (constant_string_id); 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); TREE_SET_CODE (string, STRING_CST);
length = TREE_STRING_LENGTH (string) - 1; length = TREE_STRING_LENGTH (string) - 1;
......
/* 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); }
/* 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); }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment