OSDN Git Service

* tree-predcom.c (replace_ref_with, initialize_root_vars_lm,
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index db64da5..2d893ff 100644 (file)
@@ -556,6 +556,7 @@ static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
                                                 bool *);
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
+static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -650,6 +651,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_warn_unused_result_attribute },
   { "sentinel",               0, 1, false, true, true,
                              handle_sentinel_attribute },
+  { "alloc_size",            1, 2, false, true, true,
+                             handle_alloc_size_attribute },
   { "cold",                   0, 0, true,  false, false,
                              handle_cold_attribute },
   { "hot",                    0, 0, true,  false, false,
@@ -670,11 +673,6 @@ const struct attribute_spec c_common_format_attribute_table[] =
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
-/* Functions called automatically at the beginning and end of execution.  */
-
-tree static_ctors;
-tree static_dtors;
-
 /* Push current bindings for the function name VAR_DECLS.  */
 
 void
@@ -978,40 +976,108 @@ overflow_warning (tree value)
     }
 }
 
+
+/* Warn about use of a logical || / && operator being used in a
+   context where it is likely that the bitwise equivalent was intended
+   by the programmer. CODE is the TREE_CODE of the operator, ARG1
+   and ARG2 the arguments.  */
+
+void
+warn_logical_operator (enum tree_code code, tree arg1, tree
+    arg2)
+{
+  switch (code)
+    {
+      case TRUTH_ANDIF_EXPR:
+      case TRUTH_ORIF_EXPR:
+      case TRUTH_OR_EXPR:
+      case TRUTH_AND_EXPR:
+       if (!TREE_NO_WARNING (arg1)
+           && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+           && !CONSTANT_CLASS_P (arg1)
+           && TREE_CODE (arg2) == INTEGER_CST
+           && !integer_zerop (arg2))
+         {
+           warning (OPT_Wlogical_op,
+                    "logical %<%s%> with non-zero constant "
+                    "will always evaluate as true",
+                    ((code == TRUTH_ANDIF_EXPR)
+                     || (code == TRUTH_AND_EXPR)) ? "&&" : "||");
+           TREE_NO_WARNING (arg1) = true;
+         }
+       break;
+      default:
+       break;
+    }
+}
+
+
 /* Print a warning about casts that might indicate violation
    of strict aliasing rules if -Wstrict-aliasing is used and
    strict aliasing mode is in effect. OTYPE is the original
    TREE_TYPE of EXPR, and TYPE the type we're casting to. */
 
-void
+bool
 strict_aliasing_warning (tree otype, tree type, tree expr)
 {
-  if (flag_strict_aliasing && warn_strict_aliasing
-      && POINTER_TYPE_P (type) && POINTER_TYPE_P (otype)
-      && TREE_CODE (expr) == ADDR_EXPR
+  if (!(flag_strict_aliasing && POINTER_TYPE_P (type) 
+        && POINTER_TYPE_P (otype) && !VOID_TYPE_P (TREE_TYPE (type))))
+    return false;
+
+  if ((warn_strict_aliasing > 1) && TREE_CODE (expr) == ADDR_EXPR
       && (DECL_P (TREE_OPERAND (expr, 0))
-          || handled_component_p (TREE_OPERAND (expr, 0)))
-      && !VOID_TYPE_P (TREE_TYPE (type)))
+          || handled_component_p (TREE_OPERAND (expr, 0))))
     {
       /* Casting the address of an object to non void pointer. Warn
          if the cast breaks type based aliasing.  */
-      if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
-        warning (OPT_Wstrict_aliasing, "type-punning to incomplete type "
-                 "might break strict-aliasing rules");
+      if (!COMPLETE_TYPE_P (TREE_TYPE (type)) && warn_strict_aliasing == 2)
+       {
+         warning (OPT_Wstrict_aliasing, "type-punning to incomplete type "
+                  "might break strict-aliasing rules");
+         return true;
+       }
       else
         {
-          HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
+          /* warn_strict_aliasing >= 3.   This includes the default (3).  
+             Only warn if the cast is dereferenced immediately.  */
+          HOST_WIDE_INT set1 =
+           get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
           HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
 
           if (!alias_sets_conflict_p (set1, set2))
-            warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
-                     "pointer will break strict-aliasing rules");
-          else if (warn_strict_aliasing > 1
-                  && !alias_sets_might_conflict_p (set1, set2))
-            warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
-                     "pointer might break strict-aliasing rules");
+           {
+             warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+                      "pointer will break strict-aliasing rules");
+             return true;
+           }
+          else if (warn_strict_aliasing == 2
+                  && !alias_sets_might_conflict_p (set1, set2))
+           {
+             warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+                      "pointer might break strict-aliasing rules");
+             return true;
+           }
         }
     }
