OSDN Git Service

Fix PR c++/45383
[pf3gnuchains/gcc-fork.git] / gcc / cp / cvt.c
index ddb011c..c6335a2 100644 (file)
@@ -1,13 +1,14 @@
 /* Language-level data type conversion for GNU C++.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* This file contains the functions for converting C++ expressions
@@ -33,13 +33,15 @@ Boston, MA 02110-1301, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "cp-tree.h"
+#include "intl.h"
 #include "convert.h"
 #include "toplev.h"
 #include "decl.h"
 #include "target.h"
 
-static tree cp_convert_to_pointer (tree, tree, bool);
+static tree cp_convert_to_pointer (tree, tree);
 static tree convert_to_pointer_force (tree, tree);
+static tree build_type_conversion (tree, tree);
 static tree build_up_reference (tree, tree, int, tree);
 static void warn_ref_binding (tree, tree, tree);
 
@@ -70,12 +72,10 @@ static void warn_ref_binding (tree, tree, tree);
      else if dealing with method pointers, delegate
      else convert blindly
    else if converting class, pass off to build_type_conversion
-   else try C-style pointer conversion.  If FORCE is true then allow
-   conversions via virtual bases (these are permitted by reinterpret_cast,
-   but not static_cast).  */
+   else try C-style pointer conversion.  */
 
 static tree
-cp_convert_to_pointer (tree type, tree expr, bool force)
+cp_convert_to_pointer (tree type, tree expr)
 {
   tree intype = TREE_TYPE (expr);
   enum tree_code form;
@@ -83,12 +83,12 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
   if (intype == error_mark_node)
     return error_mark_node;
 
-  if (IS_AGGR_TYPE (intype))
+  if (MAYBE_CLASS_TYPE_P (intype))
     {
       intype = complete_type (intype);
       if (!COMPLETE_TYPE_P (intype))
        {
-         error ("can't convert from incomplete type %qT to %qT",
+         error ("can%'t convert from incomplete type %qT to %qT",
                 intype, type);
          return error_mark_node;
        }
@@ -128,8 +128,8 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
       if (TYPE_MAIN_VARIANT (type) != intype
          && TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
-         && IS_AGGR_TYPE (TREE_TYPE (type))
-         && IS_AGGR_TYPE (TREE_TYPE (intype))
+         && MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
+         && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
          && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
        {
          enum tree_code code = PLUS_EXPR;
@@ -173,61 +173,17 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
 
       return build_nop (type, expr);
     }
-  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
-    {
-      tree b1;
-      tree b2;
-      tree binfo;
-      enum tree_code code = PLUS_EXPR;
-      base_kind bk;
-
-      b1 = TYPE_PTRMEM_CLASS_TYPE (type);
-      b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
-      binfo = lookup_base (b1, b2, ba_check, &bk);
-      if (!binfo)
-       {
-         binfo = lookup_base (b2, b1, ba_check, &bk);
-         code = MINUS_EXPR;
-       }
-      if (binfo == error_mark_node)
-       return error_mark_node;
-
-      if (bk == bk_via_virtual)
-       {
-         if (force)
-           warning (0, "pointer to member cast from %qT to %qT is via"
-                    " virtual base", intype, type);
-         else
-           {
-             error ("pointer to member cast from %qT to %qT is"
-                    " via virtual base", intype, type);
-             return error_mark_node;
-           }
-         /* This is a reinterpret cast, whose result is unspecified.
-            We choose to do nothing.  */
-         return build1 (NOP_EXPR, type, expr);
-       }
-
-      if (TREE_CODE (expr) == PTRMEM_CST)
-       expr = cplus_expand_constant (expr);
-
-      if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
-       expr = size_binop (code,
-                          build_nop (sizetype, expr),
-                          BINFO_OFFSET (binfo));
-      return build_nop (type, expr);
-    }
-  else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
-    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
-                            /*c_cast_p=*/false);
+  else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+          || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
+    return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
+                          /*c_cast_p=*/false, tf_warning_or_error);
   else if (TYPE_PTRMEMFUNC_P (intype))
     {
       if (!warn_pmf2ptr)
        {
          if (TREE_CODE (expr) == PTRMEM_CST)
            return cp_convert_to_pointer (type,
-                                         PTRMEM_CST_MEMBER (expr),
-                                         force);
+                                         PTRMEM_CST_MEMBER (expr));
          else if (TREE_CODE (expr) == OFFSET_REF)
            {
              tree object = TREE_OPERAND (expr, 0);
@@ -240,19 +196,17 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
       return error_mark_node;
     }
 
-  if (integer_zerop (expr))
+  if (null_ptr_cst_p (expr))
     {
       if (TYPE_PTRMEMFUNC_P (type))
        return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
-                                /*c_cast_p=*/false);
+                                /*c_cast_p=*/false, tf_warning_or_error);
 
       if (TYPE_PTRMEM_P (type))
        {
          /* A NULL pointer-to-member is represented by -1, not by
             zero.  */
-         expr = build_int_cst (type, -1);
-         /* Fix up the representation of -1 if appropriate.  */
-         expr = force_fit_type (expr, 0, false, false);
+         expr = build_int_cst_type (type, -1);
        }
       else
        expr = build_int_cst (type, 0);
@@ -280,7 +234,7 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
     }
 
   if (type_unknown_p (expr))
-    return instantiate_type (type, expr, tf_warn_or_error);
+    return instantiate_type (type, expr, tf_warning_or_error);
 
   error ("cannot convert %qE from type %qT to type %qT",
         expr, intype, type);
@@ -303,8 +257,8 @@ convert_to_pointer_force (tree type, tree expr)
 
       if (TYPE_MAIN_VARIANT (type) != intype
          && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
-         && IS_AGGR_TYPE (TREE_TYPE (type))
-         && IS_AGGR_TYPE (TREE_TYPE (intype))
+         && MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
+         && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
          && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
        {
          enum tree_code code = PLUS_EXPR;
@@ -334,7 +288,7 @@ convert_to_pointer_force (tree type, tree expr)
        }
     }
 
-  return cp_convert_to_pointer (type, expr, true);
+  return cp_convert_to_pointer (type, expr);
 }
 
 /* We are passing something to a function which requires a reference.
@@ -360,11 +314,11 @@ build_up_reference (tree type, tree arg, int flags, tree decl)
         here because it needs to live as long as DECL.  */
       tree targ = arg;
 
