OSDN Git Service

* tree-ssa-ifcombine.c (get_name_for_bit_test): Use
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index d0eaf98..026e446 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)
 
@@ -47,9 +47,11 @@ along with GCC; see the file COPYING3.  If not see
 
 static tree pfn_from_ptrmemfunc (tree);
 static tree delta_from_ptrmemfunc (tree);
-static tree convert_for_assignment (tree, tree, const char *, tree, int);
+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 (const_tree, const_tree, bool);
@@ -59,7 +61,8 @@ 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.)
@@ -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)
+       pedwarn ("%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,7 +448,8 @@ 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)))
+                       TYPE_PTRMEM_CLASS_TYPE (t2))
+         && (complain & tf_error))
        pedwarn ("%s between distinct pointer types %qT and %qT "
                 "lacks a cast",
                 location, t1, t2);
@@ -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.
@@ -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 ();
 }
@@ -962,6 +971,8 @@ structural_comptypes (tree t1, tree t2, int strict)
   if (TREE_CODE (t1) != ARRAY_TYPE
       && TYPE_QUALS (t1) != TYPE_QUALS (t2))
     return false;
+  if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
+    return false;
 
   /* Allow for two different type nodes which have essentially the same
      definition.  Note that we already checked for equality of the type
@@ -971,9 +982,6 @@ structural_comptypes (tree t1, tree t2, int strict)
       && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return true;
 
-  if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
-    return false;
-
   /* Compare the types.  Break out if they could be the same.  */
   switch (TREE_CODE (t1))
     {
@@ -1300,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;
@@ -1321,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)
+        pedwarn ("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
@@ -1347,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;
 
@@ -1369,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
@@ -1377,8 +1414,11 @@ 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");
+      if (complain & tf_error)
+        pedwarn ("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
@@ -1386,11 +1426,15 @@ cxx_alignof_expr (tree e)
     }
   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);
 }
@@ -1399,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.
@@ -1424,11 +1468,12 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
    violates these rules.  */
 
 bool
-invalid_nonstatic_memfn_p (const_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;
@@ -1462,7 +1507,7 @@ is_bitfield_expr_with_lowered_type (const_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)))
@@ -1470,8 +1515,7 @@ is_bitfield_expr_with_lowered_type (const_tree exp)
        return DECL_BIT_FIELD_TYPE (field);
       }
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
+    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));
@@ -1537,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;
@@ -1575,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);
     }
 
@@ -1677,12 +1721,14 @@ string_conv_p (const_tree totype, const_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;
     }
@@ -1716,7 +1762,8 @@ string_conv_p (const_tree totype, const_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
@@ -1734,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
@@ -1795,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;
@@ -1816,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;
     }
 
@@ -1842,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;
     }
 
@@ -1855,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
@@ -1895,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;
            }
 
@@ -1921,7 +1981,8 @@ 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 (OPT_Winvalid_offsetof, 
                    "invalid access to non-static data member %qD "
@@ -1951,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].  */
@@ -2012,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;
     }
 
@@ -2118,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;
@@ -2166,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;
     }
 
@@ -2204,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;
            }
 
@@ -2219,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;
            }
        }
@@ -2238,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)
@@ -2253,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;
            }
        }
@@ -2266,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))
@@ -2319,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;
@@ -2332,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);
@@ -2342,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)
@@ -2369,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
@@ -2386,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
@@ -2408,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))
@@ -2463,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;
@@ -2569,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
@@ -2628,13 +2713,17 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
       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:
@@ -2668,23 +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 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
                        fold_convert (sizetype, idx));
-      e2 = build_indirect_ref (e2, NULL);
+      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));
 
       e2 = fold_convert (TREE_TYPE (e3), e2);
-      e1 = build_conditional_expr (e1, e2, e3);
+      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.  */
@@ -2697,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;
@@ -2726,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
@@ -2752,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 (...)%>",
+              original);
       return error_mark_node;
     }
 
@@ -2766,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;
     }
 
@@ -2784,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);
 
@@ -2819,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;
@@ -2854,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.
@@ -2889,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);
            }
 
@@ -2958,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;
        }
     }
@@ -2986,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;
@@ -3008,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
@@ -3027,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:
@@ -3046,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;
@@ -3128,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)
+           pedwarn ("assuming cast to type %qT from overloaded function",
+                    TREE_TYPE (t));
          op0 = t;
        }
     }
@@ -3138,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)
+           pedwarn ("assuming cast to type %qT from overloaded function",
+                    TREE_TYPE (t));
          op1 = t;
        }
     }
@@ -3289,10 +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 (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");
                }
            }
@@ -3312,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.  */
@@ -3333,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.  */
@@ -3350,11 +3497,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
     case EQ_EXPR:
     case NE_EXPR:
-      if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1))
+      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;
@@ -3366,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))
@@ -3381,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;
-         pedwarn ("ISO C++ forbids comparison between pointer and integer");
+         if (complain & tf_error) 
+            pedwarn ("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)
+           pedwarn ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
        {
@@ -3405,12 +3566,16 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              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 
@@ -3421,7 +3586,7 @@ 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);
+       return cp_build_binary_op (code, op1, op0, complain);
       else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
        {
          tree type;
@@ -3435,7 +3600,8 @@ 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");
+         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);
@@ -3470,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
            {
@@ -3496,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
        {
@@ -3528,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:
@@ -3537,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)
@@ -3545,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;
@@ -3555,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)
+           pedwarn ("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)
+           pedwarn ("ISO C++ forbids comparison between pointer and integer");
+          else
+            return error_mark_node;
        }
       break;
 
@@ -3574,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;
@@ -3612,8 +3795,9 @@ 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;
     }
 
