OSDN Git Service

Revert:
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index e0617bd..53a3b06 100644 (file)
@@ -1,12 +1,13 @@
 /* Mainly the interface between cpplib and the C front ends.
    Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997
 /* 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 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   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
 
 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
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 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 "config.h"
 #include "system.h"
@@ -25,9 +25,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 
 #include "real.h"
 #include "tm.h"
 
 #include "real.h"
-#include "rtl.h"
+#include "fixed-value.h"
 #include "tree.h"
 #include "tree.h"
-#include "expr.h"
 #include "input.h"
 #include "output.h"
 #include "c-tree.h"
 #include "input.h"
 #include "output.h"
 #include "c-tree.h"
@@ -38,73 +37,42 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "c-pragma.h"
 #include "toplev.h"
 #include "intl.h"
 #include "c-pragma.h"
 #include "toplev.h"
 #include "intl.h"
-#include "tm_p.h"
 #include "splay-tree.h"
 #include "debug.h"
 #include "splay-tree.h"
 #include "debug.h"
-#include "c-incpath.h"
-
-#ifdef MULTIBYTE_CHARS
-#include "mbchar.h"
-#include <locale.h>
-#endif /* MULTIBYTE_CHARS */
-
-/* The current line map.  */
-static const struct line_map *map;
-
-/* The line used to refresh the lineno global variable after each token.  */
-static unsigned int src_lineno;
+#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;
 
 
 /* We may keep statistics about how long which files took to compile.  */
 static int header_time, body_time;
 static splay_tree file_info_tree;
 
-/* File used for outputting assembler code.  */
-extern FILE *asm_out_file;
-
-#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 */
 
 int pending_lang_change; /* If we need to switch languages - C++ only */
 int c_header_level;     /* depth in C headers - C++ only */
 
-/* Nonzero tells yylex to ignore \ in string constants.  */
-static int ignore_escape_flag;
-
-static tree interpret_integer  PARAMS ((const cpp_token *, unsigned int));
-static tree interpret_float    PARAMS ((const cpp_token *, unsigned int));
-static enum integer_type_kind
-  narrowest_unsigned_type      PARAMS ((tree, unsigned int));
-static enum integer_type_kind
-  narrowest_signed_type                PARAMS ((tree, unsigned int));
-static tree lex_string         PARAMS ((const unsigned char *, unsigned int,
-                                        int));
-static tree lex_charconst      PARAMS ((const cpp_token *));
-static void update_header_times        PARAMS ((const char *));
-static int dump_one_header     PARAMS ((splay_tree_node, void *));
-static void cb_line_change     PARAMS ((cpp_reader *, const cpp_token *, int));
-static void cb_ident           PARAMS ((cpp_reader *, unsigned int,
-                                        const cpp_string *));
-static void cb_file_change    PARAMS ((cpp_reader *, const struct line_map *));
-static void cb_def_pragma      PARAMS ((cpp_reader *, unsigned int));
-static void cb_define          PARAMS ((cpp_reader *, unsigned int,
-                                        cpp_hashnode *));
-static void cb_undef           PARAMS ((cpp_reader *, unsigned int,
-                                        cpp_hashnode *));
+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, bool);
+static tree lex_charconst (const cpp_token *);
+static void update_header_times (const char *);
+static int dump_one_header (splay_tree_node, void *);
+static void cb_line_change (cpp_reader *, const cpp_token *, int);
+static void cb_ident (cpp_reader *, unsigned int, const cpp_string *);
+static void cb_def_pragma (cpp_reader *, unsigned int);
+static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *);
+static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *);
 \f
 \f
-const char *
-init_c_lex (filename)
-     const char *filename;
+void
+init_c_lex (void)
 {
   struct cpp_callbacks *cb;
   struct c_fileinfo *toplevel;
 
 {
   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)
     {
   toplevel = get_fileinfo ("<top level>");
   if (flag_detailed_statistics)
     {
@@ -112,74 +80,41 @@ init_c_lex (filename)
       body_time = get_run_time ();
       toplevel->time = body_time;
     }
       body_time = get_run_time ();
       toplevel->time = body_time;
     }
-  
-#ifdef MULTIBYTE_CHARS
-  /* Change to the native locale for multibyte conversions.  */
-  setlocale (LC_CTYPE, "");
-  GET_ENVIRONMENT (literal_codeset, "LANG");
-#endif
 
   cb = cpp_get_callbacks (parse_in);
 
   cb->line_change = cb_line_change;
   cb->ident = cb_ident;
 
   cb = cpp_get_callbacks (parse_in);
 
   cb->line_change = cb_line_change;
   cb->ident = cb_ident;
-  cb->file_change = cb_file_change;
   cb->def_pragma = cb_def_pragma;
   cb->def_pragma = cb_def_pragma;
-  cb->simplify_path = simplify_path;
   cb->valid_pch = c_common_valid_pch;
   cb->read_pch = c_common_read_pch;
 
   /* Set the debug callbacks if we can use them.  */
   if (debug_info_level == DINFO_LEVEL_VERBOSE
   cb->valid_pch = c_common_valid_pch;
   cb->read_pch = c_common_read_pch;
 
   /* Set the debug callbacks if we can use them.  */
   if (debug_info_level == DINFO_LEVEL_VERBOSE
-      && (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG
-          || write_symbols == VMS_AND_DWARF2_DEBUG))
+      && (write_symbols == DWARF2_DEBUG
+         || write_symbols == VMS_AND_DWARF2_DEBUG))
     {
       cb->define = cb_define;
       cb->undef = cb_undef;
     }
     {
       cb->define = cb_define;
       cb->undef = cb_undef;
     }
-
-  /* Start it at 0.  */
-  lineno = 0;
-
-  return cpp_read_main_file (parse_in, filename, ident_hash);
-}
-
-/* A thin wrapper around the real parser that initializes the 
-   integrated preprocessor after debug output has been initialized.
-   Also, make sure the start_source_file debug hook gets called for
-   the primary source file.  */
-
-void
-c_common_parse_file (set_yydebug)
-     int set_yydebug ATTRIBUTE_UNUSED;
-{
-#if YYDEBUG != 0
-  yydebug = set_yydebug;
-#else
-  warning ("YYDEBUG not defined");
-#endif
-
-  (*debug_hooks->start_source_file) (lineno, input_filename);
-  cpp_finish_options (parse_in);
-
-  pch_init();
-  
-  yyparse ();
-  free_parser_stacks ();
 }
 
 struct c_fileinfo *
 }
 
 struct c_fileinfo *
-get_fileinfo (name)
-     const char *name;
+get_fileinfo (const char *name)
 {
   splay_tree_node n;
   struct c_fileinfo *fi;
 
 {
   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;
 
   n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
   if (n)
     return (struct c_fileinfo *) n->value;
 
-  fi = (struct c_fileinfo *) xmalloc (sizeof (struct c_fileinfo));
+  fi = XNEW (struct c_fileinfo);
   fi->time = 0;
   fi->interface_only = 0;
   fi->interface_unknown = 1;
   fi->time = 0;
   fi->interface_only = 0;
   fi->interface_unknown = 1;
@@ -189,8 +124,7 @@ get_fileinfo (name)
 }
 
 static void
 }
 
 static void