+  else
+    if ((warn_strict_aliasing == 1) && !VOID_TYPE_P (TREE_TYPE (otype)))
+      {
+        /* At this level, warn for any conversions, even if an address is
+           not taken in the same statement.  This will likely produce many
+           false positives, but could be useful to pinpoint problems that
+           are not revealed at higher levels.  */
+        HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (otype));
+        HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
+        if (!COMPLETE_TYPE_P(type)
+            || !alias_sets_might_conflict_p (set1, set2))
+         {
+            warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+                     "pointer might break strict-aliasing rules");
+            return true;
+          }
+      }
+
+  return false;
 }
 
 /* Print a warning about if (); or if () .. else; constructs
@@ -1020,26 +1086,23 @@ strict_aliasing_warning (tree otype, tree type, tree expr)
    block.  */
 
 void
-empty_body_warning (tree inner_then, tree inner_else)
+empty_if_body_warning (tree inner_then, tree inner_else)
 {
-  if (warn_empty_body)
-    {
-      if (TREE_CODE (inner_then) == STATEMENT_LIST
-         && STATEMENT_LIST_TAIL (inner_then))
-       inner_then = STATEMENT_LIST_TAIL (inner_then)->stmt;
+  if (TREE_CODE (inner_then) == STATEMENT_LIST
+      && STATEMENT_LIST_TAIL (inner_then))
+    inner_then = STATEMENT_LIST_TAIL (inner_then)->stmt;
 
-      if (inner_else && TREE_CODE (inner_else) == STATEMENT_LIST
-         && STATEMENT_LIST_TAIL (inner_else))
-       inner_else = STATEMENT_LIST_TAIL (inner_else)->stmt;
+  if (inner_else && TREE_CODE (inner_else) == STATEMENT_LIST
+      && STATEMENT_LIST_TAIL (inner_else))
+    inner_else = STATEMENT_LIST_TAIL (inner_else)->stmt;
 
-      if (IS_EMPTY_STMT (inner_then) && !inner_else)
-       warning (OPT_Wempty_body, "%Hempty body in an if-statement",
-                EXPR_LOCUS (inner_then));
+  if (IS_EMPTY_STMT (inner_then) && !inner_else)
+    warning (OPT_Wempty_body, "%Hsuggest braces around empty body "
+             "in an %<if%> statement", EXPR_LOCUS (inner_then));
 
-      if (inner_else && IS_EMPTY_STMT (inner_else))
-       warning (OPT_Wempty_body, "%Hempty body in an else-statement",
-                EXPR_LOCUS (inner_else));
-   }
+  else if (inner_else && IS_EMPTY_STMT (inner_else))
+    warning (OPT_Wempty_body, "%Hsuggest braces around empty body "
+             "in an %<else%> statement", EXPR_LOCUS (inner_else));
 }
 
 /* Warn for unlikely, improbable, or stupid DECL declarations
@@ -1135,7 +1198,7 @@ vector_types_convertible_p (tree t1, tree t2, bool emit_lax_note)
 }
 
 /* Warns if the conversion of EXPR to TYPE may alter a value.
-   This function is called from convert_and_check.  */
+   This is a helper function for warnings_for_convert_and_check.  */
 
 static void
 conversion_warning (tree type, tree expr)
@@ -1144,6 +1207,9 @@ conversion_warning (tree type, tree expr)
 
   unsigned int formal_prec = TYPE_PRECISION (type);
 
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* Warn for real constant that is not an exact integer converted
@@ -1160,10 +1226,13 @@ conversion_warning (tree type, tree expr)
                && !int_fits_type_p (expr, type))
         {
           if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr)))
