OSDN Git Service

PR c++/48322
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 53e84cf..a23e274 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, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -34,17 +34,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "cp-tree.h"
 #include "flags.h"
 #include "output.h"
-#include "toplev.h"
 #include "diagnostic.h"
 #include "intl.h"
 #include "target.h"
 #include "convert.h"
-#include "c-common.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
 #include "params.h"
 
 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, impl_conv_rhs, tree, int,
                                    tsubst_flags_t, int);
 static tree cp_pointer_int_sum (enum tree_code, tree, tree);
 static tree rationalize_conditional_expr (enum tree_code, tree, 
@@ -53,7 +53,7 @@ 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);
 static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, bool, bool);
+static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 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);
@@ -64,11 +64,11 @@ static int convert_arguments (tree, VEC(tree,gc) **, tree, int,
 
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)
-   Returns the error_mark_node if the VALUE does not have
+   Returns error_mark_node if the VALUE does not have
    complete type when this function returns.  */
 
 tree
-require_complete_type (tree value)
+require_complete_type_sfinae (tree value, tsubst_flags_t complain)
 {
   tree type;
 
@@ -87,12 +87,18 @@ require_complete_type (tree value)
   if (COMPLETE_TYPE_P (type))
     return value;
 
-  if (complete_type_or_else (type, value))
+  if (complete_type_or_maybe_complain (type, value, complain))
     return value;
   else
     return error_mark_node;
 }
 
+tree
+require_complete_type (tree value)
+{
+  return require_complete_type_sfinae (value, tf_warning_or_error);
+}
+
 /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
    a template instantiation, do the instantiation.  Returns TYPE,
    whether or not it could be completed, unless something goes
@@ -135,7 +141,7 @@ complete_type (tree type)
    Returns NULL_TREE if the type cannot be made complete.  */
 
 tree
-complete_type_or_else (tree type, tree value)
+complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
 {
   type = complete_type (type);
   if (type == error_mark_node)
@@ -143,13 +149,20 @@ complete_type_or_else (tree type, tree value)
     return NULL_TREE;
   else if (!COMPLETE_TYPE_P (type))
     {
-      cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+      if (complain & tf_error)
+       cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
       return NULL_TREE;
     }
   else
     return type;
 }
 
+tree
+complete_type_or_else (tree type, tree value)
+{
+  return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+}
+
 /* Return truthvalue of whether type of EXP is instantiated.  */
 
 int
@@ -258,6 +271,7 @@ cp_common_type (tree t1, tree t2)
   enum tree_code code2 = TREE_CODE (t2);
   tree attributes;
 
+
   /* In what follows, we slightly generalize the rules given in [expr] so
      as to deal with `long long' and `complex'.  First, merge the
      attributes.  */
@@ -429,6 +443,35 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
   return cp_common_type (t1, t2);
 }
 
+static void
+composite_pointer_error (diagnostic_t kind, tree t1, tree t2,
+                        composite_pointer_operation operation)
+{
+  switch (operation)
+    {
+    case CPO_COMPARISON:
+      emit_diagnostic (kind, input_location, 0,
+                      "comparison between "
+                      "distinct pointer types %qT and %qT lacks a cast",
+                      t1, t2);
+      break;
+    case CPO_CONVERSION:
+      emit_diagnostic (kind, input_location, 0,
+                      "conversion between "
+                      "distinct pointer types %qT and %qT lacks a cast",
+                      t1, t2);
+      break;
+    case CPO_CONDITIONAL_EXPR:
+      emit_diagnostic (kind, input_location, 0,
+                      "conditional expression between "
+                      "distinct pointer types %qT and %qT lacks a cast",
+                      t1, t2);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Subroutine of composite_pointer_type to implement the recursive
    case.  See that function for documentation of the parameters.  */
 
@@ -467,33 +510,18 @@ composite_pointer_type_r (tree t1, tree t2,
            && 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, operation,
-                                           complain);
+    {
+      result_type = composite_pointer_type_r (pointee1, pointee2, operation,
+                                             complain);
+      if (result_type == error_mark_node)
+       return error_mark_node;
+    }
   else
     {
       if (complain & tf_error)
-        {
-          switch (operation)
-            {
-            case CPO_COMPARISON:
-              permerror (input_location, "comparison between "
-                         "distinct pointer types %qT and %qT lacks a cast",
-                         t1, t2);
-              break;
-            case CPO_CONVERSION:
-              permerror (input_location, "conversion between "
-                         "distinct pointer types %qT and %qT lacks a cast",
-                         t1, t2);
-              break;
-            case CPO_CONDITIONAL_EXPR:
-              permerror (input_location, "conditional expression between "
-                         "distinct pointer types %qT and %qT lacks a cast",
-                         t1, t2);
-              break;
-            default:
-              gcc_unreachable ();
-            }
-        }
+       composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+      else
+       return error_mark_node;
       result_type = void_type_node;
     }
   result_type = cp_build_qualified_type (result_type,
@@ -504,30 +532,13 @@ composite_pointer_type_r (tree t1, tree t2,
   if (TYPE_PTR_TO_MEMBER_P (t1))
     {
       if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
-                       TYPE_PTRMEM_CLASS_TYPE (t2))
-         && (complain & tf_error))
-        {
-          switch (operation)
-            {
-            case CPO_COMPARISON:
-              permerror (input_location, "comparison between "
-                         "distinct pointer types %qT and %qT lacks a cast", 
-                         t1, t2);
-              break;
-            case CPO_CONVERSION:
-              permerror (input_location, "conversion between "
-                         "distinct pointer types %qT and %qT lacks a cast",
-                         t1, t2);
-              break;
-            case CPO_CONDITIONAL_EXPR:
-              permerror (input_location, "conditional expression between "
-                         "distinct pointer types %qT and %qT lacks a cast",
-                         t1, t2);
-              break;
-            default:
-              gcc_unreachable ();
-            }
-        }
+                       TYPE_PTRMEM_CLASS_TYPE (t2)))
+       {
+         if (complain & tf_error)
+           composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+         else
+           return error_mark_node;
+       }
       result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
                                       result_type);
     }
@@ -624,8 +635,8 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
   if (c_dialect_objc () && TREE_CODE (t1) == POINTER_TYPE
       && TREE_CODE (t2) == POINTER_TYPE)
     {
-      if (objc_compare_types (t1, t2, -3, NULL_TREE))
-       return t1;
+      if (objc_have_common_type (t1, t2, -3, NULL_TREE))
+       return objc_common_type (t1, t2);
     }
 
   /* [expr.eq] permits the application of a pointer conversion to
@@ -648,23 +659,7 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       else
         {
           if (complain & tf_error)
-            switch (operation)
-              {
-              case CPO_COMPARISON:
-                error ("comparison between distinct "
-                       "pointer types %qT and %qT lacks a cast", t1, t2);
-                break;
-              case CPO_CONVERSION:
-                error ("conversion between distinct "
-                       "pointer types %qT and %qT lacks a cast", t1, t2);
-                break;
-              case CPO_CONDITIONAL_EXPR:
-                error ("conditional expression between distinct "
-                       "pointer types %qT and %qT lacks a cast", t1, t2);
-                break;
-              default:
-                gcc_unreachable ();
-              }
+           composite_pointer_error (DK_ERROR, t1, t2, operation);
           return error_mark_node;
         }
     }
@@ -839,7 +834,8 @@ merge_types (tree t1, tree t2)
        gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
        rval = apply_memfn_quals (rval, type_memfn_quals (t1));
        raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-                                            TYPE_RAISES_EXCEPTIONS (t2));
+                                            TYPE_RAISES_EXCEPTIONS (t2),
+                                            NULL_TREE);
        t1 = build_exception_variant (rval, raises);
        break;
       }
@@ -848,9 +844,10 @@ merge_types (tree t1, tree t2)
       {
        /* Get this value the long way, since TYPE_METHOD_BASETYPE
           is just the main variant of this.  */
-       tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
+       tree basetype = class_of_this_parm (t2);
        tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-                                                 TYPE_RAISES_EXCEPTIONS (t2));
+                                                 TYPE_RAISES_EXCEPTIONS (t2),
+                                                 NULL_TREE);
        tree t3;
 
        /* If this was a member function type, get back to the
@@ -993,35 +990,37 @@ comp_except_specs (const_tree t1, const_tree t2, int exact)
   const_tree probe;
   const_tree base;
   int  length = 0;
-  const_tree noexcept_spec = NULL_TREE;
-  const_tree other_spec;
 
   if (t1 == t2)
     return true;
 
-  /* First test noexcept compatibility.  */
-  if (t1 && TREE_PURPOSE (t1))
-    noexcept_spec = t1, other_spec = t2;
-  else if (t2 && TREE_PURPOSE (t2))
-    noexcept_spec = t2, other_spec = t1;
-  if (noexcept_spec)
-    {
-      tree p = TREE_PURPOSE (noexcept_spec);
-      /* Two noexcept-specs are equivalent iff their exprs are.  */
-      if (other_spec && TREE_PURPOSE (other_spec))
-       return cp_tree_equal (p, TREE_PURPOSE (other_spec));
-      /* noexcept(true) is compatible with throw().  */
-      else if (exact < ce_exact && p == boolean_true_node)
-       return nothrow_spec_p (other_spec);
-      /* noexcept(false) is compatible with any throwing
-        dynamic-exception-spec.  */
-      else if (exact < ce_exact && p == boolean_false_node)
-       return !nothrow_spec_p (other_spec);
-      /* A dependent noexcept-spec is not compatible with any
-        dynamic-exception-spec.  */
-      else
-       return false;
-    }
+  /* First handle noexcept.  */
+  if (exact < ce_exact)
+    {
+      /* noexcept(false) is compatible with no exception-specification,
+        and stricter than any spec.  */
+      if (t1 == noexcept_false_spec)
+       return t2 == NULL_TREE || exact == ce_derived;
+      /* Even a derived noexcept(false) is compatible with no
+        exception-specification.  */
+      if (t2 == noexcept_false_spec)
+       return t1 == NULL_TREE;
+
+      /* Otherwise, if we aren't looking for an exact match, noexcept is
+        equivalent to throw().  */
+      if (t1 == noexcept_true_spec)
+       t1 = empty_except_spec;
+      if (t2 == noexcept_true_spec)
+       t2 = empty_except_spec;
+    }
+
+  /* If any noexcept is left, it is only comparable to itself;
+     either we're looking for an exact match or we're redeclaring a
+     template with dependent noexcept.  */
+  if ((t1 && TREE_PURPOSE (t1))
+      || (t2 && TREE_PURPOSE (t2)))
+    return (t1 && t2
+           && cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)));
 
   if (t1 == NULL_TREE)                    /* T1 is ...  */
     return t2 == NULL_TREE || exact == ce_derived;
@@ -1127,120 +1126,30 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
 static bool
 comp_template_parms_position (tree t1, tree t2)
 {
+  tree index1, index2;
   gcc_assert (t1 && t2
              && TREE_CODE (t1) == TREE_CODE (t2)
              && (TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM
                  || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM
                  || TREE_CODE (t1) == TEMPLATE_TYPE_PARM));
 
-      if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
-         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
-          || (TEMPLATE_TYPE_PARAMETER_PACK (t1) 
-              != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
-       return false;
-
-      return true;
-}
-
-/* Subroutine of incompatible_dependent_types_p.
-   Return the template parameter of the dependent type T.
-   If T is a typedef, return the template parameters of
-   the _decl_ of the typedef. T must be a dependent type.  */
-
-static tree
-get_template_parms_of_dependent_type (tree t)
-{
-  tree tinfo = NULL_TREE, tparms = NULL_TREE;
-
-  /* First, try the obvious case of getting the
-     template info from T itself.  */
-  if ((tinfo = get_template_info (t)))
-    ;
-  else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
-    return TEMPLATE_TYPE_PARM_SIBLING_PARMS (t);
-  else if (typedef_variant_p (t)
-          && !NAMESPACE_SCOPE_P (TYPE_NAME (t)))
-    tinfo = get_template_info (DECL_CONTEXT (TYPE_NAME (t)));
-  /* If T is a TYPENAME_TYPE which context is a template type
-     parameter, get the template parameters from that context.  */
-  else if (TYPE_CONTEXT (t)
-          && TREE_CODE (TYPE_CONTEXT (t)) == TEMPLATE_TYPE_PARM)
-   return TEMPLATE_TYPE_PARM_SIBLING_PARMS (TYPE_CONTEXT (t));
-  else if (TYPE_CONTEXT (t)
-          && !NAMESPACE_SCOPE_P (t))
-    tinfo = get_template_info (TYPE_CONTEXT (t));
-
-  if (tinfo)
-    tparms = DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo));
-
-  return tparms;
-}
-
-/* Subroutine of structural_comptypes.
-   Compare the dependent types T1 and T2.
-   Return TRUE if we are sure they can't be equal, FALSE otherwise.
-   The whole point of this function is to support cases where either T1 or
-   T2 is a typedef. In those cases, we need to compare the template parameters
-   of the _decl_ of the typedef. If those don't match then we know T1
-   and T2 cannot be equal.  */
-
-static bool
-incompatible_dependent_types_p (tree t1, tree t2)
-{
-  tree tparms1 = NULL_TREE, tparms2 = NULL_TREE;
-  bool t1_typedef_variant_p, t2_typedef_variant_p;
-
-  if (!uses_template_parms (t1) || !uses_template_parms (t2))
-    return false;
-
-  if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM)
-    {
-      /* If T1 and T2 don't have the same relative position in their
-        template parameters set, they can't be equal.  */
-      if (!comp_template_parms_position (t1, t2))
-       return true;
-    }
-
-  t1_typedef_variant_p = typedef_variant_p (t1);
-  t2_typedef_variant_p = typedef_variant_p (t2);
+  index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
+  index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
 