-      arg = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (arg));
+      arg = make_temporary_var_for_ref_to_temp (decl, target_type);
 
       /* Process the initializer for the declaration.  */
       DECL_INITIAL (arg) = targ;
-      cp_finish_decl (arg, targ, NULL_TREE,
+      cp_finish_decl (arg, targ, /*init_const_expr_p=*/false, NULL_TREE,
                      LOOKUP_ONLYCONVERTING|DIRECT_BIND);
     }
   else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
@@ -373,14 +327,14 @@ build_up_reference (tree type, tree arg, int flags, tree decl)
   /* If we had a way to wrap this up, and say, if we ever needed its
      address, transform all occurrences of the register, into a memory
      reference we could win better.  */
-  rval = build_unary_op (ADDR_EXPR, arg, 1);
+  rval = cp_build_addr_expr (arg, tf_warning_or_error);
   if (rval == error_mark_node)
     return error_mark_node;
 
   if ((flags & LOOKUP_PROTECT)
       && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
-      && IS_AGGR_TYPE (argtype)
-      && IS_AGGR_TYPE (target_type))
+      && MAYBE_CLASS_TYPE_P (argtype)
+      && MAYBE_CLASS_TYPE_P (target_type))
     {
       /* We go through lookup_base for the access control.  */
       tree binfo = lookup_base (argtype, target_type, ba_check, NULL);
@@ -414,19 +368,19 @@ warn_ref_binding (tree reftype, tree intype, tree decl)
       const char *msg;
 
       if (CP_TYPE_VOLATILE_P (ttl) && decl)
-         msg = "initialization of volatile reference type %q#T from"
-           " rvalue of type %qT";
+       msg = G_("initialization of volatile reference type %q#T from "
+                "rvalue of type %qT");
       else if (CP_TYPE_VOLATILE_P (ttl))
-         msg = "conversion to volatile reference type %q#T "
-           " from rvalue of type %qT";
+       msg = G_("conversion to volatile reference type %q#T "
+                "from rvalue of type %qT");
       else if (decl)
-         msg = "initialization of non-const reference type %q#T from"
-           " rvalue of type %qT";
+       msg = G_("initialization of non-const reference type %q#T from "
+                "rvalue of type %qT");
       else
-         msg = "conversion to non-const reference type %q#T from"
-           " rvalue of type %qT";
+       msg = G_("conversion to non-const reference type %q#T from "
+                "rvalue of type %qT");
 
-      pedwarn (msg, reftype, intype);
+      permerror (input_location, msg, reftype, intype);
     }
 }
 
@@ -451,7 +405,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
       && TREE_TYPE (expr) == unknown_type_node)
     expr = instantiate_type (type, expr,
                             (flags & LOOKUP_COMPLAIN)
-                            ? tf_warn_or_error : tf_none);
+                            ? tf_warning_or_error : tf_none);
 
   if (expr == error_mark_node)
     return error_mark_node;
@@ -459,12 +413,13 @@ convert_to_reference (tree reftype, tree expr, int convtype,
   intype = TREE_TYPE (expr);
 
   gcc_assert (TREE_CODE (intype) != REFERENCE_TYPE);
+  gcc_assert (TREE_CODE (reftype) == REFERENCE_TYPE);
 
   intype = TYPE_MAIN_VARIANT (intype);
 
   can_convert_intype_to_type = can_convert (type, intype);
   if (!can_convert_intype_to_type
-      && (convtype & CONV_IMPLICIT) && IS_AGGR_TYPE (intype)
+      && (convtype & CONV_IMPLICIT) && MAYBE_CLASS_TYPE_P (intype)
       && ! (flags & LOOKUP_NO_CONVERSION))
     {
       /* Look for a user-defined conversion to lvalue that we can use.  */
@@ -495,8 +450,8 @@ convert_to_reference (tree reftype, tree expr, int convtype,
 
          if (! (convtype & CONV_CONST)
                   && !at_least_as_qualified_p (ttl, ttr))
-           pedwarn ("conversion from %qT to %qT discards qualifiers",
-                    ttr, reftype);
+           permerror (input_location, "conversion from %qT to %qT discards qualifiers",
+                      ttr, reftype);
        }
 
       return build_up_reference (reftype, expr, flags, decl);
@@ -516,7 +471,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
        warning (0, "casting %qT to %qT does not dereference pointer",
                 intype, reftype);
 
-      rval = build_unary_op (ADDR_EXPR, expr, 0);
+      rval = cp_build_addr_expr (expr, tf_warning_or_error);
       if (rval != error_mark_node)
        rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
                              rval, 0);
@@ -526,7 +481,8 @@ convert_to_reference (tree reftype, tree expr, int convtype,
   else
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
-                                        "converting", 0, 0);
+                                        ICR_CONVERTING, 0, 0,
+                                         tf_warning_or_error);
       if (rval == NULL_TREE || rval == error_mark_node)
        return rval;
       warn_ref_binding (reftype, intype, decl);
