OSDN Git Service

PR c++/23194
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index f17aa80..e34fa67 100644 (file)
@@ -1,6 +1,6 @@
 /* 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, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -8,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+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,
@@ -17,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.
@@ -47,19 +46,23 @@ Boston, MA 02110-1301, USA.  */
 #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 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 int convert_arguments (int, tree *, 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.)
@@ -152,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);
@@ -394,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;
@@ -426,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,
@@ -442,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);
     }
@@ -466,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;
@@ -504,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
@@ -543,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;
        }
     }
@@ -563,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.
@@ -621,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);
 
@@ -764,7 +773,7 @@ common_type (tree t1, tree 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 ();
 }
@@ -821,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)
@@ -868,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;
@@ -943,20 +952,10 @@ structural_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;
-    }
+    t2 = resolve_typename_type (t2, /*only_current_p=*/true);
 
   if (TYPE_PTRMEMFUNC_P (t1))
     t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
@@ -986,6 +985,30 @@ structural_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)
@@ -1090,6 +1113,14 @@ structural_comptypes (tree t1, tree t2, int strict)
       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;
     }
@@ -1108,8 +1139,6 @@ comptypes (tree t1, tree t2, int strict)
 {
   if (strict == COMPARE_STRICT)
     {
-      bool result;
-
       if (t1 == t2)
        return true;
 
@@ -1121,37 +1150,34 @@ comptypes (tree t1, tree t2, int strict)
           perform a deep check. */
        return structural_comptypes (t1, t2, strict);
 
-      if (VERIFY_CANONICAL_TYPES)
+#ifdef ENABLE_CHECKING
+      if (USE_CANONICAL_TYPES)
        {
-         result = structural_comptypes (t1, t2, strict);
-
+         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.*/
-             warning(0,
-                     "canonical types differ for identical types %T and %T", 
-                     t1, t2);
-             debug_tree (t1);
-             debug_tree (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. */
-             warning (0, 
-                      "same canonical type node for different types %T and %T",
-                      t1, t2);
-             debug_tree (t1);
-             debug_tree (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
+#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);
@@ -1162,7 +1188,7 @@ comptypes (tree t1, tree t2, int 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);
@@ -1175,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);
@@ -1214,9 +1240,9 @@ comp_cv_qual_signature (tree type1, tree type2)
    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.  */
@@ -1282,10 +1308,27 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
                                   complain);
 }
 
+/* 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
+    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;
@@ -1303,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
@@ -1329,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;
 
@@ -1351,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
@@ -1359,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);
 }
@@ -1378,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.
@@ -1403,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;
@@ -1418,12 +1484,14 @@ 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)
 {
   switch (TREE_CODE (exp))
     {
     case COND_EXPR:
-      if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)))
+      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));
 
@@ -1439,7 +1507,7 @@ is_bitfield_expr_with_lowered_type (tree exp)
        tree field;
        
        field = TREE_OPERAND (exp, 1);
-       if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field))
+       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)))
@@ -1447,6 +1515,12 @@ is_bitfield_expr_with_lowered_type (tree exp)
        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;
     }
@@ -1457,7 +1531,7 @@ is_bitfield_expr_with_lowered_type (tree exp)
    than NULL_TREE.  */
 
 tree
-unlowered_expr_type (tree exp)
+unlowered_expr_type (const_tree exp)
 {
   tree type;
 
@@ -1507,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;
@@ -1545,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);
     }
 
@@ -1638,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;
 
@@ -1647,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;
     }
@@ -1686,7 +1762,8 @@ 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
@@ -1704,15 +1781,20 @@ rationalize_conditional_expr (enum tree_code code, tree t)
                                                    ? LE_EXPR : GE_EXPR),
                                                   op0, TREE_CODE (op0),
                                                   op1, TREE_CODE (op1),
-                                                  /*overloaded_p=*/NULL),
-                           build_unary_op (code, op0, 0),
-                           build_unary_op (code, op1, 0));
+                                                  /*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
@@ -1765,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;
@@ -1786,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;
     }
 
@@ -1802,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.  */
@@ -1812,10 +1896,13 @@ 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;
     }
 
