OSDN Git Service

PR c++/23194
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 220be7e..e34fa67 100644 (file)
@@ -1,13 +1,14 @@
 /* Build expressions with type checking for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 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)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +17,8 @@ MERCHANTABILITY or 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/>.  */
 
 
 /* This file is part of the C++ front end.
@@ -39,25 +39,30 @@ Boston, MA 02110-1301, USA.  */
 #include "output.h"
 #include "toplev.h"
 #include "diagnostic.h"
+#include "intl.h"
 #include "target.h"
 #include "convert.h"
 #include "c-common.h"
+#include "params.h"
 
 static tree pfn_from_ptrmemfunc (tree);
-static tree convert_for_assignment (tree, tree, const char *, tree, int);
+static tree delta_from_ptrmemfunc (tree);
+static tree convert_for_assignment (tree, tree, const char *, tree, int,
+                                   tsubst_flags_t);
 static tree cp_pointer_int_sum (enum tree_code, tree, tree);
-static tree rationalize_conditional_expr (enum tree_code, tree);
+static tree rationalize_conditional_expr (enum tree_code, tree, 
+                                         tsubst_flags_t);
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
-static bool comp_array_types (tree, tree, bool);
-static tree common_base_type (tree, tree);
+static bool comp_array_types (const_tree, const_tree, bool);
 static tree pointer_diff (tree, tree, tree);
 static tree get_delta_difference (tree, tree, bool, bool);
 static void casts_away_constness_r (tree *, tree *);
 static bool casts_away_constness (tree, tree);
 static void maybe_warn_about_returning_address_of_local (tree);
 static tree lookup_destructor (tree, tree, tree);
-static tree convert_arguments (tree, tree, tree, int);
+static int convert_arguments (int, tree *, tree, tree, tree, int,
+                              tsubst_flags_t);
 
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)
@@ -150,7 +155,7 @@ complete_type_or_else (tree type, tree value)
 /* Return truthvalue of whether type of EXP is instantiated.  */
 
 int
-type_unknown_p (tree exp)
+type_unknown_p (const_tree exp)
 {
   return (TREE_CODE (exp) == TREE_LIST
          || TREE_TYPE (exp) == unknown_type_node);
@@ -256,12 +261,10 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
 
   /* FIXME: Attributes.  */
   gcc_assert (ARITHMETIC_TYPE_P (t1)
-             || TREE_CODE (t1) == COMPLEX_TYPE
              || TREE_CODE (t1) == VECTOR_TYPE
              || TREE_CODE (t1) == ENUMERAL_TYPE);
   gcc_assert (ARITHMETIC_TYPE_P (t2)
-             || TREE_CODE (t2) == COMPLEX_TYPE
-             || TREE_CODE (t1) == VECTOR_TYPE
+             || TREE_CODE (t2) == VECTOR_TYPE
              || TREE_CODE (t2) == ENUMERAL_TYPE);
 
   /* In what follows, we slightly generalize the rules given in [expr] so
@@ -323,12 +326,6 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
 
   if (code1 != REAL_TYPE)
     {
-      /* If one is a sizetype, use it so size_binop doesn't blow up.  */
-      if (TYPE_IS_SIZETYPE (t1) > TYPE_IS_SIZETYPE (t2))
-       return build_type_attribute_variant (t1, attributes);
-      if (TYPE_IS_SIZETYPE (t2) > TYPE_IS_SIZETYPE (t1))
-       return build_type_attribute_variant (t2, attributes);
-
       /* If one is unsigned long long, then convert the other to unsigned
         long long.  */
       if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_unsigned_type_node)
@@ -400,7 +397,8 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
    case.  See that function for documentation fo the parameters.  */
 
 static tree
-composite_pointer_type_r (tree t1, tree t2, const char* location)
+composite_pointer_type_r (tree t1, tree t2, const char* location,
+                         tsubst_flags_t complain)
 {
   tree pointee1;
   tree pointee2;
@@ -432,12 +430,14 @@ composite_pointer_type_r (tree t1, tree t2, const char* location)
            && TREE_CODE (pointee2) == POINTER_TYPE)
           || (TYPE_PTR_TO_MEMBER_P (pointee1)
               && TYPE_PTR_TO_MEMBER_P (pointee2)))
-    result_type = composite_pointer_type_r (pointee1, pointee2, location);
+    result_type = composite_pointer_type_r (pointee1, pointee2, location,
+                                           complain);
   else
     {
-      pedwarn ("%s between distinct pointer types %qT and %qT "
-              "lacks a cast",
-              location, t1, t2);
+      if (complain & tf_error)
+       permerror ("%s between distinct pointer types %qT and %qT "
+                  "lacks a cast",
+                  location, t1, t2);
       result_type = void_type_node;
     }
   result_type = cp_build_qualified_type (result_type,
@@ -448,10 +448,11 @@ composite_pointer_type_r (tree t1, tree t2, const char* location)
   if (TYPE_PTR_TO_MEMBER_P (t1))
     {
       if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
-                       TYPE_PTRMEM_CLASS_TYPE (t2)))
-       pedwarn ("%s between distinct pointer types %qT and %qT "
-                "lacks a cast",
-                location, t1, t2);
+                       TYPE_PTRMEM_CLASS_TYPE (t2))
+         && (complain & tf_error))
+       permerror ("%s between distinct pointer types %qT and %qT "
+                  "lacks a cast",
+                  location, t1, t2);
       result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
                                       result_type);
     }
@@ -472,7 +473,7 @@ composite_pointer_type_r (tree t1, tree t2, const char* location)
 
 tree
 composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
-                       const char* location)
+                       const char* location, tsubst_flags_t complain)
 {
   tree class1;
   tree class2;
@@ -510,7 +511,7 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       tree attributes;
       tree result_type;
 
-      if (pedantic && TYPE_PTRFN_P (t2))
+      if (pedantic && TYPE_PTRFN_P (t2) && (complain & tf_error))
        pedwarn ("ISO C++ forbids %s between pointer of type %<void *%> "
                 "and pointer-to-function", location);
       result_type
@@ -549,8 +550,9 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
              (cp_build_qualified_type (class2, TYPE_QUALS (class1))));
       else
        {
-         error ("%s between distinct pointer types %qT and %qT "
-                "lacks a cast", location, t1, t2);
+         if (complain & tf_error)
+           error ("%s between distinct pointer types %qT and %qT "
+                  "lacks a cast", location, t1, t2);
          return error_mark_node;
        }
     }
@@ -569,13 +571,14 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
        t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
       else
        {
-         error ("%s between distinct pointer-to-member types %qT and %qT "
-                "lacks a cast", location, t1, t2);
+         if (complain & tf_error)
+           error ("%s between distinct pointer-to-member types %qT and %qT "
+                  "lacks a cast", location, t1, t2);
          return error_mark_node;
        }
     }
 
-  return composite_pointer_type_r (t1, t2, location);
+  return composite_pointer_type_r (t1, t2, location, complain);
 }
 
 /* Return the merged type of two types.
@@ -627,7 +630,7 @@ merge_types (tree t1, tree t2)
        if (code1 == POINTER_TYPE)
          t1 = build_pointer_type (target);
        else
-         t1 = build_reference_type (target);
+         t1 = cp_build_reference_type (target, TYPE_REF_IS_RVALUE (t1));
        t1 = build_type_attribute_variant (t1, attributes);
        t1 = cp_build_qualified_type (t1, quals);
 
@@ -761,16 +764,16 @@ common_type (tree t1, tree t2)
   code2 = TREE_CODE (t2);
 
   if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
-       || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
+       || code1 == VECTOR_TYPE)
       && (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
-         || code2 == COMPLEX_TYPE || code2 == VECTOR_TYPE))
+         || code2 == VECTOR_TYPE))
     return type_after_usual_arithmetic_conversions (t1, t2);
 
   else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
           || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
           || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
     return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
-                                  "conversion");
+                                  "conversion", tf_warning_or_error);
   else
     gcc_unreachable ();
 }
@@ -827,10 +830,10 @@ comp_except_types (tree a, tree b, bool exact)
    we should try to make use of that.  */
 
 bool
-comp_except_specs (tree t1, tree t2, bool exact)
+comp_except_specs (const_tree t1, const_tree t2, bool exact)
 {
-  tree probe;
-  tree base;
+  const_tree probe;
+  const_tree base;
   int  length = 0;
 
   if (t1 == t2)
@@ -874,7 +877,7 @@ comp_except_specs (tree t1, tree t2, bool exact)
    [] can match [size].  */
 
 static bool
-comp_array_types (tree t1, tree t2, bool allow_redeclaration)
+comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
 {
   tree d1;
   tree d2;
@@ -932,11 +935,10 @@ comp_array_types (tree t1, tree t2, bool allow_redeclaration)
   return true;
 }
 
-/* Return true if T1 and T2 are related as allowed by STRICT.  STRICT
-   is a bitwise-or of the COMPARE_* flags.  */
+/* Subroutine in comptypes.  */
 
-bool
-comptypes (tree t1, tree t2, int strict)
+static bool
+structural_comptypes (tree t1, tree t2, int strict)
 {
   if (t1 == t2)
     return true;
@@ -950,30 +952,10 @@ comptypes (tree t1, tree t2, int strict)
   /* TYPENAME_TYPEs should be resolved if the qualifying scope is the
      current instantiation.  */
   if (TREE_CODE (t1) == TYPENAME_TYPE)
-    {
-      tree resolved = resolve_typename_type (t1, /*only_current_p=*/true);
-
-      if (resolved != error_mark_node)
-       t1 = resolved;
-    }
+    t1 = resolve_typename_type (t1, /*only_current_p=*/true);
 
   if (TREE_CODE (t2) == TYPENAME_TYPE)
-    {
-      tree resolved = resolve_typename_type (t2, /*only_current_p=*/true);
-
-      if (resolved != error_mark_node)
-       t2 = resolved;
-    }
-
-  /* If either type is the internal version of sizetype, use the
-     language version.  */
-  if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
-      && TYPE_ORIG_SIZE_TYPE (t1))
-    t1 = TYPE_ORIG_SIZE_TYPE (t1);
-
-  if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
-      && TYPE_ORIG_SIZE_TYPE (t2))
-    t2 = TYPE_ORIG_SIZE_TYPE (t2);
+    t2 = resolve_typename_type (t2, /*only_current_p=*/true);
 
   if (TYPE_PTRMEMFUNC_P (t1))
     t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
@@ -1003,10 +985,36 @@ comptypes (tree t1, tree t2, int strict)
   /* Compare the types.  Break out if they could be the same.  */
   switch (TREE_CODE (t1))
     {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      /* All void and bool types are the same.  */
+      break;
+
+    case INTEGER_TYPE:
+    case FIXED_POINT_TYPE:
+    case REAL_TYPE:
+      /* With these nodes, we can't determine type equivalence by
+        looking at what is stored in the nodes themselves, because
+        two nodes might have different TYPE_MAIN_VARIANTs but still
+        represent the same type.  For example, wchar_t and int could
+        have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE,
+        TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs
+        and are distinct types. On the other hand, int and the
+        following typedef
+
+           typedef int INT __attribute((may_alias));
+
+        have identical properties, different TYPE_MAIN_VARIANTs, but
+        represent the same type.  The canonical type system keeps
+        track of equivalence in this case, so we fall back on it.  */
+      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
-         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+          || (TEMPLATE_TYPE_PARAMETER_PACK (t1) 
+              != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
        return false;
       if (!comp_template_parms
          (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
@@ -1041,8 +1049,12 @@ comptypes (tree t1, tree t2, int strict)
        return false;
       break;
 
-    case POINTER_TYPE:
     case REFERENCE_TYPE:
+      if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
+       return false;
+      /* fall through to checks for pointer types */
+
+    case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
          || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
          || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
@@ -1065,7 +1077,9 @@ comptypes (tree t1, tree t2, int strict)
 
     case TEMPLATE_TYPE_PARM:
       if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
-         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+          || (TEMPLATE_TYPE_PARAMETER_PACK (t1) 
+              != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
        return false;
       break;
 
@@ -1095,6 +1109,18 @@ comptypes (tree t1, tree t2, int strict)
        return false;
       break;
 
+    case TYPE_PACK_EXPANSION:
+      return same_type_p (PACK_EXPANSION_PATTERN (t1), 
+                          PACK_EXPANSION_PATTERN (t2));
+
+    case DECLTYPE_TYPE:
+      if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
+          != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
+          || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
+                             DECLTYPE_TYPE_EXPR (t2)))
+        return false;
+      break;
+
     default:
       return false;
     }
@@ -1105,10 +1131,64 @@ comptypes (tree t1, tree t2, int strict)
   return targetm.comp_type_attributes (t1, t2);
 }
 
+/* Return true if T1 and T2 are related as allowed by STRICT.  STRICT
+   is a bitwise-or of the COMPARE_* flags.  */
+
+bool
+comptypes (tree t1, tree t2, int strict)
+{
+  if (strict == COMPARE_STRICT)
+    {
+      if (t1 == t2)
+       return true;
+
+      if (t1 == error_mark_node || t2 == error_mark_node)
+       return false;
+
+      if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2))
+       /* At least one of the types requires structural equality, so
+          perform a deep check. */
+       return structural_comptypes (t1, t2, strict);
+
+#ifdef ENABLE_CHECKING
+      if (USE_CANONICAL_TYPES)
+       {
+         bool result = structural_comptypes (t1, t2, strict);
+         
+         if (result && TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
+           /* The two types are structurally equivalent, but their
+              canonical types were different. This is a failure of the
+              canonical type propagation code.*/
+           internal_error 
+             ("canonical types differ for identical types %T and %T", 
+              t1, t2);
+         else if (!result && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
+           /* Two types are structurally different, but the canonical
+              types are the same. This means we were over-eager in
+              assigning canonical types. */
+           internal_error 
+             ("same canonical type node for different types %T and %T",
+              t1, t2);
+         
+         return result;
+       }
+#else
+      if (USE_CANONICAL_TYPES)
+       return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+#endif
+      else
+       return structural_comptypes (t1, t2, strict);
+    }
+  else if (strict == COMPARE_STRUCTURAL)
+    return structural_comptypes (t1, t2, COMPARE_STRICT);
+  else
+    return structural_comptypes (t1, t2, strict);
+}
+
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
 
 bool
-at_least_as_qualified_p (tree type1, tree type2)
+at_least_as_qualified_p (const_tree type1, const_tree type2)
 {
   int q1 = cp_type_quals (type1);
   int q2 = cp_type_quals (type2);
@@ -1121,7 +1201,7 @@ at_least_as_qualified_p (tree type1, tree type2)
    more cv-qualified that TYPE1, and 0 otherwise.  */
 
 int
-comp_cv_qualification (tree type1, tree type2)
+comp_cv_qualification (const_tree type1, const_tree type2)
 {
   int q1 = cp_type_quals (type1);
   int q2 = cp_type_quals (type2);
@@ -1151,59 +1231,6 @@ comp_cv_qual_signature (tree type1, tree type2)
   else
     return 0;
 }
-
-/* If two types share a common base type, return that basetype.
-   If there is not a unique most-derived base type, this function
-   returns ERROR_MARK_NODE.  */
-
-static tree
-common_base_type (tree tt1, tree tt2)
-{
-  tree best = NULL_TREE;
-  int i;
-
-  /* If one is a baseclass of another, that's good enough.  */
-  if (UNIQUELY_DERIVED_FROM_P (tt1, tt2))
-    return tt1;
-  if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
-    return tt2;
-
-  /* Otherwise, try to find a unique baseclass of TT1
-     that is shared by TT2, and follow that down.  */
-  for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (tt1))-1; i >= 0; i--)
-    {
-      tree basetype = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (tt1), i));
-      tree trial = common_base_type (basetype, tt2);
-
-      if (trial)
-       {
-         if (trial == error_mark_node)
-           return trial;
-         if (best == NULL_TREE)
-           best = trial;
-         else if (best != trial)
-           return error_mark_node;
-       }
-    }
-
-  /* Same for TT2.  */
-  for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (tt2))-1; i >= 0; i--)
-    {
-      tree basetype = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (tt2), i));
-      tree trial = common_base_type (tt1, basetype);
-
-      if (trial)
-       {
-         if (trial == error_mark_node)
-           return trial;
-         if (best == NULL_TREE)
-           best = trial;
-         else if (best != trial)
-           return error_mark_node;
-       }
-    }
-  return best;
-}
 \f
 /* Subroutines of `comptypes'.  */
 
@@ -1213,9 +1240,9 @@ common_base_type (tree tt1, tree tt2)
    element by element.  */
 
 bool