@@ -3743,7 +3927,8 @@ 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 (OPT_Wsign_compare, "comparison between types %q#T and %q#T",
                       TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
@@ -3780,7 +3965,7 @@ 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
+         else if (complain & tf_warning)
            warning (OPT_Wsign_compare, 
                     "comparison between signed and unsigned integer expressions");
 
@@ -3825,7 +4010,8 @@ 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)
+                     if ((mask & constant) != mask
+                         && (complain & tf_warning))
                        warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with constant");
                    }
                }
@@ -3833,7 +4019,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                       && (TYPE_PRECISION (TREE_TYPE (primop0))
                           < TYPE_PRECISION (result_type))
                       && (TYPE_PRECISION (TREE_TYPE (primop1))
-                          < TYPE_PRECISION (result_type)))
+                          < TYPE_PRECISION (result_type))
+                      && (complain & tf_warning))
                warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with unsigned");
            }
        }
@@ -3849,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
@@ -3935,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))))
@@ -3956,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;
@@ -3988,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
@@ -3999,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
@@ -4029,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)
@@ -4064,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;
 }
@@ -4106,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;
@@ -4185,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;
@@ -4235,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),
@@ -4265,10 +4457,15 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       /* 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;
@@ -4282,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)
+              pedwarn ((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.  */
 
@@ -4293,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)
+                  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);
+                else
+                  return error_mark_node;
+              }
+
            inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
          }
        else
@@ -4315,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'.  */
@@ -4323,8 +4537,9 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          {
            if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
              {
-               error ("invalid use of Boolean expression as operand "
-                      "to %<operator--%>");
+                if (complain & tf_error)
+                  error ("invalid use of Boolean expression as operand "
+                         "to %<operator--%>");
                return error_mark_node;
              }
            val = boolean_increment (code, arg);
@@ -4352,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)
+            pedwarn ("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)
@@ -4406,13 +4626,15 @@ 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.  */
+                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);
              else
                pedwarn ("ISO C++ forbids taking the address of a bound member"
                         " function to form a pointer to member function."
@@ -4434,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)
+                pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+              else
+                return error_mark_node;
+            }
          break;
 
        case BASELINK:
@@ -4458,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;
              }
 
@@ -4482,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)
@@ -4521,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
@@ -4555,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.
@@ -4578,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);
     }
@@ -4586,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
@@ -4611,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;
@@ -4631,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;
@@ -4728,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;
@@ -4751,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);
@@ -4771,7 +5013,8 @@ tree build_x_compound_expr_from_list (tree list, const char *msg)
        pedwarn ("%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;
@@ -4780,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;
@@ -4796,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);
@@ -4806,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;
@@ -4894,9 +5145,11 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
 
          cond = cp_build_binary_op (EQ_EXPR,
                                     expr,
-                                    build_int_cst (TREE_TYPE (expr), -1));
+                                    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);
+         op2 = cp_build_binary_op (PLUS_EXPR, op1, delta,
+                                   tf_warning_or_error);
 
          expr = fold_build3 (COND_EXPR, ptrdiff_type_node, cond, op1, op2);
                         
@@ -4945,7 +5198,7 @@ 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;
@@ -5019,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);
@@ -5040,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]
 
@@ -5146,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;
@@ -5169,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;
 }
 
@@ -5218,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;
 
@@ -5243,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;
        }
 
@@ -5253,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;
     }
 
@@ -5302,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)
+            pedwarn ("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
@@ -5323,6 +5585,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        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))
@@ -5342,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
@@ -5358,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;
     }
 
@@ -5366,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;
@@ -5383,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,
@@ -5478,7 +5742,8 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
        }
       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);
        }
@@ -5502,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;
@@ -5518,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;
@@ -5564,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)
+            pedwarn ("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;
        }
     }
@@ -5577,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;
     }
 
@@ -5589,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
@@ -5625,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.
@@ -5633,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;
@@ -5656,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,
@@ -5675,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);
@@ -5684,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))
@@ -5710,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;
          }
 
@@ -5718,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;
@@ -5752,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;
@@ -5773,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;
@@ -5791,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;
            }
 
@@ -5810,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
@@ -5825,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
@@ -5866,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;
        }
 
@@ -5876,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;
        }
 
@@ -5887,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.  */
@@ -5900,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);
@@ -5951,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,
@@ -5965,14 +6272,15 @@ 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
@@ -6091,7 +6399,6 @@ build_ptrmemfunc1 (tree type, tree delta, tree 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)
@@ -6150,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))
@@ -6169,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);
     }
 
@@ -6313,7 +6622,8 @@ delta_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;
@@ -6337,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;
     }
 
@@ -6390,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;
        }
     }
@@ -6408,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);
@@ -6420,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.
@@ -6448,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;
@@ -6513,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
@@ -6532,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;
@@ -6809,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,
@@ -7173,11 +7492,11 @@ non_reference (tree t)
    how the lvalue is being used and so selects the error message.  */
 
 int
-lvalue_or_else (const_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;