Patchwork [C++] PR 52422 (new patch)

login
register
mail settings
Submitter Paolo Carlini
Date April 18, 2012, 10:13 a.m.
Message ID <4F8E93C3.6030705@oracle.com>
Download mbox | patch
Permalink /patch/153462/
State New
Headers show

Comments

Paolo Carlini - April 18, 2012, 10:13 a.m.
Hi again,
> Hi Jason,
>
> I have a new patch for this issue, another SFINAE issue noticed by 
> Daniel. Compared to the last version, I extended the complain-ization 
> ;) to a few more functions in typeck.c (I think the set is more 
> consistent now) and thoroughly double checked that the return values 
> of all the functions which now get a tsubst_flags_t argument are 
> checked for error_mark_node and in case early return back 
> error_mark_node itself, as you requested last time.
>
> As usual, tested x86_64-linux.
The below is what I'm going to actually commit, as approved by Jason 
off-list with a change to the convert_member_func_to_ptr bits.

Tested x86_64-linux.

Thanks,
Paolo.

/////////////////////
/cp
2012-04-18  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/52422
	* cp-tree.h (build_addr_func, decay_conversion,
	get_member_function_from_ptrfunc,
	build_m_component_ref, convert_member_func_to_ptr):
	Add tsubst_flags_t parameter.
	* typeck.c (cp_default_conversion): Add.
	(decay_conversion, default_conversion,
	get_member_function_from_ptrfunc, convert_member_func_to_ptr):
	Add tsubst_flags_t parameter and use it throughout.
	(cp_build_indirect_ref, cp_build_array_ref,
	cp_build_function_call_vec, convert_arguments, build_x_binary_op,
	cp_build_binary_op, cp_build_unary_op, build_reinterpret_cast_1,
	build_const_cast_1, expand_ptrmemfunc_cst,
	convert_for_initialization): Adjust.
	* init.c (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.
	* decl2.c (build_offset_ref_call_from_tree): 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 (cp_convert_to_pointer, force_rvalue,
	build_expr_type_conversion): Likewise.

/testsuite
2012-04-18  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/52422
	* g++.dg/cpp0x/sfinae33.C: New.
	* g++.dg/cpp0x/sfinae34.C: Likewise.

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++11 }
+
+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,27 @@ 
+// PR c++/52422
+// { dg-options -std=c++11 }
+
+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 186563)
+++ cp/typeck.c	(working copy)
@@ -1818,7 +1818,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;
@@ -1832,7 +1832,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;
     }
 
@@ -1851,13 +1852,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;
@@ -1869,7 +1871,9 @@  tree
 
       if (TREE_CODE (exp) == COMPOUND_EXPR)
 	{
-	  tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
+	  tree op1 = decay_conversion (TREE_OPERAND (exp, 1), complain);
+	  if (op1 == error_mark_node)
+            return error_mark_node;
 	  return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
 			 TREE_OPERAND (exp, 0), op1);
 	}
@@ -1877,7 +1881,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;
 	}
 
@@ -1892,7 +1897,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);
     }
 
@@ -1931,8 +1936,8 @@  tree
    applied to both operands to a binary operator before determining
    what additional conversions should apply.  */
 
-tree
-default_conversion (tree exp)
+static tree
+cp_default_conversion (tree exp, tsubst_flags_t complain)
 {
   /* Check for target-specific promotions.  */
   tree promoted_type = targetm.promoted_type (TREE_TYPE (exp));
@@ -1944,11 +1949,19 @@  tree
   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, complain);
 
   return exp;
 }
 
+/* C version.  */
+
+tree
+default_conversion (tree exp)
+{
+  return cp_default_conversion (exp, tf_warning_or_error);
+}
+
 /* EXPR is an expression with an integral or enumeration type.
    Perform the integral promotions in [conv.prom], and return the
    converted value.  */
@@ -2758,14 +2771,14 @@  cp_build_indirect_ref (tree ptr, ref_operator erro
 {
   tree pointer, type;
 
-  if (ptr == error_mark_node)
-    return error_mark_node;
-
   if (ptr == current_class_ptr)
     return current_class_ref;
 
   pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
-	     ? ptr : decay_conversion (ptr));
+	     ? ptr : decay_conversion (ptr, complain));
+  if (pointer == error_mark_node)
+    return error_mark_node;
+
   type = TREE_TYPE (pointer);
 
   if (POINTER_TYPE_P (type))