-compparms (tree parms1, tree parms2)
+compparms (const_tree parms1, const_tree parms2)
 {
-  tree t1, t2;
+  const_tree t1, t2;
 
   /* An unspecified parmlist matches any specified parmlist
      whose argument types don't need default promotions.  */
@@ -1241,44 +1268,67 @@ compparms (tree parms1, tree parms2)
 tree
 cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
 {
-  enum tree_code type_code;
   tree value;
-  const char *op_name;
+  bool dependent_p;
 
   gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR);
   if (type == error_mark_node)
     return error_mark_node;
 
-  if (dependent_type_p (type))
+  type = non_reference (type);
+  if (TREE_CODE (type) == METHOD_TYPE)
+    {
+      if (complain && (pedantic || warn_pointer_arith))
+       pedwarn ("invalid application of %qs to a member function", 
+                operator_name_info[(int) op].name);
+      value = size_one_node;
+    }
+
+  dependent_p = dependent_type_p (type);
+  if (!dependent_p)
+    complete_type (type);
+  if (dependent_p
+      /* VLA types will have a non-constant size.  In the body of an
+        uninstantiated template, we don't need to try to compute the
+        value, because the sizeof expression is not an integral
+        constant expression in that case.  And, if we do try to
+        compute the value, we'll likely end up with SAVE_EXPRs, which
+        the template substitution machinery does not expect to see.  */
+      || (processing_template_decl 
+         && COMPLETE_TYPE_P (type)
+         && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST))
     {
       value = build_min (op, size_type_node, type);
       TREE_READONLY (value) = 1;
       return value;
     }
 
-  op_name = operator_name_info[(int) op].name;
-
-  type = non_reference (type);
-  type_code = TREE_CODE (type);
+  return c_sizeof_or_alignof_type (complete_type (type),
+                                  op == SIZEOF_EXPR,
+                                  complain);
+}
 
-  if (type_code == METHOD_TYPE)
-    {
-      if (complain && (pedantic || warn_pointer_arith))
-       pedwarn ("invalid application of %qs to a member function", op_name);
-      value = size_one_node;
-    }
+/* Return the size of the type, without producing any warnings for
+   types whose size cannot be taken.  This routine should be used only
+   in some other routine that has already produced a diagnostic about
+   using the size of such a type.  */
+tree 
+cxx_sizeof_nowarn (tree type)
+{
+  if (TREE_CODE (type) == FUNCTION_TYPE
+      || TREE_CODE (type) == VOID_TYPE
+      || TREE_CODE (type) == ERROR_MARK)
+    return size_one_node;
+  else if (!COMPLETE_TYPE_P (type))
+    return size_zero_node;
   else
-    value = c_sizeof_or_alignof_type (complete_type (type),
-                                     op == SIZEOF_EXPR,
-                                     complain);
-
-  return value;
+    return cxx_sizeof_or_alignof_type (type, SIZEOF_EXPR, false);
 }
 
 /* Process a sizeof expression where the operand is an expression.  */
 
 static tree
-cxx_sizeof_expr (tree e)
+cxx_sizeof_expr (tree e, tsubst_flags_t complain)
 {
   if (e == error_mark_node)
     return error_mark_node;
@@ -1296,24 +1346,33 @@ cxx_sizeof_expr (tree e)
       && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
       && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
     {
-      error ("invalid application of %<sizeof%> to a bit-field");
+      if (complain & tf_error)
+        error ("invalid application of %<sizeof%> to a bit-field");
+      else
+        return error_mark_node;
       e = char_type_node;
     }
   else if (is_overloaded_fn (e))
     {
-      pedwarn ("ISO C++ forbids applying %<sizeof%> to an expression of "
-              "function type");
+      if (complain & tf_error)
+        permerror ("ISO C++ forbids applying %<sizeof%> to an expression of "
+                   "function type");
+      else
+        return error_mark_node;
       e = char_type_node;
     }
   else if (type_unknown_p (e))
     {
-      cxx_incomplete_type_error (e, TREE_TYPE (e));
+      if (complain & tf_error)
+        cxx_incomplete_type_error (e, TREE_TYPE (e));
+      else
+        return error_mark_node;
       e = char_type_node;
     }
   else
     e = TREE_TYPE (e);
 
-  return cxx_sizeof_or_alignof_type (e, SIZEOF_EXPR, true);
+  return cxx_sizeof_or_alignof_type (e, SIZEOF_EXPR, complain & tf_error);
 }
 
 /* Implement the __alignof keyword: Return the minimum required
@@ -1322,7 +1381,7 @@ cxx_sizeof_expr (tree e)
    "aligned" __attribute__ specification).  */
 
 static tree
-cxx_alignof_expr (tree e)
+cxx_alignof_expr (tree e, tsubst_flags_t complain)
 {
   tree t;
 
@@ -1344,7 +1403,10 @@ cxx_alignof_expr (tree e)
           && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
           && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
     {
-      error ("invalid application of %<__alignof%> to a bit-field");
+      if (complain & tf_error)
+        error ("invalid application of %<__alignof%> to a bit-field");
+      else
+        return error_mark_node;
       t = size_one_node;
     }
   else if (TREE_CODE (e) == COMPONENT_REF
@@ -1352,17 +1414,27 @@ cxx_alignof_expr (tree e)
     t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (e, 1)));
   else if (is_overloaded_fn (e))
     {
-      pedwarn ("ISO C++ forbids applying %<__alignof%> to an expression of "
-              "function type");
-      t = size_one_node;
+      if (complain & tf_error)
+        permerror ("ISO C++ forbids applying %<__alignof%> to an expression of "
+                   "function type");
+      else
+        return error_mark_node;
+      if (TREE_CODE (e) == FUNCTION_DECL)
+       t = size_int (DECL_ALIGN_UNIT (e));
+      else
+       t = size_one_node;
     }
   else if (type_unknown_p (e))
     {
-      cxx_incomplete_type_error (e, TREE_TYPE (e));
+      if (complain & tf_error)
+        cxx_incomplete_type_error (e, TREE_TYPE (e));
+      else
+        return error_mark_node;
       t = size_one_node;
     }
   else
-    return cxx_sizeof_or_alignof_type (TREE_TYPE (e), ALIGNOF_EXPR, true);
+    return cxx_sizeof_or_alignof_type (TREE_TYPE (e), ALIGNOF_EXPR, 
+                                       complain & tf_error);
 
   return fold_convert (size_type_node, t);
 }
@@ -1371,12 +1443,12 @@ cxx_alignof_expr (tree e)
    is an expression.  */
 
 tree
-cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
+cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
 {
   if (op == SIZEOF_EXPR)
-    return cxx_sizeof_expr (e);
+    return cxx_sizeof_expr (e, complain? tf_warning_or_error : tf_none);
   else
-    return cxx_alignof_expr (e);
+    return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none);
 }
 \f
 /* EXPR is being used in a context that is not a function call.
@@ -1396,11 +1468,12 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
    violates these rules.  */
 
 bool
-invalid_nonstatic_memfn_p (tree expr)
+invalid_nonstatic_memfn_p (const_tree expr, tsubst_flags_t complain)
 {
   if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
     {
-      error ("invalid use of non-static member function");
+      if (complain & tf_error)
+        error ("invalid use of non-static member function");
       return true;
     }
   return false;
@@ -1411,25 +1484,62 @@ invalid_nonstatic_memfn_p (tree expr)
    of the bitfield.  Otherwise, return NULL_TREE.  */
 
 tree
-is_bitfield_expr_with_lowered_type (tree exp)
+is_bitfield_expr_with_lowered_type (const_tree exp)
 {
-  tree field;
-
-  if (TREE_CODE (exp) == COND_EXPR)
+  switch (TREE_CODE (exp))
     {
-      if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)))
+    case COND_EXPR:
+      if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)
+                                              ? TREE_OPERAND (exp, 1)
+                                              : TREE_OPERAND (exp, 0)))
        return NULL_TREE;
       return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
+
+    case COMPOUND_EXPR:
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1));
+
+    case MODIFY_EXPR:
+    case SAVE_EXPR:
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+
+    case COMPONENT_REF:
+      {
+       tree field;
+       
+       field = TREE_OPERAND (exp, 1);
+       if (TREE_CODE (field) != FIELD_DECL || !DECL_BIT_FIELD_TYPE (field))
+         return NULL_TREE;
+       if (same_type_ignoring_top_level_qualifiers_p
+           (TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
+         return NULL_TREE;
+       return DECL_BIT_FIELD_TYPE (field);
+      }
+
+    CASE_CONVERT:
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
+         == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
+       return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+      /* Fallthrough.  */
+
+    default:
+      return NULL_TREE;
     }
-  if (TREE_CODE (exp) != COMPONENT_REF)
-    return NULL_TREE;
-  field = TREE_OPERAND (exp, 1);
-  if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field))
-    return NULL_TREE;
-  if (same_type_ignoring_top_level_qualifiers_p
-      (TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
-    return NULL_TREE;
-  return DECL_BIT_FIELD_TYPE (field);
+}
+
+/* Like is_bitfield_with_lowered_type, except that if EXP is not a
+   bitfield with a lowered type, the type of EXP is returned, rather
+   than NULL_TREE.  */
+
+tree
+unlowered_expr_type (const_tree exp)
+{
+  tree type;
+
+  type = is_bitfield_expr_with_lowered_type (exp);
+  if (!type)
+    type = TREE_TYPE (exp);
+
+  return type;
 }
 
 /* Perform the conversions in [expr] that apply when an lvalue appears
@@ -1471,10 +1581,10 @@ decay_conversion (tree exp)
       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
-  if (invalid_nonstatic_memfn_p (exp))
+  if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
     return error_mark_node;
   if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
-    return build_unary_op (ADDR_EXPR, exp, 0);
+    return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error);
   if (code == ARRAY_TYPE)
     {
       tree adr;
@@ -1509,7 +1619,7 @@ decay_conversion (tree exp)
        }
       /* This way is better for a COMPONENT_REF since it can
         simplify the offset for a component.  */
-      adr = build_unary_op (ADDR_EXPR, exp, 1);
+      adr = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
       return cp_convert (ptrtype, adr);
     }
 
@@ -1602,7 +1712,7 @@ inline_conversion (tree exp)
    decay_conversion to one.  */
 
 int
-string_conv_p (tree totype, tree exp, int warn)
+string_conv_p (const_tree totype, const_tree exp, int warn)
 {
   tree t;
 
@@ -1611,12 +1721,14 @@ string_conv_p (tree totype, tree exp, int warn)
 
   t = TREE_TYPE (totype);
   if (!same_type_p (t, char_type_node)
+      && !same_type_p (t, char16_type_node)
+      && !same_type_p (t, char32_type_node)
       && !same_type_p (t, wchar_type_node))
     return 0;
 
   if (TREE_CODE (exp) == STRING_CST)
     {
-      /* Make sure that we don't try to convert between char and wchar_t.  */
+      /* Make sure that we don't try to convert between char and wide chars.  */
       if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))), t))
        return 0;
     }
@@ -1650,30 +1762,39 @@ string_conv_p (tree totype, tree exp, int warn)
    get it there.  */
 
 static tree
-rationalize_conditional_expr (enum tree_code code, tree t)
+rationalize_conditional_expr (enum tree_code code, tree t,
+                              tsubst_flags_t complain)
 {
   /* For MIN_EXPR or MAX_EXPR, fold-const.c has arranged things so that
      the first operand is always the one to be used if both operands
      are equal, so we know what conditional expression this used to be.  */
   if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
     {
+      tree op0 = TREE_OPERAND (t, 0);
+      tree op1 = TREE_OPERAND (t, 1);
+
       /* The following code is incorrect if either operand side-effects.  */
-      gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
-                 && !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
+      gcc_assert (!TREE_SIDE_EFFECTS (op0)
+                 && !TREE_SIDE_EFFECTS (op1));
       return
        build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
                                                    ? LE_EXPR : GE_EXPR),
-                                                  TREE_OPERAND (t, 0),
-                                                  TREE_OPERAND (t, 1),
-                                                  /*overloaded_p=*/NULL),
-                           build_unary_op (code, TREE_OPERAND (t, 0), 0),
-                           build_unary_op (code, TREE_OPERAND (t, 1), 0));
+                                                  op0, TREE_CODE (op0),
+                                                  op1, TREE_CODE (op1),
+                                                  /*overloaded_p=*/NULL,
+                                                  complain),
+                                cp_build_unary_op (code, op0, 0, complain),
+                                cp_build_unary_op (code, op1, 0, complain),
+                                complain);
     }
 
   return
     build_conditional_expr (TREE_OPERAND (t, 0),
-                           build_unary_op (code, TREE_OPERAND (t, 1), 0),
-                           build_unary_op (code, TREE_OPERAND (t, 2), 0));
+                           cp_build_unary_op (code, TREE_OPERAND (t, 1), 0,
+                                               complain),
+                           cp_build_unary_op (code, TREE_OPERAND (t, 2), 0,
+                                               complain),
+                            complain);
 }
 
 /* Given the TYPE of an anonymous union field inside T, return the
@@ -1726,7 +1847,8 @@ lookup_anon_field (tree t, tree type)
 
 tree
 build_class_member_access_expr (tree object, tree member,
-                               tree access_path, bool preserve_reference)
+                               tree access_path, bool preserve_reference,
+                               tsubst_flags_t complain)
 {
   tree object_type;
   tree member_scope;
@@ -1747,8 +1869,9 @@ build_class_member_access_expr (tree object, tree member,
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
-      error ("request for member %qD in %qE, which is of non-class type %qT",
-            member, object, object_type);
+      if (complain & tf_error)
+       error ("request for member %qD in %qE, which is of non-class type %qT",
+              member, object, object_type);
       return error_mark_node;
     }
 
@@ -1763,7 +1886,7 @@ build_class_member_access_expr (tree object, tree member,
        warn_deprecated_use (member);
     }
   else
-    member_scope = BINFO_TYPE (BASELINK_BINFO (member));
+    member_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (member));
   /* If MEMBER is from an anonymous aggregate, MEMBER_SCOPE will
      presently be the anonymous union.  Go outwards until we find a
      type related to OBJECT_TYPE.  */
@@ -1773,20 +1896,23 @@ build_class_member_access_expr (tree object, tree member,
     member_scope = TYPE_CONTEXT (member_scope);
   if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
     {
-      if (TREE_CODE (member) == FIELD_DECL)
-       error ("invalid use of nonstatic data member %qE", member);
-      else
-       error ("%qD is not a member of %qT", member, object_type);
+      if (complain & tf_error)
+       {
+         if (TREE_CODE (member) == FIELD_DECL)
+           error ("invalid use of nonstatic data member %qE", member);
+         else
+           error ("%qD is not a member of %qT", member, object_type);
+       }
       return error_mark_node;
     }
 
   /* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x' into
      `(*(a ?  &b : &c)).x', and so on.  A COND_EXPR is only an lvalue
-     in the frontend; only _DECLs and _REFs are lvalues in the backend.  */
+     in the front end; only _DECLs and _REFs are lvalues in the back end.  */
   {
     tree temp = unary_complex_lvalue (ADDR_EXPR, object);
     if (temp)
-      object = build_indirect_ref (temp, NULL);
+      object = cp_build_indirect_ref (temp, NULL, complain);
   }
 
   /* In [expr.ref], there is an explicit list of the valid choices for
@@ -1826,10 +1952,13 @@ build_class_member_access_expr (tree object, tree member,
             offsetof macro.  */
          if (null_object_p && kind == bk_via_virtual)
            {
-             error ("invalid access to non-static data member %qD of "
-                    "NULL object",
-                    member);
-             error ("(perhaps the %<offsetof%> macro was used incorrectly)");
+             if (complain & tf_error)
+               {
+                 error ("invalid access to non-static data member %qD of "
+                        "NULL object",
+                        member);
+                 error ("(perhaps the %<offsetof%> macro was used incorrectly)");
+               }
              return error_mark_node;
            }
 
@@ -1852,11 +1981,14 @@ build_class_member_access_expr (tree object, tree member,
       if (null_object_p && warn_invalid_offsetof
          && CLASSTYPE_NON_POD_P (object_type)
          && !DECL_FIELD_IS_BASE (member)
-         && !skip_evaluation)
+         && !skip_evaluation
+         && (complain & tf_warning))
        {
-         warning (0, "invalid access to non-static data member %qD of NULL object",
-                  member);
-         warning (0, "(perhaps the %<offsetof%> macro was used incorrectly)");
+         warning (OPT_Winvalid_offsetof, 
+                   "invalid access to non-static data member %qD "
+                   " of NULL object", member);
+         warning (OPT_Winvalid_offsetof, 
+                   "(perhaps the %<offsetof%> macro was used incorrectly)");
        }
 
       /* If MEMBER is from an anonymous aggregate, we have converted
@@ -1880,7 +2012,8 @@ build_class_member_access_expr (tree object, tree member,
          object = build_class_member_access_expr (object,
                                                   anonymous_union,
                                                   /*access_path=*/NULL_TREE,
-                                                  preserve_reference);
+                                                  preserve_reference,
+                                                  complain);
        }
 
       /* Compute the type of the field, as described in [expr.ref].  */
@@ -1941,7 +2074,8 @@ build_class_member_access_expr (tree object, tree member,
     }
   else
     {
-      error ("invalid use of %qD", member);
+      if (complain & tf_error)
+       error ("invalid use of %qD", member);
       return error_mark_node;
     }
 