-            warning (OPT_Wconversion,
-                     "negative integer implicitly converted to unsigned type");
-          else
-            give_warning = true;
+           warning (OPT_Wsign_conversion,
+                    "negative integer implicitly converted to unsigned type");
+          else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (TREE_TYPE (expr)))
+           warning (OPT_Wsign_conversion,
+                    "conversion of unsigned constant value to negative integer");
+         else
+           give_warning = true;
         }
       else if (TREE_CODE (type) == REAL_TYPE)
         {
@@ -1201,16 +1270,20 @@ conversion_warning (tree type, tree expr)
                && TREE_CODE (type) == INTEGER_TYPE)
         {
           /* Warn for integer types converted to smaller integer types.  */
-          if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))
-              /* When they are the same width but different signedness,
-                 then the value may change.  */
-              || (formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
-                  && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
-              /* Even when converted to a bigger type, if the type is
-                 unsigned but expr is signed, then negative values
-                 will be changed.  */
-              || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
-            give_warning = true;
+          if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))) 
+           give_warning = true;
+
+         /* When they are the same width but different signedness,
+            then the value may change.  */
+         else if ((formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
+                   && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
+                  /* Even when converted to a bigger type, if the type is
+                     unsigned but expr is signed, then negative values
+                     will be changed.  */
+                  || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
+           warning (OPT_Wsign_conversion,
+                    "conversion to %qT from %qT may change the sign of the result",
+                    type, TREE_TYPE (expr));
         }
 
       /* Warn for integer types converted to real types if and only if
@@ -1243,23 +1316,13 @@ conversion_warning (tree type, tree expr)
     }
 }
 
-/* Convert EXPR to TYPE, warning about conversion problems with constants.
-   Invoke this function on every expression that is converted implicitly,
-   i.e. because of language rules and not because of an explicit cast.  */
+/* Produce warnings after a conversion. RESULT is the result of
+   converting EXPR to TYPE.  This is a helper function for
+   convert_and_check and cp_convert_and_check.  */
 
-tree
-convert_and_check (tree type, tree expr)
+void
+warnings_for_convert_and_check (tree type, tree expr, tree result)
 {
-  tree result;
-
-  if (TREE_TYPE (expr) == type)
-    return expr;
-  
-  result = convert (type, expr);
-
-  if (skip_evaluation || TREE_OVERFLOW_P (expr))
-    return result;
-
   if (TREE_CODE (expr) == INTEGER_CST
       && (TREE_CODE (type) == INTEGER_TYPE
           || TREE_CODE (type) == ENUMERAL_TYPE)
@@ -1277,10 +1340,10 @@ convert_and_check (tree type, tree expr)
           if (!int_fits_type_p (expr, c_common_signed_type (type)))
             warning (OPT_Woverflow,
                      "large integer implicitly truncated to unsigned type");
-          else if (warn_conversion)
+          else
             conversion_warning (type, expr);
         }
-      else if (!int_fits_type_p (expr, c_common_unsigned_type (type))) 
+      else if (!int_fits_type_p (expr, unsigned_type_for (type))) 
        warning (OPT_Woverflow,
                 "overflow in implicit constant conversion");
       /* No warning for converting 0x80000000 to int.  */
@@ -1291,15 +1354,34 @@ convert_and_check (tree type, tree expr)
        warning (OPT_Woverflow,
                 "overflow in implicit constant conversion");
 
-      else if (warn_conversion)
+      else
        conversion_warning (type, expr);
     }
   else if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result)) 
     warning (OPT_Woverflow,
              "overflow in implicit constant conversion");
-  else if (warn_conversion)
+  else
     conversion_warning (type, expr);
+}
+
+
+/* Convert EXPR to TYPE, warning about conversion problems with constants.
+   Invoke this function on every expression that is converted implicitly,
+   i.e. because of language rules and not because of an explicit cast.  */
+
+tree
+convert_and_check (tree type, tree expr)
+{
+  tree result;
+
+  if (TREE_TYPE (expr) == type)
+    return expr;
   
+  result = convert (type, expr);
+
+  if (!skip_evaluation && !TREE_OVERFLOW_P (expr) && result != error_mark_node)
+    warnings_for_convert_and_check (type, expr, result);
+
   return result;
 }
 \f
@@ -1956,39 +2038,6 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
   return 0;
 }
 