@@ -2982,8 +2995,8 @@  cp_build_array_ref (location_t loc, tree array, tr
     }
 
   {
-    tree ar = default_conversion (array);
-    tree ind = default_conversion (idx);
+    tree ar = cp_default_conversion (array, complain);
+    tree ind = cp_default_conversion (idx, complain);
 
     /* Put the integer in IND to simplify error checking.  */
     if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
@@ -2993,8 +3006,8 @@  cp_build_array_ref (location_t loc, tree array, tr
 	ind = temp;
       }
 
-    if (ar == error_mark_node)
-      return ar;
+    if (ar == error_mark_node || ind == error_mark_node)
+      return error_mark_node;
 
     if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)
       {
@@ -3040,7 +3053,8 @@  build_array_ref (location_t loc, tree array, tree
    later has the right member.  */
 
 tree
-get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
+get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function,
+				  tsubst_flags_t complain)
 {
   if (TREE_CODE (function) == OFFSET_REF)
     function = TREE_OPERAND (function, 1);
@@ -3059,13 +3073,14 @@  tree
 	      /* 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), complain);
 	      e1 = convert (fntype, e1);
 	      return e1;
 	    }
 	  else
 	    {
-	      error ("object missing in use of %qE", function);
+	      if (complain & tf_error)
+		error ("object missing in use of %qE", function);
 	      return error_mark_node;
 	    }
 	}
@@ -3085,25 +3100,32 @@  tree
 	case ptrmemfunc_vbit_in_pfn:
 	  e1 = cp_build_binary_op (input_location,
 				   BIT_AND_EXPR, idx, integer_one_node,
-				   tf_warning_or_error);
+				   complain);
 	  idx = cp_build_binary_op (input_location,
 				    MINUS_EXPR, idx, integer_one_node,
-				    tf_warning_or_error);
+				    complain);
+	  if (idx == error_mark_node)
+	    return error_mark_node;
 	  break;
 
 	case ptrmemfunc_vbit_in_delta:
 	  e1 = cp_build_binary_op (input_location,
 				   BIT_AND_EXPR, delta, integer_one_node,
-				   tf_warning_or_error);
+				   complain);
 	  delta = cp_build_binary_op (input_location,
 				      RSHIFT_EXPR, delta, integer_one_node,
-				      tf_warning_or_error);
+				      complain);
+	  if (delta == error_mark_node)
+	    return error_mark_node;
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
+      if (e1 == error_mark_node)
+	return error_mark_node;
+
       /* Convert down to the right base before using the instance.  A
 	 special case is that in a pointer to member of class C, C may
 	 be incomplete.  In that case, the function will of course be
@@ -3117,7 +3139,7 @@  tree
 	  basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
 				  basetype, ba_check, NULL);
 	  instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype,
-					  1, tf_warning_or_error);
+					  1, complain);
 	  if (instance_ptr == error_mark_node)
 	    return error_mark_node;
 	}
@@ -3130,7 +3152,10 @@  tree
       /* Next extract the vtable pointer from the object.  */
       vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
 		     instance_ptr);
-      vtbl = cp_build_indirect_ref (vtbl, RO_NULL, tf_warning_or_error);
+      vtbl = cp_build_indirect_ref (vtbl, RO_NULL, complain);
+      if (vtbl == error_mark_node)
+	return error_mark_node;
+
       /* If the object is not dynamic the access invokes undefined
 	 behavior.  As it is not executed in this case silence the
 	 spurious warnings it may provoke.  */
@@ -3138,17 +3163,21 @@  tree
 
       /* Finally, extract the function pointer from the vtable.  */
       e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx);
-      e2 = cp_build_indirect_ref (e2, RO_NULL, tf_warning_or_error);
+      e2 = cp_build_indirect_ref (e2, RO_NULL, complain);
+      if (e2 == error_mark_node)
+	return error_mark_node;
       TREE_CONSTANT (e2) = 1;
 
       /* When using function descriptors, the address of the
 	 vtable entry is treated as a function pointer.  */
       if (TARGET_VTABLE_USES_DESCRIPTORS)
 	e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