-  /* Either T1 or T2 must be a typedef.  */
-  if (!t1_typedef_variant_p && !t2_typedef_variant_p)
+  /* If T1 and T2 belong to template parm lists of different size,
+     let's assume they are different.  */
+  if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
+      != TEMPLATE_PARM_NUM_SIBLINGS (index2))
     return false;
 
-  if (!t1_typedef_variant_p || !t2_typedef_variant_p)
-    /* Either T1 or T2 is not a typedef so we cannot compare the
-       the template parms of the typedefs of T1 and T2.
-       At this point, if the main variant type of T1 and T2 are equal
-       it means the two types can't be incompatible, from the perspective
-       of this function.  */
-    if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
-      return false;
-
-  /* So if we reach this point, it means either T1 or T2 is a typedef variant.
-     Let's compare their template parameters.  */
-
-  tparms1 = get_template_parms_of_dependent_type (t1);
-  tparms2 = get_template_parms_of_dependent_type (t2);
-
-  /* If T2 is a template type parm and if we could not get the template
-     parms it belongs to, that means we have not finished parsing the
-     full set of template parameters of the template declaration it
-     belongs to yet. If we could get the template parms T1 belongs to,
-     that mostly means T1 and T2 belongs to templates that are
-     different and incompatible.  */
-  if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM
-      && (tparms1 == NULL_TREE || tparms2 == NULL_TREE)
-      && tparms1 != tparms2)
-    return true;
-
-  if (tparms1 == NULL_TREE
-      || tparms2 == NULL_TREE
-      || tparms1 == tparms2)
+  /* Then compare their relative position.  */
+  if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
+      || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
+      || (TEMPLATE_PARM_PARAMETER_PACK (index1)
+         != TEMPLATE_PARM_PARAMETER_PACK (index2)))
     return false;
 
-  /* And now compare the mighty template parms!  */
-  return !comp_template_parms (tparms1, tparms2);
+  return true;
 }
 
 /* Subroutine in comptypes.  */
@@ -1285,12 +1194,6 @@ structural_comptypes (tree t1, tree t2, int strict)
   if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
     return false;
 
-  /* If T1 and T2 are dependent typedefs then check upfront that
-     the template parameters of their typedef DECLs match before
-     going down checking their subtypes.  */
-  if (incompatible_dependent_types_p (t1, 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
      qualifiers (just above).  */
@@ -1391,15 +1294,19 @@ structural_comptypes (tree t1, tree t2, int strict)
       break;
 
     case TEMPLATE_TYPE_PARM:
-      /* If incompatible_dependent_types_p called earlier didn't decide
-         T1 and T2 were different, they might be equal.  */
+      /* If T1 and T2 don't have the same relative position in their
+        template parameters set, they can't be equal.  */
+      if (!comp_template_parms_position (t1, t2))
+       return false;
       break;
 
     case TYPENAME_TYPE:
       if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
                          TYPENAME_TYPE_FULLNAME (t2)))
        return false;
-      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+      /* Qualifiers don't matter on scopes.  */
+      if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
+                                                     TYPE_CONTEXT (t2)))
        return false;
       break;
 
@@ -1422,21 +1329,27 @@ structural_comptypes (tree t1, tree t2, int strict)
       break;
 
     case TYPE_PACK_EXPANSION:
-      return same_type_p (PACK_EXPANSION_PATTERN (t1), 
-                          PACK_EXPANSION_PATTERN (t2));
+      return (same_type_p (PACK_EXPANSION_PATTERN (t1),
+                          PACK_EXPANSION_PATTERN (t2))
+             && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
+                                    PACK_EXPANSION_EXTRA_ARGS (t2)));
 
     case DECLTYPE_TYPE:
       if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
           != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
          || (DECLTYPE_FOR_LAMBDA_CAPTURE (t1)
              != DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
-         || (DECLTYPE_FOR_LAMBDA_RETURN (t1)
-             != DECLTYPE_FOR_LAMBDA_RETURN (t2))
+         || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
+             != DECLTYPE_FOR_LAMBDA_PROXY (t2))
           || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), 
                              DECLTYPE_TYPE_EXPR (t2)))
         return false;
       break;
 
+    case UNDERLYING_TYPE:
+      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
+                         UNDERLYING_TYPE_TYPE (t2));
+
     default:
       return false;
     }
@@ -1444,7 +1357,7 @@ structural_comptypes (tree t1, tree t2, int strict)
   /* If we get here, we know that from a target independent POV the
      types are the same.  Make sure the target attributes are also
      the same.  */
-  return targetm.comp_type_attributes (t1, t2);
+  return comp_type_attributes (t1, t2);
 }
 
 /* Return true if T1 and T2 are related as allowed by STRICT.  STRICT
@@ -1501,6 +1414,18 @@ comptypes (tree t1, tree t2, int strict)
     return structural_comptypes (t1, t2, strict);
 }
 
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  if (type1 == error_mark_node || type2 == error_mark_node)
+    return false;
+
+  return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+}
+
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
 
 bool
@@ -1862,10 +1787,13 @@ tree
 unlowered_expr_type (const_tree exp)
 {
   tree type;
+  tree etype = TREE_TYPE (exp);
 
   type = is_bitfield_expr_with_lowered_type (exp);
-  if (!type)
-    type = TREE_TYPE (exp);
+  if (type)
+    type = cp_build_qualified_type (type, cp_type_quals (etype));
+  else
+    type = etype;
 
   return type;
 }
@@ -1902,10 +1830,16 @@ decay_conversion (tree exp)
       return error_mark_node;
     }
 
-  exp = decl_constant_value (exp);
+  /* FIXME remove? at least need to remember that this isn't really a
+     constant expression if EXP isn't decl_constant_var_p, like with
+     C_MAYBE_CONST_EXPR.  */
+  exp = decl_constant_value_safe (exp);
   if (error_operand_p (exp))
     return error_mark_node;
 
+  if (NULLPTR_TYPE_P (type))
+    return nullptr_node;
+
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Leave such NOP_EXPRs, since RHS is being used in non-lvalue context.  */
   code = TREE_CODE (type);
@@ -1917,7 +1851,7 @@ decay_conversion (tree exp)
   if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
     return error_mark_node;
   if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
-    return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error);
+    return cp_build_addr_expr (exp, tf_warning_or_error);
   if (code == ARRAY_TYPE)
     {
       tree adr;
@@ -1952,7 +1886,7 @@ decay_conversion (tree exp)
        }
       /* This way is better for a COMPONENT_REF since it can
         simplify the offset for a component.  */
-      adr = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
+      adr = cp_build_addr_expr (exp, tf_warning_or_error);
       return cp_convert (ptrtype, adr);
     }
 
@@ -2029,6 +1963,9 @@ perform_integral_promotions (tree expr)
   if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
     type = TREE_TYPE (expr);
   gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+  /* Scoped enums don't promote.  */
+  if (SCOPED_ENUM_P (type))
+    return expr;
   promoted_type = type_promotes_to (type);
   if (type != promoted_type)
     expr = cp_convert (promoted_type, expr);
@@ -2108,7 +2045,7 @@ rationalize_conditional_expr (enum tree_code code, tree t,
                                                    ? LE_EXPR : GE_EXPR),
                                                   op0, TREE_CODE (op0),
                                                   op1, TREE_CODE (op1),
-                                                  /*overloaded_p=*/NULL,
+                                                  /*overload=*/NULL,
                                                   complain),
                                 cp_build_unary_op (code, op0, 0, complain),
                                 cp_build_unary_op (code, op1, 0, complain),
@@ -2134,7 +2071,7 @@ lookup_anon_field (tree t, tree type)
 {
   tree field;
 
-  for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+  for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
     {
       if (TREE_STATIC (field))
        continue;
@@ -2180,6 +2117,7 @@ build_class_member_access_expr (tree object, tree member,
   tree object_type;
   tree member_scope;
   tree result = NULL_TREE;
+  tree using_decl = NULL_TREE;
 
   if (error_operand_p (object) || error_operand_p (member))
     return error_mark_node;
@@ -2192,13 +2130,21 @@ build_class_member_access_expr (tree object, tree member,
      complete type).  */
   object_type = TREE_TYPE (object);
   if (!currently_open_class (object_type)
-      && !complete_type_or_else (object_type, object))
+      && !complete_type_or_maybe_complain (object_type, object, complain))
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
       if (complain & tf_error)
-       error ("request for member %qD in %qE, which is of non-class type %qT",
-              member, object, object_type);
+       {
+         if (POINTER_TYPE_P (object_type)
+             && CLASS_TYPE_P (TREE_TYPE (object_type)))
+           error ("request for member %qD in %qE, which is of pointer "
+                  "type %qT (maybe you meant to use %<->%> ?)",
+                  member, object, object_type);
+         else
+           error ("request for member %qD in %qE, which is of non-class "
+                  "type %qT", member, object, object_type);
+       }
       return error_mark_node;
     }
 
@@ -2292,7 +2238,7 @@ build_class_member_access_expr (tree object, tree member,
 
          /* Convert to the base.  */
          object = build_base_path (PLUS_EXPR, object, binfo,
-                                   /*nonnull=*/1);
+                                   /*nonnull=*/1, complain);
          /* If we found the base successfully then we should be able
             to convert to it successfully.  */
          gcc_assert (object != error_mark_node);
@@ -2400,6 +2346,11 @@ build_class_member_access_expr (tree object, tree member,
        result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
                         object, result);
     }
+  else if ((using_decl = strip_using_decl (member)) != member)
+    result = build_class_member_access_expr (object,
+                                            using_decl,
+                                            access_path, preserve_reference,
+                                            complain);
   else
     {
       if (complain & tf_error)
@@ -2454,7 +2405,8 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
       return error_mark_node;
     }
   expr = lookup_member (dtor_type, complete_dtor_identifier,
-                       /*protect=*/1, /*want_type=*/false);
+                       /*protect=*/1, /*want_type=*/false,
+                       tf_warning_or_error);
   expr = (adjust_result_of_qualified_name_lookup
          (expr, dtor_type, object_type));
   return expr;
@@ -2562,19 +2514,31 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
        return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
       object = build_non_dependent_expr (object);
     }
-
+  else if (c_dialect_objc ()
+          && TREE_CODE (name) == IDENTIFIER_NODE
+          && (expr = objc_maybe_build_component_ref (object, name)))
+    return expr;
+    
   /* [expr.ref]
 
      The type of the first expression shall be "class object" (of a
      complete type).  */
   if (!currently_open_class (object_type)
-      && !complete_type_or_else (object_type, object))
+      && !complete_type_or_maybe_complain (object_type, object, complain))
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
       if (complain & tf_error)
-       error ("request for member %qD in %qE, which is of non-class type %qT",
-              name, object, object_type);
+       {
+         if (POINTER_TYPE_P (object_type)
+             && CLASS_TYPE_P (TREE_TYPE (object_type)))
+           error ("request for member %qD in %qE, which is of pointer "
+                  "type %qT (maybe you meant to use %<->%> ?)",
+                  name, object, object_type);
+         else
+           error ("request for member %qD in %qE, which is of non-class "
+                  "type %qT", name, object, object_type);
+       }
       return error_mark_node;
     }
 