@@ -2012,7 +2146,7 @@ check_template_keyword (tree decl)
       && TREE_CODE (decl) != TEMPLATE_ID_EXPR)
     {
       if (!is_overloaded_fn (decl))
-       pedwarn ("%qD is not a template", decl);
+       permerror ("%qD is not a template", decl);
       else
        {
          tree fns;
@@ -2032,7 +2166,7 @@ check_template_keyword (tree decl)
              fns = OVL_NEXT (fns);
            }
          if (!fns)
-           pedwarn ("%qD is not a template", decl);
+           permerror ("%qD is not a template", decl);
        }
     }
 }
@@ -2047,7 +2181,8 @@ check_template_keyword (tree decl)
    be a template via the use of the "A::template B" syntax.  */
 
 tree
-finish_class_member_access_expr (tree object, tree name, bool template_p)
+finish_class_member_access_expr (tree object, tree name, bool template_p,
+                                tsubst_flags_t complain)
 {
   tree expr;
   tree object_type;
@@ -2095,8 +2230,9 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
-      error ("request for member %qD in %qE, which is of non-class type %qT",
-            name, object, object_type);
+      if (complain & tf_error)
+       error ("request for member %qD in %qE, which is of non-class type %qT",
+              name, object, object_type);
       return error_mark_node;
     }
 
@@ -2133,8 +2269,9 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
             name a member of OBJECT_TYPE.  */
          if (TREE_CODE (scope) == NAMESPACE_DECL)
            {
-             error ("%<%D::%D%> is not a member of %qT",
-                    scope, name, object_type);
+             if (complain & tf_error)
+               error ("%<%D::%D%> is not a member of %qT",
+                      scope, name, object_type);
              return error_mark_node;
            }
 
@@ -2148,7 +2285,8 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
            return error_mark_node;
          if (!access_path)
            {
-             error ("%qT is not a base of %qT", scope, object_type);
+             if (complain & tf_error)
+               error ("%qT is not a base of %qT", scope, object_type);
              return error_mark_node;
            }
        }
@@ -2167,7 +2305,8 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
                                  /*want_type=*/false);
          if (member == NULL_TREE)
            {
-             error ("%qD has no member named %qE", object_type, name);
+             if (complain & tf_error)
+               error ("%qD has no member named %qE", object_type, name);
              return error_mark_node;
            }
          if (member == error_mark_node)
@@ -2182,7 +2321,8 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
            template = lookup_template_function (template, template_args);
          else
            {
-             error ("%qD is not a member template function", name);
+             if (complain & tf_error)
+               error ("%qD is not a member template function", name);
              return error_mark_node;
            }
        }
@@ -2195,7 +2335,8 @@ finish_class_member_access_expr (tree object, tree name, bool template_p)
     check_template_keyword (member);
 
   expr = build_class_member_access_expr (object, member, access_path,
-                                        /*preserve_reference=*/false);
+                                        /*preserve_reference=*/false,
+                                        complain);
   if (processing_template_decl && expr != error_mark_node)
     {
       if (BASELINK_P (member))
@@ -2248,7 +2389,8 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
    Must also handle REFERENCE_TYPEs for C++.  */
 
 tree
-build_x_indirect_ref (tree expr, const char *errorstring)
+build_x_indirect_ref (tree expr, const char *errorstring, 
+                      tsubst_flags_t complain)
 {
   tree orig_expr = expr;
   tree rval;
@@ -2261,9 +2403,9 @@ build_x_indirect_ref (tree expr, const char *errorstring)
     }
 
   rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
-                      NULL_TREE, /*overloaded_p=*/NULL);
+                      NULL_TREE, /*overloaded_p=*/NULL, complain);
   if (!rval)
-    rval = build_indirect_ref (expr, errorstring);
+    rval = cp_build_indirect_ref (expr, errorstring, complain);
 
   if (processing_template_decl && rval != error_mark_node)
     return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
@@ -2271,9 +2413,17 @@ build_x_indirect_ref (tree expr, const char *errorstring)
     return rval;
 }
 
+/* Helper function called from c-common.  */
 tree
 build_indirect_ref (tree ptr, const char *errorstring)
 {
+  return cp_build_indirect_ref (ptr, errorstring, tf_warning_or_error);
+}
+
+tree
+cp_build_indirect_ref (tree ptr, const char *errorstring, 
+                       tsubst_flags_t complain)
+{
   tree pointer, type;
 
   if (ptr == error_mark_node)
@@ -2298,11 +2448,24 @@ build_indirect_ref (tree ptr, const char *errorstring)
         types.  */
       tree t = canonical_type_variant (TREE_TYPE (type));
 
+      if (CONVERT_EXPR_P (ptr)
+          || TREE_CODE (ptr) == VIEW_CONVERT_EXPR)
+       {
+         /* If a warning is issued, mark it to avoid duplicates from
+            the backend.  This only needs to be done at
+            warn_strict_aliasing > 2.  */
+         if (warn_strict_aliasing > 2)
+           if (strict_aliasing_warning (TREE_TYPE (TREE_OPERAND (ptr, 0)),
+                                        type, TREE_OPERAND (ptr, 0)))
+             TREE_NO_WARNING (ptr) = 1;
+       }
+
       if (VOID_TYPE_P (t))
        {
          /* A pointer to incomplete type (other than cv void) can be
             dereferenced [expr.unary.op]/1  */
-         error ("%qT is not a pointer-to-object type", type);
+          if (complain & tf_error)
+            error ("%qT is not a pointer-to-object type", type);
          return error_mark_node;
        }
       else if (TREE_CODE (pointer) == ADDR_EXPR
@@ -2324,6 +2487,9 @@ build_indirect_ref (tree ptr, const char *errorstring)
          return ref;
        }
     }
+  else if (!(complain & tf_error))
+    /* Don't emit any errors; we'll just return ERROR_MARK_NODE later.  */
+    ;
   /* `pointer' won't be an error_mark_node if we were given a
      pointer to member, so it's cool to check for this here.  */
   else if (TYPE_PTR_TO_MEMBER_P (type))
@@ -2379,7 +2545,8 @@ build_array_ref (tree array, tree idx)
       return build_conditional_expr
        (TREE_OPERAND (array, 0),
         build_array_ref (TREE_OPERAND (array, 1), idx),
-        build_array_ref (TREE_OPERAND (array, 2), idx));
+        build_array_ref (TREE_OPERAND (array, 2), idx),
+         tf_warning_or_error);
 
     default:
       break;
@@ -2483,8 +2650,12 @@ build_array_ref (tree array, tree idx)
        return error_mark_node;
       }
 
-    return build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind),
-                              "array indexing");
+    warn_array_subscript_with_type_char (idx);
+
+    return cp_build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind,
+                                                  tf_warning_or_error),
+                                  "array indexing",
+                                  tf_warning_or_error);
   }
 }
 \f
@@ -2537,18 +2708,22 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
 
       /* Start by extracting all the information from the PMF itself.  */
       e3 = pfn_from_ptrmemfunc (function);
-      delta = build_ptrmemfunc_access_expr (function, delta_identifier);
+      delta = delta_from_ptrmemfunc (function);
       idx = build1 (NOP_EXPR, vtable_index_type, e3);
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
        {
        case ptrmemfunc_vbit_in_pfn:
-         e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node);
-         idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
+         e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node,
+                                  tf_warning_or_error);
+         idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node,
+                                   tf_warning_or_error);
          break;
 
        case ptrmemfunc_vbit_in_delta:
-         e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node);
-         delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node);
+         e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node,
+                                  tf_warning_or_error);
+         delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node,
+                                     tf_warning_or_error);
          break;
 
        default:
@@ -2573,8 +2748,8 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
            return error_mark_node;
        }
       /* ...and then the delta in the PMF.  */
-      instance_ptr = build2 (PLUS_EXPR, TREE_TYPE (instance_ptr),
-                            instance_ptr, delta);
+      instance_ptr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (instance_ptr),
+                            instance_ptr, fold_convert (sizetype, delta));
 
       /* Hand back the adjusted 'this' argument to our caller.  */
       *instance_ptrptr = instance_ptr;
@@ -2582,22 +2757,23 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
       /* Next extract the vtable pointer from the object.  */
       vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
                     instance_ptr);
-      vtbl = build_indirect_ref (vtbl, NULL);
+      vtbl = cp_build_indirect_ref (vtbl, NULL, tf_warning_or_error);
 
       /* Finally, extract the function pointer from the vtable.  */
-      e2 = fold_build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx);
-      e2 = build_indirect_ref (e2, NULL);
+      e2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
+                       fold_convert (sizetype, idx));
+      e2 = cp_build_indirect_ref (e2, NULL, tf_warning_or_error);
       TREE_CONSTANT (e2) = 1;
-      TREE_INVARIANT (e2) = 1;
 
       /* When using function descriptors, the address of the
         vtable entry is treated as a function pointer.  */
       if (TARGET_VTABLE_USES_DESCRIPTORS)
        e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
-                    build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1));
+                    cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1,
+                                     tf_warning_or_error));
 
-      TREE_TYPE (e2) = TREE_TYPE (e3);
-      e1 = build_conditional_expr (e1, e2, e3);
+      e2 = fold_convert (TREE_TYPE (e3), e2);
+      e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
 
       /* Make sure this doesn't get evaluated first inside one of the
         branches of the COND_EXPR.  */
@@ -2610,14 +2786,23 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
   return function;
 }
 
+/* Used by the C-common bits.  */
 tree
 build_function_call (tree function, tree params)
 {
+  return cp_build_function_call (function, params, tf_warning_or_error);
+}
+
+tree
+cp_build_function_call (tree function, tree params, tsubst_flags_t complain)
+{
   tree fntype, fndecl;
-  tree coerced_params;
   tree name = NULL_TREE;
   int is_method;
   tree original = function;
+  int nargs, parm_types_len;
+  tree *argarray;
+  tree parm_types;
 
   /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
      expressions, like those used for ObjC messenger dispatches.  */
@@ -2637,7 +2822,7 @@ build_function_call (tree function, tree params)
       fndecl = function;
 
       /* Convert anything with function type to a pointer-to-function.  */
-      if (pedantic && DECL_MAIN_P (function))
+      if (pedantic && DECL_MAIN_P (function) && (complain & tf_error))
        pedwarn ("ISO C++ forbids calling %<::main%> from within program");
 
       /* Differs from default_conversion by not setting TREE_ADDRESSABLE
@@ -2663,9 +2848,10 @@ build_function_call (tree function, tree params)
 
   if (TYPE_PTRMEMFUNC_P (fntype))
     {
-      error ("must use %<.*%> or %<->*%> to call pointer-to-member "
-            "function in %<%E (...)%>",
-            original);
+      if (complain & tf_error)
+       error ("must use %<.*%> or %<->*%> to call pointer-to-member "
+              "function in %<%E (...)%>, e.g. %<(... ->* %E) (...)%>",
+              original, original);
       return error_mark_node;
     }
 
@@ -2677,28 +2863,43 @@ build_function_call (tree function, tree params)
        || is_method
        || TREE_CODE (function) == TEMPLATE_ID_EXPR))
     {
-      error ("%qE cannot be used as a function", original);
+      if (complain & tf_error)
+       error ("%qE cannot be used as a function", original);
       return error_mark_node;
     }
 
   /* fntype now gets the type of function pointed to.  */
   fntype = TREE_TYPE (fntype);
+  parm_types = TYPE_ARG_TYPES (fntype);
+
+  /* Allocate storage for converted arguments.  */
+  parm_types_len = list_length (parm_types);
+  nargs = list_length (params);
+  if (parm_types_len > nargs)
+    nargs = parm_types_len;
+  argarray = (tree *) alloca (nargs * sizeof (tree));
 
   /* Convert the parameters to the types declared in the
      function prototype, or apply default promotions.  */
+  nargs = convert_arguments (nargs, argarray, parm_types,
+                            params, fndecl, LOOKUP_NORMAL,
+                             complain);
+  if (nargs < 0)
+    return error_mark_node;
 
-  coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
-                                     params, fndecl, LOOKUP_NORMAL);
-  if (coerced_params == error_mark_node)
+  /* Check that arguments to builtin functions match the expectations.  */
+  if (fndecl
+      && DECL_BUILT_IN (fndecl)
+      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+      && !check_builtin_function_arguments (fndecl, nargs, argarray))
     return error_mark_node;
 
   /* Check for errors in format strings and inappropriately
      null parameters.  */
+  check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
+                           parm_types);
 
-  check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
-                           TYPE_ARG_TYPES (fntype));
-
-  return build_cxx_call (function, coerced_params);
+  return build_cxx_call (function, nargs, argarray);
 }
 \f
 /* Convert the actual parameter expressions in the list VALUES
@@ -2706,23 +2907,27 @@ build_function_call (tree function, tree params)
    If parmdecls is exhausted, or when an element has NULL as its type,
    perform the default conversions.
 
+   Store the converted arguments in ARGARRAY.  NARGS is the size of this array.
+
    NAME is an IDENTIFIER_NODE or 0.  It is used only for error messages.
 
    This is also where warnings about wrong number of args are generated.
 
-   Return a list of expressions for the parameters as converted.
+   Returns the actual number of arguments processed (which might be less
+   than NARGS), or -1 on error.
 
-   Both VALUES and the returned value are chains of TREE_LIST nodes
-   with the elements of the list in the TREE_VALUE slots of those nodes.
+   VALUES is a chain of TREE_LIST nodes with the elements of the list
+   in the TREE_VALUE slots of those nodes.
 
    In C++, unspecified trailing parameters can be filled in with their
    default arguments, if such were specified.  Do so here.  */
 
-static tree
-convert_arguments (tree typelist, tree values, tree fndecl, int flags)
+static int
+convert_arguments (int nargs, tree *argarray,
+                  tree typelist, tree values, tree fndecl, int flags,
+                   tsubst_flags_t complain)
 {
   tree typetail, valtail;
-  tree result = NULL_TREE;
   const char *called_thing = 0;
   int i = 0;
 
@@ -2751,22 +2956,24 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
       tree val = TREE_VALUE (valtail);
 
       if (val == error_mark_node || type == error_mark_node)
-       return error_mark_node;
+       return -1;
 
       if (type == void_type_node)
        {
-         if (fndecl)
-           {
-             error ("too many arguments to %s %q+#D", called_thing, fndecl);
-             error ("at this point in file");
-           }
-         else
-           error ("too many arguments to function");
-         /* In case anybody wants to know if this argument
-            list is valid.  */
-         if (result)
-           TREE_TYPE (tree_last (result)) = error_mark_node;
-         break;
+          if (complain & tf_error)
+            {
+              if (fndecl)
+                {
+                  error ("too many arguments to %s %q+#D", 
+                         called_thing, fndecl);
+                  error ("at this point in file");
+                }
+              else
+                error ("too many arguments to function");
+              return i;
+            }
+          else
+            return -1;
        }
 
       /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
@@ -2785,7 +2992,7 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
        }
 
       if (val == error_mark_node)
-       return error_mark_node;
+       return -1;
 
       if (type != 0)
        {
@@ -2794,25 +3001,28 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
 
          if (!COMPLETE_TYPE_P (complete_type (type)))
            {
-             if (fndecl)
-               error ("parameter %P of %qD has incomplete type %qT",
-                      i, fndecl, type);
-             else
-               error ("parameter %P has incomplete type %qT", i, type);
+              if (complain & tf_error)
+                {
+                  if (fndecl)
+                    error ("parameter %P of %qD has incomplete type %qT",
+                           i, fndecl, type);
+                  else
+                    error ("parameter %P has incomplete type %qT", i, type);
+                }
              parmval = error_mark_node;
            }
          else
            {
              parmval = convert_for_initialization
                (NULL_TREE, type, val, flags,
-                "argument passing", fndecl, i);
+                "argument passing", fndecl, i, complain);
              parmval = convert_for_arg_passing (type, parmval);
            }
 
          if (parmval == error_mark_node)
-           return error_mark_node;
+           return -1;
 
-         result = tree_cons (NULL_TREE, parmval, result);
+         argarray[i] = parmval;
        }
       else
        {
@@ -2825,7 +3035,7 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
          else
            val = convert_arg_to_ellipsis (val);
 
-         result = tree_cons (NULL_TREE, val, result);
+         argarray[i] = val;
        }
 
       if (typetail)