-update_header_times (name)
-     const char *name;
+update_header_times (const char *name)
 {
   /* Changing files again.  This means currently collected time
      is charged against header time, and body time starts back at 0.  */
 {
   /* Changing files again.  This means currently collected time
      is charged against header time, and body time starts back at 0.  */
@@ -205,9 +139,7 @@ update_header_times (name)
 }
 
 static int
 }
 
 static int
-dump_one_header (n, dummy)
-     splay_tree_node n;
-     void *dummy ATTRIBUTE_UNUSED;
+dump_one_header (splay_tree_node n, void * ARG_UNUSED (dummy))
 {
   print_time ((const char *) n->key,
              ((struct c_fileinfo *) n->value)->time);
 {
   print_time ((const char *) n->key,
              ((struct c_fileinfo *) n->value)->time);
@@ -215,7 +147,7 @@ dump_one_header (n, dummy)
 }
 
 void
 }
 
 void
-dump_time_statistics ()
+dump_time_statistics (void)
 {
   struct c_fileinfo *file = get_fileinfo (input_filename);
   int this_time = get_run_time ();
 {
   struct c_fileinfo *file = get_fileinfo (input_filename);
   int this_time = get_run_time ();
@@ -225,24 +157,27 @@ dump_time_statistics ()
   print_time ("header files (total)", header_time);
   print_time ("main file (total)", this_time - body_time);
   fprintf (stderr, "ratio = %g : 1\n",
   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);
 }
 
 static void
   fprintf (stderr, "\n******\n");
 
   splay_tree_foreach (file_info_tree, dump_one_header, 0);
 }
 
 static void
-cb_ident (pfile, line, str)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     unsigned int line ATTRIBUTE_UNUSED;
-     const cpp_string *str ATTRIBUTE_UNUSED;
+cb_ident (cpp_reader * ARG_UNUSED (pfile),
+         unsigned int ARG_UNUSED (line),
+         const cpp_string * ARG_UNUSED (str))
 {
 #ifdef ASM_OUTPUT_IDENT
 {
 #ifdef ASM_OUTPUT_IDENT
-  if (! flag_no_ident)
+  if (!flag_no_ident)
     {
       /* Convert escapes in the string.  */
     {
       /* Convert escapes in the string.  */
-      tree value ATTRIBUTE_UNUSED = lex_string (str->text, str->len, 0);
-      ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (value));
+      cpp_string cstr = { 0, 0 };
+      if (cpp_interpret_string (pfile, str, 1, &cstr, CPP_STRING))
+       {
+         ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text);
+         free (CONST_CAST (unsigned char *, cstr.text));
+       }
     }
 #endif
 }
     }
 #endif
 }
@@ -250,34 +185,32 @@ cb_ident (pfile, line, str)
 /* Called at the start of every non-empty line.  TOKEN is the first
    lexed token on the line.  Used for diagnostic line numbers.  */
 static void
 /* Called at the start of every non-empty line.  TOKEN is the first
    lexed token on the line.  Used for diagnostic line numbers.  */
 static void
-cb_line_change (pfile, token, parsing_args)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     const cpp_token *token;
-     int parsing_args ATTRIBUTE_UNUSED;
+cb_line_change (cpp_reader * ARG_UNUSED (pfile), const cpp_token *token,
+               int parsing_args)
 {
 {
-  src_lineno = SOURCE_LINE (map, token->line);
+  if (token->type != CPP_EOF && !parsing_args)
+    input_location = token->src_loc;
 }
 
 }
 
-static void
-cb_file_change (pfile, new_map)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     const struct line_map *new_map;
+void
+fe_file_change (const struct line_map *new_map)
 {
 {
-  unsigned int to_line = SOURCE_LINE (new_map, new_map->to_line);
+  if (new_map == NULL)
+    return;
 
   if (new_map->reason == LC_ENTER)
     {
       /* Don't stack the main buffer on the input stack;
         we already did in compile_file.  */
 
   if (new_map->reason == LC_ENTER)
     {
       /* Don't stack the main buffer on the input stack;
         we already did in compile_file.  */
-      if (map == NULL)
-       main_input_filename = new_map->to_file;
-      else
+      if (!MAIN_FILE_P (new_map))
        {
        {
-          int included_at = SOURCE_LINE (new_map - 1, new_map->from_line - 1);
+         unsigned int included_at = LAST_SOURCE_LINE_LOCATION (new_map - 1);
+         int line = 0;
+         if (included_at > BUILTINS_LOCATION)
+           line = SOURCE_LINE (new_map - 1, included_at);
 
 
-         lineno = included_at;
-         push_srcloc (new_map->to_file, 1);
-         (*debug_hooks->start_source_file) (included_at, new_map->to_file);
+         input_location = new_map->start_location;
+         (*debug_hooks->start_source_file) (line, new_map->to_file);
 #ifndef NO_IMPLICIT_EXTERN_C
          if (c_header_level)
            ++c_header_level;
 #ifndef NO_IMPLICIT_EXTERN_C
          if (c_header_level)
            ++c_header_level;
@@ -295,29 +228,21 @@ cb_file_change (pfile, new_map)
       if (c_header_level && --c_header_level == 0)
        {
          if (new_map->sysp == 2)
       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
          --pending_lang_change;
        }
 #endif
-      pop_srcloc ();
-      
-      (*debug_hooks->end_source_file) (to_line);
+      input_location = new_map->start_location;
+
+      (*debug_hooks->end_source_file) (new_map->to_line);
     }
 
   update_header_times (new_map->to_file);
     }
 
   update_header_times (new_map->to_file);
-  in_system_header = new_map->sysp != 0;
-  input_filename = new_map->to_file;
-  lineno = to_line;
-  map = new_map;
-
-  /* Hook for C++.  */
-  extract_interface_info ();
+  input_location = new_map->start_location;
 }
 
 static void
 }
 
 static void
-cb_def_pragma (pfile, line)
-     cpp_reader *pfile;
-     unsigned int line;
+cb_def_pragma (cpp_reader *pfile, source_location loc)
 {
   /* Issue a warning message if we have been asked to do so.  Ignore
      unknown pragmas in system headers unless an explicit
 {
   /* Issue a warning message if we have been asked to do so.  Ignore
      unknown pragmas in system headers unless an explicit
@@ -326,6 +251,7 @@ cb_def_pragma (pfile, line)
     {
       const unsigned char *space, *name;
       const cpp_token *s;
     {
       const unsigned char *space, *name;
       const cpp_token *s;
+      location_t fe_loc = loc;
 
       space = name = (const unsigned char *) "";
       s = cpp_get_token (pfile);
 
       space = name = (const unsigned char *) "";
       s = cpp_get_token (pfile);
@@ -337,373 +263,56 @@ cb_def_pragma (pfile, line)
            name = cpp_token_as_text (pfile, s);
        }
 
            name = cpp_token_as_text (pfile, s);
        }
 
-      lineno = SOURCE_LINE (map, line);
-      warning ("ignoring #pragma %s %s", space, name);
+      warning_at (fe_loc, OPT_Wunknown_pragmas, "ignoring #pragma %s %s",
+                 space, name);
     }
 }
 
 /* #define callback for DWARF and DWARF2 debug info.  */
 static void
     }
 }
 
 /* #define callback for DWARF and DWARF2 debug info.  */
 static void
-cb_define (pfile, line, node)
-     cpp_reader *pfile;
-     unsigned int line;
-     cpp_hashnode *node;
+cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node)
 {
 {
-  (*debug_hooks->define) (SOURCE_LINE (map, line),
+  const struct line_map *map = linemap_lookup (line_table, loc);
+  (*debug_hooks->define) (SOURCE_LINE (map, loc),
                          (const char *) cpp_macro_definition (pfile, node));
 }
 
 /* #undef callback for DWARF and DWARF2 debug info.  */
 static void
                          (const char *) cpp_macro_definition (pfile, node));
 }
 
 /* #undef callback for DWARF and DWARF2 debug info.  */
 static void