-		     cp_build_addr_expr (e2, tf_warning_or_error));
+		     cp_build_addr_expr (e2, complain));
 
       e2 = fold_convert (TREE_TYPE (e3), e2);
-      e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
+      e1 = build_conditional_expr (e1, e2, e3, complain);
+      if (e1 == error_mark_node)
+	return error_mark_node;
 
       /* Make sure this doesn't get evaluated first inside one of the
 	 branches of the COND_EXPR.  */
@@ -3261,13 +3290,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)
@@ -3432,7 +3461,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)
@@ -3559,7 +3588,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);
@@ -3723,16 +3752,16 @@  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
     {
       if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
-	op0 = default_conversion (op0);
+	op0 = cp_default_conversion (op0, complain);
       if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
-	op1 = default_conversion (op1);
+	op1 = cp_default_conversion (op1, complain);
     }
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
@@ -5129,7 +5158,11 @@  cp_build_unary_op (enum tree_code code, tree xarg,
 	{
 	  code = CONJ_EXPR;
 	  if (!noconvert)
-	    arg = default_conversion (arg);
+	    {
+	      arg = cp_default_conversion (arg, complain);
+	      if (arg == error_mark_node)
+		return error_mark_node;
+	    }
 	}
       else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM
 						   | WANT_VECTOR_OR_COMPLEX,
@@ -5143,7 +5176,11 @@  cp_build_unary_op (enum tree_code code, tree xarg,
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
 	errstring = _("wrong type argument to abs");
       else if (!noconvert)
-	arg = default_conversion (arg);
+	{
+	  arg = cp_default_conversion (arg, complain);
+	  if (arg == error_mark_node)
+	    return error_mark_node;
+	}
       break;
 
     case CONJ_EXPR:
@@ -5151,7 +5188,11 @@  cp_build_unary_op (enum tree_code code, tree xarg,
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
 	errstring = _("wrong type argument to conjugation");
       else if (!noconvert)
-	arg = default_conversion (arg);
+	{
+	  arg = cp_default_conversion (arg, complain);
+	  if (arg == error_mark_node)
+	    return error_mark_node;
+	}
       break;
 
     case TRUTH_NOT_EXPR:
@@ -6129,7 +6170,7 @@  build_static_cast (tree type, tree expr, tsubst_fl
    converted expression.  */
 
 tree
-convert_member_func_to_ptr (tree type, tree expr)
+convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain)
 {
   tree intype;
   tree decl;
@@ -6138,21 +6179,27 @@  tree
   gcc_assert (TYPE_PTRMEMFUNC_P (intype)
 	      || TREE_CODE (intype) == METHOD_TYPE);
 
+  if (!(complain & tf_warning_or_error))
+    return error_mark_node;
+
   if (pedantic || warn_pmf2ptr)
     pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpmf_conversions,
 	     "converting from %qT to %qT", intype, type);
 
   if (TREE_CODE (intype) == METHOD_TYPE)
-    expr = build_addr_func (expr);
+    expr = build_addr_func (expr, complain);
   else if (TREE_CODE (expr) == PTRMEM_CST)
     expr = build_address (PTRMEM_CST_MEMBER (expr));
   else
     {
       decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
       decl = build_address (decl);
-      expr = get_member_function_from_ptrfunc (&decl, expr);
+      expr = get_member_function_from_ptrfunc (&decl, expr, complain);
     }
 
+  if (expr == error_mark_node)
+    return error_mark_node;
+
   return build_nop (type, expr);
 }
 
@@ -6230,12 +6277,12 @@  build_reinterpret_cast_1 (tree type, tree expr, bo
       && TYPE_PTR_P (type)
       && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
 	  || VOID_TYPE_P (TREE_TYPE (type))))
-    return convert_member_func_to_ptr (type, expr);
+    return convert_member_func_to_ptr (type, expr, complain);
 
   /* 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.  */
@@ -6474,12 +6521,17 @@  build_const_cast_1 (tree dst_type, tree expr, tsub
 	  if (reference_type)
 	    {
 	      expr = cp_build_addr_expr (expr, complain);
+	      if (expr == error_mark_node)
+		return error_mark_node;
 	      expr = build_nop (reference_type, expr);
 	      return convert_from_reference (expr);
 	    }
 	  else
 	    {
-	      expr = decay_conversion (expr);
+	      expr = decay_conversion (expr, complain);
+	      if (expr == error_mark_node)
+		return error_mark_node;
+
 	      /* 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.  */
@@ -7333,7 +7385,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'
@@ -7667,7 +7720,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 186563)
+++ 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.
@@ -3194,7 +3194,10 @@  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 = decay_conversion (base, complain);
+      if (base == error_mark_node)
+	return error_mark_node;
+      base = cp_convert (ptype, base);
     }
   else
     ptype = atype;
@@ -3243,7 +3246,9 @@  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);
+      if (base2 == error_mark_node)
+	return error_mark_node;
       itype = TREE_TYPE (base2);
       base2 = get_temp_regvar (itype, base2);
       itype = TREE_TYPE (itype);
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 186563)
+++ cp/decl.c	(working copy)
@@ -4668,7 +4668,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
@@ -6535,7 +6535,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 186563)
+++ cp/rtti.c	(working copy)
@@ -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
@@ -936,7 +936,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 186563)
+++ 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 186563)
+++ 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)
 