@@ -1825,7 +1912,7 @@ build_class_member_access_expr (tree object, tree member,
   {
     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
@@ -1865,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;
            }
 
@@ -1891,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
@@ -1919,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].  */
@@ -1980,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;
     }
 
@@ -2051,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;
@@ -2071,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);
        }
     }
 }
@@ -2086,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;
@@ -2134,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;
     }
 
@@ -2172,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;
            }
 
@@ -2187,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;
            }
        }
@@ -2206,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)
@@ -2221,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;
            }
        }
@@ -2234,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))
@@ -2287,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;
@@ -2300,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);
@@ -2310,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)
@@ -2337,8 +2448,7 @@ build_indirect_ref (tree ptr, const char *errorstring)
         types.  */
       tree t = canonical_type_variant (TREE_TYPE (type));
 
-      if (TREE_CODE (ptr) == CONVERT_EXPR
-          || TREE_CODE (ptr) == NOP_EXPR
+      if (CONVERT_EXPR_P (ptr)
           || TREE_CODE (ptr) == VIEW_CONVERT_EXPR)
        {
          /* If a warning is issued, mark it to avoid duplicates from
@@ -2354,7 +2464,8 @@ build_indirect_ref (tree ptr, const char *errorstring)
        {
          /* 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
@@ -2376,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))
@@ -2431,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;
@@ -2537,8 +2652,10 @@ build_array_ref (tree array, tree idx)
 
     warn_array_subscript_with_type_char (idx);
 
-    return build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind),
-                              "array indexing");
+    return cp_build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind,
+                                                  tf_warning_or_error),
+                                  "array indexing",
+                                  tf_warning_or_error);
   }
 }
 \f
@@ -2591,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:
@@ -2627,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;
@@ -2636,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.  */
@@ -2664,9 +2786,16 @@ 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 name = NULL_TREE;
   int is_method;
@@ -2693,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
@@ -2719,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;
     }
 
@@ -2733,7 +2863,8 @@ 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;
     }
 
@@ -2751,13 +2882,20 @@ build_function_call (tree function, tree params)
   /* 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);
+                            params, fndecl, LOOKUP_NORMAL,
+                             complain);
   if (nargs < 0)
     return 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);
 
@@ -2786,7 +2924,8 @@ build_function_call (tree function, tree params)
 
 static int
 convert_arguments (int nargs, tree *argarray,
-                  tree typelist, tree values, tree fndecl, int flags)
+                  tree typelist, tree values, tree fndecl, int flags,
+                   tsubst_flags_t complain)
 {
   tree typetail, valtail;
   const char *called_thing = 0;
@@ -2821,14 +2960,20 @@ convert_arguments (int nargs, tree *argarray,
 
       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");
-         return i;
+          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.
@@ -2856,18 +3001,21 @@ convert_arguments (int nargs, tree *argarray,
 
          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);
            }
 
@@ -2896,8 +3044,14 @@ convert_arguments (int nargs, tree *argarray,
 
   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)
@@ -2919,13 +3073,17 @@ convert_arguments (int nargs, tree *argarray,
        }
       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");
+          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;
        }
     }
@@ -2947,7 +3105,8 @@ convert_arguments (int nargs, tree *argarray,
 
 tree
 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)
+                  tree arg2, enum tree_code arg2_code, bool *overloaded_p,
+                  tsubst_flags_t complain)
 {
   tree orig_arg1;
   tree orig_arg2;
@@ -2969,7 +3128,7 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
     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
@@ -2988,6 +3147,15 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
   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:
@@ -3007,8 +3175,8 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
    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;
@@ -3052,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;
 
@@ -3093,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;
        }
     }
@@ -3103,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;
        }
     }
@@ -3212,7 +3378,9 @@ 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;
 
@@ -3252,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");
                }
            }
@@ -3277,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.  */
@@ -3298,13 +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, (code == LROTATE_EXPR)
-                            ? G_("left rotate count is negative")
-                            : G_("right rotate count is negative"));
+               {
+                 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, (code == LROTATE_EXPR) 
-                            ? G_("left rotate count >= width of type")
-                            : G_("right rotate count >= width of type"));
+               {
+                 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.  */
@@ -3315,11 +3497,13 @@ 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)))
+      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;
@@ -3331,14 +3515,17 @@ 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))
        {
          if (TREE_CODE (op0) == ADDR_EXPR
              && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
-           warning (OPT_Waddress, "the address of %qD will never be NULL",
-                    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))
@@ -3346,19 +3533,28 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        {
          if (TREE_CODE (op1) == ADDR_EXPR 
              && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
-           warning (OPT_Waddress, "the address of %qD will never be NULL",
-                    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))
        {
@@ -3366,17 +3562,20 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              == ptrmemfunc_vbit_in_delta)
            {
              tree pfn0 = pfn_from_ptrmemfunc (op0);
-             tree delta0 = build_ptrmemfunc_access_expr (op0,
-                                                         delta_identifier);
+             tree delta0 = delta_from_ptrmemfunc (op0);
              tree e1 = cp_build_binary_op (EQ_EXPR,
                                            pfn0,       
                                            fold_convert (TREE_TYPE (pfn0),
-                                                         integer_zero_node));
+                                                         integer_zero_node),
+                                           complain);
              tree e2 = cp_build_binary_op (BIT_AND_EXPR, 
                                            delta0,
-                                           integer_one_node);
-             e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node);
-             op0 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
+                                           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 
@@ -3387,10 +3586,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          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.  */
@@ -3401,6 +3600,17 @@ 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))
@@ -3408,10 +3618,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
          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);