-/* Return an unsigned type the same as TYPE in other respects.  */
-tree
-c_common_unsigned_type (tree type)
-{
-  tree type1 = TYPE_MAIN_VARIANT (type);
-  if (type1 == signed_char_type_node || type1 == char_type_node)
-    return unsigned_char_type_node;
-  if (type1 == integer_type_node)
-    return unsigned_type_node;
-  if (type1 == short_integer_type_node)
-    return short_unsigned_type_node;
-  if (type1 == long_integer_type_node)
-    return long_unsigned_type_node;
-  if (type1 == long_long_integer_type_node)
-    return long_long_unsigned_type_node;
-  if (type1 == widest_integer_literal_type_node)
-    return widest_unsigned_literal_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
-  if (type1 == intTI_type_node)
-    return unsigned_intTI_type_node;
-#endif
-  if (type1 == intDI_type_node)
-    return unsigned_intDI_type_node;
-  if (type1 == intSI_type_node)
-    return unsigned_intSI_type_node;
-  if (type1 == intHI_type_node)
-    return unsigned_intHI_type_node;
-  if (type1 == intQI_type_node)
-    return unsigned_intQI_type_node;
-
-  return c_common_signed_or_unsigned_type (1, type);
-}
-
 /* Return a signed type the same as TYPE in other respects.  */
 
 tree
@@ -2029,9 +2078,39 @@ c_common_signed_type (tree type)
 tree
 c_common_signed_or_unsigned_type (int unsignedp, tree type)
 {
-  if (!INTEGRAL_TYPE_P (type)
-      || TYPE_UNSIGNED (type) == unsignedp)
-    return type;
+  tree type1;
+
+  /* This block of code emulates the behavior of the old
+     c_common_unsigned_type. In particular, it returns
+     long_unsigned_type_node if passed a long, even when a int would
+     have the same size. This is necessary for warnings to work
+     correctly in archs where sizeof(int) == sizeof(long) */
+
+  type1 = TYPE_MAIN_VARIANT (type);
+  if (type1 == signed_char_type_node || type1 == char_type_node || type1 == unsigned_char_type_node)
+    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+  if (type1 == integer_type_node || type1 == unsigned_type_node)
+    return unsignedp ? unsigned_type_node : integer_type_node;
+  if (type1 == short_integer_type_node || type1 == short_unsigned_type_node)
+    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+  if (type1 == long_integer_type_node || type1 == long_unsigned_type_node)
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+  if (type1 == long_long_integer_type_node || type1 == long_long_unsigned_type_node)
+    return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
+  if (type1 == widest_integer_literal_type_node || type1 == widest_unsigned_literal_type_node)
+    return unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node;
+#if HOST_BITS_PER_WIDE_INT >= 64
+  if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node)
+    return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+#endif
+  if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node)
+    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+  if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node)
+    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+  if (type1 == intHI_type_node || type1 == unsigned_intHI_type_node)
+    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+  if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node)
+    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
 
   /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not
      the precision; they have precision set to match their range, but
@@ -2042,6 +2121,10 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
      types, and producing a signed or unsigned variant of an
      ENUMERAL_TYPE may cause other problems as well.  */
 
+  if (!INTEGRAL_TYPE_P (type)
+      || TYPE_UNSIGNED (type) == unsignedp)
+    return type;
+
 #define TYPE_OK(node)                                                      \
   (TYPE_MODE (type) == TYPE_MODE (node)                                            \
    && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node)))
@@ -2150,10 +2233,10 @@ min_precision (tree value, int unsignedp)
 }
 \f
 /* Print an error message for invalid operands to arith operation
-   CODE.  */
+   CODE with TYPE0 for operand 0, and TYPE1 for operand 1.  */
 
 void
-binary_op_error (enum tree_code code)
+binary_op_error (enum tree_code code, tree type0, tree type1)
 {
   const char *opname;
 
@@ -2204,7 +2287,8 @@ binary_op_error (enum tree_code code)
     default:
       gcc_unreachable ();
     }
-  error ("invalid operands to binary %s", opname);
+  error ("invalid operands to binary %s (have %qT and %qT)", opname,
+        type0, type1);
 }
 \f
 /* Subroutine of build_binary_op, used for comparison operations.
@@ -2431,15 +2515,16 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
              default:
                break;
              }
-         type = c_common_unsigned_type (type);
+         /* unsigned_type_for doesn't support C bit fields */
+         type = c_common_signed_or_unsigned_type (1, type);
        }
 
       if (TREE_CODE (primop0) != INTEGER_CST)
        {
          if (val == truthvalue_false_node)
-           warning (0, "comparison is always false due to limited range of data type");
+           warning (OPT_Wtype_limits, "comparison is always false due to limited range of data type");
          if (val == truthvalue_true_node)
-           warning (0, "comparison is always true due to limited range of data type");
+           warning (OPT_Wtype_limits, "comparison is always true due to limited range of data type");
        }
 
       if (val != 0)
