diff mbox

[C++] Implement __is_convertible_to

Message ID 4C371DF7.90701@oracle.com
State New
Headers show

Commit Message

Paolo Carlini July 9, 2010, 1:02 p.m. UTC
Hi all, hi Jason,

thus, this is my current best try at the code I have been working on the
last days. Actually, most of the changes are pretty straightforward, but
compared to the previous drafts I made efforts to decouple as much as
possible the implementation from the existing functionalities of the C++
front-end: now I'm pretty sure now that we should not be at risk of
creating regressions elsewhere outside __is_convertible_to. Anyway, the
patch as-is regtests ok, in the library too, where we have a good amount
of additional testcases for std::is_convertible, also exercising corner
cases pointed out by Howard time ago. What else... I wish I could figure
out something a little less "low level" than exploiting
force_target_expr, but everything else I tried failed, in particular
compile-time errors when the from type has deleted constructors, etc
(with force_target_expr we get, properly, correct boolean values for the
trait, no compile-time errors, as far as I can see). Also note that the
trait_is_convertible_to function itself lives in call.c, not in
semantics.c, due to its use of facilities, like convert_like_real, local
to that file.

Tested x86_64-linux. Is the patch Ok for mainline?

Thanks,
Paolo.

///////////////////
cp/
2010-07-09  Paolo Carlini  <paolo.carlini@oracle.com>

	* call.c (trait_is_convertible_to): Add.
	(convert_like_real): Update prototype, add a flags parameter; adjust
	convert_like_real, build_over_call, build_temp, and convert_ptrmem 
	calls.
	(perform_implicit_conversion_flags, initialize_reference): Adjust
	convert_like_real call.
	(convert_like, convert_like_with_context): Adjust,
	(build_temp): Update prototype, add a tsubst_flags_t parameter.
	* semantics.c (trait_expr_value): Call trait_is_convertible_to.
	(finish_trait_expr): Remove __is_convertible_to sorry message;
	check its arguments.
	* cp-tree.h: Declare trait_is_convertible_to; update build_ptrmemfunc
	and convert_ptrmem prototypes.
	* cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem
	and build_ptrmemfunc calls.
	* typeck.c (get_delta_difference): Update prototype, add a 
	tsubst_flags_t parameter; update get_delta_difference_1 calls and
	add checks for error_mark_node.
	(get_delta_difference_1): Update prototype, add a tsubst_flags_t
	parameter; update lookup_base call.
	(build_ptrmemfunc): Update prototype, add a tsubst_flags_t
	parameter; update get_delta_difference call and add check for
	error_mark_node.
	(convert_ptrmem): Update prototype, add a tsubst_flags_t
	parameter; update get_delta_difference call and add check for
	error_mark_node;  update build_ptrmemfunc call.
	(build_static_cast_1): Adjust convert_ptrmem call.
	(expand_ptrmemfunc_cst): Adjust get_delta_difference call.
 
testsuite/
2010-07-09  Paolo Carlini  <paolo.carlini@oracle.com>

	* g++.dg/ext/is_convertible_to.C: New.
	* g++.dg/ext/is_class_error2.C: Adjust.

libstdc++-v3
2010-07-09  Paolo Carlini  <paolo.carlini@oracle.com>

	* include/std/type_traits (is_convertible): Use __is_convertible_to.
	* testsuite/20_util/make_signed/requirements/typedefs_neg.cc:
	Adjust dg-error line numbers.
	* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc:
	Likewise.
	* testsuite/20_util/declval/requirements/1_neg.cc: Likewise.
diff mbox

Patch

Index: gcc/testsuite/g++.dg/ext/is_class_error2.C
===================================================================
--- gcc/testsuite/g++.dg/ext/is_class_error2.C	(revision 161990)
+++ gcc/testsuite/g++.dg/ext/is_class_error2.C	(working copy)
@@ -13,7 +13,7 @@  template<int> void foo()
   __is_abstract(int)(); // { dg-error "'__is_abstract\\(int\\)' cannot be used" }
   __is_base_of(int, float)(); // { dg-error "'__is_base_of\\(int, float\\)' cannot be used" }
   __is_class(int)(); // { dg-error "'__is_class\\(int\\)' cannot be used" }