+         delta0 = delta_from_ptrmemfunc (op0);
+         delta1 = delta_from_ptrmemfunc (op1);
          if (TARGET_PTRMEMFUNC_VBIT_LOCATION
              == ptrmemfunc_vbit_in_delta)
            {
@@ -3428,20 +3636,26 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
              e1 = cp_build_binary_op (BIT_AND_EXPR,
                                       delta0, 
-                                      integer_one_node);
-             e1 = cp_build_binary_op (EQ_EXPR, e1, integer_zero_node);
+                                      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);
-             e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node);
-             e1 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
+                                      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));
-             e2 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
-             e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
-             e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+                                                    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
            {
@@ -3454,18 +3668,19 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                 pointer-to-member is any member with a zero PFN; the
                 DELTA field is unspecified.  */
  
-             e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
+             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));
-             e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+                                                    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
        {
@@ -3486,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:
@@ -3495,7 +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_Waddress, "comparison with string literal results in unspecified behaviour");
+       {
+         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)
@@ -3503,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;
@@ -3513,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;
 
@@ -3532,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;
@@ -3570,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)
     {
@@ -3656,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.  */
 
@@ -3732,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));
            }
 
@@ -3769,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
@@ -3813,16 +4010,18 @@ 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");
            }
        }
     }
@@ -3837,7 +4036,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree 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)))
+         || (!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
@@ -3911,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;
@@ -3923,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))))
@@ -3944,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;
@@ -3976,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
@@ -3987,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
@@ -4017,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)
@@ -4052,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;
 }
@@ -4094,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;
@@ -4173,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;
@@ -4223,9 +4427,9 @@ 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 = build_unary_op (code, real, 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),
@@ -4247,14 +4451,21 @@ 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"));
+         || 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;
@@ -4268,9 +4479,14 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
 
        /* ARM $5.2.5 last annotation says this should be forbidden.  */
        if (TREE_CODE (argtype) == ENUMERAL_TYPE)
-         pedwarn ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
-                  ? G_("ISO C++ forbids incrementing an enum")
-                  : G_("ISO C++ forbids decrementing an enum"));
+          {
+            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.  */
 
@@ -4279,18 +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 (((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));
+              {
+                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 ((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);
+                    && !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
@@ -4301,7 +4528,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
        /* 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'.  */
@@ -4309,7 +4537,9 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          {
            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);
@@ -4337,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)
@@ -4391,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);
        }
@@ -4419,12 +4656,19 @@ 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:
-         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:
@@ -4443,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;
              }
 