@@ -551,9 +507,10 @@ convert_to_reference (tree reftype, tree expr, int convtype,
 tree
 convert_from_reference (tree val)
 {
-  if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
+  if (TREE_TYPE (val)
+      && TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
     {
-      tree t = canonical_type_variant (TREE_TYPE (TREE_TYPE (val)));
+      tree t = TREE_TYPE (TREE_TYPE (val));
       tree ref = build1 (INDIRECT_REF, t, val);
 
        /* We *must* set TREE_READONLY when dereferencing a pointer to const,
@@ -576,7 +533,7 @@ convert_from_reference (tree val)
 tree
 force_rvalue (tree expr)
 {
-  if (IS_AGGR_TYPE (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
+  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
     expr = ocp_convert (TREE_TYPE (expr), expr,
                        CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);
   else
@@ -584,7 +541,39 @@ force_rvalue (tree expr)
 
   return expr;
 }
+
 \f
+/* If EXPR and ORIG are INTEGER_CSTs, return a version of EXPR that has
+   TREE_OVERFLOW set only if it is set in ORIG.  Otherwise, return EXPR
+   unchanged.  */
+
+static tree
+ignore_overflows (tree expr, tree orig)
+{
+  if (TREE_CODE (expr) == INTEGER_CST
+      && TREE_CODE (orig) == INTEGER_CST
+      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
+    {
+      gcc_assert (!TREE_OVERFLOW (orig));
+      /* Ensure constant sharing.  */
+      expr = build_int_cst_wide (TREE_TYPE (expr),
+                                TREE_INT_CST_LOW (expr),
+                                TREE_INT_CST_HIGH (expr));
+    }
+  return expr;
+}
+
+/* Fold away simple conversions, but make sure TREE_OVERFLOW is set
+   properly.  */
+
+tree
+cp_fold_convert (tree type, tree expr)
+{
+  tree conv = fold_convert (type, expr);
+  conv = ignore_overflows (conv, expr);
+  return conv;
+}
+
 /* C++ conversions, preference to static cast conversions.  */
 
 tree
@@ -593,6 +582,31 @@ cp_convert (tree type, tree expr)
   return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
 }
 
+/* C++ equivalent of convert_and_check but using cp_convert as the
+   conversion function.
+
+   Convert EXPR to TYPE, warning about conversion problems with constants.
+   Invoke this function on every expression that is converted implicitly,
+   i.e. because of language rules and not because of an explicit cast.  */
+
+tree
+cp_convert_and_check (tree type, tree expr)
+{
+  tree result;
+
+  if (TREE_TYPE (expr) == type)
+    return expr;
+  
+  result = cp_convert (type, expr);
+
+  if (c_inhibit_evaluation_warnings == 0
+      && !TREE_OVERFLOW_P (expr)
+      && result != error_mark_node)
+    warnings_for_convert_and_check (type, expr, result);
+
+  return result;
+}
+
 /* Conversion...
 
    FLAGS indicates how we should behave.  */
@@ -603,6 +617,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
   tree e = expr;
   enum tree_code code = TREE_CODE (type);
   const char *invalid_conv_diag;
+  tree e1;
 
   if (error_operand_p (e) || type == error_mark_node)
     return error_mark_node;
@@ -617,15 +632,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       return error_mark_node;
     }
 
-  e = integral_constant_value (e);
+  /* FIXME remove when moving to c_fully_fold model.  */
+  /* FIXME do we still need this test?  */
+  if (!CLASS_TYPE_P (type))
+    e = integral_constant_value (e);
+  if (error_operand_p (e))
+    return error_mark_node;
 
-  if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
-      /* Some internal structures (vtable_entry_type, sigtbl_ptr_type)
-        don't go through finish_struct, so they don't have the synthesized
-        constructors.  So don't force a temporary.  */
-      && TYPE_HAS_CONSTRUCTOR (type))
+  if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP))
     /* We need a new temporary; don't take this shortcut.  */;
-  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+  else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
       if (same_type_p (type, TREE_TYPE (e)))
        /* The call to fold will not always remove the NOP_EXPR as
@@ -642,10 +658,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       else if (TREE_CODE (e) == TARGET_EXPR)
        {
          /* Don't build a NOP_EXPR of class type.  Instead, change the
-            type of the temporary.  Only allow this for cv-qual changes,
-            though.  */
-         gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)),
-                                  TYPE_MAIN_VARIANT (type)));
+            type of the temporary.  */
          TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
          return e;
        }
@@ -658,30 +671,52 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
        }
     }
 
