Patchwork [4.8,C++] PR 52422

login
register
mail settings
Submitter Paolo Carlini
Date Feb. 29, 2012, 11:53 a.m.
Message ID <4F4E11D5.8030408@oracle.com>
Download mbox | patch
Permalink /patch/143711/
State New
Headers show

Comments

Paolo Carlini - Feb. 29, 2012, 11:53 a.m.
Hi,

Daniel noticed a couple other SFINAE issues, which I'm fixing in the 
usual straightforward way. Tested x86_64-linux.

Thanks,
Paolo.

PS: while working on the patch, I noticed that a few functions, which in 
the meanwhile acquired a tsubst_flags_t parameter, aren't fully 
propagating it, are still passing tf_warning_or_error. Apparently a 
clean-up is in order.

////////////
/cp
2012-02-29  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/52422
	* cp-tree.h (build_addr_func, decay_conversion,
	build_m_component_ref): Add tsubst_flags_t parameter.
	* typeck.c (decay_conversion): Add tsubst_flags_t parameter and
	use it throughout.
	(default_conversion, cp_build_indirect_ref,
	get_member_function_from_ptrfunc, cp_build_function_call_vec,
	convert_arguments, build_x_binary_op, cp_build_binary_op,
	convert_member_func_to_ptr, build_reinterpret_cast_1,
	build_const_cast_1, expand_ptrmemfunc_cst,
	convert_for_initialization): Adjust.
	* init.c (build_vec_init, build_vec_init): Adjust.
	* decl.c (grok_reference_init, get_atexit_node): Likewise.
	* rtti.c (build_dynamic_cast_1, tinfo_base_init): Likewise.
	* except.c (build_throw): Likewise.
	* typeck2.c (build_x_arrow): Likewise.
	(build_m_component_ref): Add tsubst_flags_t parameter and
	use it throughout.
	* pt.c (convert_nontype_argument): Adjust.
	* semantics.c (finish_asm_stmt, maybe_add_lambda_conv_op): Likewise.
	* call.c (build_addr_func): Add tsubst_flags_t parameter and
	use it throughout.
	(build_call_a, build_conditional_expr_1, build_new_op_1,
	convert_like_real, convert_arg_to_ellipsis, build_over_call,
	build_special_member_call): Adjust.
	* cvt.c (force_rvalue, build_expr_type_conversion): Likewise.

/testsuite
2012-02-29  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/52422
	* g++.dg/cpp0x/sfinae33.C: New.
	* g++.dg/cpp0x/sfinae34.C: Likewise.
Jason Merrill - March 1, 2012, 1:38 a.m.
On 02/29/2012 06:53 AM, Paolo Carlini wrote:
> Daniel noticed a couple other SFINAE issues, which I'm fixing in the
> usual straightforward way. Tested x86_64-linux.

When fixing these things, please add checking for error_mark_node return 
as well.  For instance, in this patch the calls to decay_conversion from 
build_conditional_expr_1 could return error_mark_node, in which case we 
want to return out of build_conditional_expr_1 as well.  Similarly with 
the call in convert_like_real, and so on.

> PS: while working on the patch, I noticed that a few functions, which in
> the meanwhile acquired a tsubst_flags_t parameter, aren't fully
> propagating it, are still passing tf_warning_or_error. Apparently a
> clean-up is in order.

Please.  :)

Jason

Patch

