OSDN Git Service

* var-tracking.c (vt_expand_loc_callback): Don't run
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index 4b87561..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
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 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
-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
@@ -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
-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"
@@ -25,7 +25,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 
 #include "real.h"
-#include "rtl.h"
+#include "fixed-value.h"
 #include "tree.h"
 #include "input.h"
 #include "output.h"
@@ -37,36 +37,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "c-pragma.h"
 #include "toplev.h"
 #include "intl.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 *);
@@ -82,10 +71,8 @@ init_c_lex (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)
     {
@@ -105,7 +92,7 @@ init_c_lex (void)
   /* 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;
@@ -118,6 +105,11 @@ get_fileinfo (const char *name)
   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;
@@ -165,7 +157,7 @@ dump_time_statistics (void)
   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);
@@ -177,14 +169,14 @@ cb_ident (cpp_reader * ARG_UNUSED (pfile),
          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))
+      if (cpp_interpret_string (pfile, str, 1, &cstr, CPP_STRING))
        {
          ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text);
-         free ((void *)cstr.text);
+         free (CONST_CAST (unsigned char *, cstr.text));
        }
     }
 #endif
@@ -197,15 +189,7 @@ cb_line_change (cpp_reader * ARG_UNUSED (pfile), const cpp_token *token,
                int parsing_args)
 {
   if (token->type != CPP_EOF && !parsing_args)
-#ifdef USE_MAPPED_LOCATION
     input_location = token->src_loc;
-#else
-    {
-      source_location loc = token->src_loc;
-      const struct line_map *map = linemap_lookup (&line_table, loc);
-      input_line = SOURCE_LINE (map, loc);
-    }
-#endif
 }
 
 void
@@ -218,20 +202,15 @@ fe_file_change (const struct line_map *new_map)
     {
       /* 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);
-
-         input_location = included_at;
-         push_srcloc (new_map->start_location);
-#else
-          int included_at = LAST_SOURCE_LINE (new_map - 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);
 
-         input_line = included_at;
-         push_srcloc (new_map->to_file, 1);
-#endif
-         (*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;
@@ -249,26 +228,17 @@ fe_file_change (const struct line_map *new_map)
       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
-      pop_srcloc ();
+      input_location = new_map->start_location;
 
       (*debug_hooks->end_source_file) (new_map->to_line);
     }
 
   update_header_times (new_map->to_file);
-  in_system_header = new_map->sysp != 0;
-#ifdef USE_MAPPED_LOCATION
   input_location = new_map->start_location;
-#else
-  input_filename = new_map->to_file;
-  input_line = new_map->to_line;
-#endif
-
-  /* Hook for C++.  */
-  extract_interface_info ();
 }
 
 static void
@@ -279,11 +249,9 @@ cb_def_pragma (cpp_reader *pfile, source_location loc)
      -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;
+      location_t fe_loc = loc;
 
       space = name = (const unsigned char *) "";
       s = cpp_get_token (pfile);
@@ -295,12 +263,8 @@ cb_def_pragma (cpp_reader *pfile, source_location loc)
            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_at (fe_loc, OPT_Wunknown_pragmas, "ignoring #pragma %s %s",
+                 space, name);
     }
 }
 
@@ -308,7 +272,7 @@ cb_def_pragma (cpp_reader *pfile, source_location loc)
 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));
 }
@@ -318,39 +282,37 @@ static void
 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 ();
+  tok = cpp_get_token_with_location (parse_in, loc);
+  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));
+      *value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
       break;
 
     case CPP_NUMBER:
@@ -362,9 +324,14 @@ c_lex_with_flags (tree *value, unsigned char *cpp_flags)
          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;
 
@@ -373,40 +340,64 @@ c_lex_with_flags (tree *value, unsigned char *cpp_flags)
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
       }
       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)