@@ -2834,8 +3044,14 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
 
   if (typetail != 0 && typetail != void_list_node)
     {
-      /* See if there are default arguments that can be used.  */
-      if (TREE_PURPOSE (typetail)
+      /* See if there are default arguments that can be used.  Because
+        we hold default arguments in the FUNCTION_TYPE (which is so
+        wrong), we can see default parameters here from deduced
+        contexts (and via typeof) for indirect function calls.
+        Fortunately we know whether we have a function decl to
+        provide default arguments in a language conformant
+        manner.  */
+      if (fndecl && TREE_PURPOSE (typetail)
          && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
        {
          for (; typetail != void_list_node; ++i)
@@ -2846,9 +3062,9 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
                                       fndecl, i);
 
              if (parmval == error_mark_node)
-               return error_mark_node;
+               return -1;
 
-             result = tree_cons (0, parmval, result);
+             argarray[i] = parmval;
              typetail = TREE_CHAIN (typetail);
              /* ends with `...'.  */
              if (typetail == NULL_TREE)
@@ -2857,26 +3073,40 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
        }
       else
        {
-         if (fndecl)
-           {
-             error ("too few arguments to %s %q+#D", called_thing, fndecl);
-             error ("at this point in file");
-           }
-         else
-           error ("too few arguments to function");
-         return error_mark_node;
+          if (complain & tf_error)
+            {
+              if (fndecl)
+                {
+                  error ("too few arguments to %s %q+#D", 
+                         called_thing, fndecl);
+                  error ("at this point in file");
+                }
+              else
+                error ("too few arguments to function");
+            }
+         return -1;
        }
     }
 
-  return nreverse (result);
+  gcc_assert (i <= nargs);
+  return i;
 }
 \f
 /* Build a binary-operation expression, after performing default
-   conversions on the operands.  CODE is the kind of expression to build.  */
+   conversions on the operands.  CODE is the kind of expression to
+   build.  ARG1 and ARG2 are the arguments.  ARG1_CODE and ARG2_CODE
+   are the tree codes which correspond to ARG1 and ARG2 when issuing
+   warnings about possibly misplaced parentheses.  They may differ
+   from the TREE_CODE of ARG1 and ARG2 if the parser has done constant
+   folding (e.g., if the parser sees "a | 1 + 1", it may call this
+   routine with ARG2 being an INTEGER_CST and ARG2_CODE == PLUS_EXPR).
+   To avoid issuing any parentheses warnings, pass ARG1_CODE and/or
+   ARG2_CODE as ERROR_MARK.  */
 
 tree
-build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
-                  bool *overloaded_p)
+build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
+                  tree arg2, enum tree_code arg2_code, bool *overloaded_p,
+                  tsubst_flags_t complain)
 {
   tree orig_arg1;
   tree orig_arg2;
@@ -2898,7 +3128,18 @@ build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
     expr = build_m_component_ref (arg1, arg2);
   else
     expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
-                        overloaded_p);
+                        overloaded_p, complain);
+
+  /* Check for cases such as x+y<<z which users are likely to
+     misinterpret.  But don't warn about obj << x + y, since that is a
+     common idiom for I/O.  */
+  if (warn_parentheses
+      && !processing_template_decl
+      && !error_operand_p (arg1)
+      && !error_operand_p (arg2)
+      && (code != LSHIFT_EXPR
+         || !CLASS_TYPE_P (TREE_TYPE (arg1))))
+    warn_about_parentheses (code, arg1_code, arg2_code);
 
   if (processing_template_decl && expr != error_mark_node)
     return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
@@ -2906,6 +3147,15 @@ build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
   return expr;
 }
 
+/* For the c-common bits.  */
+tree
+build_binary_op (enum tree_code code, tree op0, tree op1,
+                int convert_p ATTRIBUTE_UNUSED)
+{
+  return cp_build_binary_op(code, op0, op1, tf_warning_or_error);
+}
+
+
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    This function differs from `build' in several ways:
@@ -2925,8 +3175,8 @@ build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
    multiple inheritance, and deal with pointer to member functions.  */
 
 tree
-build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
-                int convert_p ATTRIBUTE_UNUSED)
+cp_build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
+                   tsubst_flags_t complain)
 {
   tree op0, op1;
   enum tree_code code0, code1;
@@ -2970,10 +3220,6 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
      Also implies COMMON.  */
   int short_compare = 0;
 
-  /* Nonzero if this is a right-shift operation, which can be computed on the
-     original short and then promoted if the operand is a promoted short.  */
-  int short_shift = 0;
-
   /* Nonzero means set RESULT_TYPE to the common type of the args.  */
   int common = 0;
 
@@ -3011,8 +3257,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
       if (t != error_mark_node)
        {
-         pedwarn ("assuming cast to type %qT from overloaded function",
-                  TREE_TYPE (t));
+         if (complain & tf_error)
+           permerror ("assuming cast to type %qT from overloaded function",
+                      TREE_TYPE (t));
          op0 = t;
        }
     }
@@ -3021,8 +3268,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       tree t = instantiate_type (TREE_TYPE (op0), op1, tf_none);
       if (t != error_mark_node)
        {
-         pedwarn ("assuming cast to type %qT from overloaded function",
-                  TREE_TYPE (t));
+         if (complain & tf_error)
+           permerror ("assuming cast to type %qT from overloaded function",
+                      TREE_TYPE (t));
          op1 = t;
        }
     }
@@ -3100,17 +3348,16 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
              || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
        {
-         if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
-           warning (OPT_Wdiv_by_zero, "division by zero in %<%E / 0%>", op0);
-         else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
-           warning (OPT_Wdiv_by_zero, "division by zero in %<%E / 0.%>", op0);
+         enum tree_code tcode0 = code0, tcode1 = code1;
+
+         warn_for_div_by_zero (op1);
 
-         if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
-           code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
-         if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
-           code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+         if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE)
+           tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+         if (tcode1 == COMPLEX_TYPE || tcode1 == VECTOR_TYPE)
+           tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
 
-         if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+         if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
            resultcode = RDIV_EXPR;
          else
            /* When dividing two signed integers, we have to promote to int.
@@ -3131,16 +3378,15 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
       if ((code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
-         || (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE))
+         || (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+             && !VECTOR_FLOAT_TYPE_P (type0)
+             && !VECTOR_FLOAT_TYPE_P (type1)))
        shorten = -1;
       break;
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
-      if (code1 == INTEGER_TYPE && integer_zerop (op1))
-       warning (OPT_Wdiv_by_zero, "division by zero in %<%E %% 0%>", op0);
-      else if (code1 == REAL_TYPE && real_zerop (op1))
-       warning (OPT_Wdiv_by_zero, "division by zero in %<%E %% 0.%>", op0);
+      warn_for_div_by_zero (op1);
 
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
@@ -3174,12 +3420,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning (0, "right shift count is negative");
+               {
+                 if (complain & tf_warning)
+                   warning (0, "right shift count is negative");
+               }
              else
                {
-                 if (! integer_zerop (op1))
-                   short_shift = 1;
-                 if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+                 if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0
+                     && (complain & tf_warning))
                    warning (0, "right shift count >= width of type");
                }
            }
@@ -3199,9 +3447,15 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning (0, "left shift count is negative");
+               {
+                 if (complain & tf_warning)
+                   warning (0, "left shift count is negative");
+               }
              else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning (0, "left shift count >= width of type");
+               {
+                 if (complain & tf_warning)
+                   warning (0, "left shift count >= width of type");
+               }
            }
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
@@ -3220,11 +3474,19 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning (0, "%s rotate count is negative",
-                        (code == LROTATE_EXPR) ? "left" : "right");
+               {
+                 if (complain & tf_warning)
+                   warning (0, (code == LROTATE_EXPR)
+                                 ? G_("left rotate count is negative")
+                                 : G_("right rotate count is negative"));
+               }
              else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning (0, "%s rotate count >= width of type",
-                        (code == LROTATE_EXPR) ? "left" : "right");
+               {
+                 if (complain & tf_warning)
+                   warning (0, (code == LROTATE_EXPR) 
+                                  ? G_("left rotate count >= width of type")
+                                  : G_("right rotate count >= width of type"));
+               }
            }
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
@@ -3235,13 +3497,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
     case EQ_EXPR:
     case NE_EXPR:
-      if (code0 == REAL_TYPE || code1 == REAL_TYPE)
+      if ((complain & tf_warning)
+         && (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)))
        warning (OPT_Wfloat_equal,
                 "comparing floating point with == or != is unsafe");
-      if ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
-         || (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0)))
-       warning (OPT_Wstring_literal_comparison,
-                "comparison with string literal");
+      if ((complain & tf_warning)
+         && ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
+             || (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0))))
+       warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
 
       build_type = boolean_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -3252,34 +3515,81 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
               || (TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)))
        result_type = composite_pointer_type (type0, type1, op0, op1,
-                                             "comparison");
+                                             "comparison", complain);
       else if ((code0 == POINTER_TYPE || TYPE_PTRMEM_P (type0))
               && null_ptr_cst_p (op1))
-       result_type = type0;
+       {
+         if (TREE_CODE (op0) == ADDR_EXPR
+             && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
+           {
+             if (complain & tf_warning)
+               warning (OPT_Waddress, "the address of %qD will never be NULL",
+                        TREE_OPERAND (op0, 0));
+           }
+         result_type = type0;
+       }
       else if ((code1 == POINTER_TYPE || TYPE_PTRMEM_P (type1))
               && null_ptr_cst_p (op0))
-       result_type = type1;
+       {
+         if (TREE_CODE (op1) == ADDR_EXPR 
+             && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
+           {
+             if (complain & tf_warning)
+               warning (OPT_Waddress, "the address of %qD will never be NULL",
+                        TREE_OPERAND (op1, 0));
+           }
+         result_type = type1;
+       }
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
          result_type = type0;
-         error ("ISO C++ forbids comparison between pointer and integer");
+         if (complain & tf_error) 
+            permerror ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
          result_type = type1;
-         error ("ISO C++ forbids comparison between pointer and integer");
+         if (complain & tf_error)
+           permerror ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
        {
-         op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
-         op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
+         if (TARGET_PTRMEMFUNC_VBIT_LOCATION
+             == ptrmemfunc_vbit_in_delta)
+           {
+             tree pfn0 = pfn_from_ptrmemfunc (op0);
+             tree delta0 = delta_from_ptrmemfunc (op0);
+             tree e1 = cp_build_binary_op (EQ_EXPR,
+                                           pfn0,       
+                                           fold_convert (TREE_TYPE (pfn0),
+                                                         integer_zero_node),
+                                           complain);
+             tree e2 = cp_build_binary_op (BIT_AND_EXPR, 
+                                           delta0,
+                                           integer_one_node,
+                                           complain);
+             e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node,
+                                      complain);
+             op0 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e1, e2,
+                                       complain);
+             op1 = cp_convert (TREE_TYPE (op0), integer_one_node); 
+           }
+         else 
+           {
+             op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
+             op1 = cp_convert (TREE_TYPE (op0), integer_zero_node); 
+           }
          result_type = TREE_TYPE (op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
-       return cp_build_binary_op (code, op1, op0);
-      else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
-              && same_type_p (type0, type1))
+       return cp_build_binary_op (code, op1, op0, complain);
+      else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
        {
+         tree type;
          /* E will be the final comparison.  */
          tree e;
          /* E1 and E2 are for scratch.  */
@@ -3290,36 +3600,87 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          tree delta0;
          tree delta1;
 
+         type = composite_pointer_type (type0, type1, op0, op1, "comparison",
+                                        complain);
+
+         if (!same_type_p (TREE_TYPE (op0), type))
+           op0 = cp_convert_and_check (type, op0);
+         if (!same_type_p (TREE_TYPE (op1), type))
+           op1 = cp_convert_and_check (type, op1);
+
+         if (op0 == error_mark_node || op1 == error_mark_node)
+           return error_mark_node;
+
          if (TREE_SIDE_EFFECTS (op0))
            op0 = save_expr (op0);
          if (TREE_SIDE_EFFECTS (op1))
            op1 = save_expr (op1);
 
-         /* We generate:
-
-            (op0.pfn == op1.pfn
-             && (!op0.pfn || op0.delta == op1.delta))
-
-            The reason for the `!op0.pfn' bit is that a NULL
-            pointer-to-member is any member with a zero PFN; the
-            DELTA field is unspecified.  */
          pfn0 = pfn_from_ptrmemfunc (op0);
          pfn1 = pfn_from_ptrmemfunc (op1);
-         delta0 = build_ptrmemfunc_access_expr (op0,
-                                                delta_identifier);
-         delta1 = build_ptrmemfunc_access_expr (op1,
-                                                delta_identifier);
-         e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
-         e2 = cp_build_binary_op (EQ_EXPR,
-                                  pfn0,
-                                  cp_convert (TREE_TYPE (pfn0),
-                                              integer_zero_node));
-         e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+         delta0 = delta_from_ptrmemfunc (op0);
+         delta1 = delta_from_ptrmemfunc (op1);
+         if (TARGET_PTRMEMFUNC_VBIT_LOCATION
+             == ptrmemfunc_vbit_in_delta)
+           {
+             /* We generate:
+
+                (op0.pfn == op1.pfn
+                 && ((op0.delta == op1.delta)
+                      || (!op0.pfn && op0.delta & 1 == 0 
+                          && op1.delta & 1 == 0))
+
+                The reason for the `!op0.pfn' bit is that a NULL
+                pointer-to-member is any member with a zero PFN and
+                LSB of the DELTA field is 0.  */
+
+             e1 = cp_build_binary_op (BIT_AND_EXPR,
+                                      delta0, 
+                                      integer_one_node,
+                                      complain);
+             e1 = cp_build_binary_op (EQ_EXPR, e1, integer_zero_node,
+                                      complain);
+             e2 = cp_build_binary_op (BIT_AND_EXPR,
+                                      delta1,
+                                      integer_one_node,
+                                      complain);
+             e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node,
+                                      complain);
+             e1 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1,
+                                      complain);
+             e2 = cp_build_binary_op (EQ_EXPR,
+                                      pfn0,
+                                      fold_convert (TREE_TYPE (pfn0),
+                                                    integer_zero_node),
+                                      complain);
+             e2 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1, complain);
+             e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1, complain);
+             e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2, complain);
+           }
+         else
+           {
+             /* We generate:
+
+                (op0.pfn == op1.pfn
+                && (!op0.pfn || op0.delta == op1.delta))
+
+                The reason for the `!op0.pfn' bit is that a NULL
+                pointer-to-member is any member with a zero PFN; the
+                DELTA field is unspecified.  */
+             e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1, complain);
+             e2 = cp_build_binary_op (EQ_EXPR,
+                                      pfn0,
+                                      fold_convert (TREE_TYPE (pfn0),
+                                                    integer_zero_node),
+                                      complain);
+             e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2, complain);
+           }
          e2 = build2 (EQ_EXPR, boolean_type_node, pfn0, pfn1);
-         e = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
+         e = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1, complain);
          if (code == EQ_EXPR)
            return e;
-         return cp_build_binary_op (EQ_EXPR, e, integer_zero_node);
+         return cp_build_binary_op (EQ_EXPR, e, integer_zero_node, complain);
        }
       else
        {
@@ -3340,7 +3701,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        shorten = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        result_type = composite_pointer_type (type0, type1, op0, op1,
-                                             "comparison");
+                                             "comparison", complain);
       break;
 
     case LE_EXPR:
@@ -3349,8 +3710,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     case GT_EXPR:
       if (TREE_CODE (orig_op0) == STRING_CST
          || TREE_CODE (orig_op1) == STRING_CST)
-       warning (OPT_Wstring_literal_comparison,
-                "comparison with string literal");
+       {
+         if (complain & tf_warning)
+           warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
+       }
 
       build_type = boolean_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
@@ -3358,7 +3721,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        result_type = composite_pointer_type (type0, type1, op0, op1,
-                                             "comparison");
+                                             "comparison", complain);
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
        result_type = type0;
@@ -3368,12 +3731,18 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
          result_type = type0;
-         pedwarn ("ISO C++ forbids comparison between pointer and integer");
+         if (complain & tf_error)
+           permerror ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
          result_type = type1;
-         pedwarn ("ISO C++ forbids comparison between pointer and integer");
+         if (complain & tf_error)
+           permerror ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       break;
 
@@ -3387,7 +3756,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       build_type = integer_type_node;
       if (code0 != REAL_TYPE || code1 != REAL_TYPE)
        {
-         error ("unordered comparison on non-floating point argument");
+         if (complain & tf_error)
+           error ("unordered comparison on non-floating point argument");
          return error_mark_node;
        }
       common = 1;
@@ -3411,7 +3781,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
                                                        TREE_TYPE (type1)))
            {
-             binary_op_error (code);
+             binary_op_error (code, type0, type1);
              return error_mark_node;
            }
          arithmetic_types_p = 1;
