OSDN Git Service

2007-11-26 Andreas Krebbel <krebbel1@de.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index bde95aa..1da57c2 100644 (file)
@@ -6,7 +6,7 @@ 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 +15,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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Process declarations and symbol lookup for C front end.
    Also constructs types; the standard scalar types at initialization,
@@ -376,7 +375,7 @@ static GTY((deletable)) struct c_binding *binding_freelist;
   struct c_scope *s_ = (scope);                                \
   tree d_ = (decl);                                    \
   if (s_->list##_last)                                 \
-    TREE_CHAIN (s_->list##_last) = d_;                 \
+    BLOCK_CHAIN (s_->list##_last) = d_;                        \
   else                                                 \
     s_->list = d_;                                     \
   s_->list##_last = d_;                                        \
@@ -387,7 +386,7 @@ static GTY((deletable)) struct c_binding *binding_freelist;
   struct c_scope *t_ = (tscope);                               \
   struct c_scope *f_ = (fscope);                               \
   if (t_->to##_last)                                           \
-    TREE_CHAIN (t_->to##_last) = f_->from;                     \
+    BLOCK_CHAIN (t_->to##_last) = f_->from;                    \
   else                                                         \
     t_->to = f_->from;                                         \
   t_->to##_last = f_->from##_last;                             \
@@ -408,7 +407,7 @@ static tree lookup_name_in_scope (tree, struct c_scope *);
 static tree c_make_fname_decl (tree, int);
 static tree grokdeclarator (const struct c_declarator *,
                            struct c_declspecs *,
-                           enum decl_context, bool, tree *,
+                           enum decl_context, bool, tree *, tree *,
                            enum deprecated_states);
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
@@ -694,7 +693,7 @@ pop_scope (void)
       TREE_USED (block) = 1;
 
       /* In each subblock, record that this is its superior.  */
-      for (p = scope->blocks; p; p = TREE_CHAIN (p))
+      for (p = scope->blocks; p; p = BLOCK_CHAIN (p))
        BLOCK_SUPERCONTEXT (p) = block;
 
       BLOCK_VARS (block) = 0;
@@ -1664,12 +1663,11 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
       DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
       DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
       DECL_MODE (newdecl) = DECL_MODE (olddecl);
-      if (TREE_CODE (olddecl) != FUNCTION_DECL)
-       if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
-         {
-           DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
-           DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
-         }
+      if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+       {
+         DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+         DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
+       }
     }
 
 
@@ -1821,6 +1819,11 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 
          DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
            = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+
+         DECL_DISREGARD_INLINE_LIMITS (newdecl)
+           = DECL_DISREGARD_INLINE_LIMITS (olddecl)
+           = (DECL_DISREGARD_INLINE_LIMITS (newdecl)
+              || DECL_DISREGARD_INLINE_LIMITS (olddecl));
        }
 
       if (DECL_BUILT_IN (olddecl))
@@ -1932,7 +1935,7 @@ duplicate_decls (tree newdecl, tree olddecl)
 
   if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
     {
-      /* Avoid `unused variable' and other warnings warnings for OLDDECL.  */
+      /* Avoid `unused variable' and other warnings for OLDDECL.  */
       TREE_NO_WARNING (olddecl) = 1;
       return false;
     }
@@ -2030,11 +2033,7 @@ warn_if_shadowing (tree new_decl)
 
     Obviously, we don't want to generate a duplicate ..._TYPE node if
     the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.
-
-    Since all standard types are effectively declared at line zero
-    in the source file, we can easily check to see if we are working
-    on a standard type by checking the current value of lineno.  */
+    standard built-in type.  */
 
 static void
 clone_underlying_type (tree x)
@@ -2072,10 +2071,6 @@ pushdecl (tree x)
   struct c_binding *b;
   bool nested = false;
 
-  /* Functions need the lang_decl data.  */
-  if (TREE_CODE (x) == FUNCTION_DECL && !DECL_LANG_SPECIFIC (x))
-    DECL_LANG_SPECIFIC (x) = GGC_CNEW (struct lang_decl);
-
   /* Must set DECL_CONTEXT for everything not at file scope or
      DECL_FILE_SCOPE_P won't work.  Local externs don't count
      unless they have initializers (which generate code).  */
@@ -2813,7 +2808,7 @@ c_make_fname_decl (tree id, int type_dep)
   DECL_ARTIFICIAL (decl) = 1;
 
   init = build_string (length + 1, name);
-  free ((char *) name);
+  free (CONST_CAST (char *, name));
   TREE_TYPE (init) = type;
   DECL_INITIAL (decl) = init;
 
@@ -2847,7 +2842,6 @@ c_builtin_function (tree decl)
   tree   id = DECL_NAME (decl);
 
   const char *name = IDENTIFIER_POINTER (id);
-  DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
   C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
 
   /* Should never be called on a symbol with a preexisting meaning.  */
@@ -3087,20 +3081,13 @@ build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p,
 
 /* Set the contained declarator of an array declarator.  DECL is the
    declarator, as constructed by build_array_declarator; INNER is what
-   appears on the left of the [].  ABSTRACT_P is true if it is an
-   abstract declarator, false otherwise; this is used to reject static
-   and type qualifiers in abstract declarators, where they are not in
-   the C99 grammar (subject to possible change in DR#289).  */
+   appears on the left of the [].  */
 
 struct c_declarator *
 set_array_declarator_inner (struct c_declarator *decl,
-                           struct c_declarator *inner, bool abstract_p)
+                           struct c_declarator *inner)
 {
   decl->declarator = inner;
-  if (abstract_p && (decl->u.array.quals != TYPE_UNQUALIFIED
-                    || decl->u.array.attrs != NULL_TREE
-                    || decl->u.array.static_p))
-    error ("static or type qualifiers in abstract declarator");
   return decl;
 }
 
@@ -3142,7 +3129,7 @@ groktypename (struct c_type_name *type_name)
   type_name->specs->attrs = NULL_TREE;
 
   type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
-                        false, NULL, DEPRECATED_NORMAL);
+                        false, NULL, &attrs, DEPRECATED_NORMAL);
 
   /* Apply attributes.  */
   decl_attributes (&type, attrs, 0);
@@ -3179,7 +3166,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
     deprecated_state = DEPRECATED_SUPPRESS;
 
   decl = grokdeclarator (declarator, declspecs,
-                        NORMAL, initialized, NULL,
+                        NORMAL, initialized, NULL, &attributes,
                         deprecated_state);
   if (!decl)
     return 0;
@@ -3668,10 +3655,11 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
 tree
 grokparm (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
-                             NULL, DEPRECATED_NORMAL);
+                             NULL, &attrs, DEPRECATED_NORMAL);
 