-cb_undef (pfile, line, node)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     unsigned int line;
-     cpp_hashnode *node;
+cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc,
+         cpp_hashnode *node)
 {
 {
-  (*debug_hooks->undef) (SOURCE_LINE (map, line),
+  const struct line_map *map = linemap_lookup (line_table, loc);
+  (*debug_hooks->undef) (SOURCE_LINE (map, loc),
                         (const char *) NODE_NAME (node));
 }
                         (const char *) NODE_NAME (node));
 }
-
-#if 0 /* not yet */
-/* Returns nonzero if C is a universal-character-name.  Give an error if it
-   is not one which may appear in an identifier, as per [extendid].
-
-   Note that extended character support in identifiers has not yet been
-   implemented.  It is my personal opinion that this is not a desirable
-   feature.  Portable code cannot count on support for more than the basic
-   identifier character set.  */
-
-static inline int
-is_extended_char (c)
-     int c;
-{
-#ifdef TARGET_EBCDIC
-  return 0;
-#else
-  /* ASCII.  */
-  if (c < 0x7f)
-    return 0;
-
-  /* None of the valid chars are outside the Basic Multilingual Plane (the
-     low 16 bits).  */
-  if (c > 0xffff)
-    {
-      error ("universal-character-name '\\U%08x' not valid in identifier", c);
-      return 1;
-    }
-  
-  /* Latin */
-  if ((c >= 0x00c0 && c <= 0x00d6)
-      || (c >= 0x00d8 && c <= 0x00f6)
-      || (c >= 0x00f8 && c <= 0x01f5)
-      || (c >= 0x01fa && c <= 0x0217)
-      || (c >= 0x0250 && c <= 0x02a8)
-      || (c >= 0x1e00 && c <= 0x1e9a)
-      || (c >= 0x1ea0 && c <= 0x1ef9))
-    return 1;
-
-  /* Greek */
-  if ((c == 0x0384)
-      || (c >= 0x0388 && c <= 0x038a)
-      || (c == 0x038c)
-      || (c >= 0x038e && c <= 0x03a1)
-      || (c >= 0x03a3 && c <= 0x03ce)
-      || (c >= 0x03d0 && c <= 0x03d6)
-      || (c == 0x03da)
-      || (c == 0x03dc)
-      || (c == 0x03de)
-      || (c == 0x03e0)
-      || (c >= 0x03e2 && c <= 0x03f3)
-      || (c >= 0x1f00 && c <= 0x1f15)
-      || (c >= 0x1f18 && c <= 0x1f1d)
-      || (c >= 0x1f20 && c <= 0x1f45)
-      || (c >= 0x1f48 && c <= 0x1f4d)
-      || (c >= 0x1f50 && c <= 0x1f57)
-      || (c == 0x1f59)
-      || (c == 0x1f5b)
-      || (c == 0x1f5d)
-      || (c >= 0x1f5f && c <= 0x1f7d)
-      || (c >= 0x1f80 && c <= 0x1fb4)
-      || (c >= 0x1fb6 && c <= 0x1fbc)
-      || (c >= 0x1fc2 && c <= 0x1fc4)
-      || (c >= 0x1fc6 && c <= 0x1fcc)
-      || (c >= 0x1fd0 && c <= 0x1fd3)
-      || (c >= 0x1fd6 && c <= 0x1fdb)
-      || (c >= 0x1fe0 && c <= 0x1fec)
-      || (c >= 0x1ff2 && c <= 0x1ff4)
-      || (c >= 0x1ff6 && c <= 0x1ffc))
-    return 1;
-
-  /* Cyrillic */
-  if ((c >= 0x0401 && c <= 0x040d)
-      || (c >= 0x040f && c <= 0x044f)
-      || (c >= 0x0451 && c <= 0x045c)
-      || (c >= 0x045e && c <= 0x0481)
-      || (c >= 0x0490 && c <= 0x04c4)
-      || (c >= 0x04c7 && c <= 0x04c8)
-      || (c >= 0x04cb && c <= 0x04cc)
-      || (c >= 0x04d0 && c <= 0x04eb)
-      || (c >= 0x04ee && c <= 0x04f5)
-      || (c >= 0x04f8 && c <= 0x04f9))
-    return 1;
-
-  /* Armenian */
-  if ((c >= 0x0531 && c <= 0x0556)
-      || (c >= 0x0561 && c <= 0x0587))
-    return 1;
-
-  /* Hebrew */
-  if ((c >= 0x05d0 && c <= 0x05ea)
-      || (c >= 0x05f0 && c <= 0x05f4))
-    return 1;
-
-  /* Arabic */
-  if ((c >= 0x0621 && c <= 0x063a)
-      || (c >= 0x0640 && c <= 0x0652)
-      || (c >= 0x0670 && c <= 0x06b7)
-      || (c >= 0x06ba && c <= 0x06be)
-      || (c >= 0x06c0 && c <= 0x06ce)
-      || (c >= 0x06e5 && c <= 0x06e7))
-    return 1;
-
-  /* Devanagari */
-  if ((c >= 0x0905 && c <= 0x0939)
-      || (c >= 0x0958 && c <= 0x0962))
-    return 1;
-
-  /* Bengali */
-  if ((c >= 0x0985 && c <= 0x098c)
-      || (c >= 0x098f && c <= 0x0990)
-      || (c >= 0x0993 && c <= 0x09a8)
-      || (c >= 0x09aa && c <= 0x09b0)
-      || (c == 0x09b2)
-      || (c >= 0x09b6 && c <= 0x09b9)
-      || (c >= 0x09dc && c <= 0x09dd)
-      || (c >= 0x09df && c <= 0x09e1)
-      || (c >= 0x09f0 && c <= 0x09f1))
-    return 1;
-
-  /* Gurmukhi */
-  if ((c >= 0x0a05 && c <= 0x0a0a)
-      || (c >= 0x0a0f && c <= 0x0a10)
-      || (c >= 0x0a13 && c <= 0x0a28)
-      || (c >= 0x0a2a && c <= 0x0a30)
-      || (c >= 0x0a32 && c <= 0x0a33)
-      || (c >= 0x0a35 && c <= 0x0a36)
-      || (c >= 0x0a38 && c <= 0x0a39)
-      || (c >= 0x0a59 && c <= 0x0a5c)
-      || (c == 0x0a5e))
-    return 1;
-
-  /* Gujarati */
-  if ((c >= 0x0a85 && c <= 0x0a8b)
-      || (c == 0x0a8d)
-      || (c >= 0x0a8f && c <= 0x0a91)
-      || (c >= 0x0a93 && c <= 0x0aa8)
-      || (c >= 0x0aaa && c <= 0x0ab0)
-      || (c >= 0x0ab2 && c <= 0x0ab3)
-      || (c >= 0x0ab5 && c <= 0x0ab9)
-      || (c == 0x0ae0))
-    return 1;
-
-  /* Oriya */
-  if ((c >= 0x0b05 && c <= 0x0b0c)
-      || (c >= 0x0b0f && c <= 0x0b10)
-      || (c >= 0x0b13 && c <= 0x0b28)
-      || (c >= 0x0b2a && c <= 0x0b30)
-      || (c >= 0x0b32 && c <= 0x0b33)
-      || (c >= 0x0b36 && c <= 0x0b39)
-      || (c >= 0x0b5c && c <= 0x0b5d)
-      || (c >= 0x0b5f && c <= 0x0b61))
-    return 1;
-
-  /* Tamil */
-  if ((c >= 0x0b85 && c <= 0x0b8a)
-      || (c >= 0x0b8e && c <= 0x0b90)
-      || (c >= 0x0b92 && c <= 0x0b95)
-      || (c >= 0x0b99 && c <= 0x0b9a)
-      || (c == 0x0b9c)
-      || (c >= 0x0b9e && c <= 0x0b9f)
-      || (c >= 0x0ba3 && c <= 0x0ba4)
-      || (c >= 0x0ba8 && c <= 0x0baa)
-      || (c >= 0x0bae && c <= 0x0bb5)
-      || (c >= 0x0bb7 && c <= 0x0bb9))
-    return 1;
-
-  /* Telugu */
-  if ((c >= 0x0c05 && c <= 0x0c0c)
-      || (c >= 0x0c0e && c <= 0x0c10)
-      || (c >= 0x0c12 && c <= 0x0c28)
-      || (c >= 0x0c2a && c <= 0x0c33)
-      || (c >= 0x0c35 && c <= 0x0c39)
-      || (c >= 0x0c60 && c <= 0x0c61))
-    return 1;
-
-  /* Kannada */
-  if ((c >= 0x0c85 && c <= 0x0c8c)
-      || (c >= 0x0c8e && c <= 0x0c90)
-      || (c >= 0x0c92 && c <= 0x0ca8)
-      || (c >= 0x0caa && c <= 0x0cb3)
-      || (c >= 0x0cb5 && c <= 0x0cb9)
-      || (c >= 0x0ce0 && c <= 0x0ce1))
-    return 1;
-
-  /* Malayalam */
-  if ((c >= 0x0d05 && c <= 0x0d0c)
-      || (c >= 0x0d0e && c <= 0x0d10)
-      || (c >= 0x0d12 && c <= 0x0d28)
-      || (c >= 0x0d2a && c <= 0x0d39)
-      || (c >= 0x0d60 && c <= 0x0d61))
-    return 1;
-
-  /* Thai */
-  if ((c >= 0x0e01 && c <= 0x0e30)
-      || (c >= 0x0e32 && c <= 0x0e33)
-      || (c >= 0x0e40 && c <= 0x0e46)
-      || (c >= 0x0e4f && c <= 0x0e5b))
-    return 1;
-
-  /* Lao */
-  if ((c >= 0x0e81 && c <= 0x0e82)
-      || (c == 0x0e84)
-      || (c == 0x0e87)
-      || (c == 0x0e88)
-      || (c == 0x0e8a)
-      || (c == 0x0e0d)
-      || (c >= 0x0e94 && c <= 0x0e97)
-      || (c >= 0x0e99 && c <= 0x0e9f)
-      || (c >= 0x0ea1 && c <= 0x0ea3)
-      || (c == 0x0ea5)
-      || (c == 0x0ea7)
-      || (c == 0x0eaa)
-      || (c == 0x0eab)
-      || (c >= 0x0ead && c <= 0x0eb0)
-      || (c == 0x0eb2)
-      || (c == 0x0eb3)
-      || (c == 0x0ebd)
-      || (c >= 0x0ec0 && c <= 0x0ec4)
-      || (c == 0x0ec6))
-    return 1;
-
-  /* Georgian */
-  if ((c >= 0x10a0 && c <= 0x10c5)
-      || (c >= 0x10d0 && c <= 0x10f6))
-    return 1;
-
-  /* Hiragana */
-  if ((c >= 0x3041 && c <= 0x3094)
-      || (c >= 0x309b && c <= 0x309e))
-    return 1;
-
-  /* Katakana */
-  if ((c >= 0x30a1 && c <= 0x30fe))
-    return 1;
-
-  /* Bopmofo */
-  if ((c >= 0x3105 && c <= 0x312c))
-    return 1;
-
-  /* Hangul */
-  if ((c >= 0x1100 && c <= 0x1159)
-      || (c >= 0x1161 && c <= 0x11a2)
-      || (c >= 0x11a8 && c <= 0x11f9))
-    return 1;
-
-  /* CJK Unified Ideographs */
-  if ((c >= 0xf900 && c <= 0xfa2d)
-      || (c >= 0xfb1f && c <= 0xfb36)
-      || (c >= 0xfb38 && c <= 0xfb3c)
-      || (c == 0xfb3e)
-      || (c >= 0xfb40 && c <= 0xfb41)
-      || (c >= 0xfb42 && c <= 0xfb44)
-      || (c >= 0xfb46 && c <= 0xfbb1)
-      || (c >= 0xfbd3 && c <= 0xfd3f)
-      || (c >= 0xfd50 && c <= 0xfd8f)
-      || (c >= 0xfd92 && c <= 0xfdc7)
-      || (c >= 0xfdf0 && c <= 0xfdfb)
-      || (c >= 0xfe70 && c <= 0xfe72)
-      || (c == 0xfe74)
-      || (c >= 0xfe76 && c <= 0xfefc)
-      || (c >= 0xff21 && c <= 0xff3a)
-      || (c >= 0xff41 && c <= 0xff5a)
-      || (c >= 0xff66 && c <= 0xffbe)
-      || (c >= 0xffc2 && c <= 0xffc7)
-      || (c >= 0xffca && c <= 0xffcf)
-      || (c >= 0xffd2 && c <= 0xffd7)
-      || (c >= 0xffda && c <= 0xffdc)
-      || (c >= 0x4e00 && c <= 0x9fa5))
-    return 1;
-
-  error ("universal-character-name '\\u%04x' not valid in identifier", c);
-  return 1;
-#endif
-}
-
-/* Add the UTF-8 representation of C to the token_buffer.  */
-
-static void
-utf8_extend_token (c)
-     int c;
-{
-  int shift, mask;
-
-  if      (c <= 0x0000007f)
-    {
-      extend_token (c);
-      return;
-    }
-  else if (c <= 0x000007ff)
-    shift = 6, mask = 0xc0;
-  else if (c <= 0x0000ffff)
-    shift = 12, mask = 0xe0;
-  else if (c <= 0x001fffff)
-    shift = 18, mask = 0xf0;
-  else if (c <= 0x03ffffff)
-    shift = 24, mask = 0xf8;
-  else
-    shift = 30, mask = 0xfc;
-
-  extend_token (mask | (c >> shift));
-  do
-    {
-      shift -= 6;
-      extend_token ((unsigned char) (0x80 | (c >> shift)));
-    }
-  while (shift);
-}
-#endif
 \f
 \f