@@ -1528,7 +1529,7 @@  build_x_arrow (tree expr, tsubst_flags_t complain)
 	last_rval = convert_from_reference (last_rval);
     }
   else
-    last_rval = decay_conversion (expr);
+    last_rval = decay_conversion (expr, complain);
 
   if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
     {
@@ -1557,7 +1558,7 @@  build_x_arrow (tree expr, tsubst_flags_t complain)
    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;
@@ -1574,18 +1575,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;
     }
 
@@ -1605,9 +1606,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)
@@ -1631,14 +1632,20 @@  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);
+	  if (datum == error_mark_node)
+	    return error_mark_node;
+	}
 
       /* 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 (datum == error_mark_node)
+	return error_mark_node;
+
       /* If the object expression was an rvalue, return an rvalue.  */
       if (!is_lval)
 	datum = move (datum);
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 186563)
+++ cp/pt.c	(working copy)
@@ -5692,7 +5692,11 @@  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 (expr == error_mark_node)
+	return error_mark_node;
+    }
 
   /* If we are in a template, EXPR may be non-dependent, but still
      have a syntactic, rather than semantic, form.  For example, EXPR
@@ -5900,7 +5904,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;
 
@@ -5985,7 +5989,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 186563)
+++ 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
@@ -9365,7 +9365,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/decl2.c
===================================================================
--- cp/decl2.c	(revision 186563)
+++ cp/decl2.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* Process declarations and variables for C++ compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 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.
@@ -4175,7 +4175,8 @@  build_offset_ref_call_from_tree (tree fn, VEC(tree
     {
       tree object_addr = cp_build_addr_expr (object, tf_warning_or_error);
       fn = TREE_OPERAND (fn, 1);
-      fn = get_member_function_from_ptrfunc (&object_addr, fn);
+      fn = get_member_function_from_ptrfunc (&object_addr, fn,
+					     tf_warning_or_error);
       VEC_safe_insert (tree, gc, *args, 0, object_addr);
     }
 
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 186563)
+++ 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);
 
@@ -275,12 +275,13 @@  tree
 	{
 	  tree object = build_address (TREE_OPERAND (function, 0));
 	  return get_member_function_from_ptrfunc (&object,
-						   TREE_OPERAND (function, 1));
+						   TREE_OPERAND (function, 1),
+						   complain);
 	}
       function = build_address (function);
     }
   else
-    function = decay_conversion (function);
+    function = decay_conversion (function, complain);
 
   return function;
 }
@@ -341,7 +342,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));
@@ -4373,9 +4374,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);
 
@@ -5263,7 +5264,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:
@@ -5807,7 +5808,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);
@@ -5844,7 +5845,10 @@  convert_like_real (conversion *convs, tree expr, t
   switch (convs->kind)
     {
     case ck_rvalue:
-      expr = decay_conversion (expr);
+      expr = decay_conversion (expr, complain);
+      if (expr == error_mark_node)
+	return error_mark_node;
+
       if (! MAYBE_CLASS_TYPE_P (totype))
 	return expr;
       /* Else fall through.  */