@@ -3425,17 +3795,26 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
   if (!result_type)
     {
-      error ("invalid operands of types %qT and %qT to binary %qO",
-            TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+      if (complain & tf_error)
+       error ("invalid operands of types %qT and %qT to binary %qO",
+              TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
       return error_mark_node;
     }
 
   /* If we're in a template, the only thing we need to know is the
      RESULT_TYPE.  */
   if (processing_template_decl)
-    return build2 (resultcode,
-                  build_type ? build_type : result_type,
-                  op0, op1);
+    {
+      /* Since the middle-end checks the type when doing a build2, we
+        need to build the tree in pieces.  This built tree will never
+        get out of the front-end as we replace it when instantiating
+        the template.  */
+      tree tmp = build2 (resultcode,
+                        build_type ? build_type : result_type,
+                        NULL_TREE, op1);
+      TREE_OPERAND (tmp, 0) = op0;
+      return tmp;
+    }
 
   if (arithmetic_types_p)
     {
@@ -3511,45 +3890,6 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
            result_type = type;
        }
 
-      /* Shifts can be shortened if shifting right.  */
-
-      if (short_shift)
-       {
-         int unsigned_arg;
-         tree arg0 = get_narrower (op0, &unsigned_arg);
-
-         final_type = result_type;
-
-         if (arg0 == op0 && final_type == TREE_TYPE (op0))
-           unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
-
-         if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
-             /* We can shorten only if the shift count is less than the
-                number of bits in the smaller type size.  */
-             && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
-             /* If arg is sign-extended and then unsigned-shifted,
-                we can simulate this with a signed shift in arg's type
-                only if the extended result is at least twice as wide
-                as the arg.  Otherwise, the shift could use up all the
-                ones made by sign-extension and bring in zeros.
-                We can't optimize that case at all, but in most machines
-                it never happens because available widths are 2**N.  */
-             && (!TYPE_UNSIGNED (final_type)
-                 || unsigned_arg
-                 || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
-                     <= TYPE_PRECISION (result_type))))
-           {
-             /* Do an unsigned shift if the operand was zero-extended.  */
-             result_type
-               = c_common_signed_or_unsigned_type (unsigned_arg,
-                                                   TREE_TYPE (arg0));
-             /* Convert value-to-be-shifted to that type.  */
-             if (TREE_TYPE (op0) != result_type)
-               op0 = cp_convert (result_type, op0);
-             converted = 1;
-           }
-       }
-
       /* Comparison operations are shortened too but differently.
         They identify themselves by setting short_compare = 1.  */
 
@@ -3587,9 +3927,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
              && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
              && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
-                != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+                != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1))
+             && (complain & tf_warning))
            {
-             warning (0, "comparison between types %q#T and %q#T",
+             warning (OPT_Wsign_compare, "comparison between types %q#T and %q#T",
                       TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
            }
 
@@ -3624,8 +3965,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                            && int_fits_type_p (orig_op0, c_common_signed_type
                                                (result_type)))))
            /* OK */;
-         else
-           warning (0, "comparison between signed and unsigned integer expressions");
+         else if (complain & tf_warning)
+           warning (OPT_Wsign_compare, 
+                    "comparison between signed and unsigned integer expressions");
 
          /* Warn if two unsigned values are being compared in a size
             larger than their original size, and one (and only one) is the
@@ -3668,50 +4010,51 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                      && bits < HOST_BITS_PER_LONG && unsignedp)
                    {
                      mask = (~ (HOST_WIDE_INT) 0) << bits;
-                     if ((mask & constant) != mask)
-                       warning (0, "comparison of promoted ~unsigned with constant");
+                     if ((mask & constant) != mask
+                         && (complain & tf_warning))
+                       warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with constant");
                    }
                }
              else if (unsignedp0 && unsignedp1
                       && (TYPE_PRECISION (TREE_TYPE (primop0))
                           < TYPE_PRECISION (result_type))
                       && (TYPE_PRECISION (TREE_TYPE (primop1))
-                          < TYPE_PRECISION (result_type)))
-               warning (0, "comparison of promoted ~unsigned with unsigned");
+                          < TYPE_PRECISION (result_type))
+                      && (complain & tf_warning))
+               warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with unsigned");
            }
        }
     }
 
-  /* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
-     Then the expression will be built.
-     It will be given type FINAL_TYPE if that is nonzero;
-     otherwise, it will be given type RESULT_TYPE.  */
-
   /* Issue warnings about peculiar, but valid, uses of NULL.  */
-  if (/* It's reasonable to use pointer values as operands of &&
+  if ((orig_op0 == null_node || orig_op1 == null_node)
+      /* It's reasonable to use pointer values as operands of &&
         and ||, so NULL is no exception.  */
-      !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
-      && (/* If OP0 is NULL and OP1 is not a pointer, or vice versa.  */
-         (orig_op0 == null_node
-          && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE)
-         /* Or vice versa.  */
-         || (orig_op1 == null_node
-             && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
-         /* Or, both are NULL and the operation was not a comparison.  */
-         || (orig_op0 == null_node && orig_op1 == null_node
-             && code != EQ_EXPR && code != NE_EXPR)))
+      && code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR 
+      && ( /* Both are NULL (or 0) and the operation was not a comparison.  */
+         (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1) 
+          && code != EQ_EXPR && code != NE_EXPR) 
+         /* Or if one of OP0 or OP1 is neither a pointer nor NULL.  */
+         || (!null_ptr_cst_p (orig_op0) && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
+         || (!null_ptr_cst_p (orig_op1) && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE))
+      && (complain & tf_warning))
     /* Some sort of arithmetic operation involving NULL was
        performed.  Note that pointer-difference and pointer-addition
        have already been handled above, and so we don't end up here in
        that case.  */
-    warning (0, "NULL used in arithmetic");
+    warning (OPT_Wpointer_arith, "NULL used in arithmetic");
+  
 
+  /* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
+     Then the expression will be built.
+     It will be given type FINAL_TYPE if that is nonzero;
+     otherwise, it will be given type RESULT_TYPE.  */
   if (! converted)
     {
       if (TREE_TYPE (op0) != result_type)
-       op0 = cp_convert (result_type, op0);
+       op0 = cp_convert_and_check (result_type, op0);
       if (TREE_TYPE (op1) != result_type)
-       op1 = cp_convert (result_type, op1);
+       op1 = cp_convert_and_check (result_type, op1);
 
       if (op0 == error_mark_node || op1 == error_mark_node)
        return error_mark_node;
@@ -3724,6 +4067,12 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   result = fold_if_not_in_template (result);
   if (final_type != 0)
     result = cp_convert (final_type, result);
+
+  if (TREE_OVERFLOW_P (result) 
+      && !TREE_OVERFLOW_P (op0) 
+      && !TREE_OVERFLOW_P (op1))
+    overflow_warning (result);
+
   return result;
 }
 \f
@@ -3762,11 +4111,11 @@ pointer_diff (tree op0, tree op1, tree ptrtype)
   if (pedantic || warn_pointer_arith)
     {
       if (TREE_CODE (target_type) == VOID_TYPE)
-       pedwarn ("ISO C++ forbids using pointer of type %<void *%> in subtraction");
+       permerror ("ISO C++ forbids using pointer of type %<void *%> in subtraction");
       if (TREE_CODE (target_type) == FUNCTION_TYPE)
-       pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
+       permerror ("ISO C++ forbids using pointer to a function in subtraction");
       if (TREE_CODE (target_type) == METHOD_TYPE)
-       pedwarn ("ISO C++ forbids using pointer to a method in subtraction");
+       permerror ("ISO C++ forbids using pointer to a method in subtraction");
     }
 
   /* First do the subtraction as integers;
@@ -3774,7 +4123,8 @@ pointer_diff (tree op0, tree op1, tree ptrtype)
 
   op0 = cp_build_binary_op (MINUS_EXPR,
                            cp_convert (restype, op0),
-                           cp_convert (restype, op1));
+                           cp_convert (restype, op1),
+                           tf_warning_or_error);
 
   /* This generates an error if op1 is a pointer to an incomplete type.  */
   if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
@@ -3795,7 +4145,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype)
    and XARG is the operand.  */
 
 tree
-build_x_unary_op (enum tree_code code, tree xarg)
+build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
 {
   tree orig_expr = xarg;
   tree exp;
@@ -3827,7 +4177,7 @@ build_x_unary_op (enum tree_code code, tree xarg)
     /* Don't look for a function.  */;
   else
     exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
-                       /*overloaded_p=*/NULL);
+                       /*overloaded_p=*/NULL, complain);
   if (!exp && code == ADDR_EXPR)
     {
       /*  A pointer to member-function can be formed only by saying
@@ -3838,10 +4188,10 @@ build_x_unary_op (enum tree_code code, tree xarg)
          if (TREE_CODE (xarg) != OFFSET_REF
              || !TYPE_P (TREE_OPERAND (xarg, 0)))
            {
-             error ("invalid use of %qE to form a pointer-to-member-function",
-                    xarg);
-             if (TREE_CODE (xarg) != OFFSET_REF)
-               inform ("  a qualified-id is required");
+              error ("invalid use of %qE to form a pointer-to-member-function",
+                     xarg);
+              if (TREE_CODE (xarg) != OFFSET_REF)
+                inform ("  a qualified-id is required");
              return error_mark_node;
            }
          else
@@ -3868,9 +4218,9 @@ build_x_unary_op (enum tree_code code, tree xarg)
              PTRMEM_OK_P (xarg) = ptrmem;
            }
        }
-      else if (TREE_CODE (xarg) == TARGET_EXPR)
+      else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning))
        warning (0, "taking address of temporary");
-      exp = build_unary_op (ADDR_EXPR, xarg, 0);
+      exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain);
     }
 
   if (processing_template_decl && exp != error_mark_node)
@@ -3903,7 +4253,8 @@ condition_conversion (tree expr)
   tree t;
   if (processing_template_decl)
     return expr;
-  t = perform_implicit_conversion (boolean_type_node, expr);
+  t = perform_implicit_conversion (boolean_type_node, expr, 
+                                  tf_warning_or_error);
   t = fold_build_cleanup_point_expr (boolean_type_node, t);
   return t;
 }
@@ -3945,7 +4296,8 @@ build_nop (tree type, tree expr)
    (such as from short to int).  */
 
 tree
-build_unary_op (enum tree_code code, tree xarg, int noconvert)
+cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, 
+                   tsubst_flags_t complain)
 {
   /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
   tree arg = xarg;
@@ -4000,7 +4352,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          if (!noconvert)
            arg = default_conversion (arg);
        }
-      else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+      else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM
+                                                  | WANT_VECTOR,
                                                   arg, true)))
        errstring = "wrong type argument to bit-complement";
       else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
@@ -4023,7 +4376,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       break;
 
     case TRUTH_NOT_EXPR:
-      arg = perform_implicit_conversion (boolean_type_node, arg);
+      arg = perform_implicit_conversion (boolean_type_node, arg,
+                                        complain);
       val = invert_truthvalue (arg);
       if (arg != error_mark_node)
        return val;
@@ -4073,10 +4427,13 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          tree real, imag;
 
          arg = stabilize_reference (arg);
-         real = build_unary_op (REALPART_EXPR, arg, 1);
-         imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+         real = cp_build_unary_op (REALPART_EXPR, arg, 1, complain);
+         imag = cp_build_unary_op (IMAGPART_EXPR, arg, 1, complain);
+         real = cp_build_unary_op (code, real, 1, complain);
+         if (real == error_mark_node || imag == error_mark_node)
+           return error_mark_node;
          return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
-                        build_unary_op (code, real, 1), imag);
+                        real, imag);
        }
 
       /* Report invalid types.  */
@@ -4094,28 +4451,42 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
            errstring ="no post-decrement operator for type";
          break;
        }
+      else if (arg == error_mark_node)
+       return error_mark_node;
 
       /* Report something read-only.  */
 
       if (CP_TYPE_CONST_P (TREE_TYPE (arg))
-         || TREE_READONLY (arg))
-       readonly_error (arg, ((code == PREINCREMENT_EXPR
-                              || code == POSTINCREMENT_EXPR)
-                             ? "increment" : "decrement"),
-                       0);
+         || TREE_READONLY (arg)) 
+        {
+          if (complain & tf_error)
+            readonly_error (arg, ((code == PREINCREMENT_EXPR
+                                   || code == POSTINCREMENT_EXPR)
+                                  ? "increment" : "decrement"));
+          else
+            return error_mark_node;
+        }
 
       {
        tree inc;
+       tree declared_type;
        tree result_type = TREE_TYPE (arg);
 
+       declared_type = unlowered_expr_type (arg);
+
        arg = get_unwidened (arg, 0);
        argtype = TREE_TYPE (arg);
 
        /* ARM $5.2.5 last annotation says this should be forbidden.  */
        if (TREE_CODE (argtype) == ENUMERAL_TYPE)
-         pedwarn ("ISO C++ forbids %sing an enum",
-                  (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
-                  ? "increment" : "decrement");
+          {
+            if (complain & tf_error)
+              permerror ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+                         ? G_("ISO C++ forbids incrementing an enum")
+                         : G_("ISO C++ forbids decrementing an enum"));
+            else
+              return error_mark_node;
+          }
 
        /* Compute the increment.  */
 
@@ -4124,16 +4495,29 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
            tree type = complete_type (TREE_TYPE (argtype));
 
            if (!COMPLETE_OR_VOID_TYPE_P (type))
-             error ("cannot %s a pointer to incomplete type %qT",
-                    ((code == PREINCREMENT_EXPR
-                      || code == POSTINCREMENT_EXPR)
-                     ? "increment" : "decrement"), TREE_TYPE (argtype));
+              {
+                if (complain & tf_error)
+                  error (((code == PREINCREMENT_EXPR
+                           || code == POSTINCREMENT_EXPR))
+                         ? G_("cannot increment a pointer to incomplete type %qT")
+                         : G_("cannot decrement a pointer to incomplete type %qT"),
+                         TREE_TYPE (argtype));
+                else
+                  return error_mark_node;
+              }
            else if ((pedantic || warn_pointer_arith)
-                    && !TYPE_PTROB_P (argtype))
-             pedwarn ("ISO C++ forbids %sing a pointer of type %qT",
-                      ((code == PREINCREMENT_EXPR
-                        || code == POSTINCREMENT_EXPR)
-                       ? "increment" : "decrement"), argtype);
+                    && !TYPE_PTROB_P (argtype)) 
+              {
+                if (complain & tf_error)
+                  permerror ((code == PREINCREMENT_EXPR
+                              || code == POSTINCREMENT_EXPR)
+                             ? G_("ISO C++ forbids incrementing a pointer of type %qT")
+                             : G_("ISO C++ forbids decrementing a pointer of type %qT"),
+                             argtype);
+                else
+                  return error_mark_node;
+              }
+
            inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
          }
        else
@@ -4141,56 +4525,21 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
 
        inc = cp_convert (argtype, inc);
 
-       /* Handle incrementing a cast-expression.  */
-
-       switch (TREE_CODE (arg))
-         {
-         case NOP_EXPR:
-         case CONVERT_EXPR:
-         case FLOAT_EXPR:
-         case FIX_TRUNC_EXPR:
-         case FIX_FLOOR_EXPR:
-         case FIX_ROUND_EXPR:
-         case FIX_CEIL_EXPR:
-           {
-             tree incremented, modify, value, compound;
-             if (! lvalue_p (arg) && pedantic)
-               pedwarn ("cast to non-reference type used as lvalue");
-             arg = stabilize_reference (arg);
-             if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
-               value = arg;
-             else
-               value = save_expr (arg);
-             incremented = build2 (((code == PREINCREMENT_EXPR
-                                     || code == POSTINCREMENT_EXPR)
-                                    ? PLUS_EXPR : MINUS_EXPR),
-                                   argtype, value, inc);
-
-             modify = build_modify_expr (arg, NOP_EXPR, incremented);
-             compound = build2 (COMPOUND_EXPR, TREE_TYPE (arg),
-                                modify, value);
-
-             /* Eliminate warning about unused result of + or -.  */
-             TREE_NO_WARNING (compound) = 1;
-             return compound;
-           }
-
-         default:
-           break;
-         }
-
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
-                                  ? lv_increment : lv_decrement)))
+                                  ? lv_increment : lv_decrement),
+                             complain))
          return error_mark_node;
 
        /* Forbid using -- on `bool'.  */
-       if (TREE_TYPE (arg) == boolean_type_node)
+       if (same_type_p (declared_type, boolean_type_node))
          {
            if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
              {
-               error ("invalid use of %<--%> on bool variable %qD", arg);
+                if (complain & tf_error)
+                  error ("invalid use of Boolean expression as operand "
+                         "to %<operator--%>");
                return error_mark_node;
              }
            val = boolean_increment (code, arg);
@@ -4218,8 +4567,13 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          return arg;
        }
       else if (pedantic && DECL_MAIN_P (arg))
-       /* ARM $3.4 */
-       pedwarn ("ISO C++ forbids taking address of function %<::main%>");
+        {
+          /* ARM $3.4 */
+          if (complain & tf_error)
+            permerror ("ISO C++ forbids taking address of function %<::main%>");
+          else
+            return error_mark_node;
+        }
 
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
@@ -4272,18 +4626,20 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          if (! flag_ms_extensions)
            {
              tree name = DECL_NAME (fn);
-             if (current_class_type
-                 && TREE_OPERAND (arg, 0) == current_class_ref)
-               /* An expression like &memfn.  */
-               pedwarn ("ISO C++ forbids taking the address of an unqualified"
-                        " or parenthesized non-static member function to form"
-                        " a pointer to member function.  Say %<&%T::%D%>",
-                        base, name);
+              if (!(complain & tf_error))
+                return error_mark_node;
+             else if (current_class_type
+                       && TREE_OPERAND (arg, 0) == current_class_ref)
+                  /* An expression like &memfn.  */
+                permerror ("ISO C++ forbids taking the address of an unqualified"
+                           " or parenthesized non-static member function to form"
+                           " a pointer to member function.  Say %<&%T::%D%>",
+                           base, name);
              else
-               pedwarn ("ISO C++ forbids taking the address of a bound member"
-                        " function to form a pointer to member function."
-                        "  Say %<&%T::%D%>",
-                        base, name);
+               permerror ("ISO C++ forbids taking the address of a bound member"
+                          " function to form a pointer to member function."
+                          "  Say %<&%T::%D%>",
+                          base, name);
            }
          arg = build_offset_ref (base, fn, /*address_p=*/true);
        }