@@ -2652,11 +2616,13 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
        {
          /* Look up the member.  */
          member = lookup_member (access_path, name, /*protect=*/1,
-                                 /*want_type=*/false);
+                                 /*want_type=*/false, complain);
          if (member == NULL_TREE)
            {
              if (complain & tf_error)
-               error ("%qD has no member named %qE", object_type, name);
+               error ("%qD has no member named %qE",
+                      TREE_CODE (access_path) == TREE_BINFO
+                      ? TREE_TYPE (access_path) : object_type, name);
              return error_mark_node;
            }
          if (member == error_mark_node)
@@ -2724,7 +2690,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
   ptrmem_type = TREE_TYPE (ptrmem);
   gcc_assert (TYPE_PTRMEMFUNC_P (ptrmem_type));
   member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
-                         /*want_type=*/false);
+                         /*want_type=*/false, tf_warning_or_error);
   member_type = cp_build_qualified_type (TREE_TYPE (member),
                                         cp_type_quals (ptrmem_type));
   return fold_build3_loc (input_location,
@@ -2748,8 +2714,7 @@ build_x_indirect_ref (tree expr, ref_operator errorstring,
 
   if (processing_template_decl)
     {
-      /* Retain the type if we know the operand is a pointer so that
-        describable_type doesn't make auto deduction break.  */
+      /* Retain the type if we know the operand is a pointer.  */
       if (TREE_TYPE (expr) && POINTER_TYPE_P (TREE_TYPE (expr)))
        return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
       if (type_dependent_expression_p (expr))
@@ -2758,7 +2723,7 @@ build_x_indirect_ref (tree expr, ref_operator errorstring,
     }
 
   rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
-                      NULL_TREE, /*overloaded_p=*/NULL, complain);
+                      NULL_TREE, /*overload=*/NULL, complain);
   if (!rval)
     rval = cp_build_indirect_ref (expr, errorstring, complain);
 
@@ -2770,7 +2735,7 @@ build_x_indirect_ref (tree expr, ref_operator errorstring,
 
 /* Helper function called from c-common.  */
 tree
-build_indirect_ref (location_t loc __attribute__ ((__unused__)),
+build_indirect_ref (location_t loc ATTRIBUTE_UNUSED,
                    tree ptr, ref_operator errorstring)
 {
   return cp_build_indirect_ref (ptr, errorstring, tf_warning_or_error);
@@ -2860,23 +2825,8 @@ cp_build_indirect_ref (tree ptr, ref_operator errorstring,
            gcc_unreachable ();
       }
   else if (pointer != error_mark_node)
-    switch (errorstring)
-      {
-         case RO_NULL:
-           error ("invalid type argument");
-           break;
-         case RO_ARRAY_INDEXING:
-           error ("invalid type argument of array indexing");
-           break;
-         case RO_UNARY_STAR:
-           error ("invalid type argument of unary %<*%>");
-           break;
-         case RO_IMPLICIT_CONVERSION:
-           error ("invalid type argument of implicit conversion");
-           break;
-         default:
-           gcc_unreachable ();
-      }
+    invalid_indirection_error (input_location, type, errorstring);
+
   return error_mark_node;
 }
 
@@ -3014,7 +2964,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
        |= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
       TREE_THIS_VOLATILE (rval)
        |= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
-      ret = require_complete_type (fold_if_not_in_template (rval));
+      ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
+                                         complain);
       protected_set_expr_location (ret, loc);
       return ret;
     }
@@ -3155,13 +3106,12 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
          basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
                                  basetype, ba_check, NULL);
          instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype,
-                                         1);
+                                         1, tf_warning_or_error);
          if (instance_ptr == error_mark_node)
            return error_mark_node;
        }
       /* ...and then the delta in the PMF.  */
-      instance_ptr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (instance_ptr),
-                            instance_ptr, fold_convert (sizetype, delta));
+      instance_ptr = fold_build_pointer_plus (instance_ptr, delta);
 
       /* Hand back the adjusted 'this' argument to our caller.  */
       *instance_ptrptr = instance_ptr;
@@ -3176,9 +3126,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
       TREE_NO_WARNING (vtbl) = 1;
 
       /* Finally, extract the function pointer from the vtable.  */
-      e2 = fold_build2_loc (input_location,
-                       POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
-                       fold_convert (sizetype, idx));
+      e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx);
       e2 = cp_build_indirect_ref (e2, RO_NULL, tf_warning_or_error);
       TREE_CONSTANT (e2) = 1;
 
@@ -3186,8 +3134,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
         vtable entry is treated as a function pointer.  */
       if (TARGET_VTABLE_USES_DESCRIPTORS)
        e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
-                    cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1,
-                                     tf_warning_or_error));
+                    cp_build_addr_expr (e2, tf_warning_or_error));
 
       e2 = fold_convert (TREE_TYPE (e3), e2);
       e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
@@ -3358,8 +3305,7 @@ cp_build_function_call_vec (tree function, VEC(tree,gc) **params,
 
   /* Check for errors in format strings and inappropriately
      null parameters.  */
-  check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
-                           parm_types);
+  check_function_arguments (fntype, nargs, argarray);
 
   ret = build_cxx_call (function, nargs, argarray);
 
@@ -3403,8 +3349,17 @@ warn_args_num (location_t loc, tree fndecl, bool too_many_p)
              "declared here");
     }
   else
-    error_at (loc, too_many_p ? G_("too many arguments to function")
-                             : G_("too few arguments to function"));
+    {
+      if (c_dialect_objc ()  &&  objc_message_selector ())
+       error_at (loc,
+                 too_many_p 
+                 ? G_("too many arguments to method %q#D")
+                 : G_("too few arguments to method %q#D"),
+                 objc_message_selector ());
+      else
+       error_at (loc, too_many_p ? G_("too many arguments to function")
+                                 : G_("too few arguments to function"));
+    }
 }
 
 /* Convert the actual parameter expressions in the list VALUES to the
@@ -3493,7 +3448,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl,
            {
              parmval = convert_for_initialization
                (NULL_TREE, type, val, flags,
-                "argument passing", fndecl, i, complain);
+                ICR_ARGPASS, fndecl, i, complain);
              parmval = convert_for_arg_passing (type, parmval);
            }
 
@@ -3509,7 +3464,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl,
            /* Don't do ellipsis conversion for __built_in_constant_p
               as this will result in spurious errors for non-trivial
               types.  */
-           val = require_complete_type (val);
+           val = require_complete_type_sfinae (val, complain);
          else
            val = convert_arg_to_ellipsis (val);
 
@@ -3573,7 +3528,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl,
 
 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, tree *overload,
                   tsubst_flags_t complain)
 {
   tree orig_arg1;
@@ -3596,7 +3551,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, complain);
+                        overload, 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
@@ -3636,7 +3591,7 @@ build_x_array_ref (tree arg1, tree arg2, tsubst_flags_t complain)
     }
 
   expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
-                      /*overloaded_p=*/NULL, complain);
+                      /*overload=*/NULL, complain);
 
   if (processing_template_decl && expr != error_mark_node)
     return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
@@ -3733,16 +3688,16 @@ cp_build_binary_op (location_t location,
       || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
       || code == TRUTH_XOR_EXPR)
     {
-      if (!really_overloaded_fn (op0))
+      if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
        op0 = decay_conversion (op0);
-      if (!really_overloaded_fn (op1))
+      if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
        op1 = decay_conversion (op1);
     }
   else
     {
-      if (!really_overloaded_fn (op0))
+      if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
        op0 = default_conversion (op0);
-      if (!really_overloaded_fn (op1))
+      if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
        op1 = default_conversion (op1);
     }
 
@@ -4094,8 +4049,7 @@ cp_build_binary_op (location_t location,
              tree e1 = cp_build_binary_op (location,
                                            EQ_EXPR,
                                            pfn0,       
-                                           fold_convert (TREE_TYPE (pfn0),
-                                                         integer_zero_node),
+                                           build_zero_cst (TREE_TYPE (pfn0)),
                                            complain);
              tree e2 = cp_build_binary_op (location,
                                            BIT_AND_EXPR, 
@@ -4113,7 +4067,7 @@ cp_build_binary_op (location_t location,
          else 
            {
              op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
-             op1 = cp_convert (TREE_TYPE (op0), integer_zero_node); 
+             op1 = cp_convert (TREE_TYPE (op0), op1);
            }
          result_type = TREE_TYPE (op0);
        }
@@ -4185,8 +4139,7 @@ cp_build_binary_op (location_t location,
                                       complain);
              e2 = cp_build_binary_op (location, EQ_EXPR,
                                       pfn0,
-                                      fold_convert (TREE_TYPE (pfn0),
-                                                    integer_zero_node),
+                                      build_zero_cst (TREE_TYPE (pfn0)),
                                       complain);
              e2 = cp_build_binary_op (location,
                                       TRUTH_ANDIF_EXPR, e2, e1, complain);
@@ -4211,8 +4164,7 @@ cp_build_binary_op (location_t location,
              e2 = cp_build_binary_op (location,
                                       EQ_EXPR,
                                       pfn0,
-                                      fold_convert (TREE_TYPE (pfn0),
-                                                    integer_zero_node),
+                                      build_zero_cst (TREE_TYPE (pfn0)),
                                       complain);
              e1 = cp_build_binary_op (location,
                                       TRUTH_ORIF_EXPR, e1, e2, complain);
@@ -4268,9 +4220,19 @@ cp_build_binary_op (location_t location,
        result_type = composite_pointer_type (type0, type1, op0, op1,
                                              CPO_COMPARISON, complain);
       else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
-       result_type = type0;
+       {
+         result_type = type0;
+         if (extra_warnings && (complain & tf_warning))
+           warning (OPT_Wextra,
+                    "ordered comparison of pointer with integer zero");
+       }
       else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
-       result_type = type1;
+       {
+         result_type = type1;
+         if (extra_warnings && (complain & tf_warning))
+           warning (OPT_Wextra,
+                    "ordered comparison of pointer with integer zero");
+       }
       else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
        /* One of the operands must be of nullptr_t type.  */
         result_type = TREE_TYPE (nullptr_node);
@@ -4338,7 +4300,14 @@ cp_build_binary_op (location_t location,
   if (!result_type
       && arithmetic_types_p
       && (shorten || common || short_compare))
-    result_type = cp_common_type (type0, type1);
+    {
+      result_type = cp_common_type (type0, type1);
+      do_warn_double_promotion (result_type, type0, type1,
+                               "implicit conversion from %qT to %qT "
+                               "to match other operand of binary "
+                               "expression",
+                               location);
+    }
 
   if (!result_type)
     {
@@ -4409,6 +4378,7 @@ cp_build_binary_op (location_t location,
                {
                case MULT_EXPR:
                case TRUNC_DIV_EXPR:
+                 op1 = save_expr (op1);
                  imag = build2 (resultcode, real_type, imag, op1);
                  /* Fall through.  */
                case PLUS_EXPR:
@@ -4427,6 +4397,7 @@ cp_build_binary_op (location_t location,
              switch (code)
                {
                case MULT_EXPR:
+                 op0 = save_expr (op0);
                  imag = build2 (resultcode, real_type, op0, imag);
                  /* Fall through.  */
                case PLUS_EXPR:
@@ -4440,7 +4411,11 @@ cp_build_binary_op (location_t location,
                  gcc_unreachable();
                }
            }
-         return build2 (COMPLEX_EXPR, result_type, real, imag);
+         real = fold_if_not_in_template (real);
+         imag = fold_if_not_in_template (imag);
+         result = build2 (COMPLEX_EXPR, result_type, real, imag);
+         result = fold_if_not_in_template (result);
+         return result;
        }
 
       /* For certain operations (which identify themselves by shorten != 0)
@@ -4626,7 +4601,7 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
     /* Don't look for a function.  */;
   else
     exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
-                       /*overloaded_p=*/NULL, complain);
+                       /*overload=*/NULL, complain);
   if (!exp && code == ADDR_EXPR)
     {
       if (is_overloaded_fn (xarg))
@@ -4680,9 +4655,8 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
              PTRMEM_OK_P (xarg) = ptrmem;
            }
        }
-      else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning))
-       warning (0, "taking address of temporary");
-      exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain);
+
+      exp = cp_build_addr_expr_strict (xarg, complain);
     }
 
   if (processing_template_decl && exp != error_mark_node)
@@ -4703,7 +4677,17 @@ cp_truthvalue_conversion (tree expr)
   tree type = TREE_TYPE (expr);
   if (TYPE_PTRMEM_P (type))
     return build_binary_op (EXPR_LOCATION (expr),
-                           NE_EXPR, expr, integer_zero_node, 1);
+                           NE_EXPR, expr, nullptr_node, 1);
+  else if (TYPE_PTR_P (type) || TYPE_PTRMEMFUNC_P (type))
+    {
+      /* With -Wzero-as-null-pointer-constant do not warn for an
+        'if (p)' or a 'while (!p)', where p is a pointer.  */
+      tree ret;
+      ++c_inhibit_evaluation_warnings;
+      ret = c_common_truthvalue_conversion (input_location, expr);
+      --c_inhibit_evaluation_warnings;
+      return ret;
+    }
   else
     return c_common_truthvalue_conversion (input_location, expr);
 }