@@ -5970,7 +5974,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.  */
@@ -6014,7 +6018,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]
 
@@ -6341,7 +6345,7 @@  build_over_call (struct z_candidate *cand, int fla
      errors will be deferred until the template is instantiated.  */
   if (processing_template_decl)
     {
-      tree expr;
+      tree expr, addr;
       tree return_type;
       const tree *argarray;
       unsigned int nargs;
@@ -6363,9 +6367,12 @@  build_over_call (struct z_candidate *cand, int fla
 	    alcarray[ix + 1] = arg;
 	  argarray = alcarray;
 	}
-      expr = build_call_array_loc (input_location,
-				   return_type, build_addr_func (fn), nargs,
-				   argarray);
+
+      addr = build_addr_func (fn, complain);
+      if (addr == error_mark_node)
+	return error_mark_node;
+      expr = build_call_array_loc (input_location, return_type,
+				   addr, nargs, argarray);
       if (TREE_THIS_VOLATILE (fn) && cfun)
 	current_function_returns_abnormally = 1;
       return convert_from_reference (expr);
@@ -6782,7 +6789,11 @@  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);
+      if (fn == error_mark_node)
+	return error_mark_node;
+    }
 
   return build_cxx_call (fn, nargs, argarray);
 }
@@ -7003,7 +7014,9 @@  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);
+      if (vtt == error_mark_node)
+	return error_mark_node;
       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 186563)
+++ 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.
@@ -109,7 +109,7 @@  cp_convert_to_pointer (tree type, tree expr)
     {
       if (TYPE_PTRMEMFUNC_P (intype)
 	  || TREE_CODE (intype) == METHOD_TYPE)
-	return convert_member_func_to_ptr (type, expr);
+	return convert_member_func_to_ptr (type, expr, tf_warning_or_error);
       if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
 	return build_nop (type, expr);
       intype = TREE_TYPE (expr);
@@ -188,7 +188,8 @@  cp_convert_to_pointer (tree type, tree expr)
 	    {
 	      tree object = TREE_OPERAND (expr, 0);
 	      return get_member_function_from_ptrfunc (&object,
-						       TREE_OPERAND (expr, 1));
+						       TREE_OPERAND (expr, 1),
+						       tf_warning_or_error);
 	    }
 	}
       error ("cannot convert %qE from type %qT to type %qT",
@@ -550,7 +551,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 +1496,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 186563)
+++ cp/cp-tree.h	(working copy)
@@ -4854,7 +4854,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, ...);
@@ -5782,7 +5782,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, 
@@ -5794,7 +5794,7 @@  extern tree cp_build_indirect_ref		(tree, ref_oper
 extern tree build_array_ref			(location_t, tree, tree);
 extern tree cp_build_array_ref			(location_t, tree, tree,
 						 tsubst_flags_t);
-extern tree get_member_function_from_ptrfunc	(tree *, tree);
+extern tree get_member_function_from_ptrfunc	(tree *, tree, tsubst_flags_t);
 extern tree cp_build_function_call              (tree, tree, tsubst_flags_t);
 extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
 						ATTRIBUTE_SENTINEL;
@@ -5865,7 +5865,7 @@  extern tree build_nop				(tree, tree);
 extern tree non_reference			(tree);
 extern tree lookup_anon_field			(tree, tree);
 extern bool invalid_nonstatic_memfn_p		(const_tree, tsubst_flags_t);
-extern tree convert_member_func_to_ptr		(tree, tree);
+extern tree convert_member_func_to_ptr		(tree, tree, tsubst_flags_t);
 extern tree convert_ptrmem			(tree, tree, bool, bool,
 						 tsubst_flags_t);
 extern int lvalue_or_else			(tree, enum lvalue_use,
@@ -5895,7 +5895,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, tsubst_flags_t);
-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);