+  e1 = targetm.convert_to_type (type, e);
+  if (e1)
+    return e1;
+
   if (code == VOID_TYPE && (convtype & CONV_STATIC))
     {
-      e = convert_to_void (e, /*implicit=*/NULL);
+      e = convert_to_void (e, ICV_CAST, tf_warning_or_error);
       return e;
     }
 
   if (INTEGRAL_CODE_P (code))
     {
       tree intype = TREE_TYPE (e);
-      /* enum = enum, enum = int, enum = float, (enum)pointer are all
-        errors.  */
-      if (TREE_CODE (type) == ENUMERAL_TYPE
-         && (((INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
+      tree converted;
+
+      if (TREE_CODE (type) == ENUMERAL_TYPE)
+       {
+         /* enum = enum, enum = int, enum = float, (enum)pointer are all
+            errors.  */
+         if (((INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
                || TREE_CODE (intype) == REAL_TYPE)
               && ! (convtype & CONV_STATIC))
-             || TREE_CODE (intype) == POINTER_TYPE))
-       {
-         if (flags & LOOKUP_COMPLAIN)
-           pedwarn ("conversion from %q#T to %q#T", intype, type);
+             || TREE_CODE (intype) == POINTER_TYPE)
+           {
+             if (flags & LOOKUP_COMPLAIN)
+               permerror (input_location, "conversion from %q#T to %q#T", intype, type);
 
-         if (flag_pedantic_errors)
-           return error_mark_node;
+             if (!flag_permissive)
+               return error_mark_node;
+           }
+
+         /* [expr.static.cast]
+
+            8. A value of integral or enumeration type can be explicitly
+            converted to an enumeration type. The value is unchanged if
+            the original value is within the range of the enumeration
+            values. Otherwise, the resulting enumeration value is
+            unspecified.  */
+         if (TREE_CODE (expr) == INTEGER_CST
+             && !int_fits_type_p (expr, ENUM_UNDERLYING_TYPE (type)))
+           warning (OPT_Wconversion, 
+                    "the result of the conversion is unspecified because "
+                    "%qE is outside the range of type %qT",
+                    expr, type);
        }
-      if (IS_AGGR_TYPE (intype))
+      if (MAYBE_CLASS_TYPE_P (intype))
        {
          tree rval;
          rval = build_type_conversion (type, e);
@@ -694,14 +729,19 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       if (code == BOOLEAN_TYPE)
        return cp_truthvalue_conversion (e);
 
-      return fold_if_not_in_template (convert_to_integer (type, e));
+      converted = fold_if_not_in_template (convert_to_integer (type, e));
+
+      /* Ignore any integer overflow caused by the conversion.  */
+      return ignore_overflows (converted, e);
     }
+  if (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
+    return nullptr_node;
   if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
-    return fold_if_not_in_template (cp_convert_to_pointer (type, e, false));
+    return fold_if_not_in_template (cp_convert_to_pointer (type, e));
   if (code == VECTOR_TYPE)
     {
       tree in_vtype = TREE_TYPE (e);
-      if (IS_AGGR_TYPE (in_vtype))
+      if (MAYBE_CLASS_TYPE_P (in_vtype))
        {
          tree ret_val;
          ret_val = build_type_conversion (type, e);
@@ -715,7 +755,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
     }
   if (code == REAL_TYPE || code == COMPLEX_TYPE)
     {
-      if (IS_AGGR_TYPE (TREE_TYPE (e)))
+      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (e)))
        {
          tree rval;
          rval = build_type_conversion (type, e);
@@ -735,7 +775,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
   /* New C++ semantics:  since assignment is now based on
      memberwise copying,  if the rhs type is derived from the
      lhs type, then we may still do a conversion.  */
-  if (IS_AGGR_TYPE_CODE (code))
+  if (RECORD_OR_UNION_CODE_P (code))
     {
       tree dtype = TREE_TYPE (e);
       tree ctor = NULL_TREE;
@@ -754,24 +794,38 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       if (abstract_virtuals_error (NULL_TREE, type))
        return error_mark_node;
 
-      if ((flags & LOOKUP_ONLYCONVERTING)
-         && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype)))
+      if (BRACE_ENCLOSED_INITIALIZER_P (ctor))
+       ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error);
+      else if ((flags & LOOKUP_ONLYCONVERTING)
+              && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype)))
        /* For copy-initialization, first we create a temp of the proper type
           with a user-defined conversion sequence, then we direct-initialize
           the target with the temp (see [dcl.init]).  */
        ctor = build_user_type_conversion (type, ctor, flags);
       else
-       ctor = build_special_member_call (NULL_TREE,
-                                         complete_ctor_identifier,
-                                         build_tree_list (NULL_TREE, ctor),
-                                         type, flags);
+       {
+         VEC(tree,gc) *ctor_vec = make_tree_vector_single (ctor);
+         ctor = build_special_member_call (NULL_TREE,
+                                           complete_ctor_identifier,
+                                           &ctor_vec,
+                                           type, flags,
+                                           tf_warning_or_error);
+         release_tree_vector (ctor_vec);
+       }
       if (ctor)
        return build_cplus_new (type, ctor);
     }
 
   if (flags & LOOKUP_COMPLAIN)
-    error ("conversion from %qT to non-scalar type %qT requested",
-          TREE_TYPE (expr), type);
+    {
+      /* If the conversion failed and expr was an invalid use of pointer to
+        member function, try to report a meaningful error.  */
+      if (invalid_nonstatic_memfn_p (expr, tf_warning_or_error))
+       /* We displayed the error message.  */;
+      else
+       error ("conversion from %qT to non-scalar type %qT requested",
+              TREE_TYPE (expr), type);
+    }
   return error_mark_node;
 }
 
@@ -790,21 +844,44 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
    make it impossible to ignore the reference return value from functions. We
    issue warnings in the confusing cases.
 
-   IMPLICIT is tells us the context of an implicit void conversion.  */
+   The IMPLICIT is ICV_CAST when the user is explicitly converting an expression
+   to void via a cast. If an expression is being implicitly converted, IMPLICIT
+   indicates the context of the implicit conversion.  */
 
 tree