@@ -2509,24 +2594,26 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
          switch (code)
            {
            case GE_EXPR:
-             /* All unsigned values are >= 0, so we warn if extra warnings
-                are requested.  However, if OP0 is a constant that is
-                >= 0, the signedness of the comparison isn't an issue,
-                so suppress the warning.  */
-             if (extra_warnings && !in_system_header
+             /* All unsigned values are >= 0, so we warn.  However,
+                if OP0 is a constant that is >= 0, the signedness of
+                the comparison isn't an issue, so suppress the
+                warning.  */
+             if (warn_type_limits && !in_system_header
                  && !(TREE_CODE (primop0) == INTEGER_CST
                       && !TREE_OVERFLOW (convert (c_common_signed_type (type),
                                                   primop0))))
-               warning (0, "comparison of unsigned expression >= 0 is always true");
+               warning (OPT_Wtype_limits, 
+                        "comparison of unsigned expression >= 0 is always true");
              value = truthvalue_true_node;
              break;
 
            case LT_EXPR:
-             if (extra_warnings && !in_system_header
+             if (warn_type_limits && !in_system_header
                  && !(TREE_CODE (primop0) == INTEGER_CST
                       && !TREE_OVERFLOW (convert (c_common_signed_type (type),
                                                   primop0))))
-               warning (0, "comparison of unsigned expression < 0 is always false");
+               warning (OPT_Wtype_limits, 
+                        "comparison of unsigned expression < 0 is always false");
              value = truthvalue_false_node;
              break;
 
@@ -2852,8 +2939,26 @@ c_build_qualified_type (tree type, int type_quals)
        }
       if (!t)
        {
+          tree domain = TYPE_DOMAIN (type);
+
          t = build_variant_type_copy (type);
          TREE_TYPE (t) = element_type;
+
+          if (TYPE_STRUCTURAL_EQUALITY_P (element_type)
+              || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain)))
+            SET_TYPE_STRUCTURAL_EQUALITY (t);
+          else if (TYPE_CANONICAL (element_type) != element_type
+                   || (domain && TYPE_CANONICAL (domain) != domain))
+            {
+              tree unqualified_canon 
+                = build_array_type (TYPE_CANONICAL (element_type),
+                                    domain? TYPE_CANONICAL (domain) 
+                                          : NULL_TREE);
+              TYPE_CANONICAL (t) 
+                = c_build_qualified_type (unqualified_canon, type_quals);
+            }
+          else
+            TYPE_CANONICAL (t) = t;
        }
       return t;
     }
@@ -3580,7 +3685,7 @@ c_common_nodes_and_builtins (void)
   else
     {
       signed_wchar_type_node = c_common_signed_type (wchar_type_node);
-      unsigned_wchar_type_node = c_common_unsigned_type (wchar_type_node);
+      unsigned_wchar_type_node = unsigned_type_for (wchar_type_node);
     }
 
   /* This is for wide string constants.  */
@@ -3598,7 +3703,7 @@ c_common_nodes_and_builtins (void)
   default_function_type = build_function_type (integer_type_node, NULL_TREE);
   ptrdiff_type_node
     = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
-  unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
+  unsigned_ptrdiff_type_node = unsigned_type_for (ptrdiff_type_node);
 
   lang_hooks.decls.pushdecl
     (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
@@ -3834,6 +3939,15 @@ strip_pointer_operator (tree t)
   return t;
 }
 
+/* Recursively remove pointer or array type from TYPE. */
+tree
+strip_pointer_or_array_types (tree t)
+{
+  while (TREE_CODE (t) == ARRAY_TYPE || POINTER_TYPE_P (t))
+    t = TREE_TYPE (t);
+  return t;
+}
+
 /* Used to compare case labels.  K1 and K2 are actually tree nodes
    representing case labels, or NULL_TREE for a `default' label.
    Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
@@ -4235,21 +4349,7 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
 void
 c_expand_body (tree fndecl)
 {
-
-  if (!DECL_INITIAL (fndecl)
-      || DECL_INITIAL (fndecl) == error_mark_node)
-    return;
-
   tree_rest_of_compilation (fndecl);
-
-  if (DECL_STATIC_CONSTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
-                                decl_init_priority_lookup (fndecl));
-  if (DECL_STATIC_DESTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
-                               decl_fini_priority_lookup (fndecl));
 }
 
 /* Hook used by staticp to handle language-specific tree codes.  */