-  __is_convertible_to(int, float)(); // { dg-message "unimplemented" }
+  __is_convertible_to(int, float)(); // { dg-error "'__is_convertible_to\\(int, float\\)' cannot be used" }
   __is_empty(int)(); // { dg-error "'__is_empty\\(int\\)' cannot be used" }
   __is_enum(int)(); // { dg-error "'__is_enum\\(int\\)' cannot be used" }
   __is_pod(int)(); // { dg-error "'__is_pod\\(int\\)' cannot be used" }
Index: gcc/testsuite/g++.dg/ext/is_convertible_to.C
===================================================================
--- gcc/testsuite/g++.dg/ext/is_convertible_to.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/is_convertible_to.C	(revision 0)
@@ -0,0 +1,142 @@ 
+// { dg-do "run" }
+#include <cassert>
+
+class A
+{ };
+
+class B
+: public A { };
+
+class C
+: public A { };
+
+enum E
+{
+  e0
+};
+
+class D
+: public B, public C { };
+
+class F
+: private A { };
+
+class G
+: public virtual A { };
+
+struct X
+{
+  operator int();
+};
+
+struct Y
+{
+  operator X();
+};
+
+class Z
+{
+  operator int();
+};
+
+template<typename T, typename U>
+  bool
+  f()
+  { return __is_convertible_to(T, U); } 
+
+template<typename T, typename U>
+  class My
+  {
+  public:
+    bool
+    f()
+    { return !!__is_convertible_to(T, U); }
+  };
+
+template<typename T, typename U>
+  class My2
+  {
+  public:
+    static const bool trait = __is_convertible_to(T, U);
+  };
+
+template<typename T, typename U>
+  const bool My2<T, U>::trait;
+
+template<typename T, typename U, bool b = __is_convertible_to(T, U)>
+  struct My3_help
+  { static const bool trait = b; };
+
+template<typename T, typename U, bool b>
+  const bool My3_help<T, U, b>::trait;
+
+template<typename T, typename U>
+  class My3
+  {
+  public:
+    bool
+    f()
+    { return My3_help<T, U>::trait; }
+  };
+
+#define PTEST(T, U) (__is_convertible_to(T, U) && f<T, U>() \
+		     && My<T, U>().f() && My2<T, U>::trait && My3<T, U>().f())
+
+#define NTEST(T, U) (!__is_convertible_to(T, U) && !f<T, U>() \
+		     && !My<T, U>().f() && !My2<T, U>::trait \
+		     && !My3<T, U>().f())
+
+int main()
+{
+  assert (NTEST (int, void));
+  assert (NTEST (void, int));
+  assert (PTEST (void, void));
+  assert (PTEST (int, float));
+  assert (PTEST (float, int));
+  assert (PTEST (int*, const int*));
+  assert (NTEST (const int*, int*));
+  assert (PTEST (int*, void*));
+  assert (NTEST (void*, int*));
+  assert (NTEST (int*, float*));
+  assert (PTEST (int&, const int&));
+  assert (NTEST (const int&, int&));
+  assert (PTEST (int&, int));
+  assert (NTEST (int, int&));
+  assert (PTEST (const int, const int&));
+  assert (NTEST (volatile int, volatile int&));
+  assert (NTEST (const volatile int, const volatile int&));
+  assert (NTEST (int (int), int (int)));
+  assert (NTEST (int[], int[]));
+  assert (PTEST (int[], int*));
+  assert (PTEST (int (int), int (*) (int)));
+  assert (NTEST (int (int), int (&) (int)));
+  assert (PTEST (A, A));
+  assert (NTEST (int, A));  
+  assert (NTEST (A, int));  
+  assert (PTEST (B, A));
+  assert (NTEST (A, B));
+  assert (PTEST (B*, A*));
+  assert (NTEST (A*, B*));
+  assert (PTEST (B&, A&));
+  assert (NTEST (A&, B&));
+  assert (PTEST (int (A::*), int (B::*)));
+  assert (NTEST (int (B::*), int (A::*)));
+  assert (PTEST (int (A::*) (int), int (B::*) (int)));
+  assert (NTEST (int (B::*) (int), int (A::*) (int)));
+  assert (PTEST (E, int));
+  assert (NTEST (int, E));
+  assert (NTEST (D, A));
+  assert (NTEST (F, A));
+  assert (NTEST (F*, A*));
+  assert (NTEST (F&, A&));
+  assert (NTEST (int (A::*), int (F::*)));
+  assert (NTEST (int (A::*) (int), int (F::*) (int)));
+  assert (NTEST (int (A::*), int (G::*)));
+  assert (NTEST (int (A::*) (int), int (G::*) (int)));
+  assert (PTEST (X, int));
+  assert (NTEST (Y, int));
+  assert (PTEST (Y, X));
+  assert (NTEST (Z, int));
+
+  return 0;
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 161990)
+++ gcc/cp/typeck.c	(working copy)
@@ -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)
 