-convert_to_void (tree expr, const char *implicit)
+convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
 {
   if (expr == error_mark_node
       || TREE_TYPE (expr) == error_mark_node)
     return error_mark_node;
+
+  if (implicit == ICV_CAST)
+    mark_exp_read (expr);
+  else
+    {
+      tree exprv = expr;
+
+      while (TREE_CODE (exprv) == COMPOUND_EXPR)
+       exprv = TREE_OPERAND (exprv, 1);
+      if (DECL_P (exprv)
+         || handled_component_p (exprv)
+         || TREE_CODE (exprv) == INDIRECT_REF)
+       /* Expr is not being 'used' here, otherwise we whould have
+          called mark_{rl}value_use use here, which would have in turn
+          called mark_exp_read.  Rather, we call mark_exp_read directly
+          to avoid some warnings when
+          -Wunused-but-set-{variable,parameter} is in effect.  */
+       mark_exp_read (exprv);
+    }
+
   if (!TREE_TYPE (expr))
     return expr;
-  if (invalid_nonstatic_memfn_p (expr))
+  if (invalid_nonstatic_memfn_p (expr, complain))
     return error_mark_node;
   if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
     {
-      error ("pseudo-destructor is not called");
+      if (complain & tf_error)
+        error ("pseudo-destructor is not called");
       return error_mark_node;
     }
   if (VOID_TYPE_P (TREE_TYPE (expr)))
@@ -816,12 +893,18 @@ convert_to_void (tree expr, const char *implicit)
        /* The two parts of a cond expr might be separate lvalues.  */
        tree op1 = TREE_OPERAND (expr,1);
        tree op2 = TREE_OPERAND (expr,2);
-       tree new_op1 = convert_to_void
-         (op1, (implicit && !TREE_SIDE_EFFECTS (op2)
-                ? "second operand of conditional" : NULL));
-       tree new_op2 = convert_to_void
-         (op2, (implicit && !TREE_SIDE_EFFECTS (op1)
-                ? "third operand of conditional" : NULL));
+       bool side_effects = TREE_SIDE_EFFECTS (op1) || TREE_SIDE_EFFECTS (op2);
+       tree new_op1, new_op2;
+       if (implicit != ICV_CAST && !side_effects)
+         {
+           new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND, complain);
+           new_op2 = convert_to_void (op2, ICV_THIRD_OF_COND, complain);
+         }
+       else
+         {
+           new_op1 = convert_to_void (op1, ICV_CAST, complain);
+           new_op2 = convert_to_void (op2, ICV_CAST, complain);
+         }
 
        expr = build3 (COND_EXPR, TREE_TYPE (new_op1),
                       TREE_OPERAND (expr, 0), new_op1, new_op2);