@@ -4759,6 +4743,285 @@ build_nop (tree type, tree expr)
   return build1 (NOP_EXPR, type, expr);
 }
 
+/* Take the address of ARG, whatever that means under C++ semantics.
+   If STRICT_LVALUE is true, require an lvalue; otherwise, allow xvalues
+   and class rvalues as well.
+
+   Nothing should call this function directly; instead, callers should use
+   cp_build_addr_expr or cp_build_addr_expr_strict.  */
+
+static tree
+cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
+{
+  tree argtype;
+  tree val;
+
+  if (!arg || error_operand_p (arg))
+    return error_mark_node;
+
+  arg = mark_lvalue_use (arg);
+  argtype = lvalue_type (arg);
+
+  gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
+             || !IDENTIFIER_OPNAME_P (arg));
+
+  if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
+      && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
+    {
+      /* They're trying to take the address of a unique non-static
+        member function.  This is ill-formed (except in MS-land),
+        but let's try to DTRT.
+        Note: We only handle unique functions here because we don't
+        want to complain if there's a static overload; non-unique
+        cases will be handled by instantiate_type.  But we need to
+        handle this case here to allow casts on the resulting PMF.
+        We could defer this in non-MS mode, but it's easier to give
+        a useful error here.  */
+
+      /* Inside constant member functions, the `this' pointer
+        contains an extra const qualifier.  TYPE_MAIN_VARIANT
+        is used here to remove this const from the diagnostics
+        and the created OFFSET_REF.  */
+      tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
+      tree fn = get_first_fn (TREE_OPERAND (arg, 1));
+      mark_used (fn);
+
+      if (! flag_ms_extensions)
+       {
+         tree name = DECL_NAME (fn);
+         if (!(complain & tf_error))
+           return error_mark_node;
+         else if (current_class_type
+                  && TREE_OPERAND (arg, 0) == current_class_ref)
+           /* An expression like &memfn.  */
+           permerror (input_location, "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
+           permerror (input_location, "ISO C++ forbids taking the address of a bound member"
+                      " function to form a pointer to member function."
+                      "  Say %<&%T::%D%>",
+                      base, name);
+       }
+      arg = build_offset_ref (base, fn, /*address_p=*/true);
+    }
+
+  /* Uninstantiated types are all functions.  Taking the
+     address of a function is a no-op, so just return the
+     argument.  */
+  if (type_unknown_p (arg))
+    return build1 (ADDR_EXPR, unknown_type_node, arg);
+
+  if (TREE_CODE (arg) == OFFSET_REF)
+    /* We want a pointer to member; bypass all the code for actually taking
+       the address of something.  */
+    goto offset_ref;
+
+  /* Anything not already handled and not a true memory reference
+     is an error.  */
+  if (TREE_CODE (argtype) != FUNCTION_TYPE
+      && TREE_CODE (argtype) != METHOD_TYPE)
+    {
+      cp_lvalue_kind kind = lvalue_kind (arg);
+      if (kind == clk_none)
+       {
+         if (complain & tf_error)
+           lvalue_error (input_location, lv_addressof);
+         return error_mark_node;
+       }
+      if (strict_lvalue && (kind & (clk_rvalueref|clk_class)))
+       {
+         if (!(complain & tf_error))
+           return error_mark_node;
+         if (kind & clk_class)
+           /* Make this a permerror because we used to accept it.  */
+           permerror (input_location, "taking address of temporary");
+         else
+           error ("taking address of xvalue (rvalue reference)");
+       }
+    }
+
+  if (TREE_CODE (argtype) == REFERENCE_TYPE)
+    {
+      tree type = build_pointer_type (TREE_TYPE (argtype));
+      arg = build1 (CONVERT_EXPR, type, arg);
+      return arg;
+    }
+  else if (pedantic && DECL_MAIN_P (arg))
+    {
+      /* ARM $3.4 */
+      /* Apparently a lot of autoconf scripts for C++ packages do this,
+        so only complain if -pedantic.  */
+      if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
+       pedwarn (input_location, OPT_pedantic,
+                "ISO C++ forbids taking address of function %<::main%>");
+      else if (flag_pedantic_errors)
+       return error_mark_node;
+    }
+
+  /* Let &* cancel out to simplify resulting code.  */
+  if (TREE_CODE (arg) == INDIRECT_REF)
+    {
+      /* We don't need to have `current_class_ptr' wrapped in a
+        NON_LVALUE_EXPR node.  */
+      if (arg == current_class_ref)
+       return current_class_ptr;
+
+      arg = TREE_OPERAND (arg, 0);
+      if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
+       {
+         tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
+         arg = build1 (CONVERT_EXPR, type, arg);
+       }
+      else
+       /* Don't let this be an lvalue.  */
+       arg = rvalue (arg);
+      return arg;
+    }
+
+  /* ??? Cope with user tricks that amount to offsetof.  */
+  if (TREE_CODE (argtype) != FUNCTION_TYPE
+      && TREE_CODE (argtype) != METHOD_TYPE
+      && argtype != unknown_type_node
+      && (val = get_base_address (arg))
+      && COMPLETE_TYPE_P (TREE_TYPE (val))
+      && TREE_CODE (val) == INDIRECT_REF
+      && TREE_CONSTANT (TREE_OPERAND (val, 0)))
+    {
+      tree type = build_pointer_type (argtype);
+      return fold_convert (type, fold_offsetof_1 (arg));
+    }
+
+  /* Handle complex lvalues (when permitted)
+     by reduction to simpler cases.  */
+  val = unary_complex_lvalue (ADDR_EXPR, arg);
+  if (val != 0)
+    return val;
+
+  switch (TREE_CODE (arg))
+    {
+    CASE_CONVERT:
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+      /* Even if we're not being pedantic, we cannot allow this
+        extension when we're instantiating in a SFINAE
+        context.  */
+      if (! lvalue_p (arg) && complain == tf_none)
+       {
+         if (complain & tf_error)
+           permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+         else
+           return error_mark_node;
+       }
+      break;
+
+    case BASELINK:
+      arg = BASELINK_FUNCTIONS (arg);
+      /* Fall through.  */
+
+    case OVERLOAD:
+      arg = OVL_CURRENT (arg);
+      break;
+
+    case OFFSET_REF:
+    offset_ref:
+      /* Turn a reference to a non-static data member into a
+        pointer-to-member.  */
+      {
+       tree type;
+       tree t;
+
+       gcc_assert (PTRMEM_OK_P (arg));
+
+       t = TREE_OPERAND (arg, 1);
+       if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+         {
+           if (complain & tf_error)
+             error ("cannot create pointer to reference member %qD", t);
+           return error_mark_node;
+         }
+
+       type = build_ptrmem_type (context_for_name_lookup (t),
+                                 TREE_TYPE (t));
+       t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
+       return t;
+      }
+
+    default:
+      break;
+    }
+
+  if (argtype != error_mark_node)
+    argtype = build_pointer_type (argtype);
+
+  /* In a template, we are processing a non-dependent expression
+     so we can just form an ADDR_EXPR with the correct type.  */
+  if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
+    {
+      val = build_address (arg);
+      if (TREE_CODE (arg) == OFFSET_REF)
+       PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
+    }
+  else if (BASELINK_P (TREE_OPERAND (arg, 1)))
+    {
+      tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
+
+      /* We can only get here with a single static member
+        function.  */
+      gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
+                 && DECL_STATIC_FUNCTION_P (fn));
+      mark_used (fn);
+      val = build_address (fn);
+      if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
+       /* Do not lose object's side effects.  */
+       val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
+                     TREE_OPERAND (arg, 0), val);
+    }
+  else if (DECL_C_BIT_FIELD (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
+    {
+      tree object = TREE_OPERAND (arg, 0);
+      tree field = TREE_OPERAND (arg, 1);
+      gcc_assert (same_type_ignoring_top_level_qualifiers_p
+                 (TREE_TYPE (object), decl_type_context (field)));
+      val = build_address (arg);
+    }
+
+  if (TREE_CODE (argtype) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+    {
+      build_ptrmemfunc_type (argtype);
+      val = build_ptrmemfunc (argtype, val, 0,
+                             /*c_cast_p=*/false,
+                             tf_warning_or_error);
+    }
+
+  return val;
+}
+
+/* Take the address of ARG if it has one, even if it's an rvalue.  */
+
+tree
+cp_build_addr_expr (tree arg, tsubst_flags_t complain)
+{
+  return cp_build_addr_expr_1 (arg, 0, complain);
+}
+
+/* Take the address of ARG, but only if it's an lvalue.  */
+
+tree
+cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain)
+{
+  return cp_build_addr_expr_1 (arg, 1, complain);
+}
+
 /* C++: Must handle pointers to members.
 
    Perhaps type instantiation should be extended to handle conversion
@@ -4779,7 +5042,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
   tree val;
   const char *invalid_op_diag;
 
-  if (error_operand_p (arg))
+  if (!arg || error_operand_p (arg))
     return error_mark_node;
 
   if ((invalid_op_diag
@@ -4861,26 +5124,12 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
       break;
 
     case REALPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-       return TREE_REALPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       {
-         arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-         return fold_if_not_in_template (arg);
-       }
-      else
-       return arg;
-
     case IMAGPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-       return TREE_IMAGPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       {
-         arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-         return fold_if_not_in_template (arg);
-       }
+      arg = build_real_imag_expr (input_location, code, arg);
+      if (arg == error_mark_node)
+       return arg;
       else
-       return cp_convert (TREE_TYPE (arg), integer_zero_node);
+       return fold_if_not_in_template (arg);
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -4935,9 +5184,9 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
          || TREE_READONLY (arg)) 
         {
           if (complain & tf_error)
-            readonly_error (arg, ((code == PREINCREMENT_EXPR
-                                   || code == POSTINCREMENT_EXPR)
-                                  ? REK_INCREMENT : REK_DECREMENT));
+            cxx_readonly_error (arg, ((code == PREINCREMENT_EXPR
+                                     || code == POSTINCREMENT_EXPR)
+                                    ? lv_increment : lv_decrement));
           else
             return error_mark_node;
         }
@@ -4996,6 +5245,13 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
 
        inc = cp_convert (argtype, inc);
 
+       /* If 'arg' is an Objective-C PROPERTY_REF expression, then we
+          need to ask Objective-C to build the increment or decrement
+          expression for it.  */
+       if (objc_is_property_ref (arg))
+         return objc_build_incr_expr_for_property_ref (input_location, code, 
+                                                       arg, inc);      
+
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
@@ -5015,6 +5271,9 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
              }
            val = boolean_increment (code, arg);
          }
+       else if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+         /* An rvalue has no cv-qualifiers.  */
+         val = build2 (code, cv_unqualified (TREE_TYPE (arg)), arg, inc);
        else
          val = build2 (code, TREE_TYPE (arg), arg, inc);
 
@@ -5025,237 +5284,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     case ADDR_EXPR:
       /* Note that this operation never does default_conversion
         regardless of NOCONVERT.  */