@@ -4300,17 +4656,25 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
 
       switch (TREE_CODE (arg))
        {
-       case NOP_EXPR:
-       case CONVERT_EXPR:
+       CASE_CONVERT:
        case FLOAT_EXPR:
        case FIX_TRUNC_EXPR:
-       case FIX_FLOOR_EXPR:
-       case FIX_ROUND_EXPR:
-       case FIX_CEIL_EXPR:
-         if (! lvalue_p (arg) && pedantic)
-           pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+          /* Even if we're not being pedantic, we cannot allow this
+             extension when we're instantiating in a SFINAE
+             context.  */
+         if (! lvalue_p (arg) && (pedantic || complain == tf_none))
+            {
+              if (complain & tf_error)
+                permerror ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+              else
+                return error_mark_node;
+            }
          break;
 
+       case BASELINK:
+         arg = BASELINK_FUNCTIONS (arg);
+         /* Fall through.  */
+
        case OVERLOAD:
          arg = OVL_CURRENT (arg);
          break;
@@ -4323,12 +4687,13 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
            tree t;
 
            if (!PTRMEM_OK_P (arg))
-             return build_unary_op (code, arg, 0);
+             return cp_build_unary_op (code, arg, 0, complain);
 
            t = TREE_OPERAND (arg, 1);
            if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
              {
-               error ("cannot create pointer to reference member %qD", t);
+                if (complain & tf_error)
+                  error ("cannot create pointer to reference member %qD", t);
                return error_mark_node;
              }
 
@@ -4347,7 +4712,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       if (TREE_CODE (argtype) != FUNCTION_TYPE
          && TREE_CODE (argtype) != METHOD_TYPE
          && TREE_CODE (arg) != OFFSET_REF
-         && !lvalue_or_else (arg, lv_addressof))
+         && !lvalue_or_else (arg, lv_addressof, complain))
        return error_mark_node;
 
       if (argtype != error_mark_node)
@@ -4386,8 +4751,9 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
        }
       else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
        {
-         error ("attempt to take address of bit-field structure member %qD",
-                TREE_OPERAND (arg, 1));
+          if (complain & tf_error)
+            error ("attempt to take address of bit-field structure member %qD",
+                   TREE_OPERAND (arg, 1));
          return error_mark_node;
        }
       else
@@ -4420,10 +4786,18 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       return fold_if_not_in_template (build1 (code, argtype, arg));
     }
 
-  error ("%s", errstring);
+  if (complain & tf_error)
+    error ("%s", errstring);
   return error_mark_node;
 }
 
+/* Hook for the c-common bits that build a unary op.  */
+tree
+build_unary_op (enum tree_code code, tree xarg, int noconvert)
+{
+  return cp_build_unary_op (code, xarg, noconvert, tf_warning_or_error);
+}
+
 /* Apply unary lvalue-demanding operator CODE to the expression ARG
    for certain kinds of expressions which are not really lvalues
    but which we can accept as lvalues.
@@ -4443,7 +4817,8 @@ unary_complex_lvalue (enum tree_code code, tree arg)
   /* Handle (a, b) used as an "lvalue".  */
   if (TREE_CODE (arg) == COMPOUND_EXPR)
     {
-      tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
+      tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 1), 0,
+                                            tf_warning_or_error);
       return build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
                     TREE_OPERAND (arg, 0), real_result);
     }
@@ -4451,7 +4826,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
   /* Handle (a ? b : c) used as an "lvalue".  */
   if (TREE_CODE (arg) == COND_EXPR
       || TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR)
-    return rationalize_conditional_expr (code, arg);
+    return rationalize_conditional_expr (code, arg, tf_warning_or_error);
 
   /* Handle (a = b), (++a), and (--a) used as an "lvalue".  */
   if (TREE_CODE (arg) == MODIFY_EXPR
@@ -4476,7 +4851,8 @@ unary_complex_lvalue (enum tree_code code, tree arg)
   if (TREE_CODE (arg) == MODIFY_EXPR
       || TREE_CODE (arg) == INIT_EXPR)
     {
-      tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
+      tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 0), 0,
+                                            tf_warning_or_error);
       arg = build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
                    arg, real_result);
       TREE_NO_WARNING (arg) = 1;
@@ -4496,7 +4872,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
     if (TREE_CODE (targ) == SAVE_EXPR)
       targ = TREE_OPERAND (targ, 0);
 
-    if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (targ)))
+    if (TREE_CODE (targ) == CALL_EXPR && MAYBE_CLASS_TYPE_P (TREE_TYPE (targ)))
       {
        if (TREE_CODE (arg) == SAVE_EXPR)
          targ = arg;
@@ -4593,7 +4969,8 @@ cxx_mark_addressable (tree exp)
 /* Build and return a conditional expression IFEXP ? OP1 : OP2.  */
 
 tree
-build_x_conditional_expr (tree ifexp, tree op1, tree op2)
+build_x_conditional_expr (tree ifexp, tree op1, tree op2, 
+                          tsubst_flags_t complain)
 {
   tree orig_ifexp = ifexp;
   tree orig_op1 = op1;
@@ -4616,7 +4993,7 @@ build_x_conditional_expr (tree ifexp, tree op1, tree op2)
       op2 = build_non_dependent_expr (op2);
     }
 
-  expr = build_conditional_expr (ifexp, op1, op2);
+  expr = build_conditional_expr (ifexp, op1, op2, complain);
   if (processing_template_decl && expr != error_mark_node)
     return build_min_non_dep (COND_EXPR, expr,
                              orig_ifexp, orig_op1, orig_op2);
@@ -4633,10 +5010,11 @@ tree build_x_compound_expr_from_list (tree list, const char *msg)
   if (TREE_CHAIN (list))
     {
       if (msg)
-       pedwarn ("%s expression list treated as compound expression", msg);
+       permerror ("%s expression list treated as compound expression", msg);
 
       for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
-       expr = build_x_compound_expr (expr, TREE_VALUE (list));
+       expr = build_x_compound_expr (expr, TREE_VALUE (list), 
+                                      tf_warning_or_error);
     }
 
   return expr;
@@ -4645,7 +5023,7 @@ tree build_x_compound_expr_from_list (tree list, const char *msg)
 /* Handle overloading of the ',' operator when needed.  */
 
 tree
-build_x_compound_expr (tree op1, tree op2)
+build_x_compound_expr (tree op1, tree op2, tsubst_flags_t complain)
 {
   tree result;
   tree orig_op1 = op1;
@@ -4661,9 +5039,9 @@ build_x_compound_expr (tree op1, tree op2)
     }
 
   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
-                        /*overloaded_p=*/NULL);
+                        /*overloaded_p=*/NULL, complain);
   if (!result)
-    result = build_compound_expr (op1, op2);
+    result = cp_build_compound_expr (op1, op2, complain);
 
   if (processing_template_decl && result != error_mark_node)
     return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
@@ -4671,12 +5049,20 @@ build_x_compound_expr (tree op1, tree op2)
   return result;
 }
 
-/* Build a compound expression.  */
+/* Like cp_build_compound_expr, but for the c-common bits.  */
 
 tree
 build_compound_expr (tree lhs, tree rhs)
 {
-  lhs = convert_to_void (lhs, "left-hand operand of comma");
+  return cp_build_compound_expr (lhs, rhs, tf_warning_or_error);
+}
+
+/* Build a compound expression.  */
+
+tree
+cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
+{
+  lhs = convert_to_void (lhs, "left-hand operand of comma", complain);
 
   if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
@@ -4698,18 +5084,38 @@ build_compound_expr (tree lhs, tree rhs)
 }
 
 /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
-   casts away constness.  DIAG_FN gives the function to call if we
-   need to issue a diagnostic; if it is NULL, no diagnostic will be
-   issued.  DESCRIPTION explains what operation is taking place.  */
+   casts away constness.  CAST gives the type of cast.  */
 
 static void
 check_for_casting_away_constness (tree src_type, tree dest_type,
-                                 void (*diag_fn)(const char *, ...) ATTRIBUTE_GCC_CXXDIAG(1,2),
-                                 const char *description)
+                                 enum tree_code cast)
 {
-  if (diag_fn && casts_away_constness (src_type, dest_type))
-    diag_fn ("%s from type %qT to type %qT casts away constness",
-            description, src_type, dest_type);
+  /* C-style casts are allowed to cast away constness.  With
+     WARN_CAST_QUAL, we still want to issue a warning.  */
+  if (cast == CAST_EXPR && !warn_cast_qual)
+      return;
+  
+  if (casts_away_constness (src_type, dest_type))
+    switch (cast)
+      {
+      case CAST_EXPR:
+       warning (OPT_Wcast_qual, 
+                 "cast from type %qT to type %qT casts away constness",
+                src_type, dest_type);
+       return;
+       
+      case STATIC_CAST_EXPR:
+       error ("static_cast from type %qT to type %qT casts away constness",
+              src_type, dest_type);
+       return;
+       
+      case REINTERPRET_CAST_EXPR:
+       error ("reinterpret_cast from type %qT to type %qT casts away constness",
+              src_type, dest_type);
+       return;
+      default:
+       gcc_unreachable();
+      }
 }
 
 /* Convert EXPR (an expression with pointer-to-member type) to TYPE
@@ -4734,9 +5140,21 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
                                    allow_inverse_p,
                                    c_cast_p);
       if (!integer_zerop (delta))
-       expr = cp_build_binary_op (PLUS_EXPR,
-                                  build_nop (ptrdiff_type_node, expr),
-                                  delta);
+       {
+         tree cond, op1, op2;
+
+         cond = cp_build_binary_op (EQ_EXPR,
+                                    expr,
+                                    build_int_cst (TREE_TYPE (expr), -1),
+                                    tf_warning_or_error);
+         op1 = build_nop (ptrdiff_type_node, expr);
+         op2 = cp_build_binary_op (PLUS_EXPR, op1, delta,
+                                   tf_warning_or_error);
+
+         expr = fold_build3 (COND_EXPR, ptrdiff_type_node, cond, op1, op2);
+                        
+       }
+
       return build_nop (type, expr);
     }
   else
@@ -4745,8 +5163,8 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
 }
 
 /* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
-   a version of EXPR that has TREE_OVERFLOW and/or TREE_CONSTANT_OVERFLOW
-   set iff they are set in ORIG.  Otherwise, return EXPR unchanged.  */
+   a version of EXPR that has TREE_OVERFLOW set if it is set in ORIG.
+   Otherwise, return EXPR unchanged.  */
 
 static tree
 ignore_overflows (tree expr, tree orig)
@@ -4754,11 +5172,9 @@ ignore_overflows (tree expr, tree orig)
   if (TREE_CODE (expr) == INTEGER_CST
       && CONSTANT_CLASS_P (orig)
       && TREE_CODE (orig) != STRING_CST
-      && (TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig)
-         || TREE_CONSTANT_OVERFLOW (expr)
-            != TREE_CONSTANT_OVERFLOW (orig)))
+      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
     {
-      if (!TREE_OVERFLOW (orig) && !TREE_CONSTANT_OVERFLOW (orig))
+      if (!TREE_OVERFLOW (orig))
        /* Ensure constant sharing.  */
        expr = build_int_cst_wide (TREE_TYPE (expr),
                                   TREE_INT_CST_LOW (expr),
@@ -4768,8 +5184,6 @@ ignore_overflows (tree expr, tree orig)
          /* Avoid clobbering a shared constant.  */
          expr = copy_node (expr);
          TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
-         TREE_CONSTANT_OVERFLOW (expr)
-           = TREE_CONSTANT_OVERFLOW (orig);
        }
     }
   return expr;
@@ -4784,13 +5198,11 @@ ignore_overflows (tree expr, tree orig)
 
 static tree
 build_static_cast_1 (tree type, tree expr, bool c_cast_p,
-                    bool *valid_p)
+                    bool *valid_p, tsubst_flags_t complain)
 {
   tree intype;
   tree result;
   tree orig;
-  void (*diag_fn)(const char*, ...) ATTRIBUTE_GCC_CXXDIAG(1,2);
-  const char *desc;
 
   /* Assume the cast is valid.  */
   *valid_p = true;
@@ -4800,21 +5212,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
-  /* Determine what to do when casting away constness.  */
-  if (c_cast_p)
-    {
-      /* C-style casts are allowed to cast away constness.  With
-        WARN_CAST_QUAL, we still want to issue a warning.  */
-      diag_fn = warn_cast_qual ? warning0 : NULL;
-      desc = "cast";
-    }
-  else
-    {
-      /* A static_cast may not cast away constness.  */
-      diag_fn = error;
-      desc = "static_cast";
-    }
-
   /* [expr.static.cast]
 
      An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -4875,7 +5272,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
      t(e);" is well-formed, for some invented temporary variable
      t.  */
   result = perform_direct_initialization_if_possible (type, expr,
-                                                     c_cast_p);
+                                                     c_cast_p, complain);
   if (result)
     {
       result = convert_from_reference (result);
@@ -4896,7 +5293,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
 
      Any expression can be explicitly converted to type cv void.  */
   if (TREE_CODE (type) == VOID_TYPE)
-    return convert_to_void (expr, /*implicit=*/NULL);
+    return convert_to_void (expr, /*implicit=*/NULL, complain);
 
   /* [expr.static.cast]
 
@@ -4939,7 +5336,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       tree base;
 
       if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, diag_fn, desc);
+       check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
       base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
                          c_cast_p ? ba_unique : ba_check,
                          NULL);
@@ -4971,11 +5368,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
          t1 = intype;
          t2 = type;
        }
-      if (can_convert (t1, t2))
+      if (can_convert (t1, t2) || can_convert (t2, t1))
        {
          if (!c_cast_p)
-           check_for_casting_away_constness (intype, type, diag_fn,
-                                             desc);
+           check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
          return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
                                 c_cast_p);
        }
@@ -4992,7 +5388,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       && TYPE_PTROB_P (type))
     {
       if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, diag_fn, desc);
+       check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
       return build_nop (type, expr);
     }
 
@@ -5003,7 +5399,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
 /* Return an expression representing static_cast<TYPE>(EXPR).  */
 
 tree
-build_static_cast (tree type, tree expr)
+build_static_cast (tree type, tree expr, tsubst_flags_t complain)
 {
   tree result;
   bool valid_p;
@@ -5026,12 +5422,14 @@ build_static_cast (tree type, tree expr)
       && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
     expr = TREE_OPERAND (expr, 0);
 
-  result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p);
+  result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p,
+                                complain);
   if (valid_p)
     return result;
 
-  error ("invalid static_cast from type %qT to type %qT",
-        TREE_TYPE (expr), type);
+  if (complain & tf_error)
+    error ("invalid static_cast from type %qT to type %qT",
+           TREE_TYPE (expr), type);
   return error_mark_node;
 }
 
@@ -5075,7 +5473,7 @@ convert_member_func_to_ptr (tree type, tree expr)
 
 static tree
 build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
-                         bool *valid_p)
+                         bool *valid_p, tsubst_flags_t complain)
 {
   tree intype;
 
@@ -5100,9 +5498,10 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       if (! real_lvalue_p (expr))
        {
-         error ("invalid cast of an rvalue expression of type "
-                "%qT to type %qT",
-                intype, type);
+          if (complain & tf_error)
+            error ("invalid cast of an rvalue expression of type "
+                   "%qT to type %qT",
+                   intype, type);
          return error_mark_node;
        }
 
@@ -5110,18 +5509,19 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
         "B" are related class types; the reinterpret_cast does not
         adjust the pointer.  */
       if (TYPE_PTR_P (intype)
+          && (complain & tf_warning)
          && (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
                         COMPARE_BASE | COMPARE_DERIVED)))
        warning (0, "casting %qT to %qT does not dereference pointer",
                 intype, type);
 
-      expr = build_unary_op (ADDR_EXPR, expr, 0);
+      expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
       if (expr != error_mark_node)
        expr = build_reinterpret_cast_1
          (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
-          valid_p);
+          valid_p, complain);
       if (expr != error_mark_node)
-       expr = build_indirect_ref (expr, 0);
+       expr = cp_build_indirect_ref (expr, 0, complain);
       return expr;
     }
 