Index: testsuite/g++.dg/cpp0x/sfinae33.C
===================================================================
--- testsuite/g++.dg/cpp0x/sfinae33.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/sfinae33.C	(revision 0)
@@ -0,0 +1,27 @@ 
+// PR c++/52422
+// { dg-options -std=c++0x }
+
+template<class T>
+struct add_rval_ref
+{
+  typedef T&& type;
+};
+
+template<>
+struct add_rval_ref<void>
+{
+  typedef void type;
+};
+
+template<class T>
+typename add_rval_ref<T>::type create();
+
+template<class T, 
+  class = decltype(create<T>()())
+>
+auto f(int) -> char(&)[1];
+
+template<class>
+auto f(...) -> char(&)[2];
+
+static_assert(sizeof(f<void>(0)) != 1, "");
Index: testsuite/g++.dg/cpp0x/sfinae34.C
===================================================================
--- testsuite/g++.dg/cpp0x/sfinae34.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/sfinae34.C	(revision 0)
@@ -0,0 +1,28 @@ 
+// PR c++/52422
+// { dg-options -std=c++0x }
+
+template<class T>
+struct add_rval_ref
+{
+  typedef T&& type;
+};
+
+template<>
+struct add_rval_ref<void>
+{
+  typedef void type;
+};
+
+template<class T>
+typename add_rval_ref<T>::type create();
+
+template<class T, class U,
+  class = decltype( (create<T>().*create<U>())() )
+>
+auto f(int) -> char(&)[1];
+
+template<class, class>
+auto f(...) -> char(&)[2];
+
+static_assert(sizeof(f<void, void>(0)) != 1, "");
+
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 184643)
+++ cp/typeck.c	(working copy)
@@ -1813,7 +1813,7 @@  unlowered_expr_type (const_tree exp)
    that the return value is no longer an lvalue.  */
 
 tree
-decay_conversion (tree exp)
+decay_conversion (tree exp, tsubst_flags_t complain)
 {
   tree type;
   enum tree_code code;
@@ -1827,7 +1827,8 @@  tree
   exp = resolve_nondeduced_context (exp);
   if (type_unknown_p (exp))
     {
-      cxx_incomplete_type_error (exp, TREE_TYPE (exp));
+      if (complain & tf_error)
+	cxx_incomplete_type_error (exp, TREE_TYPE (exp));
       return error_mark_node;
     }
 
@@ -1846,13 +1847,14 @@  tree
   code = TREE_CODE (type);
   if (code == VOID_TYPE)
     {
-      error ("void value not ignored as it ought to be");
+      if (complain & tf_error)
+	error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
-  if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
+  if (invalid_nonstatic_memfn_p (exp, complain))
     return error_mark_node;
   if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
-    return cp_build_addr_expr (exp, tf_warning_or_error);
+    return cp_build_addr_expr (exp, complain);
   if (code == ARRAY_TYPE)
     {
       tree adr;
@@ -1864,7 +1866,7 @@  tree
 
       if (TREE_CODE (exp) == COMPOUND_EXPR)
 	{
-	  tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
+	  tree op1 = decay_conversion (TREE_OPERAND (exp, 1), complain);
 	  return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
 			 TREE_OPERAND (exp, 0), op1);
 	}
@@ -1872,7 +1874,8 @@  tree
       if (!lvalue_p (exp)
 	  && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
 	{
-	  error ("invalid use of non-lvalue array");
+	  if (complain & tf_error)
+	    error ("invalid use of non-lvalue array");
 	  return error_mark_node;
 	}
 
@@ -1887,7 +1890,7 @@  tree
 	}
       /* This way is better for a COMPONENT_REF since it can
 	 simplify the offset for a component.  */
-      adr = cp_build_addr_expr (exp, tf_warning_or_error);
+      adr = cp_build_addr_expr (exp, complain);
       return cp_convert (ptrtype, adr);
     }
 
@@ -1939,7 +1942,7 @@  default_conversion (tree exp)
   else if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
     exp = perform_integral_promotions (exp);
   /* Perform the other conversions.  */
-  exp = decay_conversion (exp);
+  exp = decay_conversion (exp, tf_warning_or_error);
 
   return exp;
 }
@@ -2755,7 +2758,7 @@  cp_build_indirect_ref (tree ptr, ref_operator erro
     return current_class_ref;
 
   pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
-	     ? ptr : decay_conversion (ptr));
+	     ? ptr : decay_conversion (ptr, complain));
   type = TREE_TYPE (pointer);
 
   if (POINTER_TYPE_P (type))