@@ -832,9 +915,11 @@ convert_to_void (tree expr, const char *implicit)
       {
        /* The second part of a compound expr contains the value.  */
        tree op1 = TREE_OPERAND (expr,1);
-       tree new_op1 = convert_to_void
-         (op1, (implicit && !TREE_NO_WARNING (expr)
-                ? "right-hand operand of comma" : NULL));
+       tree new_op1;
+       if (implicit != ICV_CAST && !TREE_NO_WARNING (expr))
+         new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA, complain);
+       else
+         new_op1 = convert_to_void (op1, ICV_CAST, complain);
 
        if (new_op1 != op1)
          {
@@ -862,15 +947,153 @@ convert_to_void (tree expr, const char *implicit)
        int is_volatile = TYPE_VOLATILE (type);
        int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
+       /* Can't load the value if we don't know the type.  */
        if (is_volatile && !is_complete)
-         warning (0, "object of incomplete type %qT will not be accessed in %s",
-                  type, implicit ? implicit : "void context");
-       else if (is_reference && is_volatile)
-         warning (0, "object of type %qT will not be accessed in %s",
-                  TREE_TYPE (TREE_OPERAND (expr, 0)),
-                  implicit ? implicit : "void context");
-       if (is_reference || !is_volatile || !is_complete)
-         expr = TREE_OPERAND (expr, 0);
+          {
+            if (complain & tf_warning)
+             switch (implicit)
+               {
+                 case ICV_CAST:
+                   warning (0, "conversion to void will not access "
+                               "object of incomplete type %qT", type);
+                   break;
+                 case ICV_SECOND_OF_COND:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in second operand "
+                               "of conditional expression", type);
+                   break;
+                 case ICV_THIRD_OF_COND:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in third operand "
+                               "of conditional expression", type);
+                   break;
+                 case ICV_RIGHT_OF_COMMA:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in right operand of "
+                               "comma operator", type);
+                   break;
+                 case ICV_LEFT_OF_COMMA:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in left operand of "
+                               "comma operator", type);
+                   break;
+                 case ICV_STATEMENT:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in statement", type);
+                    break;
+                 case ICV_THIRD_IN_FOR:
+                   warning (0, "indirection will not access object of "
+                               "incomplete type %qT in for increment "
+                               "expression", type);
+                   break;
+                 default:
+                   gcc_unreachable ();
+               }
+          }
+       /* Don't load the value if this is an implicit dereference, or if
+          the type needs to be handled by ctors/dtors.  */
+       else if (is_volatile && is_reference)
+          {
+            if (complain & tf_warning)
+             switch (implicit)
+               {
+                 case ICV_CAST:
+                   warning (0, "conversion to void will not access "
+                               "object of type %qT", type);
+                   break;
+                 case ICV_SECOND_OF_COND:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in second operand of "
+                               "conditional expression", type);
+                   break;
+                 case ICV_THIRD_OF_COND:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in third operand of "
+                               "conditional expression", type);
+                   break;
+                 case ICV_RIGHT_OF_COMMA:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in right operand of "
+                               "comma operator", type);
+                   break;
+                 case ICV_LEFT_OF_COMMA:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in left operand of comma operator",
+                            type);
+                   break;
+                 case ICV_STATEMENT:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in statement",  type);
+                    break;
+                 case ICV_THIRD_IN_FOR:
+                   warning (0, "implicit dereference will not access object "
+                               "of type %qT in for increment expression",
+                            type);
+                   break;
+                 default:
+                   gcc_unreachable ();
+               }
+          }
+       else if (is_volatile && TREE_ADDRESSABLE (type))
+         {
+           if (complain & tf_warning)
+             switch (implicit)
+               {
+                 case ICV_CAST:
+                   warning (0, "conversion to void will not access "
+                               "object of non-trivially-copyable type %qT",
+                            type);
+                   break;
+                 case ICV_SECOND_OF_COND:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in second "
+                               "operand of conditional expression", type);
+                   break;
+                 case ICV_THIRD_OF_COND:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in third "
+                               "operand of conditional expression", type);
+                   break;
+                 case ICV_RIGHT_OF_COMMA:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in right "
+                               "operand of comma operator", type);
+                   break;
+                 case ICV_LEFT_OF_COMMA:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in left "
+                               "operand of comma operator", type);
+                   break;
+                 case ICV_STATEMENT:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in statement",
+                             type);
+                    break;
+                 case ICV_THIRD_IN_FOR:
+                   warning (0, "indirection will not access object of "
+                               "non-trivially-copyable type %qT in for "
+                               "increment expression", type);
+                   break;
+                 default:
+                   gcc_unreachable ();
+               }
+         }
+       if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
+          {
+            /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
+               operation is stripped off. Note that we don't warn about
+               - an expression with TREE_NO_WARNING set. (For an example of
+                 such expressions, see build_over_call in call.c.)
+               - automatic dereferencing of references, since the user cannot
+                 control it. (See also warn_if_unused_value() in stmt.c.)  */
+            if (warn_unused_value
+               && implicit != ICV_CAST
+                && (complain & tf_warning)
+                && !TREE_NO_WARNING (expr)
+                && !is_reference)
+              warning (OPT_Wunused_value, "value computed is not used");
+            expr = TREE_OPERAND (expr, 0);
+          }
 
        break;
       }
@@ -881,14 +1104,74 @@ convert_to_void (tree expr, const char *implicit)
        tree type = TREE_TYPE (expr);
        int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
-       if (TYPE_VOLATILE (type) && !is_complete)
-         warning (0, "object %qE of incomplete type %qT will not be accessed in %s",
-                  expr, type, implicit ? implicit : "void context");
+       if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
+         switch (implicit)
+           {
+             case ICV_CAST:
+               warning (0, "conversion to void will not access "
+                           "object %qE of incomplete type %qT", expr, type);
+               break;
+             case ICV_SECOND_OF_COND:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in second operand of "
+                           "conditional expression", expr, type);
+               break;
+             case ICV_THIRD_OF_COND:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in third operand of "
+                           "conditional expression", expr, type);
+               break;
+             case ICV_RIGHT_OF_COMMA:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in right operand of comma operator",
+                        expr, type);
+               break;
+             case ICV_LEFT_OF_COMMA:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in left operand of comma operator",
+                        expr, type);
+               break;
+             case ICV_STATEMENT:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in statement", expr, type);
+               break;
+             case ICV_THIRD_IN_FOR:
+               warning (0, "variable %qE of incomplete type %qT will not "
+                           "be accessed in for increment expression",
+                        expr, type);
+               break;
+             default:
+               gcc_unreachable ();
+           }
+
        break;
       }
 
+    case TARGET_EXPR:
+      /* Don't bother with the temporary object returned from a function if
+        we don't use it and don't need to destroy it.  We'll still
+        allocate space for it in expand_call or declare_return_variable,
+        but we don't need to track it through all the tree phases.  */
+      if (TARGET_EXPR_IMPLICIT_P (expr)
+         && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr)))
+       {
+         tree init = TARGET_EXPR_INITIAL (expr);
+         if (TREE_CODE (init) == AGGR_INIT_EXPR
+             && !AGGR_INIT_VIA_CTOR_P (init))
+           {
+             tree fn = AGGR_INIT_EXPR_FN (init);
+             expr = build_call_array_loc (input_location,
+                                          TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+                                          fn,
+                                          aggr_init_expr_nargs (init),
+                                          AGGR_INIT_EXPR_ARGP (init));
+           }
+       }
+      break;
+
     default:;
     }