@@ -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);
@@ -5254,7 +5254,8 @@  cp_build_unary_op (enum tree_code code, tree xarg,
 	{
 	  build_ptrmemfunc_type (argtype);
 	  val = build_ptrmemfunc (argtype, val, 0,
-				  /*c_cast_p=*/false);
+				  /*c_cast_p=*/false,
+				  tf_warning_or_error);
 	}
 
       return val;
@@ -5669,7 +5670,7 @@  check_for_casting_away_constness (tree src_type, t
 
 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))
     {
@@ -5680,7 +5681,10 @@  convert_ptrmem (tree type, tree expr, bool allow_i
       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;
@@ -5704,7 +5708,7 @@  convert_ptrmem (tree type, tree expr, bool allow_i
     }
   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
@@ -5940,7 +5944,7 @@  build_static_cast_1 (tree type, tree expr, bool c_
 	  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);
 	}
     }
 
@@ -6855,20 +6859,30 @@  build_x_modify_expr (tree lhs, enum tree_code modi
 
 /* 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;
 
-  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
+  if (complain & tf_error)
+    binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
+  else
+    binfo = lookup_base (to, from,
+			 ba_quiet | (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;
     }
@@ -6880,22 +6894,26 @@  static tree
 	/* 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
@@ -6905,7 +6923,7 @@  static tree
 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;
 
@@ -6913,25 +6931,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;
@@ -6990,7 +7020,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;
@@ -7017,7 +7048,9 @@  tree
       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
@@ -7100,7 +7133,7 @@  expand_ptrmemfunc_cst (tree cst, tree *delta, tree
 
   /* 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));
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 161990)
+++ gcc/cp/semantics.c	(working copy)
@@ -5039,8 +5039,7 @@  trait_expr_value (cp_trait_kind kind, tree type1,
       return (NON_UNION_CLASS_TYPE_P (type1));
 
     case CPTK_IS_CONVERTIBLE_TO:
-      /* TODO  */
-      return false;
+      return trait_is_convertible_to (type1, type2);
 
     case CPTK_IS_EMPTY:
       return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1));
@@ -5113,12 +5112,6 @@  finish_trait_expr (cp_trait_kind kind, tree type1,
 	      || kind == CPTK_IS_TRIVIAL
 	      || kind == CPTK_IS_UNION);
 
-  if (kind == CPTK_IS_CONVERTIBLE_TO)
-    {
-      sorry ("__is_convertible_to");
-      return error_mark_node;
-    }
-
   if (type1 == error_mark_node
       || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
 	  && type2 == error_mark_node))
@@ -5171,12 +5164,24 @@  finish_trait_expr (cp_trait_kind kind, tree type1,
 	}
       break;
 
+    case CPTK_IS_CONVERTIBLE_TO:
+      if (!check_trait_type (type1))
+	{
+	  error ("incomplete type %qT not allowed", type1);
+	  return error_mark_node;
+	}
+      if (!check_trait_type (type2))
+	{
+	  error ("incomplete type %qT not allowed", type2);
+	  return error_mark_node;
+	}
+      break;
+
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
     case CPTK_IS_UNION:
       break;
     
-    case CPTK_IS_CONVERTIBLE_TO:
     default:
       gcc_unreachable ();
     }
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 161990)
+++ gcc/cp/call.c	(working copy)
@@ -139,13 +139,13 @@  static tree build_java_interface_fn_ref (tree, tre
 #define convert_like(CONV, EXPR, COMPLAIN)			\
   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0,		\
 		     /*issue_conversion_warnings=*/true,	\
-		     /*c_cast_p=*/false, (COMPLAIN))
+		     /*c_cast_p=*/false, (COMPLAIN), LOOKUP_NORMAL)
 #define convert_like_with_context(CONV, EXPR, FN, ARGNO, COMPLAIN )	\
   convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0,			\
 		     /*issue_conversion_warnings=*/true,		\