+         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_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);
+           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: break;
+           default:
+             /* ... or not.  */
+             error_at (atloc, "stray %<@%> in program");
+             *loc = newloc;
+             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[8];
+
+       *cpp_spell_token (parse_in, tok, name, true) = 0;
+
+       error ("stray %qs in program", name);
+      }
+
+      goto retry;
 
     case CPP_OTHER:
       {
@@ -415,48 +406,60 @@ c_lex_with_flags (tree *value, unsigned char *cpp_flags)
        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_CHAR:
     case CPP_WCHAR:
+    case CPP_CHAR16:
+    case CPP_CHAR32:
       *value = lex_charconst (tok);
       break;
 
     case CPP_STRING:
     case CPP_WSTRING:
-      return lex_string (tok, value, false);
+    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:
-      abort ();
+      gcc_unreachable ();
 
     default:
       *value = NULL_TREE;
       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
@@ -468,7 +471,7 @@ 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;
@@ -481,10 +484,10 @@ narrowest_unsigned_type (unsigned HOST_WIDE_INT low,
     {
       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;
+       return (enum integer_type_kind) itk;
     }
 
   return itk_none;
@@ -495,7 +498,7 @@ static enum integer_type_kind
 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;
@@ -508,11 +511,11 @@ narrowest_signed_type (unsigned HOST_WIDE_INT low,
   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;
+       return (enum integer_type_kind) itk;
     }
 
   return itk_none;
@@ -565,10 +568,11 @@ interpret_integer (const cpp_token *token, unsigned int flags)
                  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");
            }
        }
     }
@@ -579,13 +583,18 @@ interpret_integer (const cpp_token *token, unsigned int flags)
            ? 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");
+    }
 
   value = build_int_cst_wide (type, integer.low, integer.high);
 
@@ -602,70 +611,274 @@ static tree
 interpret_float (const cpp_token *token, unsigned int flags)
 {
   tree type;
+  tree const_type;
   tree value;
   REAL_VALUE_TYPE real;
+  REAL_VALUE_TYPE real_trunc;
   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)
-    {
-      type = long_double_type_node;
-      type_name = "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;
-      type_name = "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
-    {
+    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_name = "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;
-  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);
-
-  /* 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);
+  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.  */
-  value = build_real (type, real);
+  value = build_real (const_type, real);
   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;
+}
+
+/* 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
-   indicates whether an '@' token preceded the incoming token.
+/* 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,
-   or CPP_OBJC_STRING).
+   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
@@ -677,107 +890,129 @@ interpret_float (const cpp_token *token, unsigned int flags)
    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;
+  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;
 
-  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));
+    case CPP_PADDING:
+      goto retry;
+    case CPP_ATSIGN:
+      if (c_dialect_objc ())
+       {
+         objc_string = true;
+         goto retry;
+       }
+      /* FALLTHROUGH */
+
+    default:
+      break;
 
-      do
+    case CPP_WSTRING:
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_UTF8STRING:
+      if (type != tok->type)
        {
-         count++;
-         if (tok->type == CPP_WSTRING)
-           wide = true;
-         obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+         if (type == CPP_STRING)
+           type = tok->type;
+         else
+           error ("unsupported non-standard concatenation of string literals");
+       }
 
-         tok = get_nonpadding_token ();
-         if (c_dialect_objc () && tok->type == CPP_ATSIGN)
-           {
-             objc_string = true;
-             tok = get_nonpadding_token ();
-           }
+    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, type))
     {
-      value = build_string (istr.len, (char *)istr.text);
-      free ((void *)istr.text);
-
-      if (c_lex_string_translate == -1)
-       {
-         if (!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.  */
-           abort ();
-         
-         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
     {
       /* Callers cannot generally handle error_mark_node in this context,
         so return the empty string instead.  cpp_interpret_string has
         issued an error.  */
-      if (wide)
-       value = build_string (TYPE_PRECISION (wchar_type_node)
-                             / TYPE_PRECISION (char_type_node),
-                             "\0\0\0");  /* widest supported wchar_t
-                                            is 32 bits */
-      else
-       value = build_string (1, "");
+      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;
+        }
     }
 
-  TREE_TYPE (value) = wide ? wchar_array_type_node : char_array_type_node;
+  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 (strs != &str)
+  if (concats)
     obstack_free (&str_ob, 0);
 
-  return objc_string ? CPP_OBJC_STRING : wide ? CPP_WSTRING : CPP_STRING;
+  return objc_string ? CPP_OBJC_STRING : type;
 }
 
 /* Converts a (possibly wide) character constant token into a tree.  */
@@ -787,13 +1022,17 @@ lex_charconst (const cpp_token *token)
   cppchar_t result;
   tree type, value;
   unsigned int chars_seen;
-  int unsignedp;
+  int unsignedp = 0;
 
   result = cpp_interpret_charconst (parse_in, token,
                                    &chars_seen, &unsignedp);
 
   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'.  */
   else if (!c_dialect_cxx () || chars_seen > 1)