-
-      argtype = lvalue_type (arg);
-
-      arg = mark_lvalue_use (arg);
-
-      if (TREE_CODE (arg) == OFFSET_REF)
-       goto offset_ref;
-
-      if (TREE_CODE (argtype) == REFERENCE_TYPE)
-       {
-         tree type = build_pointer_type (TREE_TYPE (argtype));
-         arg = build1 (CONVERT_EXPR, type, arg);
-         return arg;
-       }
-      else if (pedantic && DECL_MAIN_P (arg))
-        {
-          /* ARM $3.4 */
-         /* Apparently a lot of autoconf scripts for C++ packages do this,
-            so only complain if -pedantic.  */
-          if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
-            pedwarn (input_location, OPT_pedantic,
-                    "ISO C++ forbids taking address of function %<::main%>");
-          else if (flag_pedantic_errors)
-            return error_mark_node;
-        }
-
-      /* Let &* cancel out to simplify resulting code.  */
-      if (TREE_CODE (arg) == INDIRECT_REF)
-       {
-         /* We don't need to have `current_class_ptr' wrapped in a
-            NON_LVALUE_EXPR node.  */
-         if (arg == current_class_ref)
-           return current_class_ptr;
-
-         arg = TREE_OPERAND (arg, 0);
-         if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
-           {
-             tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
-             arg = build1 (CONVERT_EXPR, type, arg);
-           }
-         else
-           /* Don't let this be an lvalue.  */
-           arg = rvalue (arg);
-         return arg;
-       }
-
-      /* ??? Cope with user tricks that amount to offsetof.  */
-      if (TREE_CODE (argtype) != FUNCTION_TYPE
-         && TREE_CODE (argtype) != METHOD_TYPE
-         && argtype != unknown_type_node
-         && (val = get_base_address (arg))
-         && TREE_CODE (val) == INDIRECT_REF
-         && TREE_CONSTANT (TREE_OPERAND (val, 0)))
-       {
-         tree type = build_pointer_type (argtype);
-         tree op0 = fold_convert (type, TREE_OPERAND (val, 0));
-         tree op1 = fold_convert (sizetype, fold_offsetof (arg, val));
-         return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1);
-       }
-
-      /* Uninstantiated types are all functions.  Taking the
-        address of a function is a no-op, so just return the
-        argument.  */
-
-      gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
-                 || !IDENTIFIER_OPNAME_P (arg));
-
-      if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
-         && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
-       {
-         /* They're trying to take the address of a unique non-static
-            member function.  This is ill-formed (except in MS-land),
-            but let's try to DTRT.
-            Note: We only handle unique functions here because we don't
-            want to complain if there's a static overload; non-unique
-            cases will be handled by instantiate_type.  But we need to
-            handle this case here to allow casts on the resulting PMF.
-            We could defer this in non-MS mode, but it's easier to give
-            a useful error here.  */
-
-         /* Inside constant member functions, the `this' pointer
-            contains an extra const qualifier.  TYPE_MAIN_VARIANT
-            is used here to remove this const from the diagnostics
-            and the created OFFSET_REF.  */
-         tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
-         tree fn = get_first_fn (TREE_OPERAND (arg, 1));
-         mark_used (fn);
-
-         if (! flag_ms_extensions)
-           {
-             tree name = DECL_NAME (fn);
-              if (!(complain & tf_error))
-                return error_mark_node;
-             else if (current_class_type
-                       && TREE_OPERAND (arg, 0) == current_class_ref)
-                  /* An expression like &memfn.  */
-                permerror (input_location, "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
-               permerror (input_location, "ISO C++ forbids taking the address of a bound member"
-                          " function to form a pointer to member function."
-                          "  Say %<&%T::%D%>",
-                          base, name);
-           }
-         arg = build_offset_ref (base, fn, /*address_p=*/true);
-       }
-
-    offset_ref:
-      if (type_unknown_p (arg))
-       return build1 (ADDR_EXPR, unknown_type_node, arg);
-
-      /* Handle complex lvalues (when permitted)
-        by reduction to simpler cases.  */
-      val = unary_complex_lvalue (code, arg);
-      if (val != 0)
-       return val;
-
-      switch (TREE_CODE (arg))
-       {
-       CASE_CONVERT:
-       case FLOAT_EXPR:
-       case FIX_TRUNC_EXPR:
-          /* Even if we're not being pedantic, we cannot allow this
-             extension when we're instantiating in a SFINAE
-             context.  */
-         if (! lvalue_p (arg) && complain == tf_none)
-            {
-              if (complain & tf_error)
-                permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
-              else
-                return error_mark_node;
-            }
-         break;
-
-       case BASELINK:
-         arg = BASELINK_FUNCTIONS (arg);
-         /* Fall through.  */
-
-       case OVERLOAD:
-         arg = OVL_CURRENT (arg);
-         break;
-
-       case OFFSET_REF:
-         /* Turn a reference to a non-static data member into a
-            pointer-to-member.  */
-         {
-           tree type;
-           tree t;
-
-           if (!PTRMEM_OK_P (arg))
-             return cp_build_unary_op (code, arg, 0, complain);
-
-           t = TREE_OPERAND (arg, 1);
-           if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
-             {
-                if (complain & tf_error)
-                  error ("cannot create pointer to reference member %qD", t);
-               return error_mark_node;
-             }
-
-           type = build_ptrmem_type (context_for_name_lookup (t),
-                                     TREE_TYPE (t));
-           t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
-           return t;
-         }
-
-       default:
-         break;
-       }
-
-      /* Anything not already handled and not a true memory reference
-        is an error.  */
-      if (TREE_CODE (argtype) != FUNCTION_TYPE
-         && TREE_CODE (argtype) != METHOD_TYPE
-         && TREE_CODE (arg) != OFFSET_REF
-         && !lvalue_or_else (arg, lv_addressof, complain))
-       return error_mark_node;
-
-      if (argtype != error_mark_node)
-       argtype = build_pointer_type (argtype);
-
-      /* In a template, we are processing a non-dependent expression
-        so we can just form an ADDR_EXPR with the correct type.  */
-      if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
-       {
-         val = build_address (arg);
-         if (TREE_CODE (arg) == OFFSET_REF)
-           PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
-       }
-      else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
-       {
-         tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
-
-         /* We can only get here with a single static member
-            function.  */
-         gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
-                     && DECL_STATIC_FUNCTION_P (fn));
-         mark_used (fn);
-         val = build_address (fn);
-         if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
-           /* Do not lose object's side effects.  */
-           val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
-                         TREE_OPERAND (arg, 0), val);
-       }
-      else if (DECL_C_BIT_FIELD (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
-       {
-         tree object = TREE_OPERAND (arg, 0);
-         tree field = TREE_OPERAND (arg, 1);
-         gcc_assert (same_type_ignoring_top_level_qualifiers_p
-                     (TREE_TYPE (object), decl_type_context (field)));
-         val = build_address (arg);
-       }
-
-      if (TREE_CODE (argtype) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
-       {
-         build_ptrmemfunc_type (argtype);
-         val = build_ptrmemfunc (argtype, val, 0,
-                                 /*c_cast_p=*/false);
-       }
-
-      return val;
+      return cp_build_addr_expr (arg, complain);
 
     default:
       break;
@@ -5360,7 +5389,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
        if (TREE_CODE (arg) == SAVE_EXPR)
          targ = arg;
        else
-         targ = build_cplus_new (TREE_TYPE (arg), arg);
+         targ = build_cplus_new (TREE_TYPE (arg), arg, tf_warning_or_error);
        return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
       }
 
@@ -5413,7 +5442,6 @@ cxx_mark_addressable (tree exp)
                    || DECL_EXTERNAL (x));
        /* Fall through.  */
 
-      case CONST_DECL:
       case RESULT_DECL:
        if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
            && !DECL_ARTIFICIAL (x))
@@ -5431,6 +5459,7 @@ cxx_mark_addressable (tree exp)
        TREE_ADDRESSABLE (x) = 1;
        return true;
 
+      case CONST_DECL:
       case FUNCTION_DECL:
        TREE_ADDRESSABLE (x) = 1;
        return true;
@@ -5478,26 +5507,64 @@ build_x_conditional_expr (tree ifexp, tree op1, tree 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);
+    {
+      tree min = build_min_non_dep (COND_EXPR, expr,
+                                   orig_ifexp, orig_op1, orig_op2);
+      /* Remember that the result is an lvalue or xvalue.  */
+      if (lvalue_or_rvalue_with_address_p (expr)
+         && !lvalue_or_rvalue_with_address_p (min))
+       TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
+                                                  !real_lvalue_p (expr));
+      expr = convert_from_reference (min);
+    }
   return expr;
 }
 \f
 /* Given a list of expressions, return a compound expression
    that performs them all and returns the value of the last of them.  */
 
-tree build_x_compound_expr_from_list (tree list, const char *msg)
+tree
+build_x_compound_expr_from_list (tree list, expr_list_kind exp,
+                                tsubst_flags_t complain)
 {
   tree expr = TREE_VALUE (list);
 
+  if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+      && !CONSTRUCTOR_IS_DIRECT_INIT (expr))
+    {
+      if (complain & tf_error)
+       pedwarn (EXPR_LOC_OR_HERE (expr), 0, "list-initializer for "
+                "non-class type must not be parenthesized");
+      else
+       return error_mark_node;
+    }
+
   if (TREE_CHAIN (list))
     {
-      if (msg)
-       permerror (input_location, "%s expression list treated as compound expression", msg);
+      if (complain & tf_error)
+       switch (exp)
+         {
+         case ELK_INIT:
+           permerror (input_location, "expression list treated as compound "
+                                      "expression in initializer");
+           break;
+         case ELK_MEM_INIT:
+           permerror (input_location, "expression list treated as compound "
+                                      "expression in mem-initializer");
+           break;
+         case ELK_FUNC_CAST:
+           permerror (input_location, "expression list treated as compound "
+                                      "expression in functional cast");
+           break;
+         default:
+           gcc_unreachable ();
+         }
+      else
+       return error_mark_node;
 
       for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
        expr = build_x_compound_expr (expr, TREE_VALUE (list), 
-                                      tf_warning_or_error);
+                                      complain);
     }
 
   return expr;
@@ -5550,7 +5617,7 @@ build_x_compound_expr (tree op1, tree op2, tsubst_flags_t complain)
     }
 
   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
-                        /*overloaded_p=*/NULL, complain);
+                        /*overload=*/NULL, complain);
   if (!result)
     result = cp_build_compound_expr (op1, op2, complain);
 
@@ -5573,7 +5640,7 @@ build_compound_expr (location_t loc ATTRIBUTE_UNUSED, tree lhs, tree rhs)
 tree
 cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
 {
-  lhs = convert_to_void (lhs, "left-hand operand of comma", complain);
+  lhs = convert_to_void (lhs, ICV_LEFT_OF_COMMA, complain);
 
   if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
@@ -5601,42 +5668,47 @@ cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
 }
 
 /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
-   casts away constness.  CAST gives the type of cast.  
+   casts away constness.  CAST gives the type of cast.  Returns true
+   if the cast is ill-formed, false if it is well-formed.
 
    ??? This function warns for casting away any qualifier not just
    const.  We would like to specify exactly what qualifiers are casted
    away.
 */
 
-static void
+static bool
 check_for_casting_away_constness (tree src_type, tree dest_type,
-                                 enum tree_code cast)
+                                 enum tree_code cast, tsubst_flags_t complain)
 {
   /* C-style casts are allowed to cast away constness.  With
      WARN_CAST_QUAL, we still want to issue a warning.  */
   if (cast == CAST_EXPR && !warn_cast_qual)
-      return;
+    return false;
   
   if (!casts_away_constness (src_type, dest_type))
-    return;
+    return false;
 
   switch (cast)
     {
     case CAST_EXPR:
-      warning (OPT_Wcast_qual, 
-              "cast from type %qT to type %qT casts away qualifiers",
-              src_type, dest_type);
-      return;
+      if (complain & tf_warning)
+       warning (OPT_Wcast_qual,
+                "cast from type %qT to type %qT casts away qualifiers",
+                src_type, dest_type);
+      return false;
       
     case STATIC_CAST_EXPR:
-      error ("static_cast from type %qT to type %qT casts away qualifiers",
-            src_type, dest_type);
-      return;
+      if (complain & tf_error)
+       error ("static_cast from type %qT to type %qT casts away qualifiers",
+              src_type, dest_type);
+      return true;
       
     case REINTERPRET_CAST_EXPR:
-      error ("reinterpret_cast from type %qT to type %qT casts away qualifiers",
-            src_type, dest_type);
-      return;
+      if (complain & tf_error)
+       error ("reinterpret_cast from type %qT to type %qT casts away qualifiers",
+              src_type, dest_type);
+      return true;
+
     default:
       gcc_unreachable();
     }
@@ -5651,7 +5723,7 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
 
 tree
 convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
-               bool c_cast_p)
+               bool c_cast_p, tsubst_flags_t complain)
 {
   if (TYPE_PTRMEM_P (type))
     {
@@ -5662,7 +5734,10 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
       delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
                                    TYPE_PTRMEM_CLASS_TYPE (type),
                                    allow_inverse_p,
-                                   c_cast_p);
+                                   c_cast_p, complain);
+      if (delta == error_mark_node)
+       return error_mark_node;
+
       if (!integer_zerop (delta))
        {
          tree cond, op1, op2;
@@ -5686,34 +5761,7 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
     }
   else
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
-                            allow_inverse_p, c_cast_p);
-}
-
-/* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
-   a version of EXPR that has TREE_OVERFLOW set if it is set in ORIG.
-   Otherwise, return EXPR unchanged.  */
-
-static tree
-ignore_overflows (tree expr, tree orig)
-{
-  if (TREE_CODE (expr) == INTEGER_CST
-      && CONSTANT_CLASS_P (orig)
-      && TREE_CODE (orig) != STRING_CST
-      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
-    {
-      if (!TREE_OVERFLOW (orig))
-       /* Ensure constant sharing.  */
-       expr = build_int_cst_wide (TREE_TYPE (expr),
-                                  TREE_INT_CST_LOW (expr),
-                                  TREE_INT_CST_HIGH (expr));
-      else
-       {
-         /* Avoid clobbering a shared constant.  */
-         expr = copy_node (expr);
-         TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
-       }
-    }
-  return expr;
+                            allow_inverse_p, c_cast_p, complain);
 }
 
 /* Perform a static_cast from EXPR to TYPE.  When C_CAST_P is true,
@@ -5729,7 +5777,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
 {
   tree intype;
   tree result;
-  tree orig;
 
   /* Assume the cast is valid.  */
   *valid_p = true;