@@ -5159,8 +5559,13 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
   if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
     {
       if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
-       pedwarn ("cast from %qT to %qT loses precision",
-                intype, type);
+        {
+          if (complain & tf_error)
+            permerror ("cast from %qT to %qT loses precision",
+                       intype, type);
+          else
+            return error_mark_node;
+        }
     }
   /* [expr.reinterpret.cast]
      A value of integral or enumeration type can be explicitly
@@ -5177,30 +5582,30 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
       tree sexpr = expr;
 
       if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, error,
-                                         "reinterpret_cast");
+       check_for_casting_away_constness (intype, type, REINTERPRET_CAST_EXPR);
       /* Warn about possible alignment problems.  */
       if (STRICT_ALIGNMENT && warn_cast_align
+          && (complain & tf_warning)
          && !VOID_TYPE_P (type)
          && TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
          && COMPLETE_TYPE_P (TREE_TYPE (type))
          && COMPLETE_TYPE_P (TREE_TYPE (intype))
          && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
-       warning (0, "cast from %qT to %qT increases required alignment of "
-                "target type",
-                intype, type);
+       warning (OPT_Wcast_align, "cast from %qT to %qT "
+                 "increases required alignment of target type", intype, type);
 
-      /* We need to strip nops here, because the frontend likes to
+      /* We need to strip nops here, because the front end likes to
         create (int *)&a for array-to-pointer decay, instead of &a[0].  */
       STRIP_NOPS (sexpr);
-      strict_aliasing_warning (intype, type, sexpr);
+      if (warn_strict_aliasing <= 2)
+       strict_aliasing_warning (intype, type, sexpr);
 
       return fold_if_not_in_template (build_nop (type, expr));
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
           || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
     {
-      if (pedantic)
+      if (pedantic && (complain & tf_warning))
        /* Only issue a warning, as we have always supported this
           where possible, and it is necessary in some cases.  DR 195
           addresses this issue, but as of 2004/10/26 is still in
@@ -5210,13 +5615,14 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     }
   else if (TREE_CODE (type) == VECTOR_TYPE)
     return fold_if_not_in_template (convert_to_vector (type, expr));
-  else if (TREE_CODE (intype) == VECTOR_TYPE)
+  else if (TREE_CODE (intype) == VECTOR_TYPE && INTEGRAL_TYPE_P (type))
     return fold_if_not_in_template (convert_to_integer (type, expr));
   else
     {
       if (valid_p)
        *valid_p = false;
-      error ("invalid cast from type %qT to type %qT", intype, type);
+      if (complain & tf_error)
+        error ("invalid cast from type %qT to type %qT", intype, type);
       return error_mark_node;
     }
 
@@ -5224,7 +5630,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
 }
 
 tree
-build_reinterpret_cast (tree type, tree expr)
+build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain)
 {
   if (type == error_mark_node || expr == error_mark_node)
     return error_mark_node;
@@ -5241,7 +5647,7 @@ build_reinterpret_cast (tree type, tree expr)
     }
 
   return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
-                                  /*valid_p=*/NULL);
+                                  /*valid_p=*/NULL, complain);
 }
 
 /* Perform a const_cast from EXPR to TYPE.  If the cast is valid,
@@ -5332,14 +5738,12 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
          *valid_p = true;
          /* This cast is actually a C-style cast.  Issue a warning if
             the user is making a potentially unsafe cast.  */
-         if (warn_cast_qual)
-           check_for_casting_away_constness (src_type, dst_type,
-                                             warning0,
-                                             "cast");
+         check_for_casting_away_constness (src_type, dst_type, CAST_EXPR);
        }
       if (reference_type)
        {
-         expr = build_unary_op (ADDR_EXPR, expr, 0);
+         expr = cp_build_unary_op (ADDR_EXPR, expr, 0, 
+                                    complain? tf_warning_or_error : tf_none);
          expr = build_nop (reference_type, expr);
          return convert_from_reference (expr);
        }
@@ -5363,7 +5767,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
 }
 
 tree
-build_const_cast (tree type, tree expr)
+build_const_cast (tree type, tree expr, tsubst_flags_t complain)
 {
   if (type == error_mark_node || error_operand_p (expr))
     return error_mark_node;
@@ -5379,15 +5783,23 @@ build_const_cast (tree type, tree expr)
       return convert_from_reference (t);
     }
 
-  return build_const_cast_1 (type, expr, /*complain=*/true,
+  return build_const_cast_1 (type, expr, complain & tf_error,
                             /*valid_p=*/NULL);
 }
 
+/* Like cp_build_c_cast, but for the c-common bits.  */
+
+tree
+build_c_cast (tree type, tree expr)
+{
+  return cp_build_c_cast (type, expr, tf_warning_or_error);
+}
+
 /* Build an expression representing an explicit C-style cast to type
    TYPE of expression EXPR.  */
 
 tree
-build_c_cast (tree type, tree expr)
+cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
 {
   tree value = expr;
   tree result;
@@ -5425,12 +5837,16 @@ build_c_cast (tree type, tree expr)
         NIHCL uses it. It is not valid ISO C++ however.  */
       if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
        {
-         pedwarn ("ISO C++ forbids casting to an array type %qT", type);
+          if (complain & tf_error)
+            permerror ("ISO C++ forbids casting to an array type %qT", type);
+          else
+            return error_mark_node;
          type = build_pointer_type (TREE_TYPE (type));
        }
       else
        {
-         error ("ISO C++ forbids casting to an array type %qT", type);
+          if (complain & tf_error)
+            error ("ISO C++ forbids casting to an array type %qT", type);
          return error_mark_node;
        }
     }
@@ -5438,7 +5854,8 @@ build_c_cast (tree type, tree expr)
   if (TREE_CODE (type) == FUNCTION_TYPE
       || TREE_CODE (type) == METHOD_TYPE)
     {
-      error ("invalid cast to function type %qT", type);
+      if (complain & tf_error)
+        error ("invalid cast to function type %qT", type);
       return error_mark_node;
     }
 
@@ -5450,11 +5867,11 @@ build_c_cast (tree type, tree expr)
 
   /* Or a static cast.  */
   result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
-                               &valid_p);
+                               &valid_p, complain);
   /* Or a reinterpret_cast.  */
   if (!valid_p)
     result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
-                                      &valid_p);
+                                      &valid_p, complain);
   /* The static_cast or reinterpret_cast may be followed by a
      const_cast.  */
   if (valid_p
@@ -5486,6 +5903,13 @@ build_c_cast (tree type, tree expr)
   return error_mark_node;
 }
 \f
+/* For use from the C common bits.  */
+tree
+build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+{
+  return cp_build_modify_expr (lhs, modifycode, rhs, tf_warning_or_error);
+}
+
 /* Build an assignment expression of lvalue LHS from value RHS.
    MODIFYCODE is the code for a binary operator that we use
    to combine the old value of LHS with RHS to get the new value.
@@ -5494,7 +5918,8 @@ build_c_cast (tree type, tree expr)
    C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.  */
 
 tree
-build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
+                     tsubst_flags_t complain)
 {
   tree result;
   tree newrhs = rhs;
@@ -5517,15 +5942,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
                      stabilize_reference (TREE_OPERAND (lhs, 0)),
                      TREE_OPERAND (lhs, 1));
-      return build2 (COMPOUND_EXPR, lhstype,
-                    lhs,
-                    build_modify_expr (TREE_OPERAND (lhs, 0),
-                                       modifycode, rhs));
+      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0),
+                                    modifycode, rhs, complain);
+      if (newrhs == error_mark_node)
+       return error_mark_node;
+      return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
 
       /* Handle (a, b) used as an "lvalue".  */
     case COMPOUND_EXPR:
-      newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
-                                 modifycode, rhs);
+      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+                                    modifycode, rhs, complain);
       if (newrhs == error_mark_node)
        return error_mark_node;
       return build2 (COMPOUND_EXPR, lhstype,
@@ -5536,7 +5962,8 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
                      stabilize_reference (TREE_OPERAND (lhs, 0)),
                      TREE_OPERAND (lhs, 1));
-      newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
+      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs,
+                                    complain);
       if (newrhs == error_mark_node)
        return error_mark_node;
       return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
@@ -5545,7 +5972,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     case MAX_EXPR:
       /* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues,
         when neither operand has side-effects.  */
-      if (!lvalue_or_else (lhs, lv_assign))
+      if (!lvalue_or_else (lhs, lv_assign, complain))
        return error_mark_node;
 
       gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
@@ -5569,19 +5996,27 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        tree cond;
        tree preeval = NULL_TREE;
 
+       if (VOID_TYPE_P (TREE_TYPE (rhs)))
+         {
+           if (complain & tf_error)
+             error ("void value not ignored as it ought to be");
+           return error_mark_node;
+         }
+
        rhs = stabilize_expr (rhs, &preeval);
 
        /* Check this here to avoid odd errors when trying to convert
           a throw to the type of the COND_EXPR.  */
-       if (!lvalue_or_else (lhs, lv_assign))
+       if (!lvalue_or_else (lhs, lv_assign, complain))
          return error_mark_node;
 
        cond = build_conditional_expr
          (TREE_OPERAND (lhs, 0),
-          build_modify_expr (TREE_OPERAND (lhs, 1),
-                             modifycode, rhs),
-          build_modify_expr (TREE_OPERAND (lhs, 2),
-                             modifycode, rhs));
+          cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+                                modifycode, rhs, complain),
+          cp_build_modify_expr (TREE_OPERAND (lhs, 2),
+                                modifycode, rhs, complain),
+           complain);
 
        if (cond == error_mark_node)
          return cond;
@@ -5607,13 +6042,14 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
          TREE_SIDE_EFFECTS (result) = 1;
          return result;
        }
-      else if (! IS_AGGR_TYPE (lhstype))
+      else if (! MAYBE_CLASS_TYPE_P (lhstype))
        /* Do the default thing.  */;
       else
        {
          result = build_special_member_call (lhs, complete_ctor_identifier,
                                              build_tree_list (NULL_TREE, rhs),
-                                             lhstype, LOOKUP_NORMAL);
+                                             lhstype, LOOKUP_NORMAL,
+                                              complain);
          if (result == NULL_TREE)
            return error_mark_node;
          return result;
@@ -5628,13 +6064,14 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
       if (modifycode == NOP_EXPR)
        {
          /* `operator=' is not an inheritable operator.  */
-         if (! IS_AGGR_TYPE (lhstype))
+         if (! MAYBE_CLASS_TYPE_P (lhstype))
            /* Do the default thing.  */;
          else
            {
              result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
                                     lhs, rhs, make_node (NOP_EXPR),
-                                    /*overloaded_p=*/NULL);
+                                    /*overloaded_p=*/NULL, 
+                                    complain);
              if (result == NULL_TREE)
                return error_mark_node;
              return result;
@@ -5646,14 +6083,18 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
          /* A binary op has been requested.  Combine the old LHS
             value with the RHS producing the value we should actually
             store into the LHS.  */
+         gcc_assert (!((TREE_CODE (lhstype) == REFERENCE_TYPE
+                        && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype)))
+                       || MAYBE_CLASS_TYPE_P (lhstype)));
 
-         gcc_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE));
          lhs = stabilize_reference (lhs);
-         newrhs = cp_build_binary_op (modifycode, lhs, rhs);
+         newrhs = cp_build_binary_op (modifycode, lhs, rhs,
+                                      complain);
          if (newrhs == error_mark_node)
            {
-             error ("  in evaluation of %<%Q(%#T, %#T)%>", modifycode,
-                    TREE_TYPE (lhs), TREE_TYPE (rhs));
+             if (complain & tf_error)
+               error ("  in evaluation of %<%Q(%#T, %#T)%>", modifycode,
+                      TREE_TYPE (lhs), TREE_TYPE (rhs));
              return error_mark_node;
            }
 
@@ -5665,7 +6106,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     }
 
   /* The left-hand side must be an lvalue.  */
-  if (!lvalue_or_else (lhs, lv_assign))
+  if (!lvalue_or_else (lhs, lv_assign, complain))
     return error_mark_node;
 
   /* Warn about modifying something that is `const'.  Don't warn if
@@ -5680,7 +6121,12 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
             effectively const.  */
          || (CLASS_TYPE_P (lhstype)
              && C_TYPE_FIELDS_READONLY (lhstype))))
-    readonly_error (lhs, "assignment", 0);
+    {
+      if (complain & tf_error)
+       readonly_error (lhs, "assignment");
+      else
+       return error_mark_node;
+    }
 
   /* If storing into a structure or union member, it has probably been
      given type `int'.  Compute the type that would go with the actual
@@ -5721,8 +6167,9 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
       if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
                                TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
        {
-         error ("incompatible types in assignment of %qT to %qT",
-                TREE_TYPE (rhs), lhstype);
+         if (complain & tf_error)
+           error ("incompatible types in assignment of %qT to %qT",
+                  TREE_TYPE (rhs), lhstype);
          return error_mark_node;
        }
 
@@ -5731,10 +6178,13 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        {
           /* This routine is used for both initialization and assignment.
              Make sure the diagnostic message differentiates the context.  */
-          if (modifycode == INIT_EXPR)
-            error ("array used as initializer");
-          else
-            error ("invalid array assignment");
+         if (complain & tf_error)
+           {
+             if (modifycode == INIT_EXPR)
+               error ("array used as initializer");
+             else
+               error ("invalid array assignment");
+           }
          return error_mark_node;
        }
 
@@ -5742,12 +6192,13 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
                   ? 1 + (modifycode != INIT_EXPR): 0;
       return build_vec_init (lhs, NULL_TREE, newrhs,
                             /*explicit_default_init_p=*/false,
-                            from_array);
+                            from_array, complain);
     }
 
   if (modifycode == INIT_EXPR)
     newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
-                                        "initialization", NULL_TREE, 0);
+                                        "initialization", NULL_TREE, 0,
+                                         complain);
   else
     {
       /* Avoid warnings on enum bit fields.  */
@@ -5755,12 +6206,12 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
          && TREE_CODE (lhstype) == INTEGER_TYPE)
        {
          newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
-                                          NULL_TREE, 0);
+                                          NULL_TREE, 0, complain);
          newrhs = convert_force (lhstype, newrhs, 0);
        }
       else
        newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
-                                        NULL_TREE, 0);
+                                        NULL_TREE, 0, complain);
       if (TREE_CODE (newrhs) == CALL_EXPR
          && TYPE_NEEDS_CONSTRUCTING (lhstype))
        newrhs = build_cplus_new (lhstype, newrhs);
@@ -5806,11 +6257,12 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
       return result;
     }
   return convert_for_assignment (olhstype, result, "assignment",
-                                NULL_TREE, 0);
+                                NULL_TREE, 0, complain);
 }
 
 tree
-build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
+                    tsubst_flags_t complain)
 {
   if (processing_template_decl)
     return build_min_nt (MODOP_EXPR, lhs,
@@ -5820,17 +6272,54 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     {
       tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
                                make_node (modifycode),
-                               /*overloaded_p=*/NULL);
+                               /*overloaded_p=*/NULL,
+                               complain);
       if (rval)
        {
          TREE_NO_WARNING (rval) = 1;
          return rval;
        }
     }
-  return build_modify_expr (lhs, modifycode, rhs);
+  return cp_build_modify_expr (lhs, modifycode, rhs, complain);
+}
+
+/* Helper function for get_delta_difference which assumes FROM is a base
+   class of TO.  Returns a delta for the conversion of pointer-to-member
+   of FROM to pointer-to-member of TO.  If the conversion is invalid,
+   returns zero.  If FROM is not a base class of TO, returns NULL_TREE.
+   If C_CAST_P is true, this conversion is taking place as part of a C-style
+   cast.  */
+
+static tree
+get_delta_difference_1 (tree from, tree to, bool c_cast_p)
+{
+  tree binfo;
+  base_kind kind;
+
+  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
+  if (kind == bk_inaccessible || kind == bk_ambig)
+    {
+      error ("   in pointer to member function conversion");
+      return size_zero_node;
+    }
+  else if (binfo)
+    {
+      if (kind != bk_via_virtual)
+       return BINFO_OFFSET (binfo);
+      else
+       /* FROM is a virtual base class of TO.  Issue an error or warning
+          depending on whether or not this is a reinterpret cast.  */
+       {
+         error ("pointer to member conversion via virtual base %qT",
+                BINFO_TYPE (binfo_from_vbase (binfo)));
+
+         return size_zero_node;
+       }
+      }
+    else
+      return NULL_TREE;
 }
 
-\f
 /* Get difference in deltas for different pointer to member function
    types.  Returns an integer constant of type PTRDIFF_TYPE_NODE.  If
    the conversion is invalid, the constant is zero.  If
@@ -5848,56 +6337,36 @@ get_delta_difference (tree from, tree to,
                      bool allow_inverse_p,
                      bool c_cast_p)
 {
-  tree binfo;
-  base_kind kind;
   tree result;
 
-  /* Assume no conversion is required.  */
-  result = integer_zero_node;
-  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
-  if (kind == bk_inaccessible || kind == bk_ambig)
-    error ("   in pointer to member function conversion");
-  else if (binfo)
-    {
-      if (kind != bk_via_virtual)
-       result = BINFO_OFFSET (binfo);
-      else
-       {
-         tree virt_binfo = binfo_from_vbase (binfo);
-
-         /* This is a reinterpret cast, we choose to do nothing.  */
-         if (allow_inverse_p)
-           warning (0, "pointer to member cast via virtual base %qT",
-                    BINFO_TYPE (virt_binfo));
-         else
-           error ("pointer to member conversion via virtual base %qT",
-                  BINFO_TYPE (virt_binfo));
-       }
-    }
-  else if (same_type_ignoring_top_level_qualifiers_p (from, to))
-    /* Pointer to member of incomplete class is permitted*/;
-  else if (!allow_inverse_p)
-    {
-      error_not_base_type (from, to);
-      error ("   in pointer to member conversion");
-    }
+  if (same_type_ignoring_top_level_qualifiers_p (from, to))
+    /* Pointer to member of incomplete class is permitted*/
+    result = size_zero_node;
   else
