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,105 +683,17 @@ fname_decl (rid, id) ...@@ -683,105 +683,17 @@ 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 tree
combine_strings (strings) fix_string_type (value)
tree strings; tree value;
{ {
tree value, t; const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
int length = 1; const int wide_flag = TREE_TYPE (value) == wchar_array_type_node;
int wide_length = 0;
int wide_flag = 0;
int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
int nchars;
const int nchars_max = flag_isoc99 ? 4095 : 509; const int nchars_max = flag_isoc99 ? 4095 : 509;
int length = TREE_STRING_LENGTH (value);
if (TREE_CHAIN (strings)) int nchars;
{
/* 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;
}
/* Compute the number of elements, for the array type. */ /* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length; nchars = wide_flag ? length / wchar_bytes : length;
...@@ -813,6 +725,111 @@ combine_strings (strings) ...@@ -813,6 +725,111 @@ combine_strings (strings)
TREE_STATIC (value) = 1; TREE_STATIC (value) = 1;
return value; 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;
}
static int is_valid_printf_arglist PARAMS ((tree)); static int is_valid_printf_arglist PARAMS ((tree));
static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier)); 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) ...@@ -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;
} }
......
...@@ -530,12 +530,13 @@ extern tree c_expand_expr_stmt PARAMS ((tree)); ...@@ -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_expand_start_cond PARAMS ((tree, int, tree));
extern void c_finish_then PARAMS ((void)); extern void c_finish_then PARAMS ((void));
extern void c_expand_start_else 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)); 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