@@ -3049,7 +3052,8 @@  get_member_function_from_ptrfunc (tree *instance_p
 	      /* Extracting the function address from a pmf is only
 		 allowed with -Wno-pmf-conversions. It only works for
 		 pmf constants.  */
-	      e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
+	      e1 = build_addr_func (PTRMEM_CST_MEMBER (function),
+				    tf_warning_or_error);
 	      e1 = convert (fntype, e1);
 	      return e1;
 	    }
@@ -3251,13 +3255,13 @@  cp_build_function_call_vec (tree function, VEC(tre
 	pedwarn (input_location, OPT_pedantic, 
 		 "ISO C++ forbids calling %<::main%> from within program");
 
-      function = build_addr_func (function);
+      function = build_addr_func (function, complain);
     }
   else
     {
       fndecl = NULL_TREE;
 
-      function = build_addr_func (function);
+      function = build_addr_func (function, complain);
     }
 
   if (function == error_mark_node)
@@ -3422,7 +3426,7 @@  convert_arguments (tree typelist, VEC(tree,gc) **v
 	  if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
 	      || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
 	      || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
-	    val = decay_conversion (val);
+	    val = decay_conversion (val, complain);
 	}
 
       if (val == error_mark_node)
@@ -3549,7 +3553,7 @@  build_x_binary_op (enum tree_code code, tree arg1,
     }
 
   if (code == DOTSTAR_EXPR)
-    expr = build_m_component_ref (arg1, arg2);
+    expr = build_m_component_ref (arg1, arg2, complain);
   else
     expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
 			 overload, complain);
@@ -3713,9 +3717,9 @@  cp_build_binary_op (location_t location,
       || code == TRUTH_XOR_EXPR)
     {
       if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
-	op0 = decay_conversion (op0);
+	op0 = decay_conversion (op0, complain);
       if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
-	op1 = decay_conversion (op1);
+	op1 = decay_conversion (op1, complain);
     }
   else
     {
@@ -6107,7 +6111,7 @@  convert_member_func_to_ptr (tree type, tree expr)
 	     "converting from %qT to %qT", intype, type);
 
   if (TREE_CODE (intype) == METHOD_TYPE)
-    expr = build_addr_func (expr);
+    expr = build_addr_func (expr, tf_warning_or_error);
   else if (TREE_CODE (expr) == PTRMEM_CST)
     expr = build_address (PTRMEM_CST_MEMBER (expr));
   else