-		     /*c_cast_p=*/false, (COMPLAIN))
+		     /*c_cast_p=*/false, (COMPLAIN), LOOKUP_NORMAL)
 static tree convert_like_real (conversion *, tree, tree, int, int, bool,
-			       bool, tsubst_flags_t);
+			       bool, tsubst_flags_t, int);
 static void op_error (enum tree_code, enum tree_code, tree, tree,
 		      tree, bool);
 static VEC(tree,gc) *resolve_args (VEC(tree,gc) *);
@@ -204,7 +204,7 @@  static void add_candidates (tree, tree, const VEC(
 			    tree, tree, int, struct z_candidate **);
 static conversion *merge_conversion_sequences (conversion *, conversion *);
 static bool magic_varargs_p (tree);
-static tree build_temp (tree, tree, int, diagnostic_t *);
+static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
 
 /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
    NAME can take many forms...  */
@@ -4851,7 +4851,7 @@  enforce_access (tree basetype_path, tree decl, tre
 
 static tree
 build_temp (tree expr, tree type, int flags,
-	    diagnostic_t *diagnostic_kind)
+	    diagnostic_t *diagnostic_kind, tsubst_flags_t complain)
 {
   int savew, savee;
   VEC(tree,gc) *args;
@@ -4859,7 +4859,7 @@  build_temp (tree expr, tree type, int flags,
   savew = warningcount, savee = errorcount;
   args = make_tree_vector_single (expr);
   expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
-				    &args, type, flags, tf_warning_or_error);
+				    &args, type, flags, complain);
   release_tree_vector (args);
   if (warningcount > savew)
     *diagnostic_kind = DK_WARNING;
@@ -4911,11 +4911,10 @@  conversion_null_warnings (tree totype, tree expr,
 static tree
 convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 		   int inner, bool issue_conversion_warnings,
-		   bool c_cast_p, tsubst_flags_t complain)
+		   bool c_cast_p, tsubst_flags_t complain, int flags)
 {
   tree totype = convs->type;
   diagnostic_t diag_kind;
-  int flags;
 
   if (convs->bad_p
       && convs->kind != ck_user
@@ -4941,14 +4940,14 @@  convert_like_real (conversion *convs, tree expr, t
 	      expr = convert_like_real (t, expr, fn, argnum, 1,
 					/*issue_conversion_warnings=*/false,
 					/*c_cast_p=*/false,
-					complain);
+					complain, flags);
 	      break;
 	    }
 	  else if (t->kind == ck_ambig)
 	    return convert_like_real (t, expr, fn, argnum, 1,
 				      /*issue_conversion_warnings=*/false,
 				      /*c_cast_p=*/false,
-				      complain);
+				      complain, flags);
 	  else if (t->kind == ck_identity)
 	    break;
 	}