-    {
-      binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
-      if (binfo)
-       {
-         if (kind != bk_via_virtual)
-           result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
-         else
-           {
-             /* This is a reinterpret cast, we choose to do nothing.  */
-             tree virt_binfo = binfo_from_vbase (binfo);
+    result = get_delta_difference_1 (from, to, c_cast_p);
 
-             warning (0, "pointer to member cast via virtual base %qT",
-                      BINFO_TYPE (virt_binfo));
-           }
-       }
-    }
+  if (!result)
+  {
+    if (!allow_inverse_p)
+      {
+       error_not_base_type (from, to);
+       error ("   in pointer to member conversion");
+       result = size_zero_node;
+      }
+    else
+      {
+       result = get_delta_difference_1 (to, from, c_cast_p);
+
+       if (result)
+         result = size_diffop (size_zero_node, result);
+       else
+         {
+           error_not_base_type (from, to);
+           error ("   in pointer to member conversion");
+           result = size_zero_node;
+         }
+      }
+  }
 
   return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
                                                      result));
@@ -5921,13 +6390,15 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
   /* Make sure DELTA has the type we want.  */
   delta = convert_and_check (delta_type_node, delta);
 
+  /* Convert to the correct target type if necessary.  */
+  pfn = fold_convert (TREE_TYPE (pfn_field), pfn);
+
   /* Finish creating the initializer.  */
   v = VEC_alloc(constructor_elt, gc, 2);
   CONSTRUCTOR_APPEND_ELT(v, pfn_field, pfn);
   CONSTRUCTOR_APPEND_ELT(v, delta_field, delta);
   u = build_constructor (type, v);
   TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta);
-  TREE_INVARIANT (u) = TREE_INVARIANT (pfn) & TREE_INVARIANT (delta);
   TREE_STATIC (u) = (TREE_CONSTANT (u)
                     && (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
                         != NULL_TREE)
@@ -5986,7 +6457,8 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
          if (same_type_p (to_type, pfn_type))
            return pfn;
          else if (integer_zerop (n))
-           return build_reinterpret_cast (to_type, pfn);
+           return build_reinterpret_cast (to_type, pfn, 
+                                           tf_warning_or_error);
        }
 
       if (TREE_SIDE_EFFECTS (pfn))
@@ -6005,8 +6477,9 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
       gcc_assert  (same_type_ignoring_top_level_qualifiers_p
                   (TREE_TYPE (delta), ptrdiff_type_node));
       if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
-       n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
-      delta = cp_build_binary_op (PLUS_EXPR, delta, n);
+       n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node,
+                               tf_warning_or_error);
+      delta = cp_build_binary_op (PLUS_EXPR, delta, n, tf_warning_or_error);
       return build_ptrmemfunc1 (to_type, delta, npfn);
     }
 
@@ -6122,6 +6595,25 @@ pfn_from_ptrmemfunc (tree t)
   return build_ptrmemfunc_access_expr (t, pfn_identifier);
 }
 
+/* Return an expression for DELTA from the pointer-to-member function
+   given by T.  */
+
+static tree
+delta_from_ptrmemfunc (tree t)
+{
+  if (TREE_CODE (t) == PTRMEM_CST)
+    {
+      tree delta;
+      tree pfn;
+
+      expand_ptrmemfunc_cst (t, &delta, &pfn);
+      if (delta)
+       return delta;
+    }
+
+  return build_ptrmemfunc_access_expr (t, delta_identifier);
+}
+
 /* Convert value RHS to type TYPE as preparation for an assignment to
    an lvalue of type TYPE.  ERRTYPE is a string to use in error
    messages: "assignment", "return", etc.  If FNDECL is non-NULL, we
@@ -6130,7 +6622,8 @@ pfn_from_ptrmemfunc (tree t)
 
 static tree
 convert_for_assignment (tree type, tree rhs,
-                       const char *errtype, tree fndecl, int parmnum)
+                       const char *errtype, tree fndecl, int parmnum,
+                       tsubst_flags_t complain)
 {
   tree rhstype;
   enum tree_code coder;
@@ -6143,7 +6636,7 @@ convert_for_assignment (tree type, tree rhs,
   coder = TREE_CODE (rhstype);
 
   if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE
-      && vector_types_convertible_p (type, rhstype))
+      && vector_types_convertible_p (type, rhstype, true))
     return convert (type, rhs);
 
   if (rhs == error_mark_node || rhstype == error_mark_node)
@@ -6154,7 +6647,8 @@ convert_for_assignment (tree type, tree rhs,
   /* The RHS of an assignment cannot have void type.  */
   if (coder == VOID_TYPE)
     {
-      error ("void value not ignored as it ought to be");
+      if (complain & tf_error)
+       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
 
@@ -6207,16 +6701,20 @@ convert_for_assignment (tree type, tree rhs,
        rhs = cp_convert (strip_top_quals (type), rhs);
       else
        {
-         /* If the right-hand side has unknown type, then it is an
-            overloaded function.  Call instantiate_type to get error
-            messages.  */
-         if (rhstype == unknown_type_node)
-           instantiate_type (type, rhs, tf_warning_or_error);
-         else if (fndecl)
-           error ("cannot convert %qT to %qT for argument %qP to %qD",
-                  rhstype, type, parmnum, fndecl);
-         else
-           error ("cannot convert %qT to %qT in %s", rhstype, type, errtype);
+         if (complain & tf_error)
+           {
+             /* If the right-hand side has unknown type, then it is an
+                overloaded function.  Call instantiate_type to get error
+                messages.  */
+             if (rhstype == unknown_type_node)
+               instantiate_type (type, rhs, tf_warning_or_error);
+             else if (fndecl)
+               error ("cannot convert %qT to %qT for argument %qP to %qD",
+                      rhstype, type, parmnum, fndecl);
+             else
+               error ("cannot convert %qT to %qT in %s", rhstype, type,
+                      errtype);
+           }
          return error_mark_node;
        }
     }
@@ -6225,13 +6723,28 @@ convert_for_assignment (tree type, tree rhs,
       const enum tree_code codel = TREE_CODE (type);
       if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
          && coder == codel
-         && check_missing_format_attribute (type, rhstype))
+         && check_missing_format_attribute (type, rhstype)
+         && (complain & tf_warning))
        warning (OPT_Wmissing_format_attribute,
                 "%s might be a candidate for a format attribute",
                 errtype);
     }
 
-  return perform_implicit_conversion (strip_top_quals (type), rhs);
+  /* If -Wparentheses, warn about a = b = c when a has type bool and b
+     does not.  */
+  if (warn_parentheses
+      && type == boolean_type_node
+      && TREE_CODE (rhs) == MODIFY_EXPR
+      && !TREE_NO_WARNING (rhs)
+      && TREE_TYPE (rhs) != boolean_type_node
+      && (complain & tf_warning))
+    {
+      warning (OPT_Wparentheses,
+              "suggest parentheses around assignment used as truth value");
+      TREE_NO_WARNING (rhs) = 1;
+    }
+
+  return perform_implicit_conversion (strip_top_quals (type), rhs, complain);
 }
 
 /* Convert RHS to be of type TYPE.
@@ -6252,7 +6765,8 @@ convert_for_assignment (tree type, tree rhs,
 
 tree
 convert_for_initialization (tree exp, tree type, tree rhs, int flags,
-                           const char *errtype, tree fndecl, int parmnum)
+                           const char *errtype, tree fndecl, int parmnum,
+                            tsubst_flags_t complain)
 {
   enum tree_code codel = TREE_CODE (type);
   tree rhstype;
@@ -6317,10 +6831,11 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 
   type = complete_type (type);
 
-  if (IS_AGGR_TYPE (type))
+  if (MAYBE_CLASS_TYPE_P (type))
     return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
-  return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
+  return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
+                                complain);
 }
 \f
 /* If RETVAL is the address of, or a reference to, a local variable or
@@ -6336,9 +6851,8 @@ maybe_warn_about_returning_address_of_local (tree retval)
     {
       if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
        whats_returned = TREE_OPERAND (whats_returned, 1);
-      else if (TREE_CODE (whats_returned) == CONVERT_EXPR
-              || TREE_CODE (whats_returned) == NON_LVALUE_EXPR
-              || TREE_CODE (whats_returned) == NOP_EXPR)
+      else if (CONVERT_EXPR_P (whats_returned)
+              || TREE_CODE (whats_returned) == NON_LVALUE_EXPR)
        whats_returned = TREE_OPERAND (whats_returned, 0);
       else
        break;
@@ -6400,6 +6914,7 @@ check_return_expr (tree retval, bool *no_warning)
      promotions.  */
   tree valtype;
   int fn_returns_value_p;
+  bool named_return_value_okay_p;
 
   *no_warning = false;
 
@@ -6431,6 +6946,8 @@ check_return_expr (tree retval, bool *no_warning)
   if (processing_template_decl)
     {
       current_function_returns_value = 1;
+      if (check_for_bare_parameter_packs (retval))
+        retval = error_mark_node;
       return retval;
     }
 
@@ -6447,8 +6964,8 @@ check_return_expr (tree retval, bool *no_warning)
      that's supposed to return a value.  */
   if (!retval && fn_returns_value_p)
     {
-      pedwarn ("return-statement with no value, in function returning %qT",
-              valtype);
+      permerror ("return-statement with no value, in function returning %qT",
+                valtype);
       /* Clear this, so finish_function won't say that we reach the
         end of a non-void function (which we don't, we gave a
         return!).  */
@@ -6468,8 +6985,8 @@ check_return_expr (tree retval, bool *no_warning)
           its side-effects.  */
          finish_expr_stmt (retval);
       else
-       pedwarn ("return-statement with a value, in function "
-                "returning 'void'");
+       permerror ("return-statement with a value, in function "
+                  "returning 'void'");
 
       current_function_returns_null = 1;
 
@@ -6498,7 +7015,7 @@ check_return_expr (tree retval, bool *no_warning)
        || DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
       && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
       && ! flag_check_new
-      && null_ptr_cst_p (retval))
+      && retval && null_ptr_cst_p (retval))
     warning (0, "%<operator new%> must not return NULL unless it is "
             "declared %<throw()%> (or -fcheck-new is in effect)");
 
@@ -6547,20 +7064,29 @@ check_return_expr (tree retval, bool *no_warning)
 
      See finish_function and finalize_nrv for the rest of this optimization.  */
 
+  named_return_value_okay_p = 
+    (retval != NULL_TREE
+     /* Must be a local, automatic variable.  */
+     && TREE_CODE (retval) == VAR_DECL
+     && DECL_CONTEXT (retval) == current_function_decl
+     && ! TREE_STATIC (retval)
+     && ! DECL_ANON_UNION_VAR_P (retval)
+     && (DECL_ALIGN (retval)
+         >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+     /* The cv-unqualified type of the returned value must be the
+        same as the cv-unqualified return type of the
+        function.  */
+     && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
+                     (TYPE_MAIN_VARIANT
+                      (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+     /* And the returned value must be non-volatile.  */
+     && ! TYPE_VOLATILE (TREE_TYPE (retval)));
+     
   if (fn_returns_value_p && flag_elide_constructors)
     {
-      if (retval != NULL_TREE
-         && (current_function_return_value == NULL_TREE
-             || current_function_return_value == retval)
-         && TREE_CODE (retval) == VAR_DECL
-         && DECL_CONTEXT (retval) == current_function_decl
-         && ! TREE_STATIC (retval)
-         && (DECL_ALIGN (retval)
-             >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
-         && same_type_p ((TYPE_MAIN_VARIANT
-                          (TREE_TYPE (retval))),
-                         (TYPE_MAIN_VARIANT
-                          (TREE_TYPE (TREE_TYPE (current_function_decl))))))
+      if (named_return_value_okay_p
+          && (current_function_return_value == NULL_TREE
+              || current_function_return_value == retval))
        current_function_return_value = retval;
       else
        current_function_return_value = error_mark_node;
@@ -6579,25 +7105,37 @@ check_return_expr (tree retval, bool *no_warning)
     {
       /* The type the function is declared to return.  */
       tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+      int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
 
       /* The functype's return type will have been set to void, if it
         was an incomplete type.  Just treat this as 'return;' */
       if (VOID_TYPE_P (functype))
        return error_mark_node;
 
+      /* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
+        treated as an rvalue for the purposes of overload resolution to
+        favor move constructors over copy constructors.  */
+      if ((cxx_dialect != cxx98) 
+          && named_return_value_okay_p
+          /* The variable must not have the `volatile' qualifier.  */
+         && !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
+         /* The return type must be a class type.  */
+         && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+       flags = flags | LOOKUP_PREFER_RVALUE;
+
       /* First convert the value to the function's return type, then
         to the type of return value's location to handle the
         case that functype is smaller than the valtype.  */
       retval = convert_for_initialization
-       (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
-        "return", NULL_TREE, 0);
+       (NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0,
+         tf_warning_or_error);
       retval = convert (valtype, retval);
 
       /* If the conversion failed, treat this just like `return;'.  */
       if (retval == error_mark_node)
        return retval;
       /* We can't initialize a register from a AGGR_INIT_EXPR.  */
-      else if (! current_function_returns_struct
+      else if (! cfun->returns_struct
               && TREE_CODE (retval) == TARGET_EXPR
               && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
        retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
@@ -6680,7 +7218,7 @@ comp_ptr_ttypes (tree to, tree from)
    type or inheritance-related types, regardless of cv-quals.  */
 
 int
-ptr_reasonably_similar (tree to, tree from)
+ptr_reasonably_similar (const_tree to, const_tree from)
 {
   for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
     {
@@ -6699,7 +7237,7 @@ ptr_reasonably_similar (tree to, tree from)
        continue;
 
       if (TREE_CODE (to) == VECTOR_TYPE
-         && vector_types_convertible_p (to, from))
+         && vector_types_convertible_p (to, from, false))
        return 1;
 
       if (TREE_CODE (to) == INTEGER_TYPE
@@ -6742,25 +7280,52 @@ comp_ptr_ttypes_const (tree to, tree from)
    elements for an array type.  */
 
 int
-cp_type_quals (tree type)
+cp_type_quals (const_tree type)
 {
-  type = strip_array_types (type);
+  /* This CONST_CAST is okay because strip_array_types returns it's
+     argument unmodified and we assign it to a const_tree.  */
+  type = strip_array_types (CONST_CAST_TREE(type));
   if (type == error_mark_node)
     return TYPE_UNQUALIFIED;
   return TYPE_QUALS (type);
 }
 
+/* Returns nonzero if the TYPE is const from a C++ perspective: look inside
+   arrays.  */
+
+bool
+cp_type_readonly (const_tree type)
+{
+  /* This CONST_CAST is okay because strip_array_types returns it's
+     argument unmodified and we assign it to a const_tree.  */
+  type = strip_array_types (CONST_CAST_TREE(type));
+  return TYPE_READONLY (type);
+}
+
 /* Returns nonzero if the TYPE contains a mutable member.  */
 
 bool
-cp_has_mutable_p (tree type)
+cp_has_mutable_p (const_tree type)
 {
-  type = strip_array_types (type);
+  /* This CONST_CAST is okay because strip_array_types returns it's
+     argument unmodified and we assign it to a const_tree.  */
+  type = strip_array_types (CONST_CAST_TREE(type));
 
   return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
 }
 
-/* Apply the TYPE_QUALS to the new DECL.  */
+/* Set TREE_READONLY and TREE_VOLATILE on DECL as indicated by the
+   TYPE_QUALS.  For a VAR_DECL, this may be an optimistic
+   approximation.  In particular, consider:
+
+     int f();
+     struct S { int i; };
+     const S s = { f(); }
+
+   Here, we will make "s" as TREE_READONLY (because it is declared
+   "const") -- only to reverse ourselves upon seeing that the
+   initializer is non-constant.  */
+
 void
 cp_apply_type_quals_to_decl (int type_quals, tree decl)
 {
@@ -6927,11 +7492,11 @@ non_reference (tree t)
    how the lvalue is being used and so selects the error message.  */
 
 int
-lvalue_or_else (tree ref, enum lvalue_use use)
+lvalue_or_else (const_tree ref, enum lvalue_use use, tsubst_flags_t complain)
 {
   int win = lvalue_p (ref);
 
-  if (!win)
+  if (!win && (complain & tf_error))
     lvalue_error (use);
 
   return win;