@@ -5483,6 +5583,37 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle a "alloc_size" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+                            int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree params = TYPE_ARG_TYPES (*node);
+  unsigned arg_count = 0;
+
+  for (; TREE_CHAIN (params); params = TREE_CHAIN (params))
+    arg_count ++;
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      tree position = TREE_VALUE (args);
+
+      if (TREE_CODE (position) != INTEGER_CST
+         || TREE_INT_CST_HIGH (position) 
+         || TREE_INT_CST_LOW (position) < 1
+         || TREE_INT_CST_LOW (position) > arg_count )
+       {
+         warning (OPT_Wattributes, 
+                  "alloc_size parameter outside range");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+    }
+  return NULL_TREE;
+}
+
 /* Handle a "returns_twice" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -6019,14 +6150,16 @@ handle_sentinel_attribute (tree *node, tree name, tree args,
 
       if (TREE_CODE (position) != INTEGER_CST)
        {
-         warning (0, "requested position is not an integer constant");
+         warning (OPT_Wattributes, 
+                  "requested position is not an integer constant");
          *no_add_attrs = true;
        }
       else
        {
          if (tree_int_cst_lt (position, integer_zero_node))
            {
-             warning (0, "requested position is less than zero");
+             warning (OPT_Wattributes,
+                      "requested position is less than zero");
              *no_add_attrs = true;
            }
        }
@@ -6443,6 +6576,12 @@ fold_offsetof_1 (tree expr, tree stop_ref)
       off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
       break;
 
+    case COMPOUND_EXPR:
+      /* Handle static members of volatile structs.  */
+      t = TREE_OPERAND (expr, 1);
+      gcc_assert (TREE_CODE (t) == VAR_DECL);
+      return fold_offsetof_1 (t, stop_ref);
+
     default:
       gcc_unreachable ();
     }
@@ -6931,63 +7070,21 @@ warn_for_unused_label (tree label)
     }
 }
 
-/* If FNDECL is a static constructor or destructor, add it to the list
-   of functions to be called by the file scope initialization
-   function.  */
-
-void
-c_record_cdtor_fn (tree fndecl)
-{
-  if (targetm.have_ctors_dtors)
-    return;
-
-  if (DECL_STATIC_CONSTRUCTOR (fndecl))
-    static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
-  if (DECL_STATIC_DESTRUCTOR (fndecl))
-    static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
-}
-
-/* Synthesize a function which calls all the global ctors or global
-   dtors in this file.  This is only used for targets which do not
-   support .ctors/.dtors sections.  FIXME: Migrate into cgraph.  */
-static void
-build_cdtor (int method_type, tree cdtors)
-{
-  tree body = 0;
-
-  if (!cdtors)
-    return;
-
-  for (; cdtors; cdtors = TREE_CHAIN (cdtors))
-    append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
-                             &body);
-
-  cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
-}
+#ifndef TARGET_HAS_TARGETCM
+struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
+#endif
 
-/* Generate functions to call static constructors and destructors
-   for targets that do not support .ctors/.dtors sections.  These
-   functions have magic names which are detected by collect2.  */
+/* Warn for division by zero according to the value of DIVISOR.  */
 
 void
-c_build_cdtor_fns (void)
+warn_for_div_by_zero (tree divisor)
 {
-  if (!targetm.have_ctors_dtors)
-    {
-      build_cdtor ('I', static_ctors); 
-      static_ctors = NULL_TREE;
-      build_cdtor ('D', static_dtors); 
-      static_dtors = NULL_TREE;
-    }
-  else
-    {
-      gcc_assert (!static_ctors);
-      gcc_assert (!static_dtors);
-    }
+  /* If DIVISOR is zero, and has integral type, issue a warning about
+     division by zero.  Do not issue a warning if DIVISOR has a
+     floating-point type, since we consider 0.0/0.0 a valid way of
+     generating a NaN.  */
+  if (skip_evaluation == 0 && integer_zerop (divisor))
+    warning (OPT_Wdiv_by_zero, "division by zero");
 }
 
-#ifndef TARGET_HAS_TARGETCM
-struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
-#endif
-
 #include "gt-c-common.h"