-int
-c_lex (value)
-     tree *value;
+/* 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, location_t *loc, unsigned char *cpp_flags,
+                 int lex_flags)
 {
 {
+  static bool no_more_pch;
   const cpp_token *tok;
   const cpp_token *tok;
+  enum cpp_ttype type;
+  unsigned char add_flags = 0;
 
 
-  retry:
   timevar_push (TV_CPP);
   timevar_push (TV_CPP);
-  do
-    tok = cpp_get_token (parse_in);
-  while (tok->type == CPP_PADDING);
-  timevar_pop (TV_CPP);
-
-  /* The C++ front end does horrible things with the current line
-     number.  To ensure an accurate line number, we must reset it
-     every time we return a token.  */
-  lineno = src_lineno;
+ retry:
+  tok = cpp_get_token_with_location (parse_in, loc);
+  type = tok->type;
 
 
-  *value = NULL_TREE;
-  switch (tok->type)
+ retry_after_at:
+  switch (type)
     {
     {
-    /* Issue this error here, where we can get at tok->val.c.  */
-    case CPP_OTHER:
-      if (ISGRAPH (tok->val.c))
-       error ("stray '%c' in program", tok->val.c);
-      else
-       error ("stray '\\%o' in program", tok->val.c);
+    case CPP_PADDING:
       goto retry;
       goto retry;
-      
+
     case CPP_NAME:
     case CPP_NAME:
-      *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node));
+      *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
       break;
 
     case CPP_NUMBER:
       break;
 
     case CPP_NUMBER:
@@ -715,9 +324,14 @@ c_lex (value)
          case CPP_N_INVALID:
            /* cpplib has issued an error.  */
            *value = error_mark_node;
          case CPP_N_INVALID:
            /* cpplib has issued an error.  */
            *value = error_mark_node;
+           errorcount++;
            break;
 
          case CPP_N_INTEGER:
            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;
 
            *value = interpret_integer (tok, flags);
            break;
 
@@ -726,43 +340,138 @@ c_lex (value)
            break;
 
          default:
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
       }
       break;
 
          }
       }
       break;
 
+    case CPP_ATSIGN:
+      /* An @ may give the next token special significance in Objective-C.  */
+      if (c_dialect_objc ())
+       {
+         location_t atloc = *loc;
+         location_t newloc;
+
+       retry_at:
+         tok = cpp_get_token_with_location (parse_in, &newloc);
+         type = tok->type;
+         switch (type)
+           {
+           case CPP_PADDING:
+             goto retry_at;
+
+           case CPP_STRING:
+           case CPP_WSTRING:
+           case CPP_STRING16:
+           case CPP_STRING32:
+           case CPP_UTF8STRING:
+             type = lex_string (tok, value, true, true);
+             break;
+
+           case CPP_NAME:
+             *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
+             if (objc_is_reserved_word (*value))
+               {
+                 type = CPP_AT_NAME;
+                 break;
+               }
+             /* FALLTHROUGH */
+
+           default:
+             /* ... or not.  */
+             error_at (atloc, "stray %<@%> in program");
+             *loc = newloc;
+             goto retry_after_at;
+           }
+         break;
+       }
+
+      /* FALLTHROUGH */
+    case CPP_HASH:
+    case CPP_PASTE:
+      {
+       unsigned char name[8];
+
+       *cpp_spell_token (parse_in, tok, name, true) = 0;
+
+       error ("stray %qs in program", name);
+      }
+
+      goto retry;
+
+    case CPP_OTHER:
+      {
+       cppchar_t c = tok->val.str.text[0];
+
+       if (c == '"' || c == '\'')
+         error ("missing terminating %c character", (int) c);
+       else if (ISGRAPH (c))
+         error ("stray %qc in program", (int) c);
+       else
+         error ("stray %<\\%o%> in program", (int) c);
+      }
+      goto retry;
+
     case CPP_CHAR:
     case CPP_WCHAR:
     case CPP_CHAR:
     case CPP_WCHAR:
+    case CPP_CHAR16:
+    case CPP_CHAR32:
       *value = lex_charconst (tok);
       break;
 
     case CPP_STRING:
     case CPP_WSTRING:
       *value = lex_charconst (tok);
       break;
 
     case CPP_STRING:
     case CPP_WSTRING:
-      *value = lex_string (tok->val.str.text, tok->val.str.len,
-                          tok->type == CPP_WSTRING);
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_UTF8STRING:
+      if ((lex_flags & C_LEX_STRING_NO_JOIN) == 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.  */
     case CPP_HEADER_NAME:
     case CPP_COMMENT:
     case CPP_MACRO_ARG:
       break;
 
       /* These tokens should not be visible outside cpplib.  */
     case CPP_HEADER_NAME:
     case CPP_COMMENT:
     case CPP_MACRO_ARG:
-      abort ();
+      gcc_unreachable ();
 
 
-    default: break;
+    default:
+      *value = NULL_TREE;
+      break;
+    }
+
+  if (cpp_flags)
+    *cpp_flags = tok->flags | add_flags;
+
+  if (!no_more_pch)
+    {
+      no_more_pch = true;
+      c_common_no_more_pch ();
     }
 
     }
 
-  return tok->type;
+  timevar_pop (TV_CPP);
+
+  return type;
 }
 
 /* Returns the narrowest C-visible unsigned type, starting with the
 }
 
 /* Returns the narrowest C-visible unsigned type, starting with the
-   minimum specified by FLAGS, that can fit VALUE, or itk_none if
+   minimum specified by FLAGS, that can fit HIGH:LOW, or itk_none if
    there isn't one.  */
    there isn't one.  */