@@ -5784,17 +5831,23 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       /* Convert from "B*" to "D*".  This function will check that "B"
         is not a virtual base of "D".  */
       expr = build_base_path (MINUS_EXPR, build_address (expr),
-                             base, /*nonnull=*/false);
+                             base, /*nonnull=*/false, complain);
       /* Convert the pointer to a reference -- but then remember that
-        there are no expressions with reference type in C++.  */
-      return convert_from_reference (cp_fold_convert (type, expr));
+        there are no expressions with reference type in C++.
+
+         We call rvalue so that there's an actual tree code
+         (NON_LVALUE_EXPR) for the static_cast; otherwise, if the operand
+         is a variable with the same type, the conversion would get folded
+         away, leaving just the variable and causing lvalue_kind to give
+         the wrong answer.  */
+      return convert_from_reference (rvalue (cp_fold_convert (type, expr)));
     }
 
-  /* "Alvalue of type cv1 T1 can be cast to type rvalue reference to
+  /* "A glvalue of type cv1 T1 can be cast to type rvalue reference to
      cv2 T2 if cv2 T2 is reference-compatible with cv1 T1 (8.5.3)."  */
   if (TREE_CODE (type) == REFERENCE_TYPE
       && TYPE_REF_IS_RVALUE (type)
-      && real_lvalue_p (expr)
+      && lvalue_or_rvalue_with_address_p (expr)
       && reference_related_p (TREE_TYPE (type), intype)
       && (c_cast_p || at_least_as_qualified_p (TREE_TYPE (type), intype)))
     {
@@ -5802,8 +5855,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       return convert_from_reference (expr);
     }
 
-  orig = expr;
-
   /* Resolve overloaded address here rather than once in
      implicit_conversion and again in the inverse code below.  */
   if (TYPE_PTRMEMFUNC_P (type) && type_unknown_p (expr))
@@ -5824,9 +5875,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       result = convert_from_reference (result);
 
-      /* Ignore any integer overflow caused by the cast.  */
-      result = ignore_overflows (result, orig);
-
       /* [expr.static.cast]
 
         If T is a reference type, the result is an lvalue; otherwise,
@@ -5840,7 +5888,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, complain);
+    return convert_to_void (expr, ICV_CAST, complain);
 
   /* [expr.static.cast]
 
@@ -5866,13 +5914,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
        || SCALAR_FLOAT_TYPE_P (type))
       && (INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
          || SCALAR_FLOAT_TYPE_P (intype)))
-    {
-      expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
-
-      /* Ignore any integer overflow caused by the cast.  */
-      expr = ignore_overflows (expr, orig);
-      return expr;
-    }
+    return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
 
   if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
       && CLASS_TYPE_P (TREE_TYPE (type))
@@ -5884,12 +5926,16 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       tree base;
 
-      if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+      if (!c_cast_p
+         && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR,
+                                              complain))
+       return error_mark_node;
       base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
                          c_cast_p ? ba_unique : ba_check,
                          NULL);
-      return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
+      expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
+                             complain);
+      return cp_fold_convert(type, expr);
     }
 
   if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
@@ -5919,10 +5965,13 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
        }
       if (can_convert (t1, t2) || can_convert (t2, t1))
        {
-         if (!c_cast_p)
-           check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+         if (!c_cast_p
+             && check_for_casting_away_constness (intype, type,
+                                                  STATIC_CAST_EXPR,
+                                                  complain))
+           return error_mark_node;
          return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
-                                c_cast_p);
+                                c_cast_p, complain);
        }
     }
 
@@ -5936,8 +5985,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       && VOID_TYPE_P (TREE_TYPE (intype))
       && TYPE_PTROB_P (type))
     {
-      if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+      if (!c_cast_p
+         && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR,
+                                              complain))
+       return error_mark_node;
       return build_nop (type, expr);
     }
 
@@ -6065,7 +6116,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        warning (0, "casting %qT to %qT does not dereference pointer",
                 intype, type);
 
-      expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
+      expr = cp_build_addr_expr (expr, complain);
 
       if (warn_strict_aliasing > 2)
        strict_aliasing_warning (TREE_TYPE (expr), type, expr);
@@ -6141,8 +6192,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       tree sexpr = expr;
 
-      if (!c_cast_p)
-       check_for_casting_away_constness (intype, type, REINTERPRET_CAST_EXPR);
+      if (!c_cast_p
+         && check_for_casting_away_constness (intype, type,
+                                              REINTERPRET_CAST_EXPR,
+                                              complain))
+       return error_mark_node;
       /* Warn about possible alignment problems.  */
       if (STRICT_ALIGNMENT && warn_cast_align
           && (complain & tf_warning)
@@ -6219,7 +6273,7 @@ build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain)
    whether or not the conversion succeeded.  */
 
 static tree
-build_const_cast_1 (tree dst_type, tree expr, bool complain,
+build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
                    bool *valid_p)
 {
   tree src_type;
@@ -6238,7 +6292,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
 
   if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
     {
-      if (complain)
+      if (complain & tf_error)
        error ("invalid use of const_cast with type %qT, "
               "which is not a pointer, "
               "reference, nor a pointer-to-data-member type", dst_type);
@@ -6247,7 +6301,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
 
   if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
     {
-      if (complain)
+      if (complain & tf_error)
        error ("invalid use of const_cast with type %qT, which is a pointer "
               "or reference to a function type", dst_type);
       return error_mark_node;
@@ -6263,16 +6317,31 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
 
   /* [expr.const.cast]
 
-     An lvalue of type T1 can be explicitly converted to an lvalue of
-     type T2 using the cast const_cast<T2&> (where T1 and T2 are object
-     types) if a pointer to T1 can be explicitly converted to the type
-     pointer to T2 using a const_cast.  */
+     For two object types T1 and T2, if a pointer to T1 can be explicitly
+     converted to the type "pointer to T2" using a const_cast, then the
+     following conversions can also be made:
+
+     -- an lvalue of type T1 can be explicitly converted to an lvalue of
+     type T2 using the cast const_cast<T2&>;
+
+     -- a glvalue of type T1 can be explicitly converted to an xvalue of
+     type T2 using the cast const_cast<T2&&>; and
+
+     -- if T1 is a class type, a prvalue of type T1 can be explicitly
+     converted to an xvalue of type T2 using the cast const_cast<T2&&>.  */
+
   if (TREE_CODE (dst_type) == REFERENCE_TYPE)
     {
       reference_type = dst_type;
-      if (! real_lvalue_p (expr))
+      if (!TYPE_REF_IS_RVALUE (dst_type)
+         ? real_lvalue_p (expr)
+         : (CLASS_TYPE_P (TREE_TYPE (dst_type))
+            ? lvalue_p (expr)
+            : lvalue_or_rvalue_with_address_p (expr)))
+       /* OK.  */;
+      else
        {
-         if (complain)
+         if (complain & tf_error)
            error ("invalid const_cast of an rvalue of type %qT to type %qT",
                   src_type, dst_type);
          return error_mark_node;
@@ -6291,37 +6360,44 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
        return error_mark_node;
     }
 
-  if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
-      && comp_ptr_ttypes_const (dst_type, src_type))
+  if (TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
     {
-      if (valid_p)
+      if (comp_ptr_ttypes_const (dst_type, src_type))
        {
-         *valid_p = true;
-         /* This cast is actually a C-style cast.  Issue a warning if
-            the user is making a potentially unsafe cast.  */
-         check_for_casting_away_constness (src_type, dst_type, CAST_EXPR);
-       }
-      if (reference_type)
-       {
-         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);
-       }
-      else
-       {
-         expr = decay_conversion (expr);
-         /* build_c_cast puts on a NOP_EXPR to make the result not an
-            lvalue.  Strip such NOP_EXPRs if VALUE is being used in
-            non-lvalue context.  */
-         if (TREE_CODE (expr) == NOP_EXPR
-             && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
-           expr = TREE_OPERAND (expr, 0);
-         return build_nop (dst_type, expr);
+         if (valid_p)
+           {
+             *valid_p = true;
+             /* This cast is actually a C-style cast.  Issue a warning if
+                the user is making a potentially unsafe cast.  */
+             check_for_casting_away_constness (src_type, dst_type,
+                                               CAST_EXPR, complain);
+           }
+         if (reference_type)
+           {
+             expr = cp_build_addr_expr (expr, complain);
+             expr = build_nop (reference_type, expr);
+             return convert_from_reference (expr);
+           }
+         else
+           {
+             expr = decay_conversion (expr);
+             /* build_c_cast puts on a NOP_EXPR to make the result not an
+                lvalue.  Strip such NOP_EXPRs if VALUE is being used in
+                non-lvalue context.  */
+             if (TREE_CODE (expr) == NOP_EXPR
+                 && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+               expr = TREE_OPERAND (expr, 0);
+             return build_nop (dst_type, expr);
+           }
        }
+      else if (valid_p
+              && !at_least_as_qualified_p (TREE_TYPE (dst_type),
+                                           TREE_TYPE (src_type)))
+       check_for_casting_away_constness (src_type, dst_type, CAST_EXPR,
+                                         complain);
     }
 
-  if (complain)
+  if (complain & tf_error)
     error ("invalid const_cast from type %qT to type %qT",
           src_type, dst_type);
   return error_mark_node;
@@ -6344,7 +6420,7 @@ build_const_cast (tree type, tree expr, tsubst_flags_t complain)
       return convert_from_reference (t);
     }
 
-  return build_const_cast_1 (type, expr, complain & tf_error,
+  return build_const_cast_1 (type, expr, complain,
                             /*valid_p=*/NULL);
 }
 
@@ -6430,7 +6506,7 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
                "cast to pointer from integer of different size");
 
   /* A C-style cast can be a const_cast.  */
-  result = build_const_cast_1 (type, value, /*complain=*/false,
+  result = build_const_cast_1 (type, value, complain & tf_warning,
                               &valid_p);
   if (valid_p)
     return result;
@@ -6455,7 +6531,7 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
       if (!CLASS_TYPE_P (type))
        type = TYPE_MAIN_VARIANT (type);
       result_type = TREE_TYPE (result);
-      if (!CLASS_TYPE_P (result_type))
+      if (!CLASS_TYPE_P (result_type) && TREE_CODE (type) != REFERENCE_TYPE)
        result_type = TYPE_MAIN_VARIANT (result_type);
       /* If the type of RESULT does not match TYPE, perform a
         const_cast to make it match.  If the static_cast or
@@ -6634,12 +6710,19 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
     }
   else
     {
-      lhs = require_complete_type (lhs);
+      lhs = require_complete_type_sfinae (lhs, complain);
       if (lhs == error_mark_node)
        return error_mark_node;
 
       if (modifycode == NOP_EXPR)
        {
+         if (c_dialect_objc ())
+           {
+             result = objc_maybe_build_modify_expr (lhs, rhs);
+             if (result)
+               return result;
+           }
+
          /* `operator=' is not an inheritable operator.  */
          if (! MAYBE_CLASS_TYPE_P (lhstype))
            /* Do the default thing.  */;
@@ -6647,7 +6730,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
            {
              result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
                                     lhs, rhs, make_node (NOP_EXPR),
-                                    /*overloaded_p=*/NULL, 
+                                    /*overload=*/NULL,
                                     complain);
              if (result == NULL_TREE)
                return error_mark_node;
@@ -6657,6 +6740,8 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
        }
       else
        {
+         tree init = NULL_TREE;
+
          /* A binary op has been requested.  Combine the old LHS
             value with the RHS producing the value we should actually
             store into the LHS.  */
@@ -6664,7 +6749,19 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
                         && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype)))
                        || MAYBE_CLASS_TYPE_P (lhstype)));
 