+  expr = resolve_nondeduced_context (expr);
   {
     tree probe = expr;
 
@@ -898,32 +1181,133 @@ convert_to_void (tree expr, const char *implicit)
       {
        /* [over.over] enumerates the places where we can take the address
           of an overloaded function, and this is not one of them.  */
-       pedwarn ("%s cannot resolve address of overloaded function",
-                   implicit ? implicit : "void cast");
+       if (complain & tf_error)
+         switch (implicit)
+           {
+             case ICV_CAST:
+               error ("conversion to void "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_SECOND_OF_COND:
+               error ("second operand of conditional expression "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_THIRD_OF_COND:
+               error ("third operand of conditional expression "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_RIGHT_OF_COMMA:
+               error ("right operand of comma operator "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_LEFT_OF_COMMA:
+               error ("left operand of comma operator "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_STATEMENT:
+               error ("statement "
+                      "cannot resolve address of overloaded function");
+               break;
+             case ICV_THIRD_IN_FOR:
+               error ("for increment expression "
+                      "cannot resolve address of overloaded function");
+               break;
+           }
+       else
+         return error_mark_node;
        expr = void_zero_node;
       }
-    else if (implicit && probe == expr && is_overloaded_fn (probe))
-      /* Only warn when there is no &.  */
-      warning (0, "%s is a reference, not call, to function %qE",
-                 implicit, expr);
+    else if (implicit != ICV_CAST && probe == expr && is_overloaded_fn (probe))
+      {
+       /* Only warn when there is no &.  */
+       if (complain & tf_warning)
+         switch (implicit)
+           {
+             case ICV_SECOND_OF_COND:
+               warning (OPT_Waddress,
+                        "second operand of conditional expression "
+                        "is a reference, not call, to function %qE", expr);
+               break;
+             case ICV_THIRD_OF_COND:
+               warning (OPT_Waddress,
+                        "third operand of conditional expression "
+                        "is a reference, not call, to function %qE", expr);
+               break;
+             case ICV_RIGHT_OF_COMMA:
+               warning (OPT_Waddress,
+                        "right operand of comma operator "
+                        "is a reference, not call, to function %qE", expr);
+               break;
+             case ICV_LEFT_OF_COMMA:
+               warning (OPT_Waddress,
+                        "left operand of comma operator "
+                        "is a reference, not call, to function %qE", expr);
+               break;
+             case ICV_STATEMENT:
+               warning (OPT_Waddress,
+                        "statement is a reference, not call, to function %qE",
+                        expr);
+               break;
+             case ICV_THIRD_IN_FOR:
+               warning (OPT_Waddress,
+                        "for increment expression "
+                        "is a reference, not call, to function %qE", expr);
+               break;
+             default:
+               gcc_unreachable ();
+           }
+
+       if (TREE_CODE (expr) == COMPONENT_REF)
+         expr = TREE_OPERAND (expr, 0);
+      }
   }
 
   if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
     {
-      if (implicit
+      if (implicit != ICV_CAST
          && warn_unused_value
          && !TREE_NO_WARNING (expr)
          && !processing_template_decl)
        {
          /* The middle end does not warn about expressions that have
             been explicitly cast to void, so we must do so here.  */
-         if (!TREE_SIDE_EFFECTS (expr))
-           warning (OPT_Wunused_value, "%s has no effect", implicit);
+         if (!TREE_SIDE_EFFECTS (expr)) {
+            if (complain & tf_warning)
+             switch (implicit)
+               {
+                 case ICV_SECOND_OF_COND:
+                   warning (OPT_Wunused_value,
+                            "second operand of conditional expression has no effect");
+                   break;
+                 case ICV_THIRD_OF_COND:
+                   warning (OPT_Wunused_value,
+                            "third operand of conditional expression has no effect");
+                   break;
+                 case ICV_RIGHT_OF_COMMA:
+                   warning (OPT_Wunused_value,
+                            "right operand of comma operator has no effect");
+                   break;
+                 case ICV_LEFT_OF_COMMA:
+                   warning (OPT_Wunused_value,
+                            "left operand of comma operator has no effect");
+                   break;
+                 case ICV_STATEMENT:
+                   warning (OPT_Wunused_value,
+                            "statement has no effect");
+                   break;
+                 case ICV_THIRD_IN_FOR:
+                   warning (OPT_Wunused_value,
+                            "for increment expression has no effect");
+                   break;
+                 default:
+                   gcc_unreachable ();
+               }
+          }
          else
            {
              tree e;
              enum tree_code code;
-             enum tree_code_class class;
+             enum tree_code_class tclass;
 
              e = expr;
              /* We might like to warn about (say) "(int) f()", as the
@@ -940,21 +1324,24 @@ convert_to_void (tree expr, const char *implicit)
                e = TREE_OPERAND (e, 0);
 
              code = TREE_CODE (e);
-             class = TREE_CODE_CLASS (code);
-             if (class == tcc_comparison
-                  || class == tcc_unary
-                  || (class == tcc_binary
+             tclass = TREE_CODE_CLASS (code);
+             if ((tclass == tcc_comparison
+                  || tclass == tcc_unary
+                  || (tclass == tcc_binary
                       && !(code == MODIFY_EXPR
                            || code == INIT_EXPR
                            || code == PREDECREMENT_EXPR
                            || code == PREINCREMENT_EXPR
                            || code == POSTDECREMENT_EXPR
                            || code == POSTINCREMENT_EXPR)))
+                  && (complain & tf_warning))
                warning (OPT_Wunused_value, "value computed is not used");
            }
        }
       expr = build1 (CONVERT_EXPR, void_type_node, expr);
     }
+  if (! TREE_SIDE_EFFECTS (expr))
+    expr = void_zero_node;
   return expr;
 }
 
@@ -966,7 +1353,7 @@ convert_to_void (tree expr, const char *implicit)
 
    Most of this routine is from build_reinterpret_cast.
 
-   The backend cannot call cp_convert (what was convert) because
+   The back end cannot call cp_convert (what was convert) because
    conversions to/from basetypes may involve memory references
    (vbases) and adding or subtracting small values (multiple
    inheritance), but it calls convert from the constant folding code
@@ -1019,7 +1406,7 @@ convert_force (tree type, tree expr, int convtype)
       && TYPE_PTRMEMFUNC_P (type))
     /* compatible pointer to member functions.  */
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
-                            /*c_cast_p=*/1);
+                            /*c_cast_p=*/1, tf_warning_or_error);
 
   return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
 }
@@ -1035,7 +1422,7 @@ convert_force (tree type, tree expr, int convtype)
    that doesn't do it.  This will probably wait for an overloading rewrite.
    (jason 8/9/95)  */
 
-tree
+static tree
 build_type_conversion (tree xtype, tree expr)
 {
   /* C++: check to see if we can convert this aggregate type
@@ -1058,14 +1445,15 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
   if (expr == null_node
       && (desires & WANT_INT)
       && !(desires & WANT_NULL))
-    warning (OPT_Wconversion, "converting NULL to non-pointer type");
+    warning_at (input_location, OPT_Wconversion_null,
+               "converting NULL to non-pointer type");
 
   basetype = TREE_TYPE (expr);
 
   if (basetype == error_mark_node)
     return error_mark_node;
 
-  if (! IS_AGGR_TYPE (basetype))
+  if (! MAYBE_CLASS_TYPE_P (basetype))
     switch (TREE_CODE (basetype))
       {
       case INTEGER_TYPE:
@@ -1073,7 +1461,6 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
          return expr;
        /* else fall through...  */
 
-      case VECTOR_TYPE:
       case BOOLEAN_TYPE:
        return (desires & WANT_INT) ? expr : NULL_TREE;
       case ENUMERAL_TYPE:
@@ -1087,13 +1474,31 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       case ARRAY_TYPE:
        return (desires & WANT_POINTER) ? decay_conversion (expr)
                                        : NULL_TREE;
+
+      case COMPLEX_TYPE:
+      case VECTOR_TYPE:
+       if ((desires & WANT_VECTOR_OR_COMPLEX) == 0)
+         return NULL_TREE;
+       switch (TREE_CODE (TREE_TYPE (basetype)))
+         {
+         case INTEGER_TYPE:
+         case BOOLEAN_TYPE:
+           return (desires & WANT_INT) ? expr : NULL_TREE;
+         case ENUMERAL_TYPE:
+           return (desires & WANT_ENUM) ? expr : NULL_TREE;
+         case REAL_TYPE:
+           return (desires & WANT_FLOAT) ? expr : NULL_TREE;
+         default:
+           return NULL_TREE;
+         }
+
       default:
        return NULL_TREE;
       }
 
   /* The code for conversions from class type is currently only used for
      delete expressions.  Other expressions are handled by build_new_op.  */
-  if (!complete_type_or_else (basetype, expr))
+  if (!complete_type_or_maybe_complain (basetype, expr, complain))
     return error_mark_node;
   if (!TYPE_HAS_CONVERSION (basetype))
     return NULL_TREE;
@@ -1103,10 +1508,14 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       int win = 0;
       tree candidate;
       tree cand = TREE_VALUE (conv);
+      cand = OVL_CURRENT (cand);
 
       if (winner && winner == cand)
        continue;
 
+      if (DECL_NONCONVERTING_P (cand))
+       continue;
+
       candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
 
       switch (TREE_CODE (candidate))
@@ -1121,6 +1530,24 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
        case POINTER_TYPE:
          win = (desires & WANT_POINTER); break;
 
+       case COMPLEX_TYPE:
+       case VECTOR_TYPE:
+         if ((desires & WANT_VECTOR_OR_COMPLEX) == 0)
+           break;
+         switch (TREE_CODE (TREE_TYPE (candidate)))
+           {
+           case BOOLEAN_TYPE:
+           case INTEGER_TYPE:
+             win = (desires & WANT_INT); break;
+           case ENUMERAL_TYPE:
+             win = (desires & WANT_ENUM); break;
+           case REAL_TYPE:
+             win = (desires & WANT_FLOAT); break;
+           default:
+             break;
+           }
+         break;
+
        default:
          break;
        }
@@ -1157,24 +1584,35 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
 tree
 type_promotes_to (tree type)
 {
+  tree promoted_type;
+
   if (type == error_mark_node)
     return error_mark_node;
 
   type = TYPE_MAIN_VARIANT (type);
 
+  /* Check for promotions of target-defined types first.  */
+  promoted_type = targetm.promoted_type (type);
+  if (promoted_type)
+    return promoted_type;
+
   /* bool always promotes to int (not unsigned), even if it's the same
      size.  */
-  if (type == boolean_type_node)
+  if (TREE_CODE (type) == BOOLEAN_TYPE)
     type = integer_type_node;
 
   /* Normally convert enums to int, but convert wide enums to something
      wider.  */
   else if (TREE_CODE (type) == ENUMERAL_TYPE
+          || type == char16_type_node
+          || type == char32_type_node
           || type == wchar_type_node)
     {
       int precision = MAX (TYPE_PRECISION (type),
                           TYPE_PRECISION (integer_type_node));
       tree totype = c_common_type_for_size (precision, 0);
+      if (TREE_CODE (type) == ENUMERAL_TYPE)
+       type = ENUM_UNDERLYING_TYPE (type);
       if (TYPE_UNSIGNED (type)
          && ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
        type = c_common_type_for_size (precision, 1);