-  decl_attributes (&decl, parm->attrs, 0);
+  decl_attributes (&decl, attrs, 0);
 
   return decl;
 }
@@ -3682,11 +3670,12 @@ grokparm (const struct c_parm *parm)
 void
 push_parm_decl (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl;
 
   decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
-                        DEPRECATED_NORMAL);
-  decl_attributes (&decl, parm->attrs, 0);
+                        &attrs, DEPRECATED_NORMAL);
+  decl_attributes (&decl, attrs, 0);
 
   decl = pushdecl (decl);
 
@@ -3857,10 +3846,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
       && type_mv != boolean_type_node)
     pedwarn ("type of bit-field %qs is a GCC extension", name);
 
-  if (type_mv == boolean_type_node)
-    max_width = CHAR_TYPE_SIZE;
-  else
-    max_width = TYPE_PRECISION (*type);
+  max_width = TYPE_PRECISION (*type);
 
   if (0 < compare_tree_int (*width, max_width))
     {
@@ -3958,6 +3944,9 @@ warn_variable_length_array (const char *name, tree size)
    INITIALIZED is true if the decl has an initializer.
    WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node
    representing the width of the bit-field.
+   DECL_ATTRS points to the list of attributes that should be added to this
+     decl.  Any nested attributes that belong on the decl itself will be
+     added to this list.
    DEPRECATED_STATE is a deprecated_states value indicating whether
    deprecation warnings should be suppressed.
 
@@ -3972,7 +3961,7 @@ static tree
 grokdeclarator (const struct c_declarator *declarator,
                struct c_declspecs *declspecs,
                enum decl_context decl_context, bool initialized, tree *width,
-               enum deprecated_states deprecated_state)
+               tree *decl_attrs, enum deprecated_states deprecated_state)
 {
   tree type = declspecs->type;
   bool threadp = declspecs->thread_p;
@@ -4616,6 +4605,7 @@ grokdeclarator (const struct c_declarator *declarator,
          gcc_unreachable ();
        }
     }