@@ -4997,7 +4996,7 @@  convert_like_real (conversion *convs, tree expr, t
 	for (i = 0; i < cand->num_convs; ++i)
 	  cand->convs[i]->user_conv_p = true;
 
-	expr = build_over_call (cand, LOOKUP_NORMAL, complain);
+	expr = build_over_call (cand, flags, complain);
 
 	/* If this is a constructor or a function returning an aggr type,
 	   we need to build up a TARGET_EXPR.  */
@@ -5064,7 +5063,7 @@  convert_like_real (conversion *convs, tree expr, t
 	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
 	  {
 	    tree sub = convert_like_real (convs->u.list[ix], val, fn, argnum,
-					  1, false, false, complain);
+					  1, false, false, complain, flags);
 	    if (sub == error_mark_node)
 	      return sub;
 	    check_narrowing (TREE_TYPE (sub), val);
@@ -5099,7 +5098,8 @@  convert_like_real (conversion *convs, tree expr, t
 			    convs->kind == ck_ref_bind ? -1 : 1,
 			    convs->kind == ck_ref_bind ? issue_conversion_warnings : false, 
 			    c_cast_p,
-			    complain);
+			    complain,
+			    LOOKUP_NORMAL);
   if (expr == error_mark_node)
     return error_mark_node;
 
@@ -5132,7 +5132,7 @@  convert_like_real (conversion *convs, tree expr, t
 	   conversion (i.e. the second step of copy-initialization), so
 	   don't allow any more.  */
 	flags |= LOOKUP_NO_CONVERSION;
-      expr = build_temp (expr, totype, flags, &diag_kind);
+      expr = build_temp (expr, totype, flags, &diag_kind, complain);
       if (diag_kind && fn)
 	{
 	  if ((complain & tf_error))
@@ -5246,7 +5246,7 @@  convert_like_real (conversion *convs, tree expr, t
 
     case ck_pmem:
       return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
-			     c_cast_p);
+			     c_cast_p, complain);
 
     default:
       break;
@@ -7597,7 +7597,8 @@  can_convert_arg_bad (tree to, tree from, tree arg,
    doing a bad conversion, convert_like will complain.  */
 
 tree
-perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain, int flags)
+perform_implicit_conversion_flags (tree type, tree expr,
+				   tsubst_flags_t complain, int flags)
 {
   conversion *conv;
   void *p;
@@ -7698,7 +7699,8 @@  perform_direct_initialization_if_possible (tree ty
     expr = convert_like_real (conv, expr, NULL_TREE, 0, 0,
 			      /*issue_conversion_warnings=*/false,
 			      c_cast_p,
-			      complain);
+			      complain,
+			      LOOKUP_NORMAL);
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
@@ -7706,6 +7708,43 @@  perform_direct_initialization_if_possible (tree ty
   return expr;
 }
 
+/* Called from trait_expr_value to evaluate __is_convertible_to.  */
+
+bool
+trait_is_convertible_to (tree from, tree to)
+{
+  if (error_operand_p (from) || error_operand_p (to))
+    return false;
+
+  if (VOID_TYPE_P (from))
+    return VOID_TYPE_P (to) ? true : false;
+  else
+    {
+      tree expr = force_target_expr (from, build_dummy_object (from));
+      conversion *conv;
+      void *p;
+
+      /* Get the high-water mark for the CONVERSION_OBSTACK.  */
+      p = conversion_obstack_alloc (0);
+
+      conv = implicit_conversion (to, TREE_TYPE (expr), expr,
+				  /*c_cast_p=*/false,
+				  LOOKUP_SPECULATIVE);
+      if (!conv)
+	expr = error_mark_node;
+      else
+	expr = convert_like_real (conv, expr, NULL_TREE, 0, 0,
+				  /*issue_conversion_warnings=*/true,
+				  /*c_cast_p=*/false, tf_none,
+				  LOOKUP_SPECULATIVE);
+
+      /* Free all the conversions we allocated.  */
+      obstack_free (&conversion_obstack, p);
+
+      return expr == error_mark_node ? false : true;
+    }
+}
+
 /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE.  The reference
    is being bound to a temporary.  Create and return a new VAR_DECL
    with the indicated TYPE; this variable will store the value to
@@ -7909,7 +7948,8 @@  initialize_reference (tree type, tree expr, tree d
 				/*inner=*/-1,
 				/*issue_conversion_warnings=*/true,
 				/*c_cast_p=*/false,
-				tf_warning_or_error);
+				tf_warning_or_error,
+				LOOKUP_NORMAL);
       if (error_operand_p (expr))
 	expr = error_mark_node;
       else
Index: gcc/cp/cvt.c
===================================================================
--- gcc/cp/cvt.c	(revision 161990)
+++ gcc/cp/cvt.c	(working copy)
@@ -176,7 +176,7 @@  cp_convert_to_pointer (tree type, tree expr)
   else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
 	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
     return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
-			   /*c_cast_p=*/false);
+			   /*c_cast_p=*/false, tf_warning_or_error);
   else if (TYPE_PTRMEMFUNC_P (intype))
     {
       if (!warn_pmf2ptr)
@@ -200,7 +200,7 @@  cp_convert_to_pointer (tree type, tree expr)
     {
       if (TYPE_PTRMEMFUNC_P (type))
 	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
-				 /*c_cast_p=*/false);
+				 /*c_cast_p=*/false, tf_warning_or_error);
 
       if (TYPE_PTRMEM_P (type))
 	{
@@ -1376,7 +1376,7 @@  convert_force (tree type, tree expr, int convtype)
       && TYPE_PTRMEMFUNC_P (type))
     /* compatible pointer to member functions.  */
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
-			     /*c_cast_p=*/1);
+			     /*c_cast_p=*/1, tf_warning_or_error);
 
   return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
 }
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 161990)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4629,6 +4629,7 @@  extern tree perform_implicit_conversion		(tree, tr
 extern tree perform_implicit_conversion_flags	(tree, tree, tsubst_flags_t, int);
 extern tree perform_direct_initialization_if_possible (tree, tree, bool,
                                                        tsubst_flags_t);
+extern bool trait_is_convertible_to             (tree, tree);
 extern tree in_charge_arg_for_name		(tree);
 extern tree build_cxx_call			(tree, int, tree *);
 extern bool is_std_init_list			(tree);
@@ -5483,7 +5484,8 @@  extern int comp_ptr_ttypes			(tree, tree);
 extern bool comp_ptr_ttypes_const		(tree, tree);
 extern bool error_type_p			(const_tree);
 extern int ptr_reasonably_similar		(const_tree, const_tree);
-extern tree build_ptrmemfunc			(tree, tree, int, bool);
+extern tree build_ptrmemfunc			(tree, tree, int, bool,
+						 tsubst_flags_t);
 extern int cp_type_quals			(const_tree);
 extern int type_memfn_quals			(const_tree);
 extern tree apply_memfn_quals			(tree, cp_cv_quals);
@@ -5512,7 +5514,8 @@  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_ptrmem			(tree, tree, bool, bool);
+extern tree convert_ptrmem			(tree, tree, bool, bool,
+						 tsubst_flags_t);
 extern int lvalue_or_else			(tree, enum lvalue_use,
                                                  tsubst_flags_t);
 extern void check_template_keyword		(tree);
Index: libstdc++-v3/include/std/type_traits
===================================================================
--- libstdc++-v3/include/std/type_traits	(revision 161990)
+++ libstdc++-v3/include/std/type_traits	(working copy)
@@ -306,31 +306,10 @@  namespace std
     : public integral_constant<bool, __is_base_of(_Base, _Derived)>
     { };
 
-  template<typename _From, typename _To,
-	   bool = (is_void<_From>::value || is_void<_To>::value
-		   || is_function<_To>::value || is_array<_To>::value)>
-    struct __is_convertible_helper
-    { static const bool __value = (is_void<_From>::value
-				   && is_void<_To>::value); };
-
-  template<typename _From, typename _To>
-    class __is_convertible_helper<_From, _To, false>
-    : public __sfinae_types
-    {
-      static __one __test(_To);
-      static __two __test(...);
-
-    public:
-      static const bool __value = sizeof(__test(declval<_From>())) == 1;
-    };
-
   /// is_convertible
-  // XXX FIXME
-  // The C++0x specifications require front-end support, see N2255.
   template<typename _From, typename _To>
     struct is_convertible
-    : public integral_constant<bool,
-			       __is_convertible_helper<_From, _To>::__value>
+    : public integral_constant<bool, __is_convertible_to(_From, _To)>
     { };
 
   /// is_explicitly_convertible
Index: libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(revision 161990)
+++ libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@  void test01()
 // { dg-error "instantiated from here" "" { target *-*-* } 40 }
 // { dg-error "instantiated from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 639 }
-// { dg-error "declaration of" "" { target *-*-* } 603 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 618 }
+// { dg-error "declaration of" "" { target *-*-* } 582 }
Index: libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(revision 161990)
+++ libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@  void test01()
 // { dg-error "instantiated from here" "" { target *-*-* } 40 }
 // { dg-error "instantiated from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 562 }
-// { dg-error "declaration of" "" { target *-*-* } 526 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 541 }
+// { dg-error "declaration of" "" { target *-*-* } 505 }
Index: libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc	(revision 161990)
+++ libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc	(working copy)
@@ -19,7 +19,7 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 676 }
+// { dg-error "static assertion failed" "" { target *-*-* } 655 }
 
 #include <utility>