+         /* Preevaluate the RHS to make sure its evaluation is complete
+            before the lvalue-to-rvalue conversion of the LHS:
+
+            [expr.ass] With respect to an indeterminately-sequenced
+            function call, the operation of a compound assignment is a
+            single evaluation. [ Note: Therefore, a function call shall
+            not intervene between the lvalue-to-rvalue conversion and the
+            side effect associated with any single compound assignment
+            operator. -- end note ]  */
          lhs = stabilize_reference (lhs);
+         if (TREE_SIDE_EFFECTS (rhs))
+           rhs = mark_rvalue_use (rhs);
+         rhs = stabilize_expr (rhs, &init);
          newrhs = cp_build_binary_op (input_location,
                                       modifycode, lhs, rhs,
                                       complain);
@@ -6676,8 +6773,17 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
              return error_mark_node;
            }
 
+         if (init)
+           newrhs = build2 (COMPOUND_EXPR, TREE_TYPE (newrhs), init, newrhs);
+
          /* Now it looks like a plain assignment.  */
          modifycode = NOP_EXPR;
+         if (c_dialect_objc ())
+           {
+             result = objc_maybe_build_modify_expr (lhs, newrhs);
+             if (result)
+               return result;
+           }
        }
       gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE);
       gcc_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE);
@@ -6701,7 +6807,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
              && C_TYPE_FIELDS_READONLY (lhstype))))
     {
       if (complain & tf_error)
-       readonly_error (lhs, REK_ASSIGNMENT);
+       cxx_readonly_error (lhs, lv_assign);
       else
        return error_mark_node;
     }
@@ -6728,7 +6834,9 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
            }
          if (check_array_initializer (lhs, lhstype, newrhs))
            return error_mark_node;
-         newrhs = digest_init (lhstype, newrhs);
+         newrhs = digest_init (lhstype, newrhs, complain);
+         if (newrhs == error_mark_node)
+           return error_mark_node;
        }
 
       else if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
@@ -6742,7 +6850,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
       /* Allow array assignment in compiler-generated code.  */
       else if (!current_function_decl
-              || !DECL_ARTIFICIAL (current_function_decl))
+              || !DECL_DEFAULTED_FN (current_function_decl))
        {
           /* This routine is used for both initialization and assignment.
              Make sure the diagnostic message differentiates the context.  */
@@ -6767,10 +6875,10 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
     /* Calls with INIT_EXPR are all direct-initialization, so don't set
        LOOKUP_ONLYCONVERTING.  */
     newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL,
-                                        "initialization", NULL_TREE, 0,
+                                        ICR_INIT, NULL_TREE, 0,
                                          complain);
   else
-    newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
+    newrhs = convert_for_assignment (olhstype, newrhs, ICR_ASSIGN,
                                     NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
 
   if (!same_type_p (lhstype, olhstype))
@@ -6780,7 +6888,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
     {
       if (TREE_CODE (newrhs) == CALL_EXPR
          && TYPE_NEEDS_CONSTRUCTING (lhstype))
-       newrhs = build_cplus_new (lhstype, newrhs);
+       newrhs = build_cplus_new (lhstype, newrhs, complain);
 
       /* Can't initialize directly from a TARGET_EXPR, since that would
         cause the lhs to be constructed twice, and possibly result in
@@ -6824,7 +6932,7 @@ 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,
+                               /*overload=*/NULL,
                                complain);
       if (rval)
        {
@@ -6837,20 +6945,32 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
 /* Helper function for get_delta_difference which assumes FROM is a base
    class of TO.  Returns a delta for the conversion of pointer-to-member
-   of FROM to pointer-to-member of TO.  If the conversion is invalid,
+   of FROM to pointer-to-member of TO.  If the conversion is invalid and 
+   tf_error is not set in COMPLAIN returns error_mark_node, otherwise
    returns zero.  If FROM is not a base class of TO, returns NULL_TREE.
-   If C_CAST_P is true, this conversion is taking place as part of a C-style
-   cast.  */
+   If C_CAST_P is true, this conversion is taking place as part of a 
+   C-style cast.  */
 
 static tree
-get_delta_difference_1 (tree from, tree to, bool c_cast_p)
+get_delta_difference_1 (tree from, tree to, bool c_cast_p,
+                       tsubst_flags_t complain)
 {
   tree binfo;
   base_kind kind;
+  base_access access = c_cast_p ? ba_unique : ba_check;
+
+  /* Note: ba_quiet does not distinguish between access control and
+     ambiguity.  */
+  if (!(complain & tf_error))
+    access |= ba_quiet;
+
+  binfo = lookup_base (to, from, access, &kind);
 
-  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
   if (kind == bk_inaccessible || kind == bk_ambig)
     {
+      if (!(complain & tf_error))
+       return error_mark_node;
+
       error ("   in pointer to member function conversion");
       return size_zero_node;
     }
@@ -6862,22 +6982,26 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
        /* FROM is a virtual base class of TO.  Issue an error or warning
           depending on whether or not this is a reinterpret cast.  */
        {
+         if (!(complain & tf_error))
+           return error_mark_node;
+
          error ("pointer to member conversion via virtual base %qT",
                 BINFO_TYPE (binfo_from_vbase (binfo)));
 
          return size_zero_node;
        }
       }
-    else
-      return NULL_TREE;
+  else
+    return NULL_TREE;
 }
 
 /* Get difference in deltas for different pointer to member function
-   types.  Returns an integer constant of type PTRDIFF_TYPE_NODE.  If
-   the conversion is invalid, the constant is zero.  If
-   ALLOW_INVERSE_P is true, then allow reverse conversions as well.
-   If C_CAST_P is true this conversion is taking place as part of a
-   C-style cast.
+   types.  If the conversion is invalid and tf_error is not set in
+   COMPLAIN, returns error_mark_node, otherwise returns an integer
+   constant of type PTRDIFF_TYPE_NODE and its value is zero if the
+   conversion is invalid.  If ALLOW_INVERSE_P is true, then allow reverse
+   conversions as well.  If C_CAST_P is true this conversion is taking
+   place as part of a C-style cast.
 
    Note that the naming of FROM and TO is kind of backwards; the return
    value is what we add to a TO in order to get a FROM.  They are named
@@ -6887,7 +7011,7 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
 static tree
 get_delta_difference (tree from, tree to,
                      bool allow_inverse_p,
-                     bool c_cast_p)
+                     bool c_cast_p, tsubst_flags_t complain)
 {
   tree result;
 
@@ -6895,25 +7019,37 @@ get_delta_difference (tree from, tree to,
     /* Pointer to member of incomplete class is permitted*/
     result = size_zero_node;
   else
-    result = get_delta_difference_1 (from, to, c_cast_p);
+    result = get_delta_difference_1 (from, to, c_cast_p, complain);
+
+  if (result == error_mark_node)
+    return error_mark_node;
 
   if (!result)
   {
     if (!allow_inverse_p)
       {
+       if (!(complain & tf_error))
+         return error_mark_node;
+
        error_not_base_type (from, to);
        error ("   in pointer to member conversion");
-       result = size_zero_node;
+       result = size_zero_node;
       }
     else
       {
-       result = get_delta_difference_1 (to, from, c_cast_p);
+       result = get_delta_difference_1 (to, from, c_cast_p, complain);
+
+       if (result == error_mark_node)
+         return error_mark_node;
 
        if (result)
          result = size_diffop_loc (input_location,
-                               size_zero_node, result);
+                                   size_zero_node, result);
        else
          {
+           if (!(complain & tf_error))
+             return error_mark_node;
+
            error_not_base_type (from, to);
            error ("   in pointer to member conversion");
            result = size_zero_node;
@@ -6938,7 +7074,7 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
 
   /* Pull the FIELD_DECLs out of the type.  */
   pfn_field = TYPE_FIELDS (type);
-  delta_field = TREE_CHAIN (pfn_field);
+  delta_field = DECL_CHAIN (pfn_field);
 
   /* Make sure DELTA has the type we want.  */
   delta = convert_and_check (delta_type_node, delta);
@@ -6972,7 +7108,8 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
    Return error_mark_node, if something goes wrong.  */
 
 tree
-build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p,
+                 tsubst_flags_t complain)
 {
   tree fn;
   tree pfn_type;
@@ -6999,7 +7136,9 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
       n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
                                TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
                                force,
-                               c_cast_p);
+                               c_cast_p, complain);
+      if (n == error_mark_node)
+       return error_mark_node;
 
       /* We don't have to do any conversion to convert a
         pointer-to-member to its own type.  But, we don't want to
@@ -7041,7 +7180,7 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
   /* Handle null pointer to member function conversions.  */
   if (null_ptr_cst_p (pfn))
     {
-      pfn = build_c_cast (input_location, type, integer_zero_node);
+      pfn = build_c_cast (input_location, type, nullptr_node);
       return build_ptrmemfunc1 (to_type,
                                integer_zero_node,
                                pfn);
@@ -7082,7 +7221,7 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
 
   /* First, calculate the adjustment to the function's class.  */
   *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
-                                /*c_cast_p=*/0);
+                                /*c_cast_p=*/0, tf_warning_or_error);
 
   if (!DECL_VIRTUAL_P (fn))
     *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