+  *decl_attrs = chainon (returned_attrs, *decl_attrs);
 
   /* Now TYPE has the actual type, apart from any qualifiers in
      TYPE_QUALS.  */
@@ -4648,9 +4638,9 @@ grokdeclarator (const struct c_declarator *declarator,
       if (type_quals)
        type = c_build_qualified_type (type, type_quals);
       decl = build_decl (TYPE_DECL, declarator->u.id, type);
+      DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
       if (declspecs->explicit_signed_p)
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
-      decl_attributes (&decl, returned_attrs, 0);
       if (declspecs->inline_p)
        pedwarn ("typedef %q+D declared %<inline%>", decl);
       return decl;
@@ -4670,7 +4660,6 @@ grokdeclarator (const struct c_declarator *declarator,
        pedwarn ("ISO C forbids const or volatile function types");
       if (type_quals)
        type = c_build_qualified_type (type, type_quals);
-      decl_attributes (&type, returned_attrs, 0);
       return type;
     }
 
@@ -4720,6 +4709,8 @@ grokdeclarator (const struct c_declarator *declarator,
              type = c_build_qualified_type (type, type_quals);
            type = build_pointer_type (type);
            type_quals = array_ptr_quals;
+           if (type_quals)
+             type = c_build_qualified_type (type, type_quals);
 
            /* We don't yet implement attributes in this context.  */
            if (array_ptr_attrs != NULL_TREE)
@@ -4743,6 +4734,7 @@ grokdeclarator (const struct c_declarator *declarator,
        type_as_written = type;
 
        decl = build_decl (PARM_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        if (size_varies)
          C_DECL_VARIABLE_SIZE (decl) = 1;
 
@@ -4782,6 +4774,7 @@ grokdeclarator (const struct c_declarator *declarator,
          }
        type = c_build_qualified_type (type, type_quals);
        decl = build_decl (FIELD_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        DECL_NONADDRESSABLE_P (decl) = bitfield;
        if (bitfield && !declarator->u.id)
          TREE_NO_WARNING (decl) = 1;
@@ -4818,10 +4811,9 @@ grokdeclarator (const struct c_declarator *declarator,
          }
 
        decl = build_decl (FUNCTION_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        decl = build_decl_attribute_variant (decl, decl_attr);
 
-       DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
-
        if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
          pedwarn ("ISO C forbids qualified function types");
 
@@ -4986,8 +4978,6 @@ grokdeclarator (const struct c_declarator *declarator,
      name of a variable.  Thus, if it's known before this, die horribly.  */
     gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
 
-    decl_attributes (&decl, returned_attrs, 0);
-
     return decl;
   }
 }
@@ -5389,6 +5379,7 @@ start_struct (enum tree_code code, tree name)
 /* Process the specs, declarator and width (NULL if omitted)
    of a structure component, returning a FIELD_DECL node.
    WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node.
+   DECL_ATTRS is as for grokdeclarator.
 
    This is done during the parsing of the struct declaration.
    The FIELD_DECL nodes are chained together and the lot of them
@@ -5396,7 +5387,7 @@ start_struct (enum tree_code code, tree name)
 
 tree
 grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
-          tree width)
+          tree width, tree *decl_attrs)
 {
   tree value;
 
@@ -5449,7 +5440,8 @@ grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
     }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
-                         width ? &width : NULL, DEPRECATED_NORMAL);
+                         width ? &width : NULL, decl_attrs,
+                         DEPRECATED_NORMAL);
 
   finish_decl (value, NULL_TREE, NULL_TREE);
   DECL_INITIAL (value) = width;
@@ -6090,7 +6082,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   c_break_label = c_cont_label = size_zero_node;
 
   decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
-                         DEPRECATED_NORMAL);
+                         &attributes, DEPRECATED_NORMAL);
 
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
@@ -6270,18 +6262,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   declare_parm_level ();
 
   restype = TREE_TYPE (TREE_TYPE (current_function_decl));
-  /* Promote the value to int before returning it.  */
-  if (c_promoting_integer_type_p (restype))
-    {
-      /* It retains unsignedness if not really getting wider.  */
-      if (TYPE_UNSIGNED (restype)
-         && (TYPE_PRECISION (restype)
-                 == TYPE_PRECISION (integer_type_node)))
-       restype = unsigned_type_node;
-      else
-       restype = integer_type_node;
-    }
-
   resdecl = build_decl (RESULT_DECL, NULL_TREE, restype);
   DECL_ARTIFICIAL (resdecl) = 1;
   DECL_IGNORED_P (resdecl) = 1;
@@ -6645,7 +6625,7 @@ store_parm_decls (void)
   gen_aux_info_record (fndecl, 1, 0, proto);
 
   /* Initialize the RTL code for the function.  */
-  allocate_struct_function (fndecl);
+  allocate_struct_function (fndecl, false);
 
   /* Begin the statement tree for this function.  */
   DECL_SAVED_TREE (fndecl) = push_stmt_list ();
@@ -6789,6 +6769,11 @@ finish_function (void)
   /* Finalize the ELF visibility for the function.  */
   c_determine_visibility (fndecl);
 
+  /* For GNU C extern inline functions disregard inline limits.  */
+  if (DECL_EXTERNAL (fndecl) 
+      && DECL_DECLARED_INLINE_P (fndecl))
+    DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
+
   /* Genericize before inlining.  Delay genericizing nested functions
      until their parent function is genericized.  Since finalizing
      requires GENERIC, delay that as well.  */
@@ -6805,7 +6790,7 @@ finish_function (void)
             This should be cleaned up later and this conditional removed.  */
          if (cgraph_global_info_ready)
            {
-             c_expand_body (fndecl);
+             cgraph_add_new_function (fndecl, false);
              return;
            }
 
@@ -6826,7 +6811,7 @@ finish_function (void)
   /* We're leaving the context of this function, so zap cfun.
      It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
      tree_rest_of_compilation.  */
-  cfun = NULL;
+  set_cfun (NULL);
   current_function_decl = NULL;
 }
 \f
@@ -6991,7 +6976,7 @@ current_stmt_tree (void)
    C.  */
 
 int
-anon_aggr_type_p (tree ARG_UNUSED (node))
+anon_aggr_type_p (const_tree ARG_UNUSED (node))
 {
   return 0;
 }
@@ -7148,6 +7133,7 @@ build_null_declspecs (void)
   ret->const_p = false;
   ret->volatile_p = false;
   ret->restrict_p = false;
+  ret->saturating_p = false;
   return ret;
 }
 
@@ -7210,7 +7196,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
        }
       if ((int) i <= (int) RID_LAST_MODIFIER)
        {
-         /* "long", "short", "signed", "unsigned" or "_Complex".  */
+         /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat".  */
          bool dupe = false;
          switch (i)
            {
@@ -7370,9 +7356,55 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->typespec_word == cts_dfloat128)
                error ("both %<complex%> and %<_Decimal128%> in "
                       "declaration specifiers");
+             else if (specs->typespec_word == cts_fract)
+               error ("both %<complex%> and %<_Fract%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_accum)
+               error ("both %<complex%> and %<_Accum%> in "
+                      "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<complex%> and %<_Sat%> in "
+                      "declaration specifiers");
              else
                specs->complex_p = true;
              break;
+           case RID_SAT:
+             dupe = specs->saturating_p;
+             if (pedantic)
+               pedwarn ("ISO C does not support saturating types");
+             if (specs->typespec_word == cts_void)
+               error ("both %<_Sat%> and %<void%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_bool)
+               error ("both %<_Sat%> and %<_Bool%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_char)
+               error ("both %<_Sat%> and %<char%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_int)
+               error ("both %<_Sat%> and %<int%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_float)
+               error ("both %<_Sat%> and %<float%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_double)
+               error ("both %<_Sat%> and %<double%> in "
+                      "declaration specifiers");
+              else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<_Sat%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<_Sat%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<_Sat%> and %<_Decimal128%> in "
+                      "declaration specifiers");
+             else if (specs->complex_p)
+               error ("both %<_Sat%> and %<complex%> in "
+                      "declaration specifiers");
+             else
+               specs->saturating_p = true;
+             break;
            default:
              gcc_unreachable ();
            }
@@ -7384,7 +7416,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
        }
       else
        {
-         /* "void", "_Bool", "char", "int", "float" or "double".  */
+         /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
+            "_Decimal64", "_Decimal128", "_Fract" or "_Accum".  */
          if (specs->typespec_word != cts_none)
            {
              error ("two or more data types in declaration specifiers");
@@ -7408,6 +7441,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->complex_p)
                error ("both %<complex%> and %<void%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<void%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_void;
              return specs;
@@ -7427,6 +7463,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->complex_p)
                error ("both %<complex%> and %<_Bool%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<_Bool%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_bool;
              return specs;
@@ -7437,11 +7476,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->short_p)
                error ("both %<short%> and %<char%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<char%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_char;
              return specs;
            case RID_INT:
-             specs->typespec_word = cts_int;
+             if (specs->saturating_p)
+               error ("both %<_Sat%> and %<int%> in "
+                      "declaration specifiers");
+             else
+               specs->typespec_word = cts_int;
              return specs;
            case RID_FLOAT:
              if (specs->long_p)
@@ -7456,6 +7502,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->unsigned_p)
                error ("both %<unsigned%> and %<float%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<float%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_float;
              return specs;
@@ -7472,6 +7521,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->unsigned_p)
                error ("both %<unsigned%> and %<double%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<double%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_double;
              return specs;
@@ -7504,6 +7556,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
                 else if (specs->complex_p)
                   error ("both %<complex%> and %<%s%> in "
                          "declaration specifiers", str);
+                else if (specs->saturating_p)
+                  error ("both %<_Sat%> and %<%s%> in "
+                         "declaration specifiers", str);
                else if (i == RID_DFLOAT32)
                  specs->typespec_word = cts_dfloat32;
                else if (i == RID_DFLOAT64)
@@ -7516,6 +7571,27 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              if (pedantic)
                pedwarn ("ISO C does not support decimal floating point");
              return specs;
+           case RID_FRACT:
+           case RID_ACCUM:
+             {
+               const char *str;
+               if (i == RID_FRACT)
+                 str = "_Fract";
+               else
+                 str = "_Accum";
+                if (specs->complex_p)
+                  error ("both %<complex%> and %<%s%> in "
+                         "declaration specifiers", str);
+               else if (i == RID_FRACT)
+                   specs->typespec_word = cts_fract;
+               else
+                   specs->typespec_word = cts_accum;
+             }
+             if (!targetm.fixed_point_supported_p ())
+               error ("fixed-point types not supported for this target");
+             if (pedantic)
+               pedwarn ("ISO C does not support fixed-point types");
+             return specs;
            default:
              /* ObjC reserved word "id", handled below.  */
              break;
@@ -7687,8 +7763,13 @@ finish_declspecs (struct c_declspecs *specs)
      "_Complex short" is equivalent to "_Complex short int".  */
   if (specs->typespec_word == cts_none)
     {
-      if (specs->long_p || specs->short_p
-         || specs->signed_p || specs->unsigned_p)
+      if (specs->saturating_p)
+       {
+         error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
+         specs->typespec_word = cts_fract;
+       }
+      else if (specs->long_p || specs->short_p
+              || specs->signed_p || specs->unsigned_p)
        {
          specs->typespec_word = cts_int;
        }
@@ -7806,6 +7887,88 @@ finish_declspecs (struct c_declspecs *specs)
       else
        specs->type = dfloat128_type_node;
       break;
+    case cts_fract:
+       gcc_assert (!specs->complex_p);
+       if (specs->saturating_p)
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_long_fract_type_node
+                         : sat_long_long_fract_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_fract_type_node
+                         : sat_long_fract_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_short_fract_type_node
+                         : sat_short_fract_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_fract_type_node
+                         : sat_fract_type_node;
+          }
+      else
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_long_fract_type_node
+                         : long_long_fract_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_fract_type_node
+                         : long_fract_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_short_fract_type_node
+                         : short_fract_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? unsigned_fract_type_node
+                         : fract_type_node;
+          }
+      break;
+    case cts_accum:
+       gcc_assert (!specs->complex_p);
+       if (specs->saturating_p)
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_long_accum_type_node
+                         : sat_long_long_accum_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_accum_type_node
+                         : sat_long_accum_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_short_accum_type_node
+                         : sat_short_accum_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_accum_type_node
+                         : sat_accum_type_node;
+          }
+      else
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_long_accum_type_node
+                         : long_long_accum_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_accum_type_node
+                         : long_accum_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_short_accum_type_node
+                         : short_accum_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? unsigned_accum_type_node
+                         : accum_type_node;
+          }
+      break;
     default:
       gcc_unreachable ();
     }