@@ -4467,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)
@@ -4506,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
@@ -4540,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.
@@ -4563,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);
     }
@@ -4571,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
@@ -4596,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;
@@ -4616,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;
@@ -4713,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;
@@ -4736,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);
@@ -4753,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;
@@ -4765,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;
@@ -4781,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);
@@ -4791,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;
@@ -4818,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
@@ -4854,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
@@ -4900,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;
@@ -4916,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
@@ -4991,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);
@@ -5012,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]
 
@@ -5055,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);
@@ -5087,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);
        }
@@ -5108,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);
     }
 
@@ -5119,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;
@@ -5142,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;
 }
 
@@ -5191,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;
 
@@ -5216,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;
        }
 
@@ -5226,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;
     }
 
@@ -5275,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
@@ -5293,18 +5582,17 @@ 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 front end likes to
         create (int *)&a for array-to-pointer decay, instead of &a[0].  */
@@ -5317,7 +5605,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
   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
@@ -5333,7 +5621,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       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;
     }
 
@@ -5341,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;
@@ -5358,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,
@@ -5449,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);
        }
@@ -5480,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;
@@ -5496,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;
@@ -5542,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;
        }
     }
@@ -5555,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;
     }
 
@@ -5567,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
@@ -5603,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.
@@ -5611,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;
@@ -5634,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,
@@ -5653,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);
@@ -5662,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))
@@ -5688,7 +5998,8 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 
        if (VOID_TYPE_P (TREE_TYPE (rhs)))
          {
-           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;
          }
 
@@ -5696,15 +6007,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 
        /* 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;
@@ -5730,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;
@@ -5751,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;
@@ -5769,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;
            }
 
@@ -5788,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
@@ -5803,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");
+    {
+      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
@@ -5844,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;
        }
 
@@ -5854,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;
        }
 
@@ -5865,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.  */
@@ -5878,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);
@@ -5929,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,
@@ -5943,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
@@ -5971,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));
@@ -6044,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)
@@ -6109,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))
@@ -6128,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);
     }
 
@@ -6245,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
@@ -6253,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;
@@ -6277,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;
     }
 
@@ -6330,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;
        }
     }
@@ -6348,7 +6723,8 @@ 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);
@@ -6360,14 +6736,15 @@ convert_for_assignment (tree type, tree rhs,
       && type == boolean_type_node
       && TREE_CODE (rhs) == MODIFY_EXPR
       && !TREE_NO_WARNING (rhs)
-      && TREE_TYPE (rhs) != boolean_type_node)
+      && 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);
+  return perform_implicit_conversion (strip_top_quals (type), rhs, complain);
 }
 
 /* Convert RHS to be of type TYPE.
@@ -6388,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;
@@ -6453,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
@@ -6472,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;
@@ -6568,7 +6946,8 @@ check_return_expr (tree retval, bool *no_warning)
   if (processing_template_decl)
     {
       current_function_returns_value = 1;
-      check_for_bare_parameter_packs (retval);
+      if (check_for_bare_parameter_packs (retval))
+        retval = error_mark_node;
       return retval;
     }
 
@@ -6585,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!).  */
@@ -6606,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;
 
@@ -6636,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)");
 
@@ -6691,6 +7070,7 @@ check_return_expr (tree retval, bool *no_warning)
      && 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
@@ -6698,7 +7078,9 @@ check_return_expr (tree retval, bool *no_warning)
         function.  */
      && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
                      (TYPE_MAIN_VARIANT
-                      (TREE_TYPE (TREE_TYPE (current_function_decl))))));
+                      (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)
     {
@@ -6745,14 +7127,15 @@ check_return_expr (tree retval, bool *no_warning)
         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, flags, "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,
@@ -6835,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))
     {
@@ -6897,9 +7280,11 @@ 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);
@@ -6909,23 +7294,38 @@ cp_type_quals (tree type)
    arrays.  */
 
 bool
-cp_type_readonly (tree type)
+cp_type_readonly (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 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)
 {
@@ -7092,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;