OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 3a7610a..f51722a 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
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -39,12 +39,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "target.h"
 #include "convert.h"
-#include "c-common.h"
+#include "c-family/c-common.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);
@@ -829,26 +829,17 @@ merge_types (tree t1, tree t2)
 
        /* Simple way if one arg fails to specify argument types.  */
        if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
-         {
-           parms = p2;
-           raises = TYPE_RAISES_EXCEPTIONS (t2);
-         }
+         parms = p2;
        else if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
-         {
-           parms = p1;
-           raises = TYPE_RAISES_EXCEPTIONS (t1);
-         }
+         parms = p1;
        else
-         {
-           parms = commonparms (p1, p2);
-           /* In cases where we're merging a real declaration with a
-              built-in declaration, t1 is the real one.  */
-           raises = TYPE_RAISES_EXCEPTIONS (t1);
-         }
+         parms = commonparms (p1, p2);
 
        rval = build_function_type (valtype, parms);
        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));
        t1 = build_exception_variant (rval, raises);
        break;
       }
@@ -858,7 +849,8 @@ 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 raises = TYPE_RAISES_EXCEPTIONS (t1);
+       tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
+                                                 TYPE_RAISES_EXCEPTIONS (t2));
        tree t3;
 
        /* If this was a member function type, get back to the
@@ -989,13 +981,14 @@ comp_except_types (tree a, tree b, bool exact)
 }
 
 /* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
-   If EXACT is false, T2 can be stricter than T1 (according to 15.4/7),
-   otherwise it must be exact. Exception lists are unordered, but
-   we've already filtered out duplicates. Most lists will be in order,
-   we should try to make use of that.  */
+   If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
+   If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
+   If EXACT is ce_exact, the specs must be exactly the same. Exception lists
+   are unordered, but we've already filtered out duplicates. Most lists will
+   be in order, we should try to make use of that.  */
 
 bool
-comp_except_specs (const_tree t1, const_tree t2, bool exact)
+comp_except_specs (const_tree t1, const_tree t2, int exact)
 {
   const_tree probe;
   const_tree base;
@@ -1004,14 +997,42 @@ comp_except_specs (const_tree t1, const_tree t2, bool exact)
   if (t1 == t2)
     return true;
 
+  /* First handle noexcept.  */
+  if (exact < ce_exact)
+    {
+      /* noexcept(false) is compatible with any throwing dynamic-exc-spec
+        and stricter than any spec.  */
+      if (t1 == noexcept_false_spec)
+       return !nothrow_spec_p (t2) || exact == ce_derived;
+      /* Even a derived noexcept(false) is compatible with a throwing
+        dynamic spec.  */
+      if (t2 == noexcept_false_spec)
+       return !nothrow_spec_p (t1);
+
+      /* 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;
+    return t2 == NULL_TREE || exact == ce_derived;
   if (!TREE_VALUE (t1))                           /* t1 is EMPTY */
     return t2 != NULL_TREE && !TREE_VALUE (t2);
   if (t2 == NULL_TREE)                    /* T2 is ...  */
     return false;
   if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
-    return !exact;
+    return exact == ce_derived;
 
   /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
      Count how many we find, to determine exactness. For exact matching and
@@ -1026,7 +1047,7 @@ comp_except_specs (const_tree t1, const_tree t2, bool exact)
 
          if (comp_except_types (a, b, exact))
            {
-             if (probe == base && exact)
+             if (probe == base && exact > ce_derived)
                base = TREE_CHAIN (probe);
              length++;
              break;
@@ -1035,7 +1056,7 @@ comp_except_specs (const_tree t1, const_tree t2, bool exact)
       if (probe == NULL_TREE)
        return false;
     }
-  return !exact || base == NULL_TREE || length == list_length (t1);
+  return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
 }
 
 /* Compare the array types T1 and T2.  ALLOW_REDECLARATION is true if
@@ -2115,7 +2136,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;
@@ -3474,7 +3495,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);
            }
 
@@ -4760,7 +4781,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
@@ -5233,7 +5254,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
        {
          build_ptrmemfunc_type (argtype);
          val = build_ptrmemfunc (argtype, val, 0,
-                                 /*c_cast_p=*/false);
+                                 /*c_cast_p=*/false,
+                                 tf_warning_or_error);
        }
 
       return val;
@@ -5467,14 +5489,30 @@ build_x_conditional_expr (tree ifexp, tree op1, tree op2,
 /* 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)
 {
   tree expr = TREE_VALUE (list);
 
   if (TREE_CHAIN (list))
     {
-      if (msg)
-       permerror (input_location, "%s expression list treated as compound expression", msg);
+      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 ();
+       }
 
       for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
        expr = build_x_compound_expr (expr, TREE_VALUE (list), 
@@ -5554,7 +5592,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;
@@ -5632,7 +5670,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))
     {
@@ -5643,7 +5681,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;
@@ -5667,7 +5708,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);
+                            allow_inverse_p, c_cast_p, complain);
 }
 
 /* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
@@ -5821,7 +5862,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]
 
@@ -5903,7 +5944,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
          if (!c_cast_p)
            check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
          return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
-                                c_cast_p);
+                                c_cast_p, tf_warning_or_error);
        }
     }
 
@@ -6748,10 +6789,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))
@@ -6818,20 +6859,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;
     }
@@ -6843,22 +6896,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
@@ -6868,7 +6925,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;
 
@@ -6876,25 +6933,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;
@@ -6919,7 +6988,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);
@@ -6953,7 +7022,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;
@@ -6980,7 +7050,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
@@ -7020,7 +7092,7 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
     }
 
   /* Handle null pointer to member function conversions.  */
-  if (integer_zerop (pfn))
+  if (null_ptr_cst_p (pfn))
     {
       pfn = build_c_cast (input_location, type, integer_zero_node);
       return build_ptrmemfunc1 (to_type,
@@ -7063,7 +7135,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));
@@ -7151,14 +7223,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;
@@ -7173,7 +7246,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;
@@ -7195,27 +7271,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]
@@ -7248,8 +7329,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;
        }
@@ -7261,9 +7369,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 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
@@ -7289,7 +7430,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'
@@ -7305,7 +7446,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);
@@ -7696,7 +7837,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);