+
 static enum integer_type_kind
 static enum integer_type_kind
-narrowest_unsigned_type (value, flags)
-     tree value;
-     unsigned int flags;
+narrowest_unsigned_type (unsigned HOST_WIDE_INT low,
+                        unsigned HOST_WIDE_INT high,
+                        unsigned int flags)
 {
 {
-  enum integer_type_kind itk;
+  int itk;
 
   if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
     itk = itk_unsigned_int;
 
   if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
     itk = itk_unsigned_int;
@@ -771,24 +480,25 @@ narrowest_unsigned_type (value, flags)
   else
     itk = itk_unsigned_long_long;
 
   else
     itk = itk_unsigned_long_long;
 
-  /* int_fits_type_p must think the type of its first argument is
-     wider than its second argument, or it won't do the proper check.  */
-  TREE_TYPE (value) = widest_unsigned_literal_type_node;
-
   for (; itk < itk_none; itk += 2 /* skip unsigned types */)
   for (; itk < itk_none; itk += 2 /* skip unsigned types */)
-    if (int_fits_type_p (value, integer_types[itk]))
-      return itk;
+    {
+      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
+             && TREE_INT_CST_LOW (upper) >= low))
+       return (enum integer_type_kind) itk;
+    }
 
   return itk_none;
 }
 
 /* Ditto, but narrowest signed type.  */
 static enum integer_type_kind
 
   return itk_none;
 }
 
 /* Ditto, but narrowest signed type.  */
 static enum integer_type_kind
-narrowest_signed_type (value, flags)
-     tree value;
-     unsigned int flags;
+narrowest_signed_type (unsigned HOST_WIDE_INT low,
+                      unsigned HOST_WIDE_INT high, unsigned int flags)
 {
 {
-  enum integer_type_kind itk;
+  int itk;
 
   if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
     itk = itk_int;
 
   if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
     itk = itk_int;
@@ -797,22 +507,23 @@ narrowest_signed_type (value, flags)
   else
     itk = itk_long_long;
 
   else
     itk = itk_long_long;
 
-  /* int_fits_type_p must think the type of its first argument is
-     wider than its second argument, or it won't do the proper check.  */
-  TREE_TYPE (value) = widest_unsigned_literal_type_node;
 
   for (; itk < itk_none; itk += 2 /* skip signed types */)
 
   for (; itk < itk_none; itk += 2 /* skip signed types */)
-    if (int_fits_type_p (value, integer_types[itk]))
-      return itk;
+    {
+      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
+             && TREE_INT_CST_LOW (upper) >= low))
+       return (enum integer_type_kind) itk;
+    }
 
   return itk_none;
 }
 
 /* Interpret TOKEN, an integer with FLAGS as classified by cpplib.  */
 static tree
 
   return itk_none;
 }
 
 /* Interpret TOKEN, an integer with FLAGS as classified by cpplib.  */
 static tree