@@ -6199,7 +6203,7 @@  build_reinterpret_cast_1 (tree type, tree expr, bo
   /* If the cast is not to a reference type, the lvalue-to-rvalue,
      array-to-pointer, and function-to-pointer conversions are
      performed.  */
-  expr = decay_conversion (expr);
+  expr = decay_conversion (expr, complain);
 
   /* 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.  */
@@ -6438,7 +6442,7 @@  build_const_cast_1 (tree dst_type, tree expr, tsub
 	    }
 	  else
 	    {
-	      expr = decay_conversion (expr);
+	      expr = decay_conversion (expr, complain);
 	      /* 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.  */
@@ -7282,7 +7286,8 @@  expand_ptrmemfunc_cst (tree cst, tree *delta, tree
 				 /*c_cast_p=*/0, tf_warning_or_error);
 
   if (!DECL_VIRTUAL_P (fn))
-    *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
+    *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type),
+		    build_addr_func (fn, tf_warning_or_error));
   else
     {
       /* If we're dealing with a virtual function, we have to adjust 'this'
@@ -7616,7 +7621,7 @@  convert_for_initialization (tree exp, tree type, t
 	  && (TREE_CODE (type) != REFERENCE_TYPE
 	      || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE))
       || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
-    rhs = decay_conversion (rhs);
+    rhs = decay_conversion (rhs, complain);
 
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 184643)
+++ cp/init.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   2011, 2012 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -3186,7 +3186,7 @@  build_vec_init (tree base, tree maxindex, tree ini
   if (TREE_CODE (atype) == ARRAY_TYPE)
     {
       ptype = build_pointer_type (type);
-      base = cp_convert (ptype, decay_conversion (base));
+      base = cp_convert (ptype, decay_conversion (base, complain));
     }
   else
     ptype = atype;
@@ -3235,7 +3235,7 @@  build_vec_init (tree base, tree maxindex, tree ini
     {
       if (lvalue_kind (init) & clk_rvalueref)
 	xvalue = true;
-      base2 = decay_conversion (init);
+      base2 = decay_conversion (init, complain);
       itype = TREE_TYPE (base2);
       base2 = get_temp_regvar (itype, base2);
       itype = TREE_TYPE (itype);
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 184643)
+++ cp/decl.c	(working copy)
@@ -4650,7 +4650,7 @@  grok_reference_init (tree decl, tree type, tree in
   if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE
       && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
     /* Note: default conversion is only called in very special cases.  */
-    init = decay_conversion (init);
+    init = decay_conversion (init, tf_warning_or_error);
 
   /* Convert INIT to the reference type TYPE.  This may involve the
      creation of a temporary, whose lifetime must be the same as that
@@ -6513,7 +6513,7 @@  get_atexit_node (void)
   atexit_fndecl = build_library_fn_ptr (name, fn_type);
   mark_used (atexit_fndecl);
   pop_lang_context ();
-  atexit_node = decay_conversion (atexit_fndecl);
+  atexit_node = decay_conversion (atexit_fndecl, tf_warning_or_error);
 
   return atexit_node;
 }
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 184643)
+++ cp/rtti.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* RunTime Type Identification
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007, 2008, 2009, 2010, 2011
+   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Mostly written by Jason Merrill (jason@cygnus.com).
 
@@ -551,7 +551,7 @@  build_dynamic_cast_1 (tree type, tree expr, tsubst
 
   if (tc == POINTER_TYPE)
     {
-      expr = decay_conversion (expr);
+      expr = decay_conversion (expr, complain);
       exprtype = TREE_TYPE (expr);
 
       /* If T is a pointer type, v shall be an rvalue of a pointer to
@@ -931,7 +931,8 @@  tinfo_base_init (tinfo_s *ti, tree target)
 
   v = VEC_alloc (constructor_elt, gc, 2);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, vtable_ptr);
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, decay_conversion (name_decl));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
+			  decay_conversion (name_decl, tf_warning_or_error));
 
   init = build_constructor (init_list_type_node, v);
   TREE_CONSTANT (init) = 1;
Index: cp/except.c
===================================================================
--- cp/except.c	(revision 184643)
+++ cp/except.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Handle exceptional things in C++.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2012
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann <tiemann@cygnus.com>
    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
@@ -850,7 +850,7 @@  build_throw (tree exp)
 	}
       else
 	{
-	  tmp = decay_conversion (exp);
+	  tmp = decay_conversion (exp, tf_warning_or_error);
 	  if (tmp == error_mark_node)
 	    return error_mark_node;
 	  exp = build2 (INIT_EXPR, temp_type, object, tmp);
Index: cp/typeck2.c
===================================================================
--- cp/typeck2.c	(revision 184643)
+++ cp/typeck2.c	(working copy)
@@ -1,7 +1,8 @@ 
 /* Report error messages, build initializers, and perform
    some front-end optimizations for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+   2012
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -1518,7 +1519,7 @@  build_x_arrow (tree expr)
 	last_rval = convert_from_reference (last_rval);
     }
   else
-    last_rval = decay_conversion (expr);
+    last_rval = decay_conversion (expr, tf_warning_or_error);
 
   if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
     {
@@ -1544,7 +1545,7 @@  build_x_arrow (tree expr)
    already been checked out to be of aggregate type.  */
 
 tree
-build_m_component_ref (tree datum, tree component)
+build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
 {
   tree ptrmem_type;
   tree objtype;
@@ -1561,18 +1562,18 @@  tree
   ptrmem_type = TREE_TYPE (component);
   if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type))
     {
-      error ("%qE cannot be used as a member pointer, since it is of "
-	     "type %qT",
-	     component, ptrmem_type);
+      if (complain & tf_error)
+	error ("%qE cannot be used as a member pointer, since it is of "
+	       "type %qT", component, ptrmem_type);
       return error_mark_node;
     }
 
   objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
   if (! MAYBE_CLASS_TYPE_P (objtype))
     {
-      error ("cannot apply member pointer %qE to %qE, which is of "
-	     "non-class type %qT",
-	     component, datum, objtype);
+      if (complain & tf_error)
+	error ("cannot apply member pointer %qE to %qE, which is of "
+	       "non-class type %qT", component, datum, objtype);
       return error_mark_node;
     }
 