@@ -7170,14 +7309,15 @@ delta_from_ptrmemfunc (tree t)
 }
 
 /* Convert value RHS to type TYPE as preparation for an assignment to
-   an lvalue of type TYPE.  ERRTYPE is a string to use in error
-   messages: "assignment", "return", etc.  If FNDECL is non-NULL, we
-   are doing the conversion in order to pass the PARMNUMth argument of
-   FNDECL.  */
+   an lvalue of type TYPE.  ERRTYPE indicates what kind of error the
+   implicit conversion is.  If FNDECL is non-NULL, we are doing the
+   conversion in order to pass the PARMNUMth argument of FNDECL.
+   If FNDECL is NULL, we are doing the conversion in function pointer
+   argument passing, conversion in initialization, etc. */
 
 static tree
 convert_for_assignment (tree type, tree rhs,
-                       const char *errtype, tree fndecl, int parmnum,
+                       impl_conv_rhs errtype, tree fndecl, int parmnum,
                        tsubst_flags_t complain, int flags)
 {
   tree rhstype;
@@ -7192,7 +7332,10 @@ convert_for_assignment (tree type, tree rhs,
 
   if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE
       && vector_types_convertible_p (type, rhstype, true))
-    return convert (type, rhs);
+    {
+      rhs = mark_rvalue_use (rhs);
+      return convert (type, rhs);
+    }
 
   if (rhs == error_mark_node || rhstype == error_mark_node)
     return error_mark_node;
@@ -7214,27 +7357,32 @@ convert_for_assignment (tree type, tree rhs,
   if (c_dialect_objc ())
     {
       int parmno;
+      tree selector;
       tree rname = fndecl;
 
-      if (!strcmp (errtype, "assignment"))
-       parmno = -1;
-      else if (!strcmp (errtype, "initialization"))
-       parmno = -2;
-      else
-       {
-         tree selector = objc_message_selector ();
-
-         parmno = parmnum;
-
-         if (selector && parmno > 1)
-           {
-             rname = selector;
-             parmno -= 1;
-           }
+      switch (errtype)
+        {
+         case ICR_ASSIGN:
+           parmno = -1;
+           break;
+         case ICR_INIT:
+           parmno = -2;
+           break;
+         default:
+           selector = objc_message_selector ();
+           parmno = parmnum;
+           if (selector && parmno > 1)
+             {
+               rname = selector;
+               parmno -= 1;
+             }
        }
 
       if (objc_compare_types (type, rhstype, parmno, rname))
-       return convert (type, rhs);
+       {
+         rhs = mark_rvalue_use (rhs);
+         return convert (type, rhs);
+       }
     }
 
   /* [expr.ass]
@@ -7267,8 +7415,35 @@ convert_for_assignment (tree type, tree rhs,
                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);
+               switch (errtype)
+                 {
+                   case ICR_DEFAULT_ARGUMENT:
+                     error ("cannot convert %qT to %qT in default argument",
+                            rhstype, type);
+                     break;
+                   case ICR_ARGPASS:
+                     error ("cannot convert %qT to %qT in argument passing",
+                            rhstype, type);
+                     break;
+                   case ICR_CONVERTING:
+                     error ("cannot convert %qT to %qT",
+                            rhstype, type);
+                     break;
+                   case ICR_INIT:
+                     error ("cannot convert %qT to %qT in initialization",
+                            rhstype, type);
+                     break;
+                   case ICR_RETURN:
+                     error ("cannot convert %qT to %qT in return",
+                            rhstype, type);
+                     break;
+                   case ICR_ASSIGN:
+                     error ("cannot convert %qT to %qT in assignment",
+                            rhstype, type);
+                     break;
+                   default:
+                     gcc_unreachable();
+                 }
            }
          return error_mark_node;
        }
@@ -7280,9 +7455,42 @@ convert_for_assignment (tree type, tree rhs,
          && coder == codel
          && check_missing_format_attribute (type, rhstype)
          && (complain & tf_warning))
-       warning (OPT_Wmissing_format_attribute,
-                "%s might be a candidate for a format attribute",
-                errtype);
+       switch (errtype)
+         {
+           case ICR_ARGPASS:
+           case ICR_DEFAULT_ARGUMENT:
+             if (fndecl)
+               warning (OPT_Wmissing_format_attribute,
+                        "parameter %qP of %qD might be a candidate "
+                        "for a format attribute", parmnum, fndecl);
+             else
+               warning (OPT_Wmissing_format_attribute,
+                        "parameter might be a candidate "
+                        "for a format attribute");
+             break;
+           case ICR_CONVERTING:
+             warning (OPT_Wmissing_format_attribute,
+                      "target of conversion might be a candidate "
+                      "for a format attribute");
+             break;
+           case ICR_INIT:
+             warning (OPT_Wmissing_format_attribute,
+                      "target of initialization might be a candidate "
+                      "for a format attribute");
+             break;
+           case ICR_RETURN:
+             warning (OPT_Wmissing_format_attribute,
+                      "return type might be a candidate "
+                      "for a format attribute");
+             break;
+           case ICR_ASSIGN:
+             warning (OPT_Wmissing_format_attribute,
+                      "left-hand side of assignment might be a candidate "
+                      "for a format attribute");
+             break;
+           default:
+             gcc_unreachable();
+         }
     }
 
   /* If -Wparentheses, warn about a = b = c when a has type bool and b
@@ -7294,8 +7502,7 @@ convert_for_assignment (tree type, tree rhs,
       && TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE
       && (complain & tf_warning))
     {
-      location_t loc = EXPR_HAS_LOCATION (rhs) 
-       ? EXPR_LOCATION (rhs) : input_location;
+      location_t loc = EXPR_LOC_OR_HERE (rhs);
 
       warning_at (loc, OPT_Wparentheses,
                  "suggest parentheses around assignment used as truth value");
@@ -7308,7 +7515,7 @@ convert_for_assignment (tree type, tree rhs,
 
 /* Convert RHS to be of type TYPE.
    If EXP is nonzero, it is the target of the initialization.
-   ERRTYPE is a string to use in error messages.
+   ERRTYPE indicates what kind of error the implicit conversion is.
 
    Two major differences between the behavior of
    `convert_for_assignment' and `convert_for_initialization'
@@ -7324,7 +7531,7 @@ 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,
+                           impl_conv_rhs errtype, tree fndecl, int parmnum,
                             tsubst_flags_t complain)
 {
   enum tree_code codel = TREE_CODE (type);
@@ -7369,8 +7576,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 
       if (fndecl)
        savew = warningcount, savee = errorcount;
-      rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
-                                 /*cleanup=*/NULL, complain);
+      rhs = initialize_reference (type, rhs, flags, complain);
       if (fndecl)
        {
          if (warningcount > savew)
@@ -7382,7 +7588,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
     }
 
   if (exp != 0)
-    exp = require_complete_type (exp);
+    exp = require_complete_type_sfinae (exp, complain);
   if (exp == error_mark_node)
     return error_mark_node;
 
@@ -7396,7 +7602,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
     return rhs;
 
   if (MAYBE_CLASS_TYPE_P (type))
-    return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+    return perform_implicit_conversion_flags (type, rhs, complain, flags);
 
   return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
                                 complain, flags);
@@ -7517,15 +7723,14 @@ check_return_expr (tree retval, bool *no_warning)
          tree type = lambda_return_type (retval);
          tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda);
 
-         if (VOID_TYPE_P (type))
-           { /* Nothing.  */ }
-         else if (oldtype == NULL_TREE)
-           {
-             pedwarn (input_location, OPT_pedantic, "lambda return type "
-                      "can only be deduced when the return statement is "
-                      "the only statement in the function body");
-             apply_lambda_return_type (lambda, type);
-           }
+         if (oldtype == NULL_TREE)
+           apply_lambda_return_type (lambda, type);
+         /* If one of the answers is type-dependent, we can't do any
+            better until instantiation time.  */
+         else if (oldtype == dependent_lambda_return_type_node)
+           /* Leave it.  */;
+         else if (type == dependent_lambda_return_type_node)
+           apply_lambda_return_type (lambda, type);
          else if (!same_type_p (type, oldtype))
            error ("inconsistent types %qT and %qT deduced for "
                   "lambda return type", type, oldtype);
@@ -7702,12 +7907,19 @@ check_return_expr (tree retval, bool *no_warning)
 
       /* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
         treated as an rvalue for the purposes of overload resolution to
-        favor move constructors over copy constructors.  */
-      if ((cxx_dialect != cxx98) 
-          && named_return_value_okay_p
-          /* The variable must not have the `volatile' qualifier.  */
-         && !CP_TYPE_VOLATILE_P (TREE_TYPE (retval))
-         /* The return type must be a class type.  */
+        favor move constructors over copy constructors.
+
+         Note that these conditions are similar to, but not as strict as,
+        the conditions for the named return value optimization.  */
+      if ((cxx_dialect != cxx98)
+          && (TREE_CODE (retval) == VAR_DECL
+             || TREE_CODE (retval) == PARM_DECL)
+         && DECL_CONTEXT (retval) == current_function_decl
+         && !TREE_STATIC (retval)
+         && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
+                         (TYPE_MAIN_VARIANT
+                          (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+         /* This is only interesting for class type.  */
          && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
        flags = flags | LOOKUP_PREFER_RVALUE;
 
@@ -7715,7 +7927,7 @@ 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, ICR_RETURN, NULL_TREE, 0,
          tf_warning_or_error);
       retval = convert (valtype, retval);
 
@@ -7768,15 +7980,10 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
         so the usual checks are not appropriate.  */
       if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
        {
-         /* In Objective-C++, some types may have been 'volatilized' by
-            the compiler for EH; when comparing them here, the volatile
-            qualification must be ignored.  */
-         bool objc_quals_match = objc_type_quals_match (to, from);
-
-         if (!at_least_as_qualified_p (to, from) && !objc_quals_match)
+         if (!at_least_as_qualified_p (to, from))
            return 0;
 
-         if (!at_least_as_qualified_p (from, to) && !objc_quals_match)
+         if (!at_least_as_qualified_p (from, to))
            {
              if (constp == 0)
                return 0;
@@ -7946,7 +8153,7 @@ type_memfn_quals (const_tree type)
   if (TREE_CODE (type) == FUNCTION_TYPE)
     return TYPE_QUALS (type);
   else if (TREE_CODE (type) == METHOD_TYPE)
-    return cp_type_quals (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type))));
+    return cp_type_quals (class_of_this_parm (type));
   else
     gcc_unreachable ();
 }
@@ -8014,15 +8221,13 @@ cp_apply_type_quals_to_decl (int type_quals, tree decl)
                && type_quals != TYPE_UNQUALIFIED));
 
   /* Avoid setting TREE_READONLY incorrectly.  */
-  if (/* If the object has a constructor, the constructor may modify
-        the object.  */
-      TYPE_NEEDS_CONSTRUCTING (type)
-      /* If the type isn't complete, we don't know yet if it will need
-        constructing.  */
-      || !COMPLETE_TYPE_P (type)
-      /* If the type has a mutable component, that component might be
-        modified.  */
-      || TYPE_HAS_MUTABLE_P (type))
+  /* We used to check TYPE_NEEDS_CONSTRUCTING here, but now a constexpr
+     constructor can produce constant init, so rely on cp_finish_decl to
+     clear TREE_READONLY if the variable has non-constant init.  */
+
+  /* If the type has a mutable component, that component might be
+     modified.  */
+  if (TYPE_HAS_MUTABLE_P (type))
     type_quals &= ~TYPE_QUAL_CONST;
 
   c_apply_type_quals_to_decl (type_quals, decl);
@@ -8148,7 +8353,7 @@ casts_away_constness (tree t1, tree t2)
 tree
 non_reference (tree t)
 {
-  if (TREE_CODE (t) == REFERENCE_TYPE)
+  if (t && TREE_CODE (t) == REFERENCE_TYPE)
     t = TREE_TYPE (t);
   return t;
 }
@@ -8161,11 +8366,139 @@ non_reference (tree t)
 int
 lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
 {
-  int win = lvalue_p (ref);
+  cp_lvalue_kind kind = lvalue_kind (ref);
+
+  if (kind == clk_none)
+    {
+      if (complain & tf_error)
+       lvalue_error (input_location, use);
+      return 0;
+    }
+  else if (kind & (clk_rvalueref|clk_class))
+    {
+      if (!(complain & tf_error))
+       return 0;
+      if (kind & clk_class)
+       /* Make this a permerror because we used to accept it.  */
+       permerror (input_location, "using temporary as lvalue");
+      else
+       error ("using xvalue (rvalue reference) as lvalue");
+    }
+  return 1;
+}
+
+/* Return true if a user-defined literal operator is a raw operator.  */
+
+bool
+check_raw_literal_operator (const_tree decl)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  tree argtype;
+  int arity;
+  bool maybe_raw_p = false;
+
+  /* Count the number and type of arguments and check for ellipsis.  */
+  for (argtype = argtypes, arity = 0;
+       argtype && argtype != void_list_node;
+       ++arity, argtype = TREE_CHAIN (argtype))
+    {
+      tree t = TREE_VALUE (argtype);
+
+      if (same_type_p (t, const_string_type_node))
+       maybe_raw_p = true;
+    }
+  if (!argtype)
+    return false; /* Found ellipsis.  */
+
+  if (!maybe_raw_p || arity != 1)
+    return false;
+
+  return true;
+}
+
+
+/* Return true if a user-defined literal operator has one of the allowed
+   argument types.  */
+
+bool
+check_literal_operator_args (const_tree decl,
+                            bool *long_long_unsigned_p, bool *long_double_p)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  if (processing_template_decl || processing_specialization)
+    return argtypes == void_list_node;
+  else
+    {
+      tree argtype;
+      int arity;
+      int max_arity = 2;
+
+      *long_long_unsigned_p = false;
+      *long_double_p = false;
+
+      /* Count the number and type of arguments and check for ellipsis.  */
+      for (argtype = argtypes, arity = 0;
+          argtype && argtype != void_list_node;
+          argtype = TREE_CHAIN (argtype))
+       {
+         tree t = TREE_VALUE (argtype);
+         ++arity;
 
-  if (!win && (complain & tf_error))
-    lvalue_error (use);
+         if (TREE_CODE (t) == POINTER_TYPE)
+           {
+             bool maybe_raw_p = false;
+             t = TREE_TYPE (t);
+             if (cp_type_quals (t) != TYPE_QUAL_CONST)
+               return false;
+             t = TYPE_MAIN_VARIANT (t);
+             if ((maybe_raw_p = same_type_p (t, char_type_node))
+                 || same_type_p (t, wchar_type_node)
+                 || same_type_p (t, char16_type_node)
+                 || same_type_p (t, char32_type_node))
+               {
+                 argtype = TREE_CHAIN (argtype);
+                 if (!argtype)
+                   return false;
+                 t = TREE_VALUE (argtype);
+                 if (maybe_raw_p && argtype == void_list_node)
+                   return true;
+                 else if (same_type_p (t, size_type_node))
+                   {
+                     ++arity;
+                     continue;
+                   }
+                 else
+                   return false;
+               }
+           }
+         else if (same_type_p (t, long_long_unsigned_type_node))
+           {
+             max_arity = 1;
+             *long_long_unsigned_p = true;
+           }
+         else if (same_type_p (t, long_double_type_node))
+           {
+             max_arity = 1;
+             *long_double_p = true;
+           }
+         else if (same_type_p (t, char_type_node))
+           max_arity = 1;
+         else if (same_type_p (t, wchar_type_node))
+           max_arity = 1;
+         else if (same_type_p (t, char16_type_node))
+           max_arity = 1;
+         else if (same_type_p (t, char32_type_node))
+           max_arity = 1;
+         else
+           return false;
+       }
+      if (!argtype)
+       return false; /* Found ellipsis.  */
 
-  return win;
+      if (arity != max_arity)
+       return false;
+
+      return true;
+    }
 }