-interpret_integer (token, flags)
-     const cpp_token *token;
-     unsigned int flags;
+interpret_integer (const cpp_token *token, unsigned int flags)
 {
   tree value, type;
   enum integer_type_kind itk;
 {
   tree value, type;
   enum integer_type_kind itk;
@@ -821,18 +532,19 @@ interpret_integer (token, flags)
 
   integer = cpp_interpret_integer (parse_in, token, flags);
   integer = cpp_num_sign_extend (integer, options->precision);
 
   integer = cpp_interpret_integer (parse_in, token, flags);
   integer = cpp_num_sign_extend (integer, options->precision);
-  value = build_int_2_wide (integer.low, integer.high);
 
   /* The type of a constant with a U suffix is straightforward.  */
   if (flags & CPP_N_UNSIGNED)
 
   /* The type of a constant with a U suffix is straightforward.  */
   if (flags & CPP_N_UNSIGNED)
-    itk = narrowest_unsigned_type (value, flags);
+    itk = narrowest_unsigned_type (integer.low, integer.high, flags);
   else
     {
       /* The type of a potentially-signed integer constant varies
         depending on the base it's in, the standard in use, and the
         length suffixes.  */
   else
     {
       /* The type of a potentially-signed integer constant varies
         depending on the base it's in, the standard in use, and the
         length suffixes.  */
-      enum integer_type_kind itk_u = narrowest_unsigned_type (value, flags);
-      enum integer_type_kind itk_s = narrowest_signed_type (value, flags);
+      enum integer_type_kind itk_u
+       = narrowest_unsigned_type (integer.low, integer.high, flags);
+      enum integer_type_kind itk_s
+       = narrowest_signed_type (integer.low, integer.high, flags);
 
       /* In both C89 and C99, octal and hex constants may be signed or
         unsigned, whichever fits tighter.  We do not warn about this
 
       /* In both C89 and C99, octal and hex constants may be signed or
         unsigned, whichever fits tighter.  We do not warn about this
@@ -856,10 +568,11 @@ interpret_integer (token, flags)
                  if (itk_u < itk_unsigned_long)
                    itk_u = itk_unsigned_long;
                  itk = itk_u;
                  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");
            }
        }
     }
            }
        }
     }
@@ -870,19 +583,24 @@ interpret_integer (token, flags)
            ? widest_unsigned_literal_type_node
            : widest_integer_literal_type_node);
   else
            ? widest_unsigned_literal_type_node
            : widest_integer_literal_type_node);
   else
-    type = integer_types[itk];
-
-  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",
-            (flags & CPP_N_UNSIGNED) ? "unsigned long" : "long");
+    {
+      type = integer_types[itk];
+      if (itk > itk_unsigned_long
+         && (flags & CPP_N_WIDTH) != CPP_N_LARGE)
+       emit_diagnostic
+         ((c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99)
+          ? DK_PEDWARN : DK_WARNING,
+          input_location, OPT_Wlong_long,
+          (flags & CPP_N_UNSIGNED)
+          ? "integer constant is too large for %<unsigned long%> type"
+          : "integer constant is too large for %<long%> type");
+    }
 
 
-  TREE_TYPE (value) = type;
+  value = build_int_cst_wide (type, integer.low, integer.high);
 
   /* Convert imaginary to a complex type.  */
   if (flags & CPP_N_IMAGINARY)
 
   /* Convert imaginary to a complex type.  */
   if (flags & CPP_N_IMAGINARY)
-    value = build_complex (NULL_TREE, convert (type, integer_zero_node), value);
+    value = build_complex (NULL_TREE, build_int_cst (type, 0), value);
 
   return value;
 }
 
   return value;
 }
@@ -890,200 +608,444 @@ interpret_integer (token, flags)
 /* Interpret TOKEN, a floating point number with FLAGS as classified
    by cpplib.  */
 static tree
 /* Interpret TOKEN, a floating point number with FLAGS as classified
    by cpplib.  */
 static tree
-interpret_float (token, flags)
-     const cpp_token *token;
-     unsigned int flags;
+interpret_float (const cpp_token *token, unsigned int flags)
 {
   tree type;
 {
   tree type;
+  tree const_type;
   tree value;
   REAL_VALUE_TYPE real;
   tree value;
   REAL_VALUE_TYPE real;
+  REAL_VALUE_TYPE real_trunc;
   char *copy;
   size_t copylen;
   char *copy;
   size_t copylen;
-  const char *typename;
 
 
-  /* FIXME: make %T work in error/warning, then we don't need typename.  */
-  if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
-    {
-      type = long_double_type_node;
-      typename = "long double";
-    }
-  else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
-          || flag_single_precision_constant)
+  /* Default (no suffix) depends on whether the FLOAT_CONST_DECIMAL64
+     pragma has been used and is either double or _Decimal64.  Types
+     that are not allowed with decimal float default to double.  */
+  if (flags & CPP_N_DEFAULT)
     {
     {
-      type = float_type_node;
-      typename = "float";
+      flags ^= CPP_N_DEFAULT;
+      flags |= CPP_N_MEDIUM;
+
+      if (((flags & CPP_N_HEX) == 0) && ((flags & CPP_N_IMAGINARY) == 0))
+       {
+         warning (OPT_Wunsuffixed_float_constants,
+                  "unsuffixed float constant");
+         if (float_const_decimal64_p ())
+           flags |= CPP_N_DFLOAT;
+       }
     }
     }
+
+  /* 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
   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
+         pedwarn (input_location, OPT_pedantic, "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;
+    else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
+            || flag_single_precision_constant)
+      type = float_type_node;
+    else
       type = double_type_node;
       type = double_type_node;
-      typename = "double";
-    }
+
+  const_type = excess_precision_type (type);
+  if (!const_type)
+    const_type = type;
 
   /* 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;
 
   /* 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 = alloca (copylen + 1);
+  copy = (char *) alloca (copylen + 1);
   memcpy (copy, token->val.str.text, copylen);
   copy[copylen] = '\0';
 
   memcpy (copy, token->val.str.text, copylen);
   copy[copylen] = '\0';
 
-  real_from_string (&real, copy);
-  real_convert (&real, TYPE_MODE (type), &real);
-
-  /* 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\"", typename);
+  real_from_string3 (&real, copy, TYPE_MODE (const_type));
+  if (const_type != type)
+    /* Diagnosing if the result of converting the value with excess
+       precision to the semantic type would overflow (with associated
+       double rounding) is more appropriate than diagnosing if the
+       result of converting the string directly to the semantic type
+       would overflow.  */
+    real_convert (&real_trunc, TYPE_MODE (type), &real);
+
+  /* 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)
+      || (const_type != type && REAL_VALUE_ISINF (real_trunc)))
+    {
+      if (!MODE_HAS_INFINITIES (TYPE_MODE (type)))
+       pedwarn (input_location, 0, "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)
+          || (const_type != type && REAL_VALUES_EQUAL (real_trunc, 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.  */
 
   /* Create a node with determined type and value.  */
-  value = build_real (type, real);
+  value = build_real (const_type, real);
   if (flags & CPP_N_IMAGINARY)
   if (flags & CPP_N_IMAGINARY)
-    value = build_complex (NULL_TREE, convert (type, integer_zero_node), value);
+    value = build_complex (NULL_TREE, convert (const_type, integer_zero_node),
+                          value);
+
+  if (type != const_type)
+    value = build1 (EXCESS_PRECISION_EXPR, type, value);
 
   return value;
 }
 
 
   return value;
 }
 
+/* Interpret TOKEN, a fixed-point number with FLAGS as classified
+   by cpplib.  */
+
 static tree
 static tree
-lex_string (str, len, wide)
-     const unsigned char *str;
-     unsigned int len;
-     int wide;
+interpret_fixed (const cpp_token *token, unsigned int flags)
 {
 {
+  tree type;
   tree value;
   tree value;
-  char *buf = alloca ((len + 1) * (wide ? WCHAR_BYTES : 1));
-  char *q = buf;
-  const unsigned char *p = str, *limit = str + len;
-  cppchar_t c;
-
-#ifdef MULTIBYTE_CHARS
-  /* Reset multibyte conversion state.  */
-  (void) local_mbtowc (NULL, NULL, 0);
-#endif
+  FIXED_VALUE_TYPE fixed;
+  char *copy;
+  size_t copylen;
 
 
-  while (p < limit)
-    {
-#ifdef MULTIBYTE_CHARS
-      wchar_t wc;
-      int char_len;
+  copylen = token->val.str.len;
 
 
-      char_len = local_mbtowc (&wc, (const char *) p, limit - p);
-      if (char_len == -1)
+  if (flags & CPP_N_FRACT) /* _Fract.  */
+    {
+      if (flags & CPP_N_UNSIGNED) /* Unsigned _Fract.  */
        {
        {
-         warning ("ignoring invalid multibyte character");
-         char_len = 1;
-         c = *p++;
+         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
+      else /* Signed _Fract.  */
        {
        {
-         p += char_len;
-         c = wc;
-       }
-#else
-      c = *p++;
-#endif
-
-      if (c == '\\' && !ignore_escape_flag)
-       c = cpp_parse_escape (parse_in, &p, limit, wide);
-       
-      /* Add this single character into the buffer either as a wchar_t,
-        a multibyte sequence, or as a single byte.  */
-      if (wide)
+         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.  */
        {
        {
-         unsigned charwidth = TYPE_PRECISION (char_type_node);
-         unsigned bytemask = (1 << charwidth) - 1;
-         int byte;
-
-         for (byte = 0; byte < WCHAR_BYTES; ++byte)
+         if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
            {
            {
-             int n;
-             if (byte >= (int) sizeof (c))
-               n = 0;
-             else
-               n = (c >> (byte * charwidth)) & bytemask;
-             if (BYTES_BIG_ENDIAN)
-               q[WCHAR_BYTES - byte - 1] = n;
-             else
-               q[byte] = n;
+             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;
            }
            }
-         q += WCHAR_BYTES;
        }
        }
-#ifdef MULTIBYTE_CHARS
-      else if (char_len > 1)
-       {
-         /* We're dealing with a multibyte character.  */
-         for ( ; char_len >0; --char_len)
+      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
            {
            {
-             *q++ = *(p - char_len);
+             type = accum_type_node;
+             copylen --;
            }
        }
            }
        }
-#endif
-      else
+    }
+
+  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, WSTRING, STRING16, STRING32 and/or
+   UTF8STRING 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 indicates whether an '@' token
+   preceded the incoming token.
+   Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING,
+   CPP_STRING32, CPP_STRING16, CPP_UTF8STRING, or CPP_OBJC_STRING).
+
+   This is unfortunately more work than it should be.  If any of the
+   strings in the series has an L prefix, the result is a wide string
+   (6.4.5p4).  Whether or not the result is a wide string affects the
+   meaning of octal and hexadecimal escapes (6.4.4.4p6,9).  But escape
+   sequences do not continue across the boundary between two strings in
+   a series (6.4.5p7), so we must not lose the boundaries.  Therefore
+   cpp_interpret_string takes a vector of cpp_string structures, which
+   we must arrange to provide.  */
+
+static enum cpp_ttype
+lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
+{
+  tree value;
+  size_t concats = 0;
+  struct obstack str_ob;
+  cpp_string istr;
+  enum cpp_ttype type = tok->type;
+
+  /* Try to avoid the overhead of creating and destroying an obstack
+     for the common case of just one string.  */
+  cpp_string str = tok->val.str;
+  cpp_string *strs = &str;
+
+ retry:
+  tok = cpp_get_token (parse_in);
+  switch (tok->type)
+    {
+    case CPP_PADDING:
+      goto retry;
+    case CPP_ATSIGN:
+      if (c_dialect_objc ())
+       {
+         objc_string = true;
+         goto retry;
+       }
+      /* FALLTHROUGH */
+
+    default:
+      break;
+
+    case CPP_WSTRING:
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_UTF8STRING:
+      if (type != tok->type)
+       {
+         if (type == CPP_STRING)
+           type = tok->type;
+         else
+           error ("unsupported non-standard concatenation of string literals");
+       }
+
+    case CPP_STRING:
+      if (!concats)
        {
        {
-         *q++ = c;
+         gcc_obstack_init (&str_ob);
+         obstack_grow (&str_ob, &str, sizeof (cpp_string));
        }
        }
+
+      concats++;
+      obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+      goto retry;
     }
 
     }
 
-  /* Terminate the string value, either with a single byte zero
-     or with a wide zero.  */
+  /* We have read one more token than we want.  */
+  _cpp_backup_tokens (parse_in, 1);
+  if (concats)
+    strs = XOBFINISH (&str_ob, cpp_string *);
+
+  if (concats && !objc_string && !in_system_header)
+    warning (OPT_Wtraditional,
+            "traditional C rejects string constant concatenation");
 
 
-  if (wide)
+  if ((translate
+       ? cpp_interpret_string : cpp_interpret_string_notranslate)
+      (parse_in, strs, concats + 1, &istr, type))
     {
     {
-      memset (q, 0, WCHAR_BYTES);
-      q += WCHAR_BYTES;
+      value = build_string (istr.len, (const char *) istr.text);
+      free (CONST_CAST (unsigned char *, istr.text));
     }
   else
     {
     }
   else
     {
-      *q++ = '\0';
+      /* Callers cannot generally handle error_mark_node in this context,
+        so return the empty string instead.  cpp_interpret_string has
+        issued an error.  */
+      switch (type)
+       {
+       default:
+       case CPP_STRING:
+       case CPP_UTF8STRING:
+         value = build_string (1, "");
+         break;
+       case CPP_STRING16:
+         value = build_string (TYPE_PRECISION (char16_type_node)
+                               / TYPE_PRECISION (char_type_node),
+                               "\0");  /* char16_t is 16 bits */
+         break;
+       case CPP_STRING32:
+         value = build_string (TYPE_PRECISION (char32_type_node)
+                               / TYPE_PRECISION (char_type_node),
+                               "\0\0\0");  /* char32_t is 32 bits */
+         break;
+       case CPP_WSTRING:
+         value = build_string (TYPE_PRECISION (wchar_type_node)
+                               / TYPE_PRECISION (char_type_node),
+                               "\0\0\0");  /* widest supported wchar_t
+                                              is 32 bits */
+         break;
+        }
     }
 
     }
 
-  value = build_string (q - buf, buf);
+  switch (type)
+    {
+    default:
+    case CPP_STRING:
+    case CPP_UTF8STRING:
+      TREE_TYPE (value) = char_array_type_node;
+      break;
+    case CPP_STRING16:
+      TREE_TYPE (value) = char16_array_type_node;
+      break;
+    case CPP_STRING32:
+      TREE_TYPE (value) = char32_array_type_node;
+      break;
+    case CPP_WSTRING:
+      TREE_TYPE (value) = wchar_array_type_node;
+    }
+  *valp = fix_string_type (value);
 
 
-  if (wide)
-    TREE_TYPE (value) = wchar_array_type_node;
-  else
-    TREE_TYPE (value) = char_array_type_node;
-  return value;
+  if (concats)
+    obstack_free (&str_ob, 0);
+
+  return objc_string ? CPP_OBJC_STRING : type;
 }
 
 /* Converts a (possibly wide) character constant token into a tree.  */
 static tree
 }
 
 /* Converts a (possibly wide) character constant token into a tree.  */
 static tree
-lex_charconst (token)
-     const cpp_token *token;
+lex_charconst (const cpp_token *token)
 {
   cppchar_t result;
   tree type, value;
   unsigned int chars_seen;
 {
   cppchar_t result;
   tree type, value;
   unsigned int chars_seen;
-  int unsignedp;
+  int unsignedp = 0;
 
   result = cpp_interpret_charconst (parse_in, token,
 
   result = cpp_interpret_charconst (parse_in, token,
-                                   &chars_seen, &unsignedp);
-
-  /* Cast to cppchar_signed_t to get correct sign-extension of RESULT
-     before possibly widening to HOST_WIDE_INT for build_int_2.  */
-  if (unsignedp || (cppchar_signed_t) result >= 0)
-    value = build_int_2 (result, 0);
-  else
-    value = build_int_2 ((cppchar_signed_t) result, -1);
+                                   &chars_seen, &unsignedp);
 
   if (token->type == CPP_WCHAR)
     type = wchar_type_node;
 
   if (token->type == CPP_WCHAR)
     type = wchar_type_node;
+  else if (token->type == CPP_CHAR32)
+    type = char32_type_node;
+  else if (token->type == CPP_CHAR16)
+    type = char16_type_node;
   /* In C, a character constant has type 'int'.
      In C++ 'char', but multi-char charconsts have type 'int'.  */
   /* In C, a character constant has type 'int'.
      In C++ 'char', but multi-char charconsts have type 'int'.  */
-  else if ((c_language == clk_c) || chars_seen > 1)
+  else if (!c_dialect_cxx () || chars_seen > 1)
     type = integer_type_node;
   else
     type = char_type_node;
 
     type = integer_type_node;
   else
     type = char_type_node;
 
-  TREE_TYPE (value) = type;
+  /* Cast to cppchar_signed_t to get correct sign-extension of RESULT
+     before possibly widening to HOST_WIDE_INT for build_int_cst.  */
+  if (unsignedp || (cppchar_signed_t) result >= 0)
+    value = build_int_cst_wide (type, result, 0);
+  else
+    value = build_int_cst_wide (type, (cppchar_signed_t) result, -1);
+
   return value;
 }
   return value;
 }