/* Mainly the interface between cpplib and the C front ends.
Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997
- 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "tm_p.h"
#include "splay-tree.h"
#include "debug.h"
+#include "target.h"
/* We may keep statistics about how long which files took to compile. */
static int header_time, body_time;
static splay_tree file_info_tree;
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node)
-
-/* Number of bytes in a wide character. */
-#define WCHAR_BYTES (WCHAR_TYPE_SIZE / BITS_PER_UNIT)
-
int pending_lang_change; /* If we need to switch languages - C++ only */
int c_header_level; /* depth in C headers - C++ only */
-/* If we need to translate characters received. This is tri-state:
- 0 means use only the untranslated string; 1 means use only
- the translated string; -1 means chain the translated string
- to the untranslated one. */
-int c_lex_string_translate = 1;
-
static tree interpret_integer (const cpp_token *, unsigned int);
static tree interpret_float (const cpp_token *, unsigned int);
+static tree interpret_fixed (const cpp_token *, unsigned int);
static enum integer_type_kind narrowest_unsigned_type
(unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int);
static enum integer_type_kind narrowest_signed_type
(unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int);
-static enum cpp_ttype lex_string (const cpp_token *, tree *, bool);
+static enum cpp_ttype lex_string (const cpp_token *, tree *, bool, bool);
static tree lex_charconst (const cpp_token *);
static void update_header_times (const char *);
static int dump_one_header (splay_tree_node, void *);
struct cpp_callbacks *cb;
struct c_fileinfo *toplevel;
- /* Set up filename timing. Must happen before cpp_read_main_file. */
- file_info_tree = splay_tree_new ((splay_tree_compare_fn)strcmp,
- 0,
- (splay_tree_delete_value_fn)free);
+ /* The get_fileinfo data structure must be initialized before
+ cpp_read_main_file is called. */
toplevel = get_fileinfo ("<top level>");
if (flag_detailed_statistics)
{
/* Set the debug callbacks if we can use them. */
if (debug_info_level == DINFO_LEVEL_VERBOSE
&& (write_symbols == DWARF2_DEBUG
- || write_symbols == VMS_AND_DWARF2_DEBUG))
+ || write_symbols == VMS_AND_DWARF2_DEBUG))
{
cb->define = cb_define;
cb->undef = cb_undef;
splay_tree_node n;
struct c_fileinfo *fi;
+ if (!file_info_tree)
+ file_info_tree = splay_tree_new ((splay_tree_compare_fn) strcmp,
+ 0,
+ (splay_tree_delete_value_fn) free);
+
n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
if (n)
return (struct c_fileinfo *) n->value;
print_time ("header files (total)", header_time);
print_time ("main file (total)", this_time - body_time);
fprintf (stderr, "ratio = %g : 1\n",
- (double)header_time / (double)(this_time - body_time));
+ (double) header_time / (double) (this_time - body_time));
fprintf (stderr, "\n******\n");
splay_tree_foreach (file_info_tree, dump_one_header, 0);
const cpp_string * ARG_UNUSED (str))
{
#ifdef ASM_OUTPUT_IDENT
- if (! flag_no_ident)
+ if (!flag_no_ident)
{
/* Convert escapes in the string. */
cpp_string cstr = { 0, 0 };
if (cpp_interpret_string (pfile, str, 1, &cstr, false))
{
ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text);
- free ((void *)cstr.text);
+ free (CONST_CAST (unsigned char *, cstr.text));
}
}
#endif
#else
{
source_location loc = token->src_loc;
- const struct line_map *map = linemap_lookup (&line_table, loc);
+ const struct line_map *map = linemap_lookup (line_table, loc);
input_line = SOURCE_LINE (map, loc);
}
#endif
{
/* Don't stack the main buffer on the input stack;
we already did in compile_file. */
- if (! MAIN_FILE_P (new_map))
+ if (!MAIN_FILE_P (new_map))
{
#ifdef USE_MAPPED_LOCATION
- int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1);
+ int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1);
input_location = included_at;
push_srcloc (new_map->start_location);
#else
- int included_at = LAST_SOURCE_LINE (new_map - 1);
+ int included_at = LAST_SOURCE_LINE (new_map - 1);
input_line = included_at;
push_srcloc (new_map->to_file, 1);
if (c_header_level && --c_header_level == 0)
{
if (new_map->sysp == 2)
- warning ("badly nested C headers from preprocessor");
+ warning (0, "badly nested C headers from preprocessor");
--pending_lang_change;
}
#endif
input_filename = new_map->to_file;
input_line = new_map->to_line;
#endif
-
- /* Hook for C++. */
- extract_interface_info ();
}
static void
-Wunknown-pragmas has been given. */
if (warn_unknown_pragmas > in_system_header)
{
-#ifndef USE_MAPPED_LOCATION
- const struct line_map *map = linemap_lookup (&line_table, loc);
-#endif
const unsigned char *space, *name;
const cpp_token *s;
+#ifndef USE_MAPPED_LOCATION
+ location_t fe_loc;
+ const struct line_map *map = linemap_lookup (line_table, loc);
+ fe_loc.file = map->to_file;
+ fe_loc.line = SOURCE_LINE (map, loc);
+#else
+ location_t fe_loc = loc;
+#endif
space = name = (const unsigned char *) "";
s = cpp_get_token (pfile);
name = cpp_token_as_text (pfile, s);
}
-#ifdef USE_MAPPED_LOCATION
- input_location = loc;
-#else
- input_line = SOURCE_LINE (map, loc);
-#endif
- warning ("ignoring #pragma %s %s", space, name);
+ warning (OPT_Wunknown_pragmas, "%Hignoring #pragma %s %s",
+ &fe_loc, space, name);
}
}
static void
cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node)
{
- const struct line_map *map = linemap_lookup (&line_table, loc);
+ const struct line_map *map = linemap_lookup (line_table, loc);
(*debug_hooks->define) (SOURCE_LINE (map, loc),
(const char *) cpp_macro_definition (pfile, node));
}
cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc,
cpp_hashnode *node)
{
- const struct line_map *map = linemap_lookup (&line_table, loc);
+ const struct line_map *map = linemap_lookup (line_table, loc);
(*debug_hooks->undef) (SOURCE_LINE (map, loc),
(const char *) NODE_NAME (node));
}
\f
-static inline const cpp_token *
-get_nonpadding_token (void)
-{
- const cpp_token *tok;
- timevar_push (TV_CPP);
- do
- tok = cpp_get_token (parse_in);
- while (tok->type == CPP_PADDING);
- timevar_pop (TV_CPP);
-
- return tok;
-}
+/* Read a token and return its type. Fill *VALUE with its value, if
+ applicable. Fill *CPP_FLAGS with the token's flags, if it is
+ non-NULL. */
enum cpp_ttype
-c_lex_with_flags (tree *value, unsigned char *cpp_flags)
+c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
+ int lex_flags)
{
- const cpp_token *tok;
- location_t atloc;
static bool no_more_pch;
+ const cpp_token *tok;
+ enum cpp_ttype type;
+ unsigned char add_flags = 0;
+ timevar_push (TV_CPP);
retry:
- tok = get_nonpadding_token ();
+#ifdef USE_MAPPED_LOCATION
+ tok = cpp_get_token_with_location (parse_in, loc);
+#else
+ tok = cpp_get_token (parse_in);
+ *loc = input_location;
+#endif
+ type = tok->type;
retry_after_at:
- switch (tok->type)
+ switch (type)
{
+ case CPP_PADDING:
+ goto retry;
+
case CPP_NAME:
*value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node));
break;
case CPP_N_INVALID:
/* cpplib has issued an error. */
*value = error_mark_node;
+ errorcount++;
break;
case CPP_N_INTEGER:
+ /* C++ uses '0' to mark virtual functions as pure.
+ Set PURE_ZERO to pass this information to the C++ parser. */
+ if (tok->val.str.len == 1 && *tok->val.str.text == '0')
+ add_flags = PURE_ZERO;
*value = interpret_integer (tok, flags);
break;
case CPP_ATSIGN:
/* An @ may give the next token special significance in Objective-C. */
- atloc = input_location;
- tok = get_nonpadding_token ();
if (c_dialect_objc ())
{
- tree val;
- switch (tok->type)
+#ifdef USE_MAPPED_LOCATION
+ location_t atloc = *loc;
+ location_t newloc;
+#else
+ location_t atloc = input_location;
+#endif
+
+ retry_at:
+#ifdef USE_MAPPED_LOCATION
+ tok = cpp_get_token_with_location (parse_in, &newloc);
+#else
+ tok = cpp_get_token (parse_in);
+#endif
+ type = tok->type;
+ switch (type)
{
- case CPP_NAME:
- val = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node));
- if (objc_is_reserved_word (val))
- {
- *value = val;
- return CPP_AT_NAME;
- }
- break;
+ case CPP_PADDING:
+ goto retry_at;
case CPP_STRING:
case CPP_WSTRING:
- return lex_string (tok, value, true);
+ type = lex_string (tok, value, true, true);
+ break;
+
+ case CPP_NAME:
+ *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node));
+ if (objc_is_reserved_word (*value))
+ {
+ type = CPP_AT_NAME;
+ break;
+ }
+ /* FALLTHROUGH */
- default: break;
+ default:
+ /* ... or not. */
+ error ("%Hstray %<@%> in program", &atloc);
+#ifdef USE_MAPPED_LOCATION
+ *loc = newloc;
+#endif
+ goto retry_after_at;
}
+ break;
}
- /* ... or not. */
- error ("%Hstray '@' in program", &atloc);
- goto retry_after_at;
+ /* FALLTHROUGH */
+ case CPP_HASH:
+ case CPP_PASTE:
+ {
+ unsigned char name[4];
+
+ *cpp_spell_token (parse_in, tok, name, true) = 0;
+
+ error ("stray %qs in program", name);
+ }
+
+ goto retry;
case CPP_OTHER:
{
if (c == '"' || c == '\'')
error ("missing terminating %c character", (int) c);
else if (ISGRAPH (c))
- error ("stray '%c' in program", (int) c);
+ error ("stray %qc in program", (int) c);
else
- error ("stray '\\%o' in program", (int) c);
+ error ("stray %<\\%o%> in program", (int) c);
}
goto retry;
case CPP_STRING:
case CPP_WSTRING:
- return lex_string (tok, value, false);
+ if ((lex_flags & C_LEX_RAW_STRINGS) == 0)
+ {
+ type = lex_string (tok, value, false,
+ (lex_flags & C_LEX_STRING_NO_TRANSLATE) == 0);
+ break;
+ }
+ *value = build_string (tok->val.str.len, (const char *) tok->val.str.text);
+ break;
+
+ case CPP_PRAGMA:
+ *value = build_int_cst (NULL, tok->val.pragma);
break;
/* These tokens should not be visible outside cpplib. */
break;
}
- if (! no_more_pch)
+ if (cpp_flags)
+ *cpp_flags = tok->flags | add_flags;
+
+ if (!no_more_pch)
{
no_more_pch = true;
c_common_no_more_pch ();
}
- if (cpp_flags)
- *cpp_flags = tok->flags;
- return tok->type;
-}
+ timevar_pop (TV_CPP);
-enum cpp_ttype
-c_lex (tree *value)
-{
- return c_lex_with_flags (value, NULL);
+ return type;
}
/* Returns the narrowest C-visible unsigned type, starting with the
{
tree upper = TYPE_MAX_VALUE (integer_types[itk]);
- if ((unsigned HOST_WIDE_INT)TREE_INT_CST_HIGH (upper) > high
- || ((unsigned HOST_WIDE_INT)TREE_INT_CST_HIGH (upper) == high
+ if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high
+ || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high
&& TREE_INT_CST_LOW (upper) >= low))
return itk;
}
for (; itk < itk_none; itk += 2 /* skip signed types */)
{
tree upper = TYPE_MAX_VALUE (integer_types[itk]);
-
- if ((unsigned HOST_WIDE_INT)TREE_INT_CST_HIGH (upper) > high
- || ((unsigned HOST_WIDE_INT)TREE_INT_CST_HIGH (upper) == high
+
+ if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high
+ || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high
&& TREE_INT_CST_LOW (upper) >= low))
return itk;
}
if (itk_u < itk_unsigned_long)
itk_u = itk_unsigned_long;
itk = itk_u;
- warning ("this decimal constant is unsigned only in ISO C90");
+ warning (0, "this decimal constant is unsigned only in ISO C90");
}
- else if (warn_traditional)
- warning ("this decimal constant would be unsigned in ISO C90");
+ else
+ warning (OPT_Wtraditional,
+ "this decimal constant would be unsigned in ISO C90");
}
}
}
if (itk > itk_unsigned_long
&& (flags & CPP_N_WIDTH) != CPP_N_LARGE
- && ! in_system_header && ! flag_isoc99)
- pedwarn ("integer constant is too large for \"%s\" type",
+ && !in_system_header && !flag_isoc99)
+ pedwarn ("integer constant is too large for %qs type",
(flags & CPP_N_UNSIGNED) ? "unsigned long" : "long");
value = build_int_cst_wide (type, integer.low, integer.high);
REAL_VALUE_TYPE real;
char *copy;
size_t copylen;
- const char *type_name;
- /* FIXME: make %T work in error/warning, then we don't need type_name. */
- if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
- {
+ /* Decode _Fract and _Accum. */
+ if (flags & CPP_N_FRACT || flags & CPP_N_ACCUM)
+ return interpret_fixed (token, flags);
+
+ /* Decode type based on width and properties. */
+ if (flags & CPP_N_DFLOAT)
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ type = dfloat128_type_node;
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ type = dfloat32_type_node;
+ else
+ type = dfloat64_type_node;
+ else
+ if (flags & CPP_N_WIDTH_MD)
+ {
+ char suffix;
+ enum machine_mode mode;
+
+ if ((flags & CPP_N_WIDTH_MD) == CPP_N_MD_W)
+ suffix = 'w';
+ else
+ suffix = 'q';
+
+ mode = targetm.c.mode_for_suffix (suffix);
+ if (mode == VOIDmode)
+ {
+ error ("unsupported non-standard suffix on floating constant");
+ errorcount++;
+
+ return error_mark_node;
+ }
+ else if (pedantic)
+ pedwarn ("non-standard suffix on floating constant");
+
+ type = c_common_type_for_mode (mode, 0);
+ gcc_assert (type);
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
type = long_double_type_node;
- type_name = "long double";
- }
- else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
- || flag_single_precision_constant)
- {
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
+ || flag_single_precision_constant)
type = float_type_node;
- type_name = "float";
- }
- else
- {
+ else
type = double_type_node;
- type_name = "double";
- }
/* Copy the constant to a nul-terminated buffer. If the constant
has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF
can't handle them. */
copylen = token->val.str.len;
- if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM)
- /* Must be an F or L suffix. */
- copylen--;
- if (flags & CPP_N_IMAGINARY)
- /* I or J suffix. */
- copylen--;
+ if (flags & CPP_N_DFLOAT)
+ copylen -= 2;
+ else
+ {
+ if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM)
+ /* Must be an F or L or machine defined suffix. */
+ copylen--;
+ if (flags & CPP_N_IMAGINARY)
+ /* I or J suffix. */
+ copylen--;
+ }
copy = (char *) alloca (copylen + 1);
memcpy (copy, token->val.str.text, copylen);
copy[copylen] = '\0';
- real_from_string (&real, copy);
- real_convert (&real, TYPE_MODE (type), &real);
+ real_from_string3 (&real, copy, TYPE_MODE (type));
- /* A diagnostic is required for "soft" overflow by some ISO C
- testsuites. This is not pedwarn, because some people don't want
- an error for this.
- ??? That's a dubious reason... is this a mandatory diagnostic or
- isn't it? -- zw, 2001-08-21. */
- if (REAL_VALUE_ISINF (real) && pedantic)
- warning ("floating constant exceeds range of \"%s\"", type_name);
+ /* Both C and C++ require a diagnostic for a floating constant
+ outside the range of representable values of its type. Since we
+ have __builtin_inf* to produce an infinity, this is now a
+ mandatory pedwarn if the target does not support infinities. */
+ if (REAL_VALUE_ISINF (real))
+ {
+ if (!MODE_HAS_INFINITIES (TYPE_MODE (type)))
+ pedwarn ("floating constant exceeds range of %qT", type);
+ else
+ warning (OPT_Woverflow, "floating constant exceeds range of %qT", type);
+ }
+ /* We also give a warning if the value underflows. */
+ else if (REAL_VALUES_EQUAL (real, dconst0))
+ {
+ REAL_VALUE_TYPE realvoidmode;
+ int overflow = real_from_string (&realvoidmode, copy);
+ if (overflow < 0 || !REAL_VALUES_EQUAL (realvoidmode, dconst0))
+ warning (OPT_Woverflow, "floating constant truncated to zero");
+ }
/* Create a node with determined type and value. */
value = build_real (type, real);
return value;
}
+/* Interpret TOKEN, a fixed-point number with FLAGS as classified
+ by cpplib. */
+
+static tree
+interpret_fixed (const cpp_token *token, unsigned int flags)
+{
+ tree type;
+ tree value;
+ FIXED_VALUE_TYPE fixed;
+ char *copy;
+ size_t copylen;
+
+ copylen = token->val.str.len;
+
+ if (flags & CPP_N_FRACT) /* _Fract. */
+ {
+ if (flags & CPP_N_UNSIGNED) /* Unsigned _Fract. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = unsigned_long_long_fract_type_node;
+ copylen -= 4;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = unsigned_long_fract_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = unsigned_short_fract_type_node;
+ copylen -= 3;
+ }
+ else
+ {
+ type = unsigned_fract_type_node;
+ copylen -= 2;
+ }
+ }
+ else /* Signed _Fract. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = long_long_fract_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = long_fract_type_node;
+ copylen -= 2;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = short_fract_type_node;
+ copylen -= 2;
+ }
+ else
+ {
+ type = fract_type_node;
+ copylen --;
+ }
+ }
+ }
+ else /* _Accum. */
+ {
+ if (flags & CPP_N_UNSIGNED) /* Unsigned _Accum. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = unsigned_long_long_accum_type_node;
+ copylen -= 4;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = unsigned_long_accum_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = unsigned_short_accum_type_node;
+ copylen -= 3;
+ }
+ else
+ {
+ type = unsigned_accum_type_node;
+ copylen -= 2;
+ }
+ }
+ else /* Signed _Accum. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = long_long_accum_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = long_accum_type_node;
+ copylen -= 2;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = short_accum_type_node;
+ copylen -= 2;
+ }
+ else
+ {
+ type = accum_type_node;
+ copylen --;
+ }
+ }
+ }
+
+ copy = (char *) alloca (copylen + 1);
+ memcpy (copy, token->val.str.text, copylen);
+ copy[copylen] = '\0';
+
+ fixed_from_string (&fixed, copy, TYPE_MODE (type));
+
+ /* Create a node with determined type and value. */
+ value = build_fixed (type, fixed);
+
+ return value;
+}
+
/* Convert a series of STRING and/or WSTRING tokens into a tree,
performing string constant concatenation. TOK is the first of
these. VALP is the location to write the string into. OBJC_STRING
we must arrange to provide. */
static enum cpp_ttype
-lex_string (const cpp_token *tok, tree *valp, bool objc_string)
+lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
{
tree value;
bool wide = false;
- size_t count = 1;
+ size_t concats = 0;
struct obstack str_ob;
cpp_string istr;
if (tok->type == CPP_WSTRING)
wide = true;
- tok = get_nonpadding_token ();
- if (c_dialect_objc () && tok->type == CPP_ATSIGN)
- {
- objc_string = true;
- tok = get_nonpadding_token ();
- }
- if (tok->type == CPP_STRING || tok->type == CPP_WSTRING)
+ retry:
+ tok = cpp_get_token (parse_in);
+ switch (tok->type)
{
- gcc_obstack_init (&str_ob);
- obstack_grow (&str_ob, &str, sizeof (cpp_string));
-
- do
+ case CPP_PADDING:
+ goto retry;
+ case CPP_ATSIGN:
+ if (c_dialect_objc ())
{
- count++;
- if (tok->type == CPP_WSTRING)
- wide = true;
- obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+ objc_string = true;
+ goto retry;
+ }
+ /* FALLTHROUGH */
- tok = get_nonpadding_token ();
- if (c_dialect_objc () && tok->type == CPP_ATSIGN)
- {
- objc_string = true;
- tok = get_nonpadding_token ();
- }
+ default:
+ break;
+
+ case CPP_WSTRING:
+ wide = true;
+ /* FALLTHROUGH */
+
+ case CPP_STRING:
+ if (!concats)
+ {
+ gcc_obstack_init (&str_ob);
+ obstack_grow (&str_ob, &str, sizeof (cpp_string));
}
- while (tok->type == CPP_STRING || tok->type == CPP_WSTRING);
- strs = (cpp_string *) obstack_finish (&str_ob);
+
+ concats++;
+ obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+ goto retry;
}
/* We have read one more token than we want. */
_cpp_backup_tokens (parse_in, 1);
+ if (concats)
+ strs = XOBFINISH (&str_ob, cpp_string *);
- if (count > 1 && !objc_string && warn_traditional && !in_system_header)
- warning ("traditional C rejects string constant concatenation");
+ if (concats && !objc_string && !in_system_header)
+ warning (OPT_Wtraditional,
+ "traditional C rejects string constant concatenation");
- if ((c_lex_string_translate
+ if ((translate
? cpp_interpret_string : cpp_interpret_string_notranslate)
- (parse_in, strs, count, &istr, wide))
+ (parse_in, strs, concats + 1, &istr, wide))
{
- value = build_string (istr.len, (char *)istr.text);
- free ((void *)istr.text);
-
- if (c_lex_string_translate == -1)
- {
- int xlated = cpp_interpret_string_notranslate (parse_in, strs, count,
- &istr, wide);
- /* Assume that, if we managed to translate the string above,
- then the untranslated parsing will always succeed. */
- gcc_assert (xlated);
-
- if (TREE_STRING_LENGTH (value) != (int)istr.len
- || 0 != strncmp (TREE_STRING_POINTER (value), (char *)istr.text,
- istr.len))
- {
- /* Arrange for us to return the untranslated string in
- *valp, but to set up the C type of the translated
- one. */
- *valp = build_string (istr.len, (char *)istr.text);
- valp = &TREE_CHAIN (*valp);
- }
- free ((void *)istr.text);
- }
+ value = build_string (istr.len, (const char *) istr.text);
+ free (CONST_CAST (unsigned char *, istr.text));
}
else
{
TREE_TYPE (value) = wide ? wchar_array_type_node : char_array_type_node;
*valp = fix_string_type (value);
- if (strs != &str)
+ if (concats)
obstack_free (&str_ob, 0);
return objc_string ? CPP_OBJC_STRING : wide ? CPP_WSTRING : CPP_STRING;