@@ -1592,9 +1593,9 @@  tree
       if (!binfo)
 	{
 	mismatch:
-	  error ("pointer to member type %qT incompatible with object "
-		 "type %qT",
-		 type, objtype);
+	  if (complain & tf_error)
+	    error ("pointer to member type %qT incompatible with object "
+		   "type %qT", type, objtype);
 	  return error_mark_node;
 	}
       else if (binfo == error_mark_node)
@@ -1618,14 +1619,13 @@  tree
 
       /* Convert object to the correct base.  */
       if (binfo)
-	datum = build_base_path (PLUS_EXPR, datum, binfo, 1,
-				 tf_warning_or_error);
+	datum = build_base_path (PLUS_EXPR, datum, binfo, 1, complain);
 
       /* Build an expression for "object + offset" where offset is the
 	 value stored in the pointer-to-data-member.  */
       ptype = build_pointer_type (type);
       datum = fold_build_pointer_plus (fold_convert (ptype, datum), component);
-      datum = cp_build_indirect_ref (datum, RO_NULL, tf_warning_or_error);
+      datum = cp_build_indirect_ref (datum, RO_NULL, complain);
       /* If the object expression was an rvalue, return an rvalue.  */
       if (!is_lval)
 	datum = move (datum);
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 184643)
+++ cp/pt.c	(working copy)
@@ -5688,7 +5688,7 @@  convert_nontype_argument (tree type, tree expr, ts
      value_dependent_expression_p.  */
   if (TYPE_PTROBV_P (type)
       && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE)
-    expr = decay_conversion (expr);
+    expr = decay_conversion (expr, complain);
 
   /* If we are in a template, EXPR may be non-dependent, but still
      have a syntactic, rather than semantic, form.  For example, EXPR
@@ -5896,7 +5896,7 @@  convert_nontype_argument (tree type, tree expr, ts
 	    }
 	}
 
-      expr = decay_conversion (expr);
+      expr = decay_conversion (expr, complain);
       if (expr == error_mark_node)
 	return error_mark_node;
 
@@ -5981,7 +5981,7 @@  convert_nontype_argument (tree type, tree expr, ts
 	 context information to decay the pointer.  */
       if (!type_unknown_p (expr_type))
 	{
-	  expr = decay_conversion (expr);
+	  expr = decay_conversion (expr, complain);
 	  if (expr == error_mark_node)
 	    return error_mark_node;
 	}
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 184643)
+++ cp/semantics.c	(working copy)
@@ -1382,7 +1382,7 @@  finish_asm_stmt (int volatile_p, tree string, tree
       for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
 	{
 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-	  operand = decay_conversion (TREE_VALUE (t));
+	  operand = decay_conversion (TREE_VALUE (t), tf_warning_or_error);
 
 	  /* If the type of the operand hasn't been determined (e.g.,
 	     because it involves an overloaded function), then issue
@@ -9356,7 +9356,7 @@  maybe_add_lambda_conv_op (tree type)
   body = begin_function_body ();
   compound_stmt = begin_compound_stmt (0);
 
-  finish_return_stmt (decay_conversion (statfn));
+  finish_return_stmt (decay_conversion (statfn, tf_warning_or_error));
 
   finish_compound_stmt (compound_stmt);
   finish_function_body (body);
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 184643)
+++ cp/call.c	(working copy)
@@ -263,7 +263,7 @@  check_dtor_name (tree basetype, tree name)
    pointer-to-member function.  */
 
 tree
-build_addr_func (tree function)
+build_addr_func (tree function, tsubst_flags_t complain)
 {
   tree type = TREE_TYPE (function);
 
@@ -280,7 +280,7 @@  tree
       function = build_address (function);
     }
   else
-    function = decay_conversion (function);
+    function = decay_conversion (function, complain);
 
   return function;
 }
@@ -341,7 +341,7 @@  build_call_a (tree function, int n, tree *argarray
   tree fntype;
   int i;
 
-  function = build_addr_func (function);
+  function = build_addr_func (function, tf_warning_or_error);
 
   gcc_assert (TYPE_PTR_P (TREE_TYPE (function)));
   fntype = TREE_TYPE (TREE_TYPE (function));
@@ -4342,9 +4342,9 @@  build_conditional_expr_1 (tree arg1, tree arg2, tr
 	 since it can't have any effect and since decay_conversion
 	 does not handle that case gracefully.  */
       if (!VOID_TYPE_P (arg2_type))
-	arg2 = decay_conversion (arg2);
+	arg2 = decay_conversion (arg2, complain);
       if (!VOID_TYPE_P (arg3_type))
-	arg3 = decay_conversion (arg3);
+	arg3 = decay_conversion (arg3, complain);
       arg2_type = TREE_TYPE (arg2);
       arg3_type = TREE_TYPE (arg3);
 
@@ -5232,7 +5232,7 @@  build_new_op_1 (enum tree_code code, int flags, tr
     case MEMBER_REF:
       return build_m_component_ref (cp_build_indirect_ref (arg1, RO_NULL, 
                                                            complain), 
-                                    arg2);
+                                    arg2, complain);
 
       /* The caller will deal with these.  */
     case ADDR_EXPR:
@@ -5776,7 +5776,7 @@  convert_like_real (conversion *convs, tree expr, t
 	/* Build up the initializer_list object.  */
 	totype = complete_type (totype);
 	field = next_initializable_field (TYPE_FIELDS (totype));
-	CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array));
+	CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array, complain));
 	field = next_initializable_field (DECL_CHAIN (field));
 	CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
 	new_ctor = build_constructor (totype, vec);
@@ -5812,7 +5812,7 @@  convert_like_real (conversion *convs, tree expr, t
   switch (convs->kind)
     {
     case ck_rvalue:
-      expr = decay_conversion (expr);
+      expr = decay_conversion (expr, complain);
       if (! MAYBE_CLASS_TYPE_P (totype))
 	return expr;
       /* Else fall through.  */
@@ -5938,7 +5938,7 @@  convert_like_real (conversion *convs, tree expr, t
       }
 
     case ck_lvalue:
-      return decay_conversion (expr);
+      return decay_conversion (expr, complain);
 
     case ck_qual:
       /* Warn about deprecated conversion if appropriate.  */
@@ -5982,7 +5982,7 @@  convert_arg_to_ellipsis (tree arg)
 
      The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
      standard conversions are performed.  */
-  arg = decay_conversion (arg);
+  arg = decay_conversion (arg, tf_warning_or_error);
   arg_type = TREE_TYPE (arg);
   /* [expr.call]
 
@@ -6332,8 +6332,9 @@  build_over_call (struct z_candidate *cand, int fla
 	  argarray = alcarray;
 	}
       expr = build_call_array_loc (input_location,
-				   return_type, build_addr_func (fn), nargs,
-				   argarray);
+				   return_type,
+				   build_addr_func (fn, complain),
+				   nargs, argarray);
       if (TREE_THIS_VOLATILE (fn) && cfun)
 	current_function_returns_abnormally = 1;
       return convert_from_reference (expr);
@@ -6750,7 +6751,7 @@  build_over_call (struct z_candidate *cand, int fla
       TREE_TYPE (fn) = t;
     }
   else
-    fn = build_addr_func (fn);
+    fn = build_addr_func (fn, complain);
 
   return build_cxx_call (fn, nargs, argarray);
 }
@@ -6971,7 +6972,7 @@  build_special_member_call (tree instance, tree nam
 	 or destructor, then we fetch the VTT directly.
 	 Otherwise, we look it up using the VTT we were given.  */
       vtt = DECL_CHAIN (CLASSTYPE_VTABLES (current_class_type));
-      vtt = decay_conversion (vtt);
+      vtt = decay_conversion (vtt, complain);
       vtt = build3 (COND_EXPR, TREE_TYPE (vtt),
 		    build2 (EQ_EXPR, boolean_type_node,
 			    current_in_charge_parm, integer_zero_node),
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 184643)
+++ cp/cvt.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* 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, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   2011, 2012 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -550,7 +550,7 @@  force_rvalue (tree expr, tsubst_flags_t complain)
       expr = build_cplus_new (type, expr, complain);
     }
   else
-    expr = decay_conversion (expr);
+    expr = decay_conversion (expr, complain);
 
   return expr;
 }
@@ -1495,7 +1495,8 @@  build_expr_type_conversion (int desires, tree expr
 
       case FUNCTION_TYPE:
       case ARRAY_TYPE:
-	return (desires & WANT_POINTER) ? decay_conversion (expr)
+	return (desires & WANT_POINTER) ? decay_conversion (expr,
+							    tf_warning_or_error)
 					: NULL_TREE;
 
       case COMPLEX_TYPE:
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 184643)
+++ cp/cp-tree.h	(working copy)
@@ -4845,7 +4845,7 @@  extern bool check_dtor_name			(tree, tree);
 
 extern tree build_conditional_expr		(tree, tree, tree, 
                                                  tsubst_flags_t);
-extern tree build_addr_func			(tree);
+extern tree build_addr_func			(tree, tsubst_flags_t);
 extern void set_flags_from_callee		(tree);
 extern tree build_call_a			(tree, int, tree*);
 extern tree build_call_n			(tree, int, ...);
@@ -5769,7 +5769,7 @@  extern tree cxx_sizeof_or_alignof_type		(tree, enu
 extern tree cxx_sizeof_nowarn                   (tree);
 extern tree is_bitfield_expr_with_lowered_type  (const_tree);
 extern tree unlowered_expr_type                 (const_tree);
-extern tree decay_conversion			(tree);
+extern tree decay_conversion			(tree, tsubst_flags_t);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool,
 						 tsubst_flags_t);
 extern tree finish_class_member_access_expr     (tree, tree, bool, 
@@ -5881,7 +5881,7 @@  extern tree digest_init				(tree, tree, tsubst_fla
 extern tree digest_init_flags			(tree, tree, int);
 extern tree build_scoped_ref			(tree, tree, tree *);
 extern tree build_x_arrow			(tree);
-extern tree build_m_component_ref		(tree, tree);
+extern tree build_m_component_ref		(tree, tree, tsubst_flags_t);
 extern tree build_functional_cast		(tree, tree, tsubst_flags_t);
 extern tree add_exception_specifier		(tree, tree, int);
 extern tree merge_exception_specifiers